From 32d1642b9e0642520c962e303bf406067128353e Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 11:35:32 +0100 Subject: [PATCH 01/15] Get basic compile/errors/autocompile working --- .../web/app/views/project/editor/pdf.jade | 40 +++++++++++++--- .../app/ide/editor/EditorManager.coffee | 8 ++++ .../ide/pdf/controllers/PdfController.coffee | 48 ++++++++++++++----- .../public/stylesheets/app/editor/pdf.less | 30 +++++++++--- 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 567053699f..34df057a85 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -14,17 +14,20 @@ div.full-size(ng-controller="PdfController") a.log-btn( href ng-click="toggleLogs()" - ng-class="{ 'active': pdf.view == 'logs' }" + ng-class="{ 'active': (pdf.view == 'logs' || pdf.failure) && !pdf.error && !pdf.timeout && !pdf.uncompiled }" tooltip="Logs" tooltip-placement="bottom" ) i.fa.fa-file-text-o - span.label.label-danger(ng-show="pdf.logEntries.errors.length > 0") - | {{ pdf.logEntries.errors.length }} - span.label.label-warning(ng-show="pdf.logEntries.warnings.length > 0") - | {{ pdf.logEntries.warnings.length }} + span.label( + ng-show="pdf.logEntries.warnings.length + pdf.logEntries.errors.length > 0" + ng-class="{\ + 'label-warning': pdf.logEntries.errors.length == 0,\ + 'label-danger': pdf.logEntries.errors.length > 0\ + }" + ) {{ pdf.logEntries.errors.length + pdf.logEntries.warnings.length }} - .pdf-viewer(ng-show="pdf.url && pdf.view == 'pdf'") + .pdf-viewer(ng-show="pdf.url && pdf.view == 'pdf' && !pdf.failure && !pdf.timeout && !pdf.error") div( pdfjs pdf-src="pdf.url" @@ -32,7 +35,30 @@ div.full-size(ng-controller="PdfController") resize-on="layout:main:resize,layout:pdf:resize" ) - .logs(ng-show="pdf.view == 'logs'") + .pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling") + |   + i.fa.fa-level-up.fa-flip-horizontal.fa-2x + |   Click here to preview your work as a PDF. + + .pdf-errors(ng-show="pdf.timeout || pdf.error") + .alert.alert-danger(ng-show="pdf.error") + strong Server Error. + span Sorry, something went wrong and your project could not be compiled. Please try again in a few moments. + + .alert.alert-danger(ng-show="pdf.timeout") + strong Timed out. + span Sorry, your compile was taking too long and timed out. + | This may be due to a large number of high-res images, or lots of complicated diagrams. + | Please try to make your document simpler, or contact support for help. + + .pdf-logs(ng-show="(pdf.view == 'logs' || pdf.failure) && !pdf.error && !pdf.timeout && !pdf.uncompiled") + .alert.alert-success(ng-show="pdf.logEntries.all.length == 0") + | No errors, good job! + + .alert.alert-danger(ng-show="pdf.failure") + strong Compile Error. + span Sorry, your LaTeX code couldn't compile for some reason. Please check the errors below for details, or view the raw log. + div(ng-repeat="entry in pdf.logEntries.all") .alert( ng-class="{\ diff --git a/services/web/public/coffee/app/ide/editor/EditorManager.coffee b/services/web/public/coffee/app/ide/editor/EditorManager.coffee index 948cf292a0..09dc79bbdb 100644 --- a/services/web/public/coffee/app/ide/editor/EditorManager.coffee +++ b/services/web/public/coffee/app/ide/editor/EditorManager.coffee @@ -49,6 +49,8 @@ define [ @ide.showGenericServerErrorMessage() return + @$scope.$broadcast "doc:opened" + @$scope.$apply () => @$scope.editor.opening = false @$scope.editor.sharejs_doc = sharejs_doc @@ -93,3 +95,9 @@ define [ lastUpdated: () -> @$scope.editor.last_updated + + getCurrentDocValue: () -> + @$scope.editor.sharejs_doc?.getSnapshot() + + getCurrentDocId: () -> + @$scope.editor.open_doc_id diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 33ebef8c32..ba8693e3cd 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -2,7 +2,7 @@ define [ "base" "libs/latex-log-parser" ], (App, LogParser) -> - App.controller "PdfController", ["$scope", "$http", ($scope, $http) -> + App.controller "PdfController", ["$scope", "$http", "ide", ($scope, $http, ide) -> $scope.pdf = url: null # Pdf Url view: null # 'pdf' 'logs' @@ -10,28 +10,38 @@ define [ timeout: false # Server timed out failure: false # PDF failed to compile compiling: false + uncompiled: true logEntries: [] + autoCompile = true + $scope.$on "doc:opened", () -> + console.log "DOC OPENED" + return if !autoCompile + autoCompile = false + $scope.recompile(isAutoCompile: true) + sendCompileRequest = (options = {}) -> url = "/project/#{$scope.project_id}/compile" if options.isAutoCompile url += "?auto_compile=true" return $http.post url, { - rootDoc_id: options.rootDocOverride_id or null + settingsOverride: + rootDoc_id: options.rootDocOverride_id or null _csrf: window.csrfToken } parseCompileResponse = (response) -> # Reset everything - $scope.pdf.error = false - $scope.pdf.timedout = false - $scope.pdf.failure = false - $scope.pdf.url = null + $scope.pdf.error = false + $scope.pdf.timedout = false + $scope.pdf.failure = false + $scope.pdf.uncompiled = false + $scope.pdf.url = null if response.status == "timedout" $scope.pdf.timedout = true else if response.status == "autocompile-backoff" - # Nothing to do + $scope.pdf.uncompiled = true else if response.status == "failure" $scope.pdf.failure = true fetchLogs() @@ -48,14 +58,28 @@ define [ for entry in logEntries.all entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "") entry.file = entry.file.replace(/^\/compile\//, "") - console.log "LOG", logEntries + .error () -> + $scope.pdf.logEntries = [] - $scope.recompile = () -> - console.log "Recompiling" + getRootDocOverride_id = () -> + doc = ide.editorManager.getCurrentDocValue() + return null if !doc? + for line in doc.split("\n") + match = line.match /(.*)\\documentclass/ + if match and !match[1].match /%/ + return ide.editorManager.getCurrentDocId() + return null + + $scope.recompile = (options = {}) -> + console.log "Recompiling", options return if $scope.pdf.compiling $scope.pdf.compiling = true - sendCompileRequest() + + options.rootDocOverride_id = getRootDocOverride_id() + + sendCompileRequest(options) .success (data) -> + $scope.pdf.view = "pdf" $scope.pdf.compiling = false parseCompileResponse(data) .error () -> @@ -63,7 +87,7 @@ define [ $scope.pdf.error = true $scope.toggleLogs = () -> - if $scope.pdf.view == "pdf" + if !$scope.pdf.view? or $scope.pdf.view == "pdf" $scope.pdf.view = "logs" else $scope.pdf.view = "pdf" diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index 8eadf940a7..1a719e5470 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -1,8 +1,18 @@ -.pdf-viewer, .logs { +.pdf-viewer, .pdf-logs, .pdf-errors, .pdf-uncompiled { .full-size; top: 58px; } +.pdf-logs, .pdf-errors, .pdf-uncompiled { + padding: @line-height-computed / 2; +} + +.pdf-uncompiled { + .fa { + color: @blue; + } +} + .pdf-viewer { .pdfjs-viewer { .full-size; @@ -59,16 +69,22 @@ } .log-btn { + position: relative; .label { - margin-left: .4em; - padding: .2em .4em .3em; - vertical-align: text-bottom; - line-height: inherit; + position: absolute; + top: 0; + right: 0; + padding: .15em .6em .2em; + font-size: 60%; + } + &.active, &:active { + .label { + display: none; + } } } -.logs { - padding: @line-height-computed / 2; +.pdf-logs { overflow: auto; .alert { font-size: 0.9rem; From aee7b5477b97412153d5b76785a6aba6472a67ac Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 12:05:43 +0100 Subject: [PATCH 02/15] View raw log and download aux files --- .../web/app/views/project/editor/pdf.jade | 29 ++++++++++++++++--- .../ide/pdf/controllers/PdfController.coffee | 24 +++++++++++++-- .../public/stylesheets/app/editor/pdf.less | 6 ++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 34df057a85..49aa59d164 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -75,9 +75,30 @@ div.full-size(ng-controller="PdfController") p .pull-right - a.btn.btn-default.btn-sm(href) Other logs & files - |   - a.btn.btn-default.btn-sm(href, tooltip="Clear cached files", tooltip-placement="top") + a.btn.btn-default.btn-sm( + href, + tooltip="Clear cached files", + tooltip-placement="top", + tooltip-append-to-body="true" + ) i.fa.fa-trash-o - a.btn.btn-info.btn-sm(href) View Raw Logs + |   + div.dropdown(style="display: inline-block;") + a.btn.btn-default.btn-sm( + href + data-toggle="dropdown" + ) + | Other logs & files + span.caret + ul.dropdown-menu.dropdown-menu-right + li(ng-repeat="file in pdf.outputFiles") + a( + href="/project/{{project_id}}/output/{{file.path}}" + target="_blank" + ng-click="openOutputFile(file)" + ) {{ file.name }} + a.btn.btn-info.btn-sm(href, ng-click="toggleRawLog()") + span(ng-show="!pdf.showRawLog") View Raw Logs + span(ng-show="pdf.showRawLog") Hide Raw Logs + pre(ng-bind="pdf.rawLog", ng-show="pdf.showRawLog") diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index ba8693e3cd..f3dc9d485d 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -5,17 +5,18 @@ define [ App.controller "PdfController", ["$scope", "$http", "ide", ($scope, $http, ide) -> $scope.pdf = url: null # Pdf Url - view: null # 'pdf' 'logs' error: false # Server error timeout: false # Server timed out failure: false # PDF failed to compile compiling: false uncompiled: true logEntries: [] + rawLog: "" + view: null # 'pdf' 'logs' + showRawLog: false autoCompile = true $scope.$on "doc:opened", () -> - console.log "DOC OPENED" return if !autoCompile autoCompile = false $scope.recompile(isAutoCompile: true) @@ -49,9 +50,21 @@ define [ $scope.pdf.url = "/project/#{$scope.project_id}/output/output.pdf?cache_bust=#{Date.now()}" fetchLogs() + IGNORE_FILES = ["output.fls", "output.fdb_latexmk"] + $scope.pdf.outputFiles = [] + for file in response.outputFiles + if IGNORE_FILES.indexOf(file.path) == -1 + # Turn 'output.blg' into 'blg file'. + if file.path.match(/^output\./) + file.name = "#{file.path.replace(/^output\./, "")} file" + else + file.name = file.path + $scope.pdf.outputFiles.push file + fetchLogs = () -> $http.get "/project/#{$scope.project_id}/output/output.log" .success (log) -> + $scope.pdf.rawLog = log logEntries = LogParser.parse(log, ignoreDuplicates: true) $scope.pdf.logEntries = logEntries $scope.pdf.logEntries.all = logEntries.errors.concat(logEntries.warnings).concat(logEntries.typesetting) @@ -60,6 +73,7 @@ define [ entry.file = entry.file.replace(/^\/compile\//, "") .error () -> $scope.pdf.logEntries = [] + $scope.pdf.rawLog = "" getRootDocOverride_id = () -> doc = ide.editorManager.getCurrentDocValue() @@ -94,4 +108,10 @@ define [ $scope.showPdf = () -> $scope.pdf.view = "pdf" + + $scope.toggleRawLog = () -> + $scope.pdf.showRawLog = !$scope.pdf.showRawLog + + $scope.openOutputFile = (file) -> + window.open("/project/#{$scope.project_id}/output/#{file.path}") ] \ No newline at end of file diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index 1a719e5470..ae8d026e75 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -104,5 +104,11 @@ //font-family: @font-family-monospace; } } + pre { + font-size: 12px; + } + .dropdown { + position: relative; + } } \ No newline at end of file From 8b6f962275efdddb5c844e4b7a4b81d9c68258a6 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 12:36:17 +0100 Subject: [PATCH 03/15] Allow clearing of aux files --- .../web/app/views/project/editor/pdf.jade | 22 ++++++++++++- .../ide/pdf/controllers/PdfController.coffee | 33 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 49aa59d164..b2b7fc9df2 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -79,7 +79,8 @@ div.full-size(ng-controller="PdfController") href, tooltip="Clear cached files", tooltip-placement="top", - tooltip-append-to-body="true" + tooltip-append-to-body="true", + ng-click="openClearCacheModal()" ) i.fa.fa-trash-o |   @@ -102,3 +103,22 @@ div.full-size(ng-controller="PdfController") span(ng-show="pdf.showRawLog") Hide Raw Logs pre(ng-bind="pdf.rawLog", ng-show="pdf.showRawLog") + +script(type='text/ng-template', id='clearCacheModalTemplate') + .modal-header + h3 Clear cache? + .modal-body + p This will clear all hidden LaTeX files (.aux, .bbl, etc) from our compile server. + | You generally don't need to do this unless you're having trouble with references. + p Your project files will not be deleted or changed. + .modal-footer + button.btn.btn-default( + ng-click="cancel()" + ng-disabled="state.inflight" + ) Cancel + button.btn.btn-info( + ng-click="clear()" + ng-disabled="state.inflight" + ) + span(ng-show="!state.inflight") Clear cache + span(ng-show="state.inflight") Clearing... diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index f3dc9d485d..6e31ee603f 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -2,7 +2,7 @@ define [ "base" "libs/latex-log-parser" ], (App, LogParser) -> - App.controller "PdfController", ["$scope", "$http", "ide", ($scope, $http, ide) -> + App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) -> $scope.pdf = url: null # Pdf Url error: false # Server error @@ -100,6 +100,14 @@ define [ $scope.pdf.compiling = false $scope.pdf.error = true + $scope.clearCache = () -> + $http { + url: "/project/#{$scope.project_id}/output" + method: "DELETE" + headers: + "X-Csrf-Token": window.csrfToken + } + $scope.toggleLogs = () -> if !$scope.pdf.view? or $scope.pdf.view == "pdf" $scope.pdf.view = "logs" @@ -114,4 +122,27 @@ define [ $scope.openOutputFile = (file) -> window.open("/project/#{$scope.project_id}/output/#{file.path}") + + $scope.openClearCacheModal = () -> + modalInstance = $modal.open( + templateUrl: "clearCacheModalTemplate" + controller: "ClearCacheModalController" + scope: $scope + ) + ] + + App.controller 'ClearCacheModalController', ["$scope", "$modalInstance", ($scope, $modalInstance) -> + $scope.state = + inflight: false + + $scope.clear = () -> + $scope.state.inflight = true + $scope + .clearCache() + .then () -> + $scope.state.inflight = false + $modalInstance.close() + + $scope.cancel = () -> + $modalInstance.dismiss('cancel') ] \ No newline at end of file From 797dcf5c840b61635bc13e3966ec70b8fab8a078 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 13:41:32 +0100 Subject: [PATCH 04/15] Jump to error when clicking on log entry --- .../web/app/views/project/editor/editor.jade | 6 +- .../web/app/views/project/editor/pdf.jade | 3 +- .../views/project/editor/track-changes.jade | 2 +- .../app/ide/editor/EditorManager.coffee | 15 +- .../CursorPositionManager.coffee | 12 +- .../ide/editor/directives/aceEditor.coffee | 21 +- .../highlights/HighlightsManager.coffee | 224 ++++++++++++++++++ .../app/ide/file-tree/FileTreeManager.coffee | 15 ++ .../online-users/OnlineUsersManager.coffee | 8 +- .../coffee/app/ide/pdf/PdfManager.coffee | 14 +- .../ide/pdf/controllers/PdfController.coffee | 34 ++- .../track-changes/TrackChangesManager.coffee | 12 +- .../public/stylesheets/app/editor/pdf.less | 1 + 13 files changed, 330 insertions(+), 37 deletions(-) create mode 100644 services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee diff --git a/services/web/app/views/project/editor/editor.jade b/services/web/app/views/project/editor/editor.jade index 394d432c27..3956b417fa 100644 --- a/services/web/app/views/project/editor/editor.jade +++ b/services/web/app/views/project/editor/editor.jade @@ -16,12 +16,14 @@ div.full-size( font-size="settings.fontSize", auto-complete="settings.autoComplete", spell-check-language="project.spellCheckLanguage", - annotations="onlineUserCursorAnnotations[editor.open_doc_id]" + highlights="onlineUserCursorHighlights[editor.open_doc_id]" show-print-margin="false", sharejs-doc="editor.sharejs_doc", last-updated="editor.last_updated", cursor-position="editor.cursorPosition", - resize-on="layout:main:resize,layout:pdf:resize" + goto-line="editor.gotoLine", + resize-on="layout:main:resize,layout:pdf:resize", + annotations="pdf.logEntryAnnotations[editor.open_doc_id]" ) .ui-layout-east diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index b2b7fc9df2..0487d818fa 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -59,13 +59,14 @@ div.full-size(ng-controller="PdfController") strong Compile Error. span Sorry, your LaTeX code couldn't compile for some reason. Please check the errors below for details, or view the raw log. - div(ng-repeat="entry in pdf.logEntries.all") + div(ng-repeat="entry in pdf.logEntries.all", ng-controller="PdfLogEntryController") .alert( ng-class="{\ 'alert-danger': entry.level == 'error',\ 'alert-warning': entry.level == 'warning',\ 'alert-info': entry.level == 'typesetting'\ }" + ng-click="openInEditor(entry)" ) span.line-no span(ng-show="entry.file") {{ entry.file }} diff --git a/services/web/app/views/project/editor/track-changes.jade b/services/web/app/views/project/editor/track-changes.jade index 77cb6230de..f66a7bbbc2 100644 --- a/services/web/app/views/project/editor/track-changes.jade +++ b/services/web/app/views/project/editor/track-changes.jade @@ -71,7 +71,7 @@ div#trackChanges(ng-show="ui.view == 'track-changes'") theme="settings.theme", font-size="settings.fontSize", text="trackChanges.diff.text", - annotations="trackChanges.diff.annotations", + highlights="trackChanges.diff.highlights", read-only="true", resize-on="layout:main:resize" ) diff --git a/services/web/public/coffee/app/ide/editor/EditorManager.coffee b/services/web/public/coffee/app/ide/editor/EditorManager.coffee index 09dc79bbdb..ed331f4583 100644 --- a/services/web/public/coffee/app/ide/editor/EditorManager.coffee +++ b/services/web/public/coffee/app/ide/editor/EditorManager.coffee @@ -10,6 +10,7 @@ define [ open_doc_id: null opening: true cursorPosition: null + gotoLine: null } @$scope.$on "entity:selected", (event, entity) => @@ -33,18 +34,23 @@ define [ openDoc: (doc, options = {}) -> @$scope.ui.view = "editor" + + done = () => + if options.gotoLine? + @$scope.editor.gotoLine = options.gotoLine - console.log "Trying to open doc", doc.id - return if doc.id == @$scope.editor.open_doc_id and !options.forceReopen + if doc.id == @$scope.editor.open_doc_id and !options.forceReopen + @$scope.$apply () => + done() + return + @$scope.editor.open_doc_id = doc.id - console.log "Actually opening doc", doc.id $.localStorage "doc.open_id.#{@$scope.project_id}", doc.id @ide.fileTreeManager.selectEntity(doc) @$scope.editor.opening = true @_openNewDocument doc, (error, sharejs_doc) => - console.log "OPENED DOC", error, sharejs_doc if error? @ide.showGenericServerErrorMessage() return @@ -54,6 +60,7 @@ define [ @$scope.$apply () => @$scope.editor.opening = false @$scope.editor.sharejs_doc = sharejs_doc + done() _openNewDocument: (doc, callback = (error, sharejs_doc) ->) -> current_sharejs_doc = @$scope.editor.sharejs_doc diff --git a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee index e1346ef9ee..46cae9465a 100644 --- a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee +++ b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee @@ -11,6 +11,13 @@ define [], () -> @gotoStoredPosition() + @$scope.$watch "gotoLine", (value) => + console.log "Going to line", value + if value? + setTimeout () => + @gotoLine(value) + , 0 + onScrollTopChange: (event) -> if !@ignoreCursorPositionChanges and doc_id = @$scope.sharejsDoc?.doc_id docPosition = $.localStorage("doc.position.#{doc_id}") || {} @@ -30,4 +37,7 @@ define [], () -> @ignoreCursorPositionChanges = true @editor.moveCursorToPosition(pos.cursorPosition or {row: 0, column: 0}) @editor.getSession().setScrollTop(pos.scrollTop or 0) - delete @ignoreCursorPositionChanges \ No newline at end of file + delete @ignoreCursorPositionChanges + + gotoLine: (line) -> + @editor.moveCursorToPosition({row: line, column: 0}) \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee index 7b8f09973a..5f5f238a44 100644 --- a/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee @@ -4,7 +4,7 @@ define [ "ide/editor/undo/UndoManager" "ide/editor/auto-complete/AutoCompleteManager" "ide/editor/spell-check/SpellCheckManager" - "ide/editor/annotations/AnnotationsManager" + "ide/editor/highlights/HighlightsManager" "ide/editor/cursor-position/CursorPositionManager" "ace/keyboard/vim" "ace/keyboard/emacs" @@ -26,9 +26,11 @@ define [ lastUpdated: "=" spellCheckLanguage: "=" cursorPosition: "=" - annotations: "=" + highlights: "=" text: "=" readOnly: "=" + gotoLine: "=" + annotations: "=" } link: (scope, element, attrs) -> # Don't freak out if we're already in an apply callback @@ -100,15 +102,26 @@ define [ session.setUseWrapMode(true) session.setMode(new LatexMode()) + scope.$watch "annotations", (annotations) -> + console.log "SETTING ANNOTATIONS", annotations + if annotations? + session = editor.getSession() + session.setAnnotations annotations + scope.$watch "readOnly", (value) -> editor.setReadOnly !!value + resetSession = () -> + session = editor.getSession() + session.setUseWrapMode(true) + session.setMode(new LatexMode()) + session.setAnnotations scope.annotations + attachToAce = (sharejs_doc) -> lines = sharejs_doc.getSnapshot().split("\n") editor.setSession(new EditSession(lines)) + resetSession() session = editor.getSession() - session.setUseWrapMode(true) - session.setMode(new LatexMode()) autoCompleteManager.bindToSession(session) annotationsManager.redrawAnnotations() diff --git a/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee b/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee new file mode 100644 index 0000000000..6f7f65351e --- /dev/null +++ b/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee @@ -0,0 +1,224 @@ +define [ + "ace/range" +], () -> + Range = require("ace/range").Range + + class HighlightsManager + constructor: (@$scope, @editor, @element) -> + @markerIds = [] + @labels = [] + + @$scope.annotationLabel = { + show: false + right: "auto" + left: "auto" + top: "auto" + bottom: "auto" + backgroundColor: "black" + text: "" + } + + @$scope.$watch "highlights", (value) => + @redrawAnnotations() + + @$scope.$watch "theme", (value) => + @redrawAnnotations() + + @editor.on "mousemove", (e) => + position = @editor.renderer.screenToTextCoordinates(e.clientX, e.clientY) + e.position = position + @showAnnotationLabels(position) + + redrawAnnotations: () -> + @_clearMarkers() + @_clearLabels() + + for annotation in @$scope.highlights or [] + do (annotation) => + colorScheme = @_getColorScheme(annotation.hue) + if annotation.cursor? + @labels.push { + text: annotation.text + range: new Range( + annotation.cursor.row, annotation.cursor.column, + annotation.cursor.row, annotation.cursor.column + 1 + ) + colorScheme: colorScheme + snapToStartOfRange: true + } + @_drawCursor(annotation, colorScheme) + else if annotation.highlight? + @labels.push { + text: annotation.label + range: new Range( + annotation.highlight.start.row, annotation.highlight.start.column, + annotation.highlight.end.row, annotation.highlight.end.column + ) + colorScheme: colorScheme + } + @_drawHighlight(annotation, colorScheme) + else if annotation.strikeThrough? + @labels.push { + text: annotation.label + range: new Range( + annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, + annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + ) + colorScheme: colorScheme + } + @_drawStrikeThrough(annotation, colorScheme) + + showAnnotationLabels: (position) -> + labelToShow = null + for label in @labels or [] + if label.range.contains(position.row, position.column) + labelToShow = label + + if !labelToShow? + @$scope.$apply () => + @$scope.annotationLabel.show = false + else + $ace = $(@editor.renderer.container).find(".ace_scroller") + # Move the label into the Ace content area so that offsets and positions are easy to calculate. + $ace.append(@element.find(".annotation-label")) + + if labelToShow.snapToStartOfRange + coords = @editor.renderer.textToScreenCoordinates(labelToShow.range.start.row, labelToShow.range.start.column) + else + coords = @editor.renderer.textToScreenCoordinates(position.row, position.column) + + offset = $ace.offset() + height = $ace.height() + coords.pageX = coords.pageX - offset.left + coords.pageY = coords.pageY - offset.top + + if coords.pageY > @editor.renderer.lineHeight * 2 + top = "auto" + bottom = height - coords.pageY + else + top = coords.pageY + @editor.renderer.lineHeight + bottom = "auto" + + # Apply this first that the label has the correct width when calculating below + @$scope.$apply () => + @$scope.annotationLabel.text = labelToShow.text + @$scope.annotationLabel.show = true + + $label = @element.find(".annotation-label") + console.log "pageX", coords.pageX, "label", $label.outerWidth(), "ace", $ace.width() + + if coords.pageX + $label.outerWidth() < $ace.width() + left = coords.pageX + right = "auto" + else + right = 0 + left = "auto" + + @$scope.$apply () => + @$scope.annotationLabel = { + show: true + left: left + right: right + bottom: bottom + top: top + backgroundColor: labelToShow.colorScheme.labelBackgroundColor + text: labelToShow.text + } + + _clearMarkers: () -> + for marker_id in @markerIds + @editor.getSession().removeMarker(marker_id) + @markerIds = [] + + _clearLabels: () -> + @labels = [] + + _drawCursor: (annotation, colorScheme) -> + @markerIds.push @editor.getSession().addMarker new Range( + annotation.cursor.row, annotation.cursor.column, + annotation.cursor.row, annotation.cursor.column + 1 + ), "annotation remote-cursor", (html, range, left, top, config) -> + div = """ +
+
+
+ """ + html.push div + , true + + _drawHighlight: (annotation, colorScheme) -> + @_addMarkerWithCustomStyle( + new Range( + annotation.highlight.start.row, annotation.highlight.start.column, + annotation.highlight.end.row, annotation.highlight.end.column + 1 + ), + "annotation highlight", + false, + "background-color: #{colorScheme.highlightBackgroundColor}" + ) + + _drawStrikeThrough: (annotation, colorScheme) -> + lineHeight = @editor.renderer.lineHeight + @_addMarkerWithCustomStyle( + new Range( + annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, + annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1 + ), + "annotation strike-through-background", + false, + "background-color: #{colorScheme.strikeThroughBackgroundColor}" + ) + @_addMarkerWithCustomStyle( + new Range( + annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, + annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1 + ), + "annotation strike-through-foreground", + true, + """ + height: #{Math.round(lineHeight/2) + 2}px; + border-bottom: 2px solid #{colorScheme.strikeThroughForegroundColor}; + """ + ) + + _addMarkerWithCustomStyle: (range, klass, foreground, style) -> + if foreground? + markerLayer = @editor.renderer.$markerBack + else + markerLayer = @editor.renderer.$markerFront + + @markerIds.push @editor.getSession().addMarker range, klass, (html, range, left, top, config) -> + if range.isMultiLine() + markerLayer.drawTextMarker(html, range, klass, config, style) + else + markerLayer.drawSingleLineMarker(html, range, "#{klass} ace_start", config, 0, style) + , foreground + + _getColorScheme: (hue) -> + if @_isDarkTheme() + return { + cursor: "hsl(#{hue}, 100%, 50%)" + labelBackgroundColor: "hsl(#{hue}, 100%, 50%)" + highlightBackgroundColor: "hsl(#{hue}, 100%, 28%);" + strikeThroughBackgroundColor: "hsl(#{hue}, 100%, 20%);" + strikeThroughForegroundColor: "hsl(#{hue}, 100%, 60%);" + } + else + return { + cursor: "hsl(#{hue}, 100%, 50%)" + labelBackgroundColor: "hsl(#{hue}, 100%, 50%)" + highlightBackgroundColor: "hsl(#{hue}, 70%, 85%);" + strikeThroughBackgroundColor: "hsl(#{hue}, 70%, 95%);" + strikeThroughForegroundColor: "hsl(#{hue}, 70%, 40%);" + } + + _isDarkTheme: () -> + rgb = @element.find(".ace_editor").css("background-color"); + [m, r, g, b] = rgb.match(/rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)/) + r = parseInt(r, 10) + g = parseInt(g, 10) + b = parseInt(b, 10) + return r + g + b < 3 * 128 \ No newline at end of file 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 423a02f569..d592fd0ecd 100644 --- a/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee @@ -88,6 +88,21 @@ define [ return null + findEntityByPath: (path) -> + @_findEntityByPathInFolder @$scope.rootFolder, path + + _findEntityByPathInFolder: (folder, path) -> + parts = path.split("/") + name = parts.shift() + rest = parts.join("/") + for entity in folder.children + if entity.name == name + if rest == "" + return entity + else if entity.type == "folder" + return @_findEntityByPathInFolder(entity, rest) + return null + forEachEntity: (callback = (entity, parent_folder) ->) -> @_forEachEntityInFolder(@$scope.rootFolder, callback) diff --git a/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee b/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee index 1ff4b0b3dd..5a908fd336 100644 --- a/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee +++ b/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee @@ -4,7 +4,7 @@ define [ class OnlineUsersManager constructor: (@ide, @$scope) -> @$scope.onlineUsers = {} - @$scope.onlineUserCursorAnnotations = {} + @$scope.onlineUserCursorHighlights = {} @$scope.$watch "editor.cursorPosition", (position) => if position? @@ -23,12 +23,12 @@ define [ updateCursorHighlights: () -> console.log "UPDATING CURSOR HIGHLIGHTS" - @$scope.onlineUserCursorAnnotations = {} + @$scope.onlineUserCursorHighlights = {} for client_id, client of @$scope.onlineUsers doc_id = client.doc_id continue if !doc_id? - @$scope.onlineUserCursorAnnotations[doc_id] ||= [] - @$scope.onlineUserCursorAnnotations[doc_id].push { + @$scope.onlineUserCursorHighlights[doc_id] ||= [] + @$scope.onlineUserCursorHighlights[doc_id].push { label: client.name cursor: row: client.row diff --git a/services/web/public/coffee/app/ide/pdf/PdfManager.coffee b/services/web/public/coffee/app/ide/pdf/PdfManager.coffee index b8f9ae2690..f41572aa88 100644 --- a/services/web/public/coffee/app/ide/pdf/PdfManager.coffee +++ b/services/web/public/coffee/app/ide/pdf/PdfManager.coffee @@ -4,5 +4,15 @@ define [ ], () -> class PdfManager constructor: (@ide, @$scope) -> - - # All the logic actually happens in the controller + @$scope.pdf = + url: null # Pdf Url + error: false # Server error + timeout: false # Server timed out + failure: false # PDF failed to compile + compiling: false + uncompiled: true + logEntries: [] + logEntryAnnotations: {} + rawLog: "" + view: null # 'pdf' 'logs' + showRawLog: false diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 6e31ee603f..626feb0db8 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -3,18 +3,6 @@ define [ "libs/latex-log-parser" ], (App, LogParser) -> App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) -> - $scope.pdf = - url: null # Pdf Url - error: false # Server error - timeout: false # Server timed out - failure: false # PDF failed to compile - compiling: false - uncompiled: true - logEntries: [] - rawLog: "" - view: null # 'pdf' 'logs' - showRawLog: false - autoCompile = true $scope.$on "doc:opened", () -> return if !autoCompile @@ -68,9 +56,21 @@ define [ logEntries = LogParser.parse(log, ignoreDuplicates: true) $scope.pdf.logEntries = logEntries $scope.pdf.logEntries.all = logEntries.errors.concat(logEntries.warnings).concat(logEntries.typesetting) + + $scope.pdf.logEntryAnnotations = {} for entry in logEntries.all entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "") entry.file = entry.file.replace(/^\/compile\//, "") + + entity = ide.fileTreeManager.findEntityByPath(entry.file) + if entity? + $scope.pdf.logEntryAnnotations[entity.id] ||= [] + $scope.pdf.logEntryAnnotations[entity.id].push { + row: entry.line - 1 + type: if entry.level == "error" then "error" else "warning" + text: entry.message + } + .error () -> $scope.pdf.logEntries = [] $scope.pdf.rawLog = "" @@ -131,6 +131,16 @@ define [ ) ] + App.controller "PdfLogEntryController", ["$scope", "ide", ($scope, ide) -> + $scope.openInEditor = (entry) -> + console.log "OPENING", entry.file, entry.line + entity = ide.fileTreeManager.findEntityByPath(entry.file) + return if entity.type != "doc" + if entry.line? + line = entry.line - 1 + ide.editorManager.openDoc(entity, gotoLine: line) + ] + App.controller 'ClearCacheModalController', ["$scope", "$modalInstance", ($scope, $modalInstance) -> $scope.state = inflight: false diff --git a/services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee b/services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee index 7f8f5216dc..6339eb0457 100644 --- a/services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee +++ b/services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee @@ -110,9 +110,9 @@ define [ .get(url) .success (data) => diff.loading = false - {text, annotations} = @_parseDiff(data) + {text, highlights} = @_parseDiff(data) diff.text = text - diff.annotations = annotations + diff.highlights = highlights .error () -> diff.loading = false diff.error = true @@ -129,7 +129,7 @@ define [ _parseDiff: (diff) -> row = 0 column = 0 - annotations = [] + highlights = [] text = "" for entry, i in diff.diff or [] content = entry.u or entry.i or entry.d @@ -162,19 +162,19 @@ define [ name = "you" date = moment(entry.meta.end_ts).format("Do MMM YYYY, h:mm a") if entry.i? - annotations.push { + highlights.push { label: "Added by #{name} on #{date}" highlight: range hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user.id) } else if entry.d? - annotations.push { + highlights.push { label: "Deleted by #{name} on #{date}" strikeThrough: range hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user.id) } - return {text, annotations} + return {text, highlights} _loadUpdates: (updates = []) -> previousUpdate = @$scope.trackChanges.updates[@$scope.trackChanges.updates.length - 1] diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index ae8d026e75..cb2e1983f1 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -89,6 +89,7 @@ .alert { font-size: 0.9rem; margin-bottom: @line-height-computed / 2; + cursor: pointer; .line-no { float: right; color: @gray; From 0f9f04803e03b4dadbe6096b0d7ba33033f0dcb9 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 13:47:37 +0100 Subject: [PATCH 05/15] Improve goto line functionalitt --- .../annotations/AnnotationsManager.coffee | 224 ------------------ .../CursorPositionManager.coffee | 5 +- .../ide/pdf/controllers/PdfController.coffee | 2 +- 3 files changed, 5 insertions(+), 226 deletions(-) delete mode 100644 services/web/public/coffee/app/ide/editor/annotations/AnnotationsManager.coffee diff --git a/services/web/public/coffee/app/ide/editor/annotations/AnnotationsManager.coffee b/services/web/public/coffee/app/ide/editor/annotations/AnnotationsManager.coffee deleted file mode 100644 index 8b0836bf4d..0000000000 --- a/services/web/public/coffee/app/ide/editor/annotations/AnnotationsManager.coffee +++ /dev/null @@ -1,224 +0,0 @@ -define [ - "ace/range" -], () -> - Range = require("ace/range").Range - - class AnnotationsManager - constructor: (@$scope, @editor, @element) -> - @markerIds = [] - @labels = [] - - @$scope.annotationLabel = { - show: false - right: "auto" - left: "auto" - top: "auto" - bottom: "auto" - backgroundColor: "black" - text: "" - } - - @$scope.$watch "annotations", (value) => - @redrawAnnotations() - - @$scope.$watch "theme", (value) => - @redrawAnnotations() - - @editor.on "mousemove", (e) => - position = @editor.renderer.screenToTextCoordinates(e.clientX, e.clientY) - e.position = position - @showAnnotationLabels(position) - - redrawAnnotations: () -> - @_clearMarkers() - @_clearLabels() - - for annotation in @$scope.annotations or [] - do (annotation) => - colorScheme = @_getColorScheme(annotation.hue) - if annotation.cursor? - @labels.push { - text: annotation.text - range: new Range( - annotation.cursor.row, annotation.cursor.column, - annotation.cursor.row, annotation.cursor.column + 1 - ) - colorScheme: colorScheme - snapToStartOfRange: true - } - @_drawCursor(annotation, colorScheme) - else if annotation.highlight? - @labels.push { - text: annotation.label - range: new Range( - annotation.highlight.start.row, annotation.highlight.start.column, - annotation.highlight.end.row, annotation.highlight.end.column - ) - colorScheme: colorScheme - } - @_drawHighlight(annotation, colorScheme) - else if annotation.strikeThrough? - @labels.push { - text: annotation.label - range: new Range( - annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, - annotation.strikeThrough.end.row, annotation.strikeThrough.end.column - ) - colorScheme: colorScheme - } - @_drawStrikeThrough(annotation, colorScheme) - - showAnnotationLabels: (position) -> - labelToShow = null - for label in @labels or [] - if label.range.contains(position.row, position.column) - labelToShow = label - - if !labelToShow? - @$scope.$apply () => - @$scope.annotationLabel.show = false - else - $ace = $(@editor.renderer.container).find(".ace_scroller") - # Move the label into the Ace content area so that offsets and positions are easy to calculate. - $ace.append(@element.find(".annotation-label")) - - if labelToShow.snapToStartOfRange - coords = @editor.renderer.textToScreenCoordinates(labelToShow.range.start.row, labelToShow.range.start.column) - else - coords = @editor.renderer.textToScreenCoordinates(position.row, position.column) - - offset = $ace.offset() - height = $ace.height() - coords.pageX = coords.pageX - offset.left - coords.pageY = coords.pageY - offset.top - - if coords.pageY > @editor.renderer.lineHeight * 2 - top = "auto" - bottom = height - coords.pageY - else - top = coords.pageY + @editor.renderer.lineHeight - bottom = "auto" - - # Apply this first that the label has the correct width when calculating below - @$scope.$apply () => - @$scope.annotationLabel.text = labelToShow.text - @$scope.annotationLabel.show = true - - $label = @element.find(".annotation-label") - console.log "pageX", coords.pageX, "label", $label.outerWidth(), "ace", $ace.width() - - if coords.pageX + $label.outerWidth() < $ace.width() - left = coords.pageX - right = "auto" - else - right = 0 - left = "auto" - - @$scope.$apply () => - @$scope.annotationLabel = { - show: true - left: left - right: right - bottom: bottom - top: top - backgroundColor: labelToShow.colorScheme.labelBackgroundColor - text: labelToShow.text - } - - _clearMarkers: () -> - for marker_id in @markerIds - @editor.getSession().removeMarker(marker_id) - @markerIds = [] - - _clearLabels: () -> - @labels = [] - - _drawCursor: (annotation, colorScheme) -> - @markerIds.push @editor.getSession().addMarker new Range( - annotation.cursor.row, annotation.cursor.column, - annotation.cursor.row, annotation.cursor.column + 1 - ), "annotation remote-cursor", (html, range, left, top, config) -> - div = """ -
-
-
- """ - html.push div - , true - - _drawHighlight: (annotation, colorScheme) -> - @_addMarkerWithCustomStyle( - new Range( - annotation.highlight.start.row, annotation.highlight.start.column, - annotation.highlight.end.row, annotation.highlight.end.column + 1 - ), - "annotation highlight", - false, - "background-color: #{colorScheme.highlightBackgroundColor}" - ) - - _drawStrikeThrough: (annotation, colorScheme) -> - lineHeight = @editor.renderer.lineHeight - @_addMarkerWithCustomStyle( - new Range( - annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, - annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1 - ), - "annotation strike-through-background", - false, - "background-color: #{colorScheme.strikeThroughBackgroundColor}" - ) - @_addMarkerWithCustomStyle( - new Range( - annotation.strikeThrough.start.row, annotation.strikeThrough.start.column, - annotation.strikeThrough.end.row, annotation.strikeThrough.end.column + 1 - ), - "annotation strike-through-foreground", - true, - """ - height: #{Math.round(lineHeight/2) + 2}px; - border-bottom: 2px solid #{colorScheme.strikeThroughForegroundColor}; - """ - ) - - _addMarkerWithCustomStyle: (range, klass, foreground, style) -> - if foreground? - markerLayer = @editor.renderer.$markerBack - else - markerLayer = @editor.renderer.$markerFront - - @markerIds.push @editor.getSession().addMarker range, klass, (html, range, left, top, config) -> - if range.isMultiLine() - markerLayer.drawTextMarker(html, range, klass, config, style) - else - markerLayer.drawSingleLineMarker(html, range, "#{klass} ace_start", config, 0, style) - , foreground - - _getColorScheme: (hue) -> - if @_isDarkTheme() - return { - cursor: "hsl(#{hue}, 100%, 50%)" - labelBackgroundColor: "hsl(#{hue}, 100%, 50%)" - highlightBackgroundColor: "hsl(#{hue}, 100%, 28%);" - strikeThroughBackgroundColor: "hsl(#{hue}, 100%, 20%);" - strikeThroughForegroundColor: "hsl(#{hue}, 100%, 60%);" - } - else - return { - cursor: "hsl(#{hue}, 100%, 50%)" - labelBackgroundColor: "hsl(#{hue}, 100%, 50%)" - highlightBackgroundColor: "hsl(#{hue}, 70%, 85%);" - strikeThroughBackgroundColor: "hsl(#{hue}, 70%, 95%);" - strikeThroughForegroundColor: "hsl(#{hue}, 70%, 40%);" - } - - _isDarkTheme: () -> - rgb = @element.find(".ace_editor").css("background-color"); - [m, r, g, b] = rgb.match(/rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)/) - r = parseInt(r, 10) - g = parseInt(g, 10) - b = parseInt(b, 10) - return r + g + b < 3 * 128 \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee index 46cae9465a..1c94cc06e6 100644 --- a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee +++ b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee @@ -16,6 +16,8 @@ define [], () -> if value? setTimeout () => @gotoLine(value) + @$scope.$apply () => + @$scope.gotoLine = null , 0 onScrollTopChange: (event) -> @@ -40,4 +42,5 @@ define [], () -> delete @ignoreCursorPositionChanges gotoLine: (line) -> - @editor.moveCursorToPosition({row: line, column: 0}) \ No newline at end of file + @editor.gotoLine(line) + @editor.focus() \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 626feb0db8..89683e9268 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -137,7 +137,7 @@ define [ entity = ide.fileTreeManager.findEntityByPath(entry.file) return if entity.type != "doc" if entry.line? - line = entry.line - 1 + line = entry.line ide.editorManager.openDoc(entity, gotoLine: line) ] From d3d18c384a5136478b99ffae58de270d06b1fa08 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 14:01:39 +0100 Subject: [PATCH 06/15] Fix remote cursors --- .../ide/editor/cursor-position/CursorPositionManager.coffee | 6 ++++++ .../coffee/app/ide/editor/directives/aceEditor.coffee | 6 ------ .../app/ide/editor/highlights/HighlightsManager.coffee | 3 ++- .../coffee/app/ide/online-users/OnlineUsersManager.coffee | 1 + services/web/public/stylesheets/app/editor.less | 1 + 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee index 1c94cc06e6..be90f8fcec 100644 --- a/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee +++ b/services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee @@ -11,6 +11,12 @@ define [], () -> @gotoStoredPosition() + @editor.on "changeSelection", () => + cursor = @editor.getCursorPosition() + console.log "Updating cursor position", cursor + @$scope.$apply () => + @$scope.cursorPosition = cursor + @$scope.$watch "gotoLine", (value) => console.log "Going to line", value if value? diff --git a/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee index 5f5f238a44..d7235ce771 100644 --- a/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee @@ -65,12 +65,6 @@ define [ scope.$on event, () -> editor.resize() - editor.on "changeSelection", () -> - cursor = editor.getCursorPosition() - scope.$apply () -> - if scope.cursorPosition? - scope.cursorPosition = cursor - scope.$watch "theme", (value) -> editor.setTheme("ace/theme/#{value}") diff --git a/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee b/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee index 6f7f65351e..b1afe3fb57 100644 --- a/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee +++ b/services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee @@ -37,8 +37,9 @@ define [ do (annotation) => colorScheme = @_getColorScheme(annotation.hue) if annotation.cursor? + console.log "DRAWING CURSOR", annotation @labels.push { - text: annotation.text + text: annotation.label range: new Range( annotation.cursor.row, annotation.cursor.column, annotation.cursor.row, annotation.cursor.column + 1 diff --git a/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee b/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee index 5a908fd336..ef4a343bda 100644 --- a/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee +++ b/services/web/public/coffee/app/ide/online-users/OnlineUsersManager.coffee @@ -38,6 +38,7 @@ define [ UPDATE_INTERVAL: 500 sendCursorPositionUpdate: () -> + console.log "SENDING CURSOR POSITION UPDATE", @$scope.editor.cursorPosition if !@cursorUpdateTimeout? @cursorUpdateTimeout = setTimeout ()=> position = @$scope.editor.cursorPosition diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index c3ad368b4c..185fec5e64 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -69,6 +69,7 @@ background-position: bottom left; } .remote-cursor { + position: absolute; border-left: 2px solid transparent; .nubbin { height: 5px; From 11d951f0214867d54dfbb27554a42e1ee43ca8a8 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 18:35:01 +0100 Subject: [PATCH 07/15] Get synctex working --- .../web/app/views/project/editor/editor.jade | 22 +++- .../web/app/views/project/editor/pdf.jade | 3 + .../coffee/app/ide/directives/layout.coffee | 10 ++ .../app/ide/file-tree/FileTreeManager.coffee | 24 ++++ .../coffee/app/ide/pdf/PdfManager.coffee | 2 + .../ide/pdf/controllers/PdfController.coffee | 119 +++++++++++++++++- .../app/ide/pdf/directives/pdfJs.coffee | 44 ++++++- .../public/stylesheets/app/editor/pdf.less | 8 ++ 8 files changed, 226 insertions(+), 6 deletions(-) diff --git a/services/web/app/views/project/editor/editor.jade b/services/web/app/views/project/editor/editor.jade index 3956b417fa..b5fd2b65ac 100644 --- a/services/web/app/views/project/editor/editor.jade +++ b/services/web/app/views/project/editor/editor.jade @@ -27,4 +27,24 @@ div.full-size( ) .ui-layout-east - include ./pdf \ No newline at end of file + include ./pdf + + .ui-layout-resizer-controls.synctex-controls( + ng-show="!!pdf.url" + ng-controller="PdfSynctexController" + ) + a.btn.btn-default.btn-xs( + tooltip="Go to code location in PDF" + tooltip-placement="right" + tooltip-append-to-body="true" + ng-click="syncToPdf()" + ) + i.fa.fa-long-arrow-right + br + a.btn.btn-default.btn-xs( + tooltip-html-unsafe="Go to PDF location in code
(or double click PDF)" + tooltip-placement="right" + tooltip-append-to-body="true" + ng-click="syncToCode()" + ) + i.fa.fa-long-arrow-left \ No newline at end of file diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 0487d818fa..142fac6a08 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -33,6 +33,9 @@ div.full-size(ng-controller="PdfController") pdf-src="pdf.url" key="project_id" resize-on="layout:main:resize,layout:pdf:resize" + highlights="pdf.highlights" + position="pdf.position" + dbl-click-callback="syncToCode" ) .pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling") diff --git a/services/web/public/coffee/app/ide/directives/layout.coffee b/services/web/public/coffee/app/ide/directives/layout.coffee index fd0c39a836..d5657e7c12 100644 --- a/services/web/public/coffee/app/ide/directives/layout.coffee +++ b/services/web/public/coffee/app/ide/directives/layout.coffee @@ -12,6 +12,7 @@ define [ onresize: () => console.log "Triggering", "layout:#{name}:resize", name scope.$broadcast "layout:#{name}:resize" + repositionControls() #maskIframesOnResize: true # Restore previously recorded state @@ -28,4 +29,13 @@ define [ # Save state when exiting $(window).unload () -> $.localStorage("layout.#{name}", element.layout().readState()) + + repositionControls = () -> + state = element.layout().readState() + if state.east? + element.find(".ui-layout-resizer-controls").css({ + position: "absolute" + right: state.east.size + "z-index": 10 + }) } \ No newline at end of file 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 d592fd0ecd..26aeb03853 100644 --- a/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee @@ -95,6 +95,10 @@ define [ parts = path.split("/") name = parts.shift() rest = parts.join("/") + + if name == "." + return @_findEntityByPathInFolder(folder, rest) + for entity in folder.children if entity.name == name if rest == "" @@ -115,6 +119,26 @@ define [ if entity.children? @_forEachEntityInFolder(entity, callback) + getEntityPath: (entity) -> + @_getEntityPathInFolder @$scope.rootFolder, entity + + _getEntityPathInFolder: (folder, entity) -> + for child in folder.children or [] + if child == entity + return entity.name + else if child.type == "folder" + path = @_getEntityPathInFolder(child, entity) + if path? + return child.name + "/" + path + return null + + getRootDocDirname: () -> + rootDoc = @findEntityById @$scope.project.rootDoc_id + return if !rootDoc? + path = @getEntityPath(rootDoc) + return if !path? + return path.split("/").slice(0, -1).join("/") + # forEachFolder: (callback) -> # @forEachEntity (entity) -> # if entity.type == "folder" diff --git a/services/web/public/coffee/app/ide/pdf/PdfManager.coffee b/services/web/public/coffee/app/ide/pdf/PdfManager.coffee index f41572aa88..47ac42a1b6 100644 --- a/services/web/public/coffee/app/ide/pdf/PdfManager.coffee +++ b/services/web/public/coffee/app/ide/pdf/PdfManager.coffee @@ -16,3 +16,5 @@ define [ rawLog: "" view: null # 'pdf' 'logs' showRawLog: false + highlights: [] + position: null diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 89683e9268..28e278d870 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -2,7 +2,7 @@ define [ "base" "libs/latex-log-parser" ], (App, LogParser) -> - App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) -> + App.controller "PdfController", ["$scope", "$http", "ide", "$modal", "synctex", ($scope, $http, ide, $modal, synctex) -> autoCompile = true $scope.$on "doc:opened", () -> return if !autoCompile @@ -59,8 +59,7 @@ define [ $scope.pdf.logEntryAnnotations = {} for entry in logEntries.all - entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "") - entry.file = entry.file.replace(/^\/compile\//, "") + entry.file = normalizeFilePath(entry.file) entity = ide.fileTreeManager.findEntityByPath(entry.file) if entity? @@ -84,6 +83,16 @@ define [ return ide.editorManager.getCurrentDocId() return null + normalizeFilePath = (path) -> + path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "") + path = path.replace(/^\/compile\//, "") + + rootDocDirname = ide.fileTreeManager.getRootDocDirname() + if rootDocDirname? + path = path.replace(/^\.\//, rootDocDirname) + + return path + $scope.recompile = (options = {}) -> console.log "Recompiling", options return if $scope.pdf.compiling @@ -129,13 +138,115 @@ define [ controller: "ClearCacheModalController" scope: $scope ) + + $scope.syncToCode = (position) -> + console.log "SYNCING VIA DBL CLICK", position + synctex + .syncToCode(position) + .then (data) -> + {doc, line} = data + ide.editorManager.openDoc(doc, gotoLine: line) + + ] + + App.factory "synctex", ["ide", "$http", "$q", (ide, $http, $q) -> + synctex = + syncToPdf: (cursorPosition) -> + deferred = $q.defer() + + doc_id = ide.editorManager.getCurrentDocId() + if !doc_id? + deferred.reject() + return deferred.promise() + doc = ide.fileTreeManager.findEntityById(doc_id) + if !doc? + deferred.reject() + return deferred.promise() + path = ide.fileTreeManager.getEntityPath(doc) + if !path? + deferred.reject() + return deferred.promise() + + # If the root file is folder/main.tex, then synctex sees the + # path as folder/./main.tex + rootDocDirname = ide.fileTreeManager.getRootDocDirname() + if rootDocDirname? and rootDocDirname != "" + path = path.replace(RegExp("^#{rootDocDirname}"), "#{rootDocDirname}/.") + + {row, column} = cursorPosition + + $http({ + url: "/project/#{ide.project_id}/sync/code", + method: "GET", + params: { + file: path + line: row + 1 + column: column + } + }) + .success (data) -> + console.log "SYNCTEX RESPONSE", data + deferred.resolve(data.pdf or []) + .error (error) -> + deferred.reject(error) + + return deferred.promise + + syncToCode: (position, options = {}) -> + deferred = $q.defer() + if !position? + deferred.reject() + return deferred.promise() + + # It's not clear exactly where we should sync to if it wasn't directly + # clicked on, but a little bit down from the very top seems best. + if options.includeVisualOffset + position.offset.top = position.offset.top + 80 + + $http({ + url: "/project/#{ide.project_id}/sync/pdf", + method: "GET", + params: { + page: position.page + 1 + h: position.offset.left.toFixed(2) + v: position.offset.top.toFixed(2) + } + }) + .success (data) -> + console.log "SYNCTEX RESPONSE", data + if data.code? and data.code.length > 0 + doc = ide.fileTreeManager.findEntityByPath(data.code[0].file) + return if !doc? + deferred.resolve({doc: doc, line: data.code[0].line}) + .error (error) -> + deferred.reject(error) + + return deferred.promise + + return synctex + ] + + App.controller "PdfSynctexController", ["$scope", "synctex", "ide", ($scope, synctex, ide) -> + $scope.syncToPdf = () -> + synctex + .syncToPdf($scope.editor.cursorPosition) + .then (highlights) -> + $scope.pdf.highlights = highlights + + $scope.syncToCode = () -> + synctex + .syncToCode($scope.pdf.position, includeVisualOffset: true) + .then (data) -> + {doc, line} = data + console.log "OPENING DOC", doc, line + ide.editorManager.openDoc(doc, gotoLine: line) ] App.controller "PdfLogEntryController", ["$scope", "ide", ($scope, ide) -> $scope.openInEditor = (entry) -> console.log "OPENING", entry.file, entry.line entity = ide.fileTreeManager.findEntityByPath(entry.file) - return if entity.type != "doc" + return if !entity? or entity.type != "doc" if entry.line? line = entry.line ide.editorManager.openDoc(entity, gotoLine: line) diff --git a/services/web/public/coffee/app/ide/pdf/directives/pdfJs.coffee b/services/web/public/coffee/app/ide/pdf/directives/pdfJs.coffee index f614310331..b5ef69c4e3 100644 --- a/services/web/public/coffee/app/ide/pdf/directives/pdfJs.coffee +++ b/services/web/public/coffee/app/ide/pdf/directives/pdfJs.coffee @@ -28,12 +28,16 @@ define [ return { scope: { "pdfSrc": "=" + "highlights": "=" + "position": "=" + "dblClickCallback": "=" } link: (scope, element, attrs) -> pdfListView = new PDFListView element.find(".pdfjs-viewer")[0], textLayerBuilder: TextLayerBuilder annotationsLayerBuilder: AnnotationsLayerBuilder highlightsLayerBuilder: HighlightsLayerBuilder + ondblclick: (e) -> onDoubleClick(e) logLevel: PDFListView.Logger.DEBUG pdfListView.listView.pageWidthOffset = 20 pdfListView.listView.pageHeightOffset = 20 @@ -58,6 +62,8 @@ define [ if (position = $.localStorage("pdf.position.#{attrs.key}")) pdfListView.setPdfPosition(position) + scope.position = pdfListView.getPdfPosition(true) + $(window).unload () => $.localStorage "pdf.scale", { scaleMode: pdfListView.getScaleMode() @@ -69,7 +75,14 @@ define [ scope.flashControls = true $timeout () -> scope.flashControls = false - , 1000 + , 1000 + + element.find(".pdfjs-viewer").scroll () -> + console.log "UPDATING POSITION", pdfListView.getPdfPosition(true) + scope.position = pdfListView.getPdfPosition(true) + + onDoubleClick = (e) -> + scope.dblClickCallback?(page: e.page, offset: { top: e.y, left: e.x }) scope.$watch "pdfSrc", (url) -> if url @@ -85,6 +98,35 @@ define [ initializePosition() flashControls() + scope.$watch "highlights", (areas) -> + console.log "UPDATING HIGHLIGHTS", areas + return if !areas? + highlights = for area in areas or [] + { + page: area.page - 1 + highlight: + left: area.h + top: area.v + height: area.height + width: area.width + } + + if highlights.length > 0 + first = highlights[0] + pdfListView.setPdfPosition({ + page: first.page + offset: + left: first.highlight.left + top: first.highlight.top - 80 + }, true) + + pdfListView.clearHighlights() + pdfListView.setHighlights(highlights, true) + + setTimeout () => + pdfListView.clearHighlights() + , 1000 + scope.fitToHeight = () -> pdfListView.setToFitHeight() diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index cb2e1983f1..7b95eea5e9 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -112,4 +112,12 @@ position: relative; } } + +.synctex-controls { + padding: 68px 2px 0; + .btn-xs { + line-height: 1.3; + padding: 0 2px 0; + } +} \ No newline at end of file From 96696e745e8070e02a937cc86071da8e2278bb09 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 30 Jun 2014 18:37:39 +0100 Subject: [PATCH 08/15] Fix path normalization --- .../public/coffee/app/ide/pdf/controllers/PdfController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 28e278d870..2b6a303dc1 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -89,7 +89,7 @@ define [ rootDocDirname = ide.fileTreeManager.getRootDocDirname() if rootDocDirname? - path = path.replace(/^\.\//, rootDocDirname) + path = path.replace(/^\.\//, rootDocDirname + "/") return path From 9097fdd93096ae2028873fc06eec0c2a6769831e Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 11:00:47 +0100 Subject: [PATCH 09/15] Allow switching between pdfjs and native viewer --- .../web/app/views/project/editor/editor.jade | 2 +- .../app/views/project/editor/left-menu.jade | 9 ++++++++ .../web/app/views/project/editor/pdf.jade | 5 +++++ .../coffee/app/ide/directives/layout.coffee | 13 ++++++++---- .../ide/pdf/controllers/PdfController.coffee | 21 +++++++++++++------ .../app/ide/settings/SettingsManager.coffee | 4 ++++ .../public/stylesheets/app/editor/pdf.less | 5 +++++ 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/services/web/app/views/project/editor/editor.jade b/services/web/app/views/project/editor/editor.jade index b5fd2b65ac..2836480468 100644 --- a/services/web/app/views/project/editor/editor.jade +++ b/services/web/app/views/project/editor/editor.jade @@ -30,7 +30,7 @@ div.full-size( include ./pdf .ui-layout-resizer-controls.synctex-controls( - ng-show="!!pdf.url" + ng-show="!!pdf.url && settings.pdfViewer == 'pdfjs' && showControls" ng-controller="PdfSynctexController" ) a.btn.btn-default.btn-xs( diff --git a/services/web/app/views/project/editor/left-menu.jade b/services/web/app/views/project/editor/left-menu.jade index 8ef522920d..c21e973409 100644 --- a/services/web/app/views/project/editor/left-menu.jade +++ b/services/web/app/views/project/editor/left-menu.jade @@ -64,6 +64,15 @@ aside#left-menu.full-size( each size in ['10','11','12','13','14','16','20','24'] option(value=size) #{size}px + .form-controls + label(for="pdfViewer") PDF Viewer + select.form-control( + name="pdfViewer" + ng-model="settings.pdfViewer" + ) + option(value="pdfjs") Built-In + option(value="native") Native + #left-menu-mask( ng-show="ui.leftMenuShown", ng-click="ui.leftMenuShown = false" diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 142fac6a08..3fd6eea126 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -30,6 +30,7 @@ div.full-size(ng-controller="PdfController") .pdf-viewer(ng-show="pdf.url && pdf.view == 'pdf' && !pdf.failure && !pdf.timeout && !pdf.error") div( pdfjs + ng-if="settings.pdfViewer == 'pdfjs'" pdf-src="pdf.url" key="project_id" resize-on="layout:main:resize,layout:pdf:resize" @@ -37,6 +38,10 @@ div.full-size(ng-controller="PdfController") position="pdf.position" dbl-click-callback="syncToCode" ) + iframe( + ng-src="{{ pdf.url }}" + ng-if="settings.pdfViewer == 'native'" + ) .pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling") |   diff --git a/services/web/public/coffee/app/ide/directives/layout.coffee b/services/web/public/coffee/app/ide/directives/layout.coffee index d5657e7c12..15a982cade 100644 --- a/services/web/public/coffee/app/ide/directives/layout.coffee +++ b/services/web/public/coffee/app/ide/directives/layout.coffee @@ -10,10 +10,15 @@ define [ spacing_open: 24 spacing_closed: 24 onresize: () => - console.log "Triggering", "layout:#{name}:resize", name - scope.$broadcast "layout:#{name}:resize" - repositionControls() - #maskIframesOnResize: true + onResize() + maskIframesOnResize: scope.$eval( + attrs.maskIframesOnResize or "false" + ) + + onResize = () -> + state = element.layout().readState() + scope.$broadcast "layout:#{name}:resize", state + repositionControls() # Restore previously recorded state if (state = $.localStorage("layout.#{name}"))? diff --git a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee index 2b6a303dc1..fe2836862c 100644 --- a/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee @@ -157,15 +157,15 @@ define [ doc_id = ide.editorManager.getCurrentDocId() if !doc_id? deferred.reject() - return deferred.promise() + return deferred.promise doc = ide.fileTreeManager.findEntityById(doc_id) if !doc? deferred.reject() - return deferred.promise() + return deferred.promise path = ide.fileTreeManager.getEntityPath(doc) if !path? deferred.reject() - return deferred.promise() + return deferred.promise # If the root file is folder/main.tex, then synctex sees the # path as folder/./main.tex @@ -185,7 +185,6 @@ define [ } }) .success (data) -> - console.log "SYNCTEX RESPONSE", data deferred.resolve(data.pdf or []) .error (error) -> deferred.reject(error) @@ -196,7 +195,7 @@ define [ deferred = $q.defer() if !position? deferred.reject() - return deferred.promise() + return deferred.promise # It's not clear exactly where we should sync to if it wasn't directly # clicked on, but a little bit down from the very top seems best. @@ -213,7 +212,6 @@ define [ } }) .success (data) -> - console.log "SYNCTEX RESPONSE", data if data.code? and data.code.length > 0 doc = ide.fileTreeManager.findEntityByPath(data.code[0].file) return if !doc? @@ -227,6 +225,17 @@ define [ ] App.controller "PdfSynctexController", ["$scope", "synctex", "ide", ($scope, synctex, ide) -> + $scope.showControls = true + $scope.$on "layout:pdf:resize", (event, data) -> + console.log "RESIZE DATA", data.east + if data.east.initClosed + $scope.showControls = false + else + $scope.showControls = true + setTimeout () -> + $scope.$digest() + , 0 + $scope.syncToPdf = () -> synctex .syncToPdf($scope.editor.cursorPosition) diff --git a/services/web/public/coffee/app/ide/settings/SettingsManager.coffee b/services/web/public/coffee/app/ide/settings/SettingsManager.coffee index 4a64ce0752..bf5bba6ea8 100644 --- a/services/web/public/coffee/app/ide/settings/SettingsManager.coffee +++ b/services/web/public/coffee/app/ide/settings/SettingsManager.coffee @@ -22,6 +22,10 @@ define [], () -> if autoComplete != oldAutoComplete @saveSettings({autoComplete: autoComplete}) + @$scope.$watch "settings.pdfViewer", (pdfViewer, oldPdfViewer) => + if pdfViewer != oldPdfViewer + @saveSettings({pdfViewer: pdfViewer}) + @$scope.$watch "project.spellCheckLanguage", (language, oldLanguage) => return if @ignoreUpdates if oldLanguage? and language != oldLanguage diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index 7b95eea5e9..269f67b6f6 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -14,6 +14,11 @@ } .pdf-viewer { + iframe { + width: 100%; + height: 100%; + border: none; + } .pdfjs-viewer { .full-size; background-color: @gray-lighter; From be48ab2a30e8aeeeee0560c5a7c4d35124c411f9 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 14:12:28 +0100 Subject: [PATCH 10/15] Add in basic share modal --- .../Collaborators/CollaboratorsHandler.coffee | 3 +- .../Features/Editor/EditorController.coffee | 2 +- services/web/app/views/project/editor.jade | 29 +-------- .../web/app/views/project/editor/header.jade | 8 ++- .../web/app/views/project/editor/share.jade | 61 +++++++++++++++++++ services/web/public/coffee/app/ide.coffee | 1 + .../share/controllers/ShareController.coffee | 11 ++++ .../ShareProjectModalController.coffee | 57 +++++++++++++++++ .../public/coffee/app/ide/share/index.coffee | 5 ++ .../ide/share/services/projectMembers.coffee | 30 +++++++++ .../web/public/stylesheets/app/editor.less | 1 + .../public/stylesheets/app/editor/share.less | 49 +++++++++++++++ .../public/stylesheets/components/modals.less | 4 ++ 13 files changed, 231 insertions(+), 30 deletions(-) create mode 100644 services/web/app/views/project/editor/share.jade create mode 100644 services/web/public/coffee/app/ide/share/controllers/ShareController.coffee create mode 100644 services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee create mode 100644 services/web/public/coffee/app/ide/share/index.coffee create mode 100644 services/web/public/coffee/app/ide/share/services/projectMembers.coffee create mode 100644 services/web/public/stylesheets/app/editor/share.less diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee index d84ae95d3a..f428b9bb14 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee @@ -26,7 +26,8 @@ module.exports = addUserToProject: (project_id, email, privilegeLevel, callback)-> emails = mimelib.parseAddresses(email) - email = emails[0].address?.toLowerCase() + email = emails[0]?.address?.toLowerCase() + return callback(new Error("no valid email provided")) if !email? self = @ User.findOne {'email':email}, (err, user)-> async.waterfall [ diff --git a/services/web/app/coffee/Features/Editor/EditorController.coffee b/services/web/app/coffee/Features/Editor/EditorController.coffee index 3bb489ea12..32c770e0da 100644 --- a/services/web/app/coffee/Features/Editor/EditorController.coffee +++ b/services/web/app/coffee/Features/Editor/EditorController.coffee @@ -138,7 +138,7 @@ module.exports = EditorController = CollaboratorsHandler.addUserToProject project_id, email, privileges, (err, user)=> ProjectEntityHandler.flushProjectToThirdPartyDataStore project_id, "", -> EditorRealTimeController.emitToRoom(project_id, 'userAddedToProject', user, privileges) - callback null, true + callback null, ProjectEditorHandler.buildUserModelView(user, privileges) removeUserFromProject: (project_id, user_id, callback)-> CollaboratorsHandler.removeUserFromProject project_id, user_id, => diff --git a/services/web/app/views/project/editor.jade b/services/web/app/views/project/editor.jade index 2193b2a927..1fba8d539e 100644 --- a/services/web/app/views/project/editor.jade +++ b/services/web/app/views/project/editor.jade @@ -37,6 +37,8 @@ block content include ./editor/header + include ./editor/share + #ide-body(ng-cloak, layout="main", ng-hide="state.loading") .ui-layout-west include ./editor/file-tree @@ -45,33 +47,6 @@ block content include ./editor/editor include ./editor/track-changes - //- #loadingScreen - //- h3 Loading... - //- p#loadingMessage Loading editor - - //- #errorMessages - //- #connectionLostMessage(style="display: none;") - //- | Lost connection. - //- span#trying-reconnect - //- | Reconnecting in - //- span#reconnection-countdown ? - //- | seconds. - //- a(href='#')#try-reconnect-now Try now. - //- span#reconnecting - //- | Reconnecting... - - //- #savingProblems(style="display: none") - //- | Saving... - - //- div#toolbar.sidebar-navigation - //- ul#tabs - //- #toolbar-footer - - //- #tab-content.tab-content - - //- include ../templates - //- include ../templates/dropbox - script(src='/socket.io/socket.io.js') script(type='text/javascript'). diff --git a/services/web/app/views/project/editor/header.jade b/services/web/app/views/project/editor/header.jade index 6ebd08762a..a6859981ee 100644 --- a/services/web/app/views/project/editor/header.jade +++ b/services/web/app/views/project/editor/header.jade @@ -13,7 +13,13 @@ header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading") i.fa.fa-pencil .toolbar-right - a.btn.btn-full-height(href='#', tooltip="Share", tooltip-placement="bottom") + a.btn.btn-full-height( + href, + tooltip="Share", + tooltip-placement="bottom", + ng-click="openShareProjectModal()", + ng-controller="ShareController" + ) i.fa.fa-fw.fa-group a.btn.btn-full-height( href, diff --git a/services/web/app/views/project/editor/share.jade b/services/web/app/views/project/editor/share.jade new file mode 100644 index 0000000000..4efdb72cc4 --- /dev/null +++ b/services/web/app/views/project/editor/share.jade @@ -0,0 +1,61 @@ +script(type='text/ng-template', id='shareProjectModalTemplate') + .modal-header + h3 Share Project + .modal-body.modal-body-share + .container-fluid + .row.public-access-level + .col-md-9 This project is private and can only be accessed by the people below. + .col-md-3.text-right + a(href) Make public + .row.project-member + .col-md-8 {{ project.owner.email }} + .text-right( + ng-class="{'col-md-3': project.members.length > 0, 'col-md-4': project.members.length == 0}" + ) Owner + .row.project-member(ng-repeat="member in project.members") + .col-md-8 {{ member.email }} + .col-md-3.text-right + span(ng-show="member.privileges == 'readAndWrite'") Can Edit + span(ng-show="member.privileges == 'readOnly'") Read Only + .col-md-1 + a( + href + tooltip="Remove collaborator" + tooltip-placement="bottom" + ng-click="removeMember(member)" + ) + i.fa.fa-times + .row.invite-controls + form(ng-show="canAddCollaborators") + .small Share with your collaborators + .form-group + input.form-control( + type="email" + placeholder="Enter email address..." + ng-model="inputs.email" + focus-on="open" + ) + .form-group + .pull-right + select.privileges.form-control( + ng-model="inputs.privileges" + name="privileges" + ) + option(value="readAndWrite") Can Edit + option(value="readOnly") Read Only + |    + button.btn.btn-info( + type="submit" + ng-click="addMember()" + ) Share + div.text-center(ng-hide="canAddCollaborators") + p You need to upgrade your account to add more collaborators. + a.btn.btn-info(href) Start Free Trial + + .modal-footer + .modal-footer-left + i.fa.fa-refresh.fa-spin(ng-show="state.inflight") + span.text-danger.error(ng-show="state.error") {{ state.error }} + button.btn.btn-primary( + ng-click="done()" + ) Done \ 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 87bb3a78dc..39e25dd77e 100644 --- a/services/web/public/coffee/app/ide.coffee +++ b/services/web/public/coffee/app/ide.coffee @@ -7,6 +7,7 @@ define [ "ide/online-users/OnlineUsersManager" "ide/track-changes/TrackChangesManager" "ide/pdf/PdfManager" + "ide/share/index" "ide/directives/layout" "ide/services/ide" "directives/focus" diff --git a/services/web/public/coffee/app/ide/share/controllers/ShareController.coffee b/services/web/public/coffee/app/ide/share/controllers/ShareController.coffee new file mode 100644 index 0000000000..d76bd07965 --- /dev/null +++ b/services/web/public/coffee/app/ide/share/controllers/ShareController.coffee @@ -0,0 +1,11 @@ +define [ + "base" +], (App) -> + App.controller "ShareController", ["$scope", "$modal", ($scope, $modal) -> + $scope.openShareProjectModal = () -> + $modal.open( + templateUrl: "shareProjectModalTemplate" + controller: "ShareProjectModalController" + scope: $scope + ) + ] diff --git a/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee new file mode 100644 index 0000000000..de849e4d8a --- /dev/null +++ b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee @@ -0,0 +1,57 @@ +define [ + "base" +], (App) -> + App.controller "ShareProjectModalController", ["$scope", "$modalInstance", "$timeout", "projectMembers", ($scope, $modalInstance, $timeout, projectMembers) -> + $scope.inputs = { + privileges: "readAndWrite" + email: "" + } + $scope.state = { + error: null + inflight: false + } + + $modalInstance.opened.then () -> + $timeout () -> + $scope.$broadcast "open" + , 200 + + INFINITE_COLLABORATORS = -1 + $scope.$watch "project.members.length", (noOfMembers) -> + allowedNoOfMembers = $scope.project.features.collaborators + $scope.canAddCollaborators = noOfMembers < allowedNoOfMembers or allowedNoOfMembers == INFINITE_COLLABORATORS + + $scope.addMember = () -> + console.log "EMAIL", $scope.inputs.email + return if !$scope.inputs.email? or $scope.inputs.email == "" + $scope.state.error = null + $scope.state.inflight = true + projectMembers + .addMember($scope.inputs.email, $scope.inputs.privileges) + .then (user) -> + $scope.state.inflight = false + $scope.inputs.email = "" + console.log "GOT USER", user + $scope.project.members.push user + .catch () -> + $scope.state.inflight = false + $scope.state.error = "Sorry, something went wrong :(" + + + $scope.removeMember = (member) -> + $scope.state.error = null + $scope.state.inflight = true + projectMembers + .removeMember(member) + .then () -> + $scope.state.inflight = false + index = $scope.project.members.indexOf(member) + return if index == -1 + $scope.project.members.splice(index, 1) + .catch () -> + $scope.state.inflight = false + $scope.state.error = "Sorry, something went wrong :(" + + $scope.done = () -> + $modalInstance.close() + ] \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/share/index.coffee b/services/web/public/coffee/app/ide/share/index.coffee new file mode 100644 index 0000000000..545a145be3 --- /dev/null +++ b/services/web/public/coffee/app/ide/share/index.coffee @@ -0,0 +1,5 @@ +define [ + "ide/share/controllers/ShareController" + "ide/share/controllers/ShareProjectModalController" + "ide/share/services/projectMembers" +], () -> \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/share/services/projectMembers.coffee b/services/web/public/coffee/app/ide/share/services/projectMembers.coffee new file mode 100644 index 0000000000..144a6c2684 --- /dev/null +++ b/services/web/public/coffee/app/ide/share/services/projectMembers.coffee @@ -0,0 +1,30 @@ +define [ + "base" +], (App) -> + App.factory "projectMembers", ["ide", "$q", (ide, $q) -> + return { + removeMember: (member) -> + deferred = $q.defer() + + ide.socket.emit "removeUserFromProject", member._id, (error) => + if error? + return deferred.reject(error) + deferred.resolve() + + return deferred.promise + + addMember: (email, privileges) -> + deferred = $q.defer() + + ide.socket.emit "addUserToProject", email, privileges, (error, user) => + if error? + return deferred.reject(error) + + if !user + deferred.reject() + else + deferred.resolve(user) + + return deferred.promise + } + ] \ No newline at end of file diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index 185fec5e64..c1ff220a71 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -3,6 +3,7 @@ @import "./editor/toolbar.less"; @import "./editor/left-menu.less"; @import "./editor/pdf.less"; +@import "./editor/share.less"; .full-size { position: absolute; diff --git a/services/web/public/stylesheets/app/editor/share.less b/services/web/public/stylesheets/app/editor/share.less new file mode 100644 index 0000000000..21230a9145 --- /dev/null +++ b/services/web/public/stylesheets/app/editor/share.less @@ -0,0 +1,49 @@ +.modal-body-share { + h3 { + border-bottom: 1px solid @gray-lighter; + padding-bottom: @line-height-computed / 4; + margin: 0; + font-size: 1rem; + } + + .project-member, .public-access-level { + padding: (@line-height-computed / 2) 0; + border-bottom: 1px solid @gray-lighter; + font-size: 14px; + } + + .public-access-level { + color: @gray; + padding-top: 0; + font-size: 12px; + } + + .project-member { + &:hover { + background-color: @gray-lightest; + } + } + + .invite-controls { + .small { + padding: 2px; + } + padding: @line-height-computed / 2; + background-color: @gray-lightest; + margin-top: @line-height-computed / 2; + form { + .form-group { + margin-bottom: @line-height-computed / 2; + &:last-child { + margin-bottom: 0; + } + } + .privileges { + display: inline-block; + width: auto; + height: 30px; + font-size: 14px; + } + } + } +} \ No newline at end of file diff --git a/services/web/public/stylesheets/components/modals.less b/services/web/public/stylesheets/components/modals.less index 4b5d5c5953..a325d0da32 100755 --- a/services/web/public/stylesheets/components/modals.less +++ b/services/web/public/stylesheets/components/modals.less @@ -126,6 +126,10 @@ .btn-block + .btn-block { margin-left: 0; } + + .modal-footer-left { + float: left; + } } // Scale up the modal From 08f702a7c50f6f51ee01f2bd45041eb780cde0d6 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 14:16:41 +0100 Subject: [PATCH 11/15] Get free trial button working in share modal --- services/web/app/views/project/editor/share.jade | 5 ++++- .../share/controllers/ShareProjectModalController.coffee | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/services/web/app/views/project/editor/share.jade b/services/web/app/views/project/editor/share.jade index 4efdb72cc4..735cc2ac0e 100644 --- a/services/web/app/views/project/editor/share.jade +++ b/services/web/app/views/project/editor/share.jade @@ -50,7 +50,10 @@ script(type='text/ng-template', id='shareProjectModalTemplate') ) Share div.text-center(ng-hide="canAddCollaborators") p You need to upgrade your account to add more collaborators. - a.btn.btn-info(href) Start Free Trial + p + a.btn.btn-info(href, ng-click="startFreeTrial()") Start Free Trial + p.small(ng-show="state.startedFreeTrial") + | Please refresh this page after starting your free trial. .modal-footer .modal-footer-left diff --git a/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee index de849e4d8a..35ca3aa178 100644 --- a/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee +++ b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee @@ -9,6 +9,7 @@ define [ $scope.state = { error: null inflight: false + startedFreeTrial: false } $modalInstance.opened.then () -> @@ -52,6 +53,11 @@ define [ $scope.state.inflight = false $scope.state.error = "Sorry, something went wrong :(" + $scope.startFreeTrial = () -> + ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', "projectMembers") + window.open("/user/subscription/plans") + $scope.state.startedFreeTrial = true + $scope.done = () -> $modalInstance.close() ] \ No newline at end of file From d599cfa7aca61fc1100a5296306c844b3c5ea5e6 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 14:19:52 +0100 Subject: [PATCH 12/15] Fix unit tests --- .../UnitTests/coffee/Editor/EditorControllerTests.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/web/test/UnitTests/coffee/Editor/EditorControllerTests.coffee b/services/web/test/UnitTests/coffee/Editor/EditorControllerTests.coffee index 2f2335e19c..a5883f2720 100644 --- a/services/web/test/UnitTests/coffee/Editor/EditorControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Editor/EditorControllerTests.coffee @@ -296,6 +296,7 @@ describe "EditorController", -> @email = "Jane.Doe@example.com" @priveleges = "readOnly" @addedUser = { _id: "added-user" } + @ProjectEditorHandler.buildUserModelView = sinon.stub().returns(@addedUser) @CollaboratorsHandler.addUserToProject = sinon.stub().callsArgWith(3, null, @addedUser) @EditorRealTimeController.emitToRoom = sinon.stub() @callback = sinon.stub() @@ -314,9 +315,9 @@ describe "EditorController", -> @EditorRealTimeController.emitToRoom.calledWith(@project_id, "userAddedToProject", @addedUser).should.equal true done() - it "should return true to the callback", (done)-> + it "should return the user to the callback", (done)-> @EditorController.addUserToProject @project_id, @email, @priveleges, (err, result)=> - result.should.equal true + result.should.equal @addedUser done() From 9839f3fc621513d063b582bf5e6269fd905db761 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 15:05:32 +0100 Subject: [PATCH 13/15] Get public sharing modal working --- .../app/views/project/editor/left-menu.jade | 2 +- .../web/app/views/project/editor/share.jade | 66 ++++++++++++++++++- services/web/public/coffee/app/ide.coffee | 5 +- .../app/ide/settings/SettingsManager.coffee | 59 ----------------- .../controllers/SettingsController.coffee | 51 ++++++++++++++ .../coffee/app/ide/settings/index.coffee | 5 ++ .../app/ide/settings/services/settings.coffee | 14 ++++ .../ShareProjectModalController.coffee | 43 +++++++++++- 8 files changed, 178 insertions(+), 67 deletions(-) delete mode 100644 services/web/public/coffee/app/ide/settings/SettingsManager.coffee create mode 100644 services/web/public/coffee/app/ide/settings/controllers/SettingsController.coffee create mode 100644 services/web/public/coffee/app/ide/settings/index.coffee create mode 100644 services/web/public/coffee/app/ide/settings/services/settings.coffee diff --git a/services/web/app/views/project/editor/left-menu.jade b/services/web/app/views/project/editor/left-menu.jade index c21e973409..b15afdeace 100644 --- a/services/web/app/views/project/editor/left-menu.jade +++ b/services/web/app/views/project/editor/left-menu.jade @@ -3,7 +3,7 @@ aside#left-menu.full-size( ng-cloak ) h4 Settings - form + form(ng-controller="SettingsController") .form-controls label(for="compiler") Compiler select.form-control( diff --git a/services/web/app/views/project/editor/share.jade b/services/web/app/views/project/editor/share.jade index 735cc2ac0e..775df52aa4 100644 --- a/services/web/app/views/project/editor/share.jade +++ b/services/web/app/views/project/editor/share.jade @@ -1,12 +1,29 @@ script(type='text/ng-template', id='shareProjectModalTemplate') .modal-header + button.close( + type="button" + data-dismiss="modal" + ng-click="cancel()" + ) × h3 Share Project .modal-body.modal-body-share .container-fluid - .row.public-access-level + .row.public-access-level(ng-show="project.publicAccesLevel == 'private'") .col-md-9 This project is private and can only be accessed by the people below. .col-md-3.text-right - a(href) Make public + a( + href + ng-click="openMakePublicModal()" + ) Make Public + .row.public-access-level(ng-show="project.publicAccesLevel != 'private'") + .col-md-9 + strong(ng-if="project.publicAccesLevel == 'readAndWrite'") This project is public and can be edited by anyone with the URL. + strong(ng-if="project.publicAccesLevel == 'readOnly'") This project is public and can be viewed by anyone with the URL. + .col-md-3.text-right + a( + href + ng-click="openMakePrivateModal()" + ) Make Private .row.project-member .col-md-8 {{ project.owner.email }} .text-right( @@ -61,4 +78,47 @@ script(type='text/ng-template', id='shareProjectModalTemplate') span.text-danger.error(ng-show="state.error") {{ state.error }} button.btn.btn-primary( ng-click="done()" - ) Done \ No newline at end of file + ) Done + +script(type="text/ng-template", id="makePublicModalTemplate") + .modal-header + button.close( + type="button" + data-dismiss="modal" + ng-click="cancel()" + ) × + h3 Make project public? + .modal-body.modal-body-share + p If you make your project public then anyone with the URL will be able to access it. + p + select.form-control( + ng-model="inputs.privileges" + name="privileges" + ) + option(value="readAndWrite") Allow public editing + option(value="readOnly") Allow public read only access + .modal-footer + button.btn.btn-default( + ng-click="cancel()" + ) Cancel + button.btn.btn-info( + ng-click="makePublic()" + ) Make public + +script(type="text/ng-template", id="makePrivateModalTemplate") + .modal-header + button.close( + type="button" + data-dismiss="modal" + ng-click="cancel()" + ) × + h3 Make project private? + .modal-body.modal-body-share + p If you make your project public then only the people you choose to share it with will have access. + .modal-footer + button.btn.btn-default( + ng-click="cancel()" + ) Cancel + button.btn.btn-info( + ng-click="makePrivate()" + ) Make private diff --git a/services/web/public/coffee/app/ide.coffee b/services/web/public/coffee/app/ide.coffee index 39e25dd77e..3a10089306 100644 --- a/services/web/public/coffee/app/ide.coffee +++ b/services/web/public/coffee/app/ide.coffee @@ -3,10 +3,10 @@ define [ "ide/file-tree/FileTreeManager" "ide/connection/ConnectionManager" "ide/editor/EditorManager" - "ide/settings/SettingsManager" "ide/online-users/OnlineUsersManager" "ide/track-changes/TrackChangesManager" "ide/pdf/PdfManager" + "ide/settings/index" "ide/share/index" "ide/directives/layout" "ide/services/ide" @@ -19,7 +19,6 @@ define [ FileTreeManager ConnectionManager EditorManager - SettingsManager OnlineUsersManager TrackChangesManager PdfManager @@ -43,6 +42,7 @@ define [ view: "editor" } $scope.user = window.user + $scope.settings = window.userSettings window._ide = ide @@ -52,7 +52,6 @@ define [ ide.connectionManager = new ConnectionManager(ide, $scope) ide.fileTreeManager = new FileTreeManager(ide, $scope) ide.editorManager = new EditorManager(ide, $scope) - ide.settingsManager = new SettingsManager(ide, $scope) ide.onlineUsersManager = new OnlineUsersManager(ide, $scope) ide.trackChangesManager = new TrackChangesManager(ide, $scope) ide.pdfManager = new PdfManager(ide, $scope) diff --git a/services/web/public/coffee/app/ide/settings/SettingsManager.coffee b/services/web/public/coffee/app/ide/settings/SettingsManager.coffee deleted file mode 100644 index bf5bba6ea8..0000000000 --- a/services/web/public/coffee/app/ide/settings/SettingsManager.coffee +++ /dev/null @@ -1,59 +0,0 @@ -define [], () -> - class SettingsManager - constructor: (@ide, @$scope) -> - @$scope.settings = window.userSettings - - if @$scope.settings.mode not in ["default", "vim", "emacs"] - @$scope.settings.mode = "default" - - @$scope.$watch "settings.theme", (theme, oldTheme) => - if theme != oldTheme - @saveSettings({theme: theme}) - - @$scope.$watch "settings.fontSize", (fontSize, oldFontSize) => - if fontSize != oldFontSize - @saveSettings({fontSize: parseInt(fontSize, 10)}) - - @$scope.$watch "settings.mode", (mode, oldMode) => - if mode != oldMode - @saveSettings({mode: mode}) - - @$scope.$watch "settings.autoComplete", (autoComplete, oldAutoComplete) => - if autoComplete != oldAutoComplete - @saveSettings({autoComplete: autoComplete}) - - @$scope.$watch "settings.pdfViewer", (pdfViewer, oldPdfViewer) => - if pdfViewer != oldPdfViewer - @saveSettings({pdfViewer: pdfViewer}) - - @$scope.$watch "project.spellCheckLanguage", (language, oldLanguage) => - return if @ignoreUpdates - if oldLanguage? and language != oldLanguage - @saveProjectSettings({spellCheckLanguage: language}) - # Also set it as the default for the user - @saveSettings({spellCheckLanguage: language}) - - @$scope.$watch "project.compiler", (compiler, oldCompiler) => - return if @ignoreUpdates - if oldCompiler? and compiler != oldCompiler - @saveProjectSettings({compiler: compiler}) - - @ide.socket.on "compilerUpdated", (compiler) => - @ignoreUpdates = true - @$scope.$apply () => - @$scope.project.compiler = compiler - delete @ignoreUpdates - - @ide.socket.on "spellCheckLanguageUpdated", (languageCode) => - @ignoreUpdates = true - @$scope.$apply () => - @$scope.project.spellCheckLanguage = languageCode - delete @ignoreUpdates - - saveSettings: (data) -> - data._csrf = window.csrfToken - @ide.$http.post "/user/settings", data - - saveProjectSettings: (data) -> - data._csrf = window.csrfToken - @ide.$http.post "/project/#{@ide.project_id}/settings", data diff --git a/services/web/public/coffee/app/ide/settings/controllers/SettingsController.coffee b/services/web/public/coffee/app/ide/settings/controllers/SettingsController.coffee new file mode 100644 index 0000000000..2cf5cc4690 --- /dev/null +++ b/services/web/public/coffee/app/ide/settings/controllers/SettingsController.coffee @@ -0,0 +1,51 @@ +define [ + "base" +], (App) -> + App.controller "SettingsController", ["$scope", "settings", "ide", ($scope, settings, ide) -> + if $scope.settings.mode not in ["default", "vim", "emacs"] + $scope.settings.mode = "default" + + $scope.$watch "settings.theme", (theme, oldTheme) => + if theme != oldTheme + settings.saveSettings({theme: theme}) + + $scope.$watch "settings.fontSize", (fontSize, oldFontSize) => + if fontSize != oldFontSize + settings.saveSettings({fontSize: parseInt(fontSize, 10)}) + + $scope.$watch "settings.mode", (mode, oldMode) => + if mode != oldMode + settings.saveSettings({mode: mode}) + + $scope.$watch "settings.autoComplete", (autoComplete, oldAutoComplete) => + if autoComplete != oldAutoComplete + settings.saveSettings({autoComplete: autoComplete}) + + $scope.$watch "settings.pdfViewer", (pdfViewer, oldPdfViewer) => + if pdfViewer != oldPdfViewer + settings.saveSettings({pdfViewer: pdfViewer}) + + $scope.$watch "project.spellCheckLanguage", (language, oldLanguage) => + return if @ignoreUpdates + if oldLanguage? and language != oldLanguage + settings.saveProjectSettings({spellCheckLanguage: language}) + # Also set it as the default for the user + settings.saveSettings({spellCheckLanguage: language}) + + $scope.$watch "project.compiler", (compiler, oldCompiler) => + return if @ignoreUpdates + if oldCompiler? and compiler != oldCompiler + settings.saveProjectSettings({compiler: compiler}) + + ide.socket.on "compilerUpdated", (compiler) => + @ignoreUpdates = true + $scope.$apply () => + $scope.project.compiler = compiler + delete @ignoreUpdates + + ide.socket.on "spellCheckLanguageUpdated", (languageCode) => + @ignoreUpdates = true + $scope.$apply () => + $scope.project.spellCheckLanguage = languageCode + delete @ignoreUpdates + ] \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/settings/index.coffee b/services/web/public/coffee/app/ide/settings/index.coffee new file mode 100644 index 0000000000..ae5f6a9c66 --- /dev/null +++ b/services/web/public/coffee/app/ide/settings/index.coffee @@ -0,0 +1,5 @@ +define [ + "ide/settings/services/settings" + "ide/settings/controllers/SettingsController" +], () -> + diff --git a/services/web/public/coffee/app/ide/settings/services/settings.coffee b/services/web/public/coffee/app/ide/settings/services/settings.coffee new file mode 100644 index 0000000000..78dda105ad --- /dev/null +++ b/services/web/public/coffee/app/ide/settings/services/settings.coffee @@ -0,0 +1,14 @@ +define [ + "base" +], (App) -> + App.factory "settings", ["ide", (ide) -> + return { + saveSettings: (data) -> + data._csrf = window.csrfToken + ide.$http.post "/user/settings", data + + saveProjectSettings: (data) -> + data._csrf = window.csrfToken + ide.$http.post "/project/#{ide.project_id}/settings", data + } + ] \ No newline at end of file diff --git a/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee index 35ca3aa178..6de4dae037 100644 --- a/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee +++ b/services/web/public/coffee/app/ide/share/controllers/ShareProjectModalController.coffee @@ -1,7 +1,7 @@ define [ "base" ], (App) -> - App.controller "ShareProjectModalController", ["$scope", "$modalInstance", "$timeout", "projectMembers", ($scope, $modalInstance, $timeout, projectMembers) -> + App.controller "ShareProjectModalController", ["$scope", "$modalInstance", "$timeout", "projectMembers", "$modal", ($scope, $modalInstance, $timeout, projectMembers, $modal) -> $scope.inputs = { privileges: "readAndWrite" email: "" @@ -58,6 +58,47 @@ define [ window.open("/user/subscription/plans") $scope.state.startedFreeTrial = true + $scope.openMakePublicModal = () -> + $modal.open { + templateUrl: "makePublicModalTemplate" + controller: "MakePublicModalController" + scope: $scope + } + + $scope.openMakePrivateModal = () -> + $modal.open { + templateUrl: "makePrivateModalTemplate" + controller: "MakePrivateModalController" + scope: $scope + } + $scope.done = () -> $modalInstance.close() + + $scope.cancel = () -> + $modalInstance.dismiss() + ] + + App.controller "MakePublicModalController", ["$scope", "$modalInstance", "settings", ($scope, $modalInstance, settings) -> + $scope.inputs = { + privileges: "readAndWrite" + } + + $scope.makePublic = () -> + $scope.project.publicAccesLevel = $scope.inputs.privileges + settings.saveProjectSettings({publicAccessLevel: $scope.inputs.privileges}) + $modalInstance.close() + + $scope.cancel = () -> + $modalInstance.dismiss() + ] + + App.controller "MakePrivateModalController", ["$scope", "$modalInstance", "settings", ($scope, $modalInstance, settings) -> + $scope.makePrivate = () -> + $scope.project.publicAccesLevel = "private" + settings.saveProjectSettings({publicAccessLevel: "private"}) + $modalInstance.close() + + $scope.cancel = () -> + $modalInstance.dismiss() ] \ No newline at end of file From 0b0f7eab0b0076577b649e556a366ef2f3f51090 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 15:15:54 +0100 Subject: [PATCH 14/15] Stop public status looking like a table header --- services/web/app/views/project/editor/share.jade | 5 +++-- services/web/public/stylesheets/app/editor/share.less | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/editor/share.jade b/services/web/app/views/project/editor/share.jade index 775df52aa4..b85b5df026 100644 --- a/services/web/app/views/project/editor/share.jade +++ b/services/web/app/views/project/editor/share.jade @@ -9,8 +9,9 @@ script(type='text/ng-template', id='shareProjectModalTemplate') .modal-body.modal-body-share .container-fluid .row.public-access-level(ng-show="project.publicAccesLevel == 'private'") - .col-md-9 This project is private and can only be accessed by the people below. - .col-md-3.text-right + .col-md-12.text-center + | This project is private and can only be accessed by the people below. + |    a( href ng-click="openMakePublicModal()" diff --git a/services/web/public/stylesheets/app/editor/share.less b/services/web/public/stylesheets/app/editor/share.less index 21230a9145..77ed2e0df6 100644 --- a/services/web/public/stylesheets/app/editor/share.less +++ b/services/web/public/stylesheets/app/editor/share.less @@ -16,6 +16,7 @@ color: @gray; padding-top: 0; font-size: 12px; + padding-bottom: @line-height-computed; } .project-member { From e1bce859334a96b98c65a3f32a0e59f813fe344c Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 1 Jul 2014 15:17:42 +0100 Subject: [PATCH 15/15] Update style when project is public too --- services/web/app/views/project/editor/share.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/editor/share.jade b/services/web/app/views/project/editor/share.jade index b85b5df026..a6a6df8f9a 100644 --- a/services/web/app/views/project/editor/share.jade +++ b/services/web/app/views/project/editor/share.jade @@ -17,10 +17,10 @@ script(type='text/ng-template', id='shareProjectModalTemplate') ng-click="openMakePublicModal()" ) Make Public .row.public-access-level(ng-show="project.publicAccesLevel != 'private'") - .col-md-9 + .col-md-12.text-center strong(ng-if="project.publicAccesLevel == 'readAndWrite'") This project is public and can be edited by anyone with the URL. strong(ng-if="project.publicAccesLevel == 'readOnly'") This project is public and can be viewed by anyone with the URL. - .col-md-3.text-right + |    a( href ng-click="openMakePrivateModal()"