diff --git a/services/web/app/views/project/editor.jade b/services/web/app/views/project/editor.jade
index 5e7df86ffd..55df72976b 100644
--- a/services/web/app/views/project/editor.jade
+++ b/services/web/app/views/project/editor.jade
@@ -40,125 +40,10 @@ block content
i.fa.fa-comment
#editor-content(ng-cloak, layout="main", ng-hide="state.loading")
- aside#file-tree.ui-layout-west(ng-controller="FileTreeController")
- .toolbar.toolbar-small
- a(
- href,
- ng-click="openNewDocModal()",
- tooltip-html-unsafe="New
File",
- tooltip-placement="bottom"
- )
- i.fa.fa-file
- a(
- href,
- ng-click="openNewFolderModal()",
- tooltip="New Folder",
- tooltip-placement="bottom"
- )
- i.fa.fa-folder
- a(href, tooltip="Upload File", tooltip-placement="bottom")
- i.fa.fa-upload
-
- .toolbar-right
- a(href, tooltip="Rename", tooltip-placement="bottom")
- i.fa.fa-pencil
- a(href, tooltip="Delete", tooltip-placement="bottom", tooltip-append-to-body="true")
- i.fa.fa-trash-o
-
- ul.list-unstyled.file-tree-list
- file-entity(
- entity="entity",
- ng-repeat="entity in rootFolder.children | orderBy:[orderByFoldersFirst, 'name']"
- )
+ include ./editor/file-tree
+
.ui-layout-center
- script(type='text/ng-template', id='entityListItemTemplate')
- li(
- ng-class="{ 'selected': entity.selected }",
- ng-controller="FileTreeEntityController"
- )
- .entity(ng-if="entity.type == 'doc'")
- .entity-name(ng-click="select()")
- //- Just a spacer to align with folders
- i.fa.fa-fw.toggle
- i.fa.fa-fw.fa-file
- | {{ entity.name }}
-
- .entity(ng-if="entity.type == 'file'")
- .entity-name(ng-click="select()")
- i.fa.fa-fw.toggle
- i.fa.fa-fw.fa-image
- | {{ entity.name }}
-
- .entity(ng-if="entity.type == 'folder'", ng-controller="FileTreeFolderController")
- .entity-name
- i.fa.fa-fw.toggle(
- ng-class="{'fa-chevron-right': !expanded, 'fa-chevron-down': expanded}"
- ng-click="toggleExpanded()"
- )
-
- i.fa.fa-fw(
- ng-class="{\
- 'fa-folder': !expanded, \
- 'fa-folder-open': expanded \
- }"
- ng-click="select()"
- )
- span(ng-click="select()") {{ entity.name }}
-
- ul.list-unstyled(ng-show="expanded")
- file-entity(entity="child", ng-repeat="child in entity.children | orderBy:[orderByFoldersFirst, 'name']")
-
- script(type='text/ng-template', id='newDocModalTemplate')
- .modal-header
- h3 New File
- .modal-body
- form(novalidate, name="newDocForm")
- input.form-control(
- type="text",
- placeholder="File Name",
- required,
- ng-model="inputs.name",
- ng-enter="create()",
- focus-on="open"
- )
- .modal-footer
- button.btn.btn-default(
- ng-disabled="state.inflight"
- ng-click="cancel()"
- ) Cancel
- button.btn.btn-primary(
- ng-disabled="newDocForm.$invalid || state.inflight"
- ng-click="create()"
- )
- span(ng-hide="state.inflight") Create
- span(ng-show="state.inflight") Creating...
-
- script(type='text/ng-template', id='newFolderModalTemplate')
- .modal-header
- h3 New File
- .modal-body
- form(novalidate, name="newFolderForm")
- input.form-control(
- type="text",
- placeholder="Folder Name",
- required,
- ng-model="inputs.name",
- ng-enter="create()",
- focus-on="open"
- )
- .modal-footer
- button.btn.btn-default(
- ng-disabled="state.inflight"
- ng-click="cancel()"
- ) Cancel
- button.btn.btn-primary(
- ng-disabled="newFolderForm.$invalid || state.inflight"
- ng-click="create()"
- )
- span(ng-hide="state.inflight") Create
- span(ng-show="state.inflight") Creating...
-
//- #loadingScreen
//- h3 Loading...
//- p#loadingMessage Loading editor
diff --git a/services/web/app/views/project/editor/file-tree.jade b/services/web/app/views/project/editor/file-tree.jade
new file mode 100644
index 0000000000..1120f16906
--- /dev/null
+++ b/services/web/app/views/project/editor/file-tree.jade
@@ -0,0 +1,143 @@
+aside#file-tree.ui-layout-west(ng-controller="FileTreeController")
+ .toolbar.toolbar-small
+ a(
+ href,
+ ng-click="openNewDocModal()",
+ tooltip-html-unsafe="New
File",
+ tooltip-placement="bottom"
+ )
+ i.fa.fa-file
+ a(
+ href,
+ ng-click="openNewFolderModal()",
+ tooltip="New Folder",
+ tooltip-placement="bottom"
+ )
+ i.fa.fa-folder
+ a(
+ href,
+ ng-click="openUploadFileModal()",
+ tooltip="Upload",
+ tooltip-placement="bottom"
+ )
+ i.fa.fa-upload
+
+ .toolbar-right
+ a(href, tooltip="Rename", tooltip-placement="bottom")
+ i.fa.fa-pencil
+ a(href, tooltip="Delete", tooltip-placement="bottom", tooltip-append-to-body="true")
+ i.fa.fa-trash-o
+
+ ul.list-unstyled.file-tree-list
+ file-entity(
+ entity="entity",
+ ng-repeat="entity in rootFolder.children | orderBy:[orderByFoldersFirst, 'name']"
+ )
+
+
+script(type='text/ng-template', id='entityListItemTemplate')
+ li(
+ ng-class="{ 'selected': entity.selected }",
+ ng-controller="FileTreeEntityController"
+ )
+ .entity(ng-if="entity.type == 'doc'")
+ .entity-name(ng-click="select()")
+ //- Just a spacer to align with folders
+ i.fa.fa-fw.toggle
+ i.fa.fa-fw.fa-file
+ | {{ entity.name }}
+
+ .entity(ng-if="entity.type == 'file'")
+ .entity-name(ng-click="select()")
+ i.fa.fa-fw.toggle
+ i.fa.fa-fw.fa-image
+ | {{ entity.name }}
+
+ .entity(ng-if="entity.type == 'folder'", ng-controller="FileTreeFolderController")
+ .entity-name
+ i.fa.fa-fw.toggle(
+ ng-class="{'fa-chevron-right': !expanded, 'fa-chevron-down': expanded}"
+ ng-click="toggleExpanded()"
+ )
+
+ i.fa.fa-fw(
+ ng-class="{\
+ 'fa-folder': !expanded, \
+ 'fa-folder-open': expanded \
+ }"
+ ng-click="select()"
+ )
+ span(ng-click="select()") {{ entity.name }}
+
+ ul.list-unstyled(ng-show="expanded")
+ file-entity(entity="child", ng-repeat="child in entity.children | orderBy:[orderByFoldersFirst, 'name']")
+
+script(type='text/ng-template', id='newDocModalTemplate')
+ .modal-header
+ h3 New File
+ .modal-body
+ form(novalidate, name="newDocForm")
+ input.form-control(
+ type="text",
+ placeholder="File Name",
+ required,
+ ng-model="inputs.name",
+ ng-enter="create()",
+ focus-on="open"
+ )
+ .modal-footer
+ button.btn.btn-default(
+ ng-disabled="state.inflight"
+ ng-click="cancel()"
+ ) Cancel
+ button.btn.btn-primary(
+ ng-disabled="newDocForm.$invalid || state.inflight"
+ ng-click="create()"
+ )
+ span(ng-hide="state.inflight") Create
+ span(ng-show="state.inflight") Creating...
+
+script(type='text/ng-template', id='newFolderModalTemplate')
+ .modal-header
+ h3 New File
+ .modal-body
+ form(novalidate, name="newFolderForm")
+ input.form-control(
+ type="text",
+ placeholder="Folder Name",
+ required,
+ ng-model="inputs.name",
+ ng-enter="create()",
+ focus-on="open"
+ )
+ .modal-footer
+ button.btn.btn-default(
+ ng-disabled="state.inflight"
+ ng-click="cancel()"
+ ) Cancel
+ button.btn.btn-primary(
+ ng-disabled="newFolderForm.$invalid || state.inflight"
+ ng-click="create()"
+ )
+ span(ng-hide="state.inflight") Create
+ span(ng-show="state.inflight") Creating...
+
+script(type="text/ng-template", id="uploadFileModalTemplate")
+ .modal-header
+ h3 Upload File(s)
+ .modal-body(
+ fine-upload
+ endpoint="/project/{{ project_id }}/upload"
+ waiting-for-response-text="Inserting file..."
+ failed-upload-text="Upload failed, sorry :("
+ upload-button-text="Select file(s)"
+ drag-area-text="drag file(s)"
+ hint-text="Hint: Press and hold the Control (Ctrl) key to select multiple files"
+ multiple="true"
+ on-complete-callback="onComplete"
+ on-upload-callback="onUpload"
+ params="{'folder_id': parent_folder_id}"
+ )
+ span Upload file(s)
+ .modal-footer
+ button.btn.btn-default(ng-click="cancel()") Cancel
diff --git a/services/web/app/views/project/list.jade b/services/web/app/views/project/list.jade
index db48e620ba..0c103ff9e5 100644
--- a/services/web/app/views/project/list.jade
+++ b/services/web/app/views/project/list.jade
@@ -419,7 +419,17 @@ block content
script(type="text/ng-template", id="uploadProjectModalTemplate")
.modal-header
h3 Upload Zipped Project
- .modal-body(ng-fine-upload)
+ .modal-body(
+ fine-upload
+ endpoint="/project/new/upload"
+ waiting-for-response-text="Creating project..."
+ failed-upload-text="Upload failed. Is it a valid zip file?"
+ upload-button-text="Select a .zip file"
+ drag-area-text="drag .zip file"
+ multiple="false"
+ allowed-extensions="['zip']"
+ on-complete-callback="onComplete"
+ )
span Upload a zipped project
.modal-footer
button.btn.btn-default(ng-click="cancel()") Cancel
diff --git a/services/web/app/views/project/partials/manage.jade b/services/web/app/views/project/partials/manage.jade
deleted file mode 100644
index 000f34daf4..0000000000
--- a/services/web/app/views/project/partials/manage.jade
+++ /dev/null
@@ -1,76 +0,0 @@
-.box
- .page-header
- h2 Project Settings
- .tabbable
- ul.nav.nav-tabs
- li.active
- a(href='#generalProjectSettings', data-toggle="tab") General
- li
- a(href='#exportSettings', data-toggle="tab") Export & Copy
- li
- a(href='#deleteProjectTab', data-toggle="tab") Delete Project
- li#manageDropboxSettiingsTabLink
- a(href='#dropboxProjectSettings', data-toggle='tab') Dropbox
- span.label.label-warning beta
-
- .tab-content.form-horizontal
- .tab-pane#generalProjectSettings.form.form-horizontal.active
- if privilegeLevel == 'owner' || privilegeLevel == 'readAndWrite'
- .control-group
- label(for='xlInput').control-label Project Name
- .controls
- .input
- input.projectName(type='text', value=project.name)
-
- .control-group
- label(for='input').control-label Root Document
- .controls
- .input
- select#rootDocList
-
- .control-group
- label(for='spellCheck').control-label
- | Spell check
- .controls
- select(name="spellCheckLanguage")#spellCheckLanguageSelection
- option(value="",selected=(project.spellCheckLanguage == "")) Off
- optgroup(label="Language")
- for language in languages
- option(
- value=language.code,
- selected=(language.code == project.spellCheckLanguage)
- )= language.name
-
- .control-group#multipleCompilers
- label(for='input').control-label Compiler
- .controls
- .input
- select#compilers
- option(value='latex') LaTeX
- option(value='pdflatex') pdfLaTeX
- option(value='xelatex') XeLaTeX
- option(value='lualatex') LuaLaTeX
- else
- span You do not have permission to modify these settings.
-
- if privilegeLevel == 'owner'
- .control-group
- label(for='select').control-label Public Access
- .controls
- select#publicAccessLevel
- option(value='private') Private
- option(value='readOnly') Public - Read Only
- option(value='readAndWrite') Public - Read and Write
-
- .tab-pane#exportSettings
- a.btn#DownloadZip Download Project as Zip
- div
- a.btn(href='/project/'+project._id+'/clone').cloneProject Clone Project
-
- .tab-pane#deleteProjectTab
- if privilegeLevel == 'owner'
- button#deleteProject.btn.btn-danger Delete Project
- else
- span You do not have permission to modify these settings.
-
- .tab-pane#dropboxProjectSettings
diff --git a/services/web/app/views/project/partials/pdf.jade b/services/web/app/views/project/partials/pdf.jade
deleted file mode 100644
index 8b8118549a..0000000000
--- a/services/web/app/views/project/partials/pdf.jade
+++ /dev/null
@@ -1,38 +0,0 @@
-#controls
- button#previous
- img(src='images/go-up.svg', align='top', height='32')
- | Previous
- button#next
- img(src='images/go-down.svg', align='top', height='32')
- | Next
- .separator
- input#pageNumber(type='number', value='1', size='4', min='1')
- span /
- span#numPages --
- .separator
- button#next(title='Zoom Out')
- img(src='images/zoom-out.svg', align='top', height='32')
- button#next(title='Zoom In')
- img(src='images/zoom-in.svg', align='top', height='32')
- .separator
- select#scaleSelect
- option#customScaleOption(value='custom')
- option(value='0.5') 50%
- option(value='0.75') 75%
- option(value='1') 100%
- option(value='1.25') 125%
- option(value='1.5', selected='selected') 150%
- option(value='2') 200%
- option#pageWidthOption(value='page-width') Page Width
- option#pageFitOption(value='page-fit') Page Fit
- .separator
- button#print
- img(src='images/document-print.svg', align='top', height='32')
- | Print
- .separator
- input#fileInput(type='file')
- .separator
- span#info --
-#loading Loading... 0%
-#viewer
-
diff --git a/services/web/public/coffee/app/directives/fineUpload.coffee b/services/web/public/coffee/app/directives/fineUpload.coffee
new file mode 100644
index 0000000000..287edbb8b1
--- /dev/null
+++ b/services/web/public/coffee/app/directives/fineUpload.coffee
@@ -0,0 +1,69 @@
+define [
+ "base"
+ "../../libs/fineuploader"
+], (App) ->
+ App.directive 'fineUpload', ($timeout) ->
+ return {
+ scope: {
+ multiple: "="
+ endpoint: "@"
+ waitingForResponseText: "@"
+ failedUploadText: "@"
+ uploadButtonText: "@"
+ dragAreaText: "@"
+ hintText: "@"
+ allowedExtensions: "="
+ onCompleteCallback: "="
+ onUploadCallback: "="
+ params: "="
+ }
+ link: (scope, element, attrs) ->
+ multiple = scope.multiple or false
+ endpoint = scope.endpoint
+ if scope.allowedExtensions?
+ validation =
+ allowedExtensions: scope.allowedExtensions
+ else
+ validation = {}
+ text =
+ waitingForResponse: scope.waitingForResponseText or "Processing..."
+ failUpload: scope.failedUploadText or "Failed :("
+ uploadButton: scope.uploadButtonText or "Upload"
+ dragAreaText = scope.dragAreaText or "drag here"
+ hintText = scope.hintText or ""
+
+ onComplete = scope.onCompleteCallback or () ->
+ onUpload = scope.onUploadCallback or () ->
+ params = scope.params or {}
+ params._csrf = window.csrfToken
+
+ console.log "PARAMS", params
+
+ new qq.FineUploader
+ element: element[0]
+ multiple: multiple
+ disabledCancelForFormUploads: true
+ validation: validation
+ request:
+ endpoint: endpoint
+ forceMultipart: true
+ params: params
+ paramsInBody: false
+ callbacks:
+ onComplete: onComplete
+ onUpload: onUpload
+ text: text
+ template: """
+