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: """ +
+
{dragZoneText}
+
+
{uploadButtonText}
+
+ or + #{dragAreaText} + {dropProcessingText} +
#{hintText}
+ +
+ """ + } \ No newline at end of file diff --git a/services/web/public/coffee/app/ide.coffee b/services/web/public/coffee/app/ide.coffee index 5e3b398c43..9813673187 100644 --- a/services/web/public/coffee/app/ide.coffee +++ b/services/web/public/coffee/app/ide.coffee @@ -4,6 +4,7 @@ define [ "ide/directives/layout" "ide/services/ide" "directives/focusOn" + "directives/fineUpload" ], ( App FileTreeManager @@ -16,7 +17,7 @@ define [ window._ide = ide - ide.project_id = window.project_id + ide.project_id = $scope.project_id = window.project_id ide.$scope = $scope ide.socket = io.connect null, reconnect: false diff --git a/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee b/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee index 52acc80ecd..433db9e7c7 100644 --- a/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee @@ -97,7 +97,11 @@ define [ return folder - getCurrentFolder: (startFolder = @$scope.rootFolder) -> + getCurrentFolder: () -> + # Return the root folder if nothing is selected + @_getCurrentFolder(@$scope.rootFolder) or @$scope.rootFolder + + _getCurrentFolder: (startFolder = @$scope.rootFolder) -> for entity in startFolder.children or [] # The 'current' folder is either the one selected, or # the one containing the selected doc/file @@ -108,7 +112,7 @@ define [ return startFolder if entity.type == "folder" - result = @getCurrentFolder(entity) + result = @_getCurrentFolder(entity) return result if result? return null diff --git a/services/web/public/coffee/app/ide/file-tree/controllers/FileTreeController.coffee b/services/web/public/coffee/app/ide/file-tree/controllers/FileTreeController.coffee index f5bf3c889e..72911bf557 100644 --- a/services/web/public/coffee/app/ide/file-tree/controllers/FileTreeController.coffee +++ b/services/web/public/coffee/app/ide/file-tree/controllers/FileTreeController.coffee @@ -14,6 +14,13 @@ define [ controller: "NewFolderModalController" ) + $scope.openUploadFileModal = () -> + $modal.open( + templateUrl: "uploadFileModalTemplate" + controller: "UploadFileModalController" + scope: $scope + ) + $scope.orderByFoldersFirst = (entity) -> return 0 if entity.type == "folder" return 1 @@ -61,6 +68,27 @@ define [ $scope.state.inflight = false $modalInstance.close() + $scope.cancel = () -> + $modalInstance.dismiss('cancel') + ] + + App.controller "UploadFileModalController", [ + "$scope", "ide", "$modalInstance", "$timeout", + ($scope, ide, $modalInstance, $timeout) -> + parent_folder = ide.fileTreeManager.getCurrentFolder() + $scope.parent_folder_id = parent_folder?.id + + uploadCount = 0 + $scope.onUpload = () -> + uploadCount++ + + $scope.onComplete = (error, name, response) -> + $timeout (() -> + uploadCount-- + if uploadCount == 0 and response? and response.success + $modalInstance.close("done") + ), 250 + $scope.cancel = () -> $modalInstance.dismiss('cancel') ] \ No newline at end of file diff --git a/services/web/public/coffee/app/main.coffee b/services/web/public/coffee/app/main.coffee index 9a8651e1e0..be794fd018 100644 --- a/services/web/public/coffee/app/main.coffee +++ b/services/web/public/coffee/app/main.coffee @@ -7,5 +7,6 @@ define [ "directives/focusInput" "directives/focusOn" "directives/equals" + "directives/fineUpload" ], () -> angular.bootstrap(document.body, ["SharelatexApp"]) \ No newline at end of file diff --git a/services/web/public/coffee/app/project-list.coffee b/services/web/public/coffee/app/project-list.coffee index ffe8d130ba..8e442dee10 100644 --- a/services/web/public/coffee/app/project-list.coffee +++ b/services/web/public/coffee/app/project-list.coffee @@ -1,6 +1,5 @@ define [ "base" - "../libs/fineuploader" ], (App) -> App.directive 'ngEnter', () -> return (scope, element, attrs) -> @@ -10,7 +9,6 @@ define [ scope.$eval(attrs.ngEnter, event: event) event.preventDefault() - App.filter "formatDate", () -> (date, format = "Do MMM YYYY, h:mm a") -> moment(date).format(format) @@ -607,40 +605,11 @@ define [ $scope.cancel = () -> $modalInstance.dismiss('cancel') - App.directive 'ngFineUpload', ($timeout) -> - return (scope, element, attrs) -> - new qq.FineUploader - element: element[0] - multiple: false - disabledCancelForFormUploads: true - validation: - allowedExtensions: ["zip"] - request: - endpoint: "/project/new/upload" - forceMultipart: true - params: - _csrf: window.csrfToken - callbacks: - onComplete: (error, name, response)-> - if response.project_id? - window.location = '/project/'+response.project_id - text: - waitingForResponse: "Creating project..." - failUpload: "Upload failed. Is it a valid zip file?" - uploadButton: "Select a .zip file" - template: """ -
-
{dragZoneText}
-
-
{uploadButtonText}
-
- or - drag a .zip file - {dropProcessingText} - -
- """ App.controller 'UploadProjectModalController', ($scope, $modalInstance, $timeout) -> $scope.cancel = () -> $modalInstance.dismiss('cancel') + + $scope.onComplete = (error, name, response) -> + if response.project_id? + window.location = '/project/' + response.project_id