From 79cb8270e58c4efc7f9a9921ae1f5c1181b84c59 Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 9 Apr 2014 12:35:23 +0100 Subject: [PATCH] Add in floating buttons for syncing between code and PDF --- services/web/app/views/templates.jade | 5 +++ .../web/public/bootstrap/less/tooltip.less | 2 +- .../web/public/coffee/editor/Editor.coffee | 6 ++- .../web/public/coffee/pdf/CompiledView.coffee | 3 ++ .../web/public/coffee/pdf/PDFjsView.coffee | 10 ++++- .../web/public/coffee/pdf/PdfManager.coffee | 29 +++++++++++- .../public/coffee/pdf/SyncButtonsView.coffee | 45 +++++++++++++++++++ .../public/js/libs/pdfListView/PdfListView.js | 9 ++-- .../web/public/stylesheets/less/editor.less | 21 ++++++++- 9 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 services/web/public/coffee/pdf/SyncButtonsView.coffee diff --git a/services/web/app/views/templates.jade b/services/web/app/views/templates.jade index 386ecb51a3..104ddc07e9 100644 --- a/services/web/app/views/templates.jade +++ b/services/web/app/views/templates.jade @@ -202,6 +202,11 @@ #rawLogArea(style='display: none;') pre + script(type="text/template")#syncButtonsTemplate + div.sync-buttons + button.btn.sync-code-to-pdf → + button.btn.sync-pdf-to-code ← + script(type="text/template")#outputFileLinkTemplate li a(href="/project/{{ project_id }}/output/{{ path }}", target="_blank") Download {{ name }} diff --git a/services/web/public/bootstrap/less/tooltip.less b/services/web/public/bootstrap/less/tooltip.less index 5111a193f0..3b2cbe834b 100644 --- a/services/web/public/bootstrap/less/tooltip.less +++ b/services/web/public/bootstrap/less/tooltip.less @@ -9,7 +9,7 @@ padding: 5px; font-size: 11px; .opacity(0); - &.in { .opacity(80); } + &.in { .opacity(100); } &.top { margin-top: -2px; } &.right { margin-left: 2px; } &.bottom { margin-top: 2px; } diff --git a/services/web/public/coffee/editor/Editor.coffee b/services/web/public/coffee/editor/Editor.coffee index 2b46df5ab2..62fa4daa28 100644 --- a/services/web/public/coffee/editor/Editor.coffee +++ b/services/web/public/coffee/editor/Editor.coffee @@ -50,7 +50,7 @@ define [ @openDoc doc_id, options initSplitView: () -> - splitter = @editorPanel.find("#editorSplitter") + @$splitter = splitter = @editorPanel.find("#editorSplitter") options = spacing_open: 8 spacing_closed: 16 @@ -286,6 +286,7 @@ define [ $.localStorage("doc.position.#{@current_doc_id}", docPosition) onCursorChange: (event) -> + @trigger "cursor:change", event if !@ignoreCursorPositionChanges docPosition = $.localStorage("doc.position.#{@current_doc_id}") || {} docPosition.cursorPosition = @getCursorPosition() @@ -341,6 +342,9 @@ define [ getContainerElement: () -> $(@aceEditor.renderer.getContainerElement()) + getCursorElement: () -> + @getContainerElement().find(".ace_cursor") + textToEditorCoordinates: (x, y) -> editorAreaOffset = @getContainerElement().offset() {pageX, pageY} = @aceEditor.renderer.textToScreenCoordinates(x, y) diff --git a/services/web/public/coffee/pdf/CompiledView.coffee b/services/web/public/coffee/pdf/CompiledView.coffee index 6b6478d520..4f0cd4c242 100644 --- a/services/web/public/coffee/pdf/CompiledView.coffee +++ b/services/web/public/coffee/pdf/CompiledView.coffee @@ -218,4 +218,7 @@ define [ highlightInPdf: (args...) -> @pdfView.highlightInPdf?(args...) + getPdfPosition: () -> + @pdfView.getPdfPosition?() + diff --git a/services/web/public/coffee/pdf/PDFjsView.coffee b/services/web/public/coffee/pdf/PDFjsView.coffee index 1c3fd0b3ef..e69ede132b 100644 --- a/services/web/public/coffee/pdf/PDFjsView.coffee +++ b/services/web/public/coffee/pdf/PDFjsView.coffee @@ -143,7 +143,7 @@ define [ page: first.page offset: left: first.highlight.left - top: first.highlight.top - 100 + top: first.highlight.top - 80 }, true) @pdfListView.clearHighlights() @@ -154,6 +154,14 @@ define [ @pdfListView.clearHighlights() , 1000 + getPdfPosition: () -> + position = @pdfListView.getPdfPosition(true) + return if !position? + return { + page: position.page + x: position.offset.left + y: position.offset.top + } diff --git a/services/web/public/coffee/pdf/PdfManager.coffee b/services/web/public/coffee/pdf/PdfManager.coffee index 6b483b987d..c9c74c7f90 100644 --- a/services/web/public/coffee/pdf/PdfManager.coffee +++ b/services/web/public/coffee/pdf/PdfManager.coffee @@ -1,17 +1,19 @@ define [ "utils/Modal" "pdf/CompiledView" + "pdf/SyncButtonsView" "libs/latex-log-parser" "libs/jquery.storage" "libs/underscore" "libs/backbone" -], (Modal, CompiledView, LogParser) -> +], (Modal, CompiledView, SyncButtonsView, LogParser) -> class PdfManager templates: pdfLink: $("#pdfSideBarLinkTemplate").html() constructor: (@ide) -> _.extend @, Backbone.Events + @createSyncButtons() @createPdfPanel() @ide.editor.aceEditor.commands.addCommand name: "compile", @@ -35,6 +37,15 @@ define [ else @switchToSplitView() + createSyncButtons: () -> + unless @ide.userSettings.pdfViewer == "native" + @syncButtonsView = new SyncButtonsView(ide: @ide) + @syncButtonsView.on "click:sync-code-to-pdf", () => + @syncToPdf() + @syncButtonsView.on "click:sync-pdf-to-code", () => + @syncToCode() + @syncButtonsView.hide() + switchToFlatView: (options = {showPdf: false}) -> @teardownSplitView() @setupFlatView() @@ -85,6 +96,11 @@ define [ @view.undelegateEvents() @view.delegateEvents() + + @ide.editor.$splitter.append( + @syncButtonsView?.$el + ) + setTimeout(@ide.layoutManager.resizeAllSplitters, 100) teardownSplitView: () -> @@ -112,7 +128,9 @@ define [ doneCompiling = _.once => @compiling = false @view.doneCompiling() + @syncButtonsView?.show() setTimeout doneCompiling, 1000 * 60 + if !@ide.project.get("rootDoc_id")? new Modal title: "No root document selected" @@ -123,6 +141,7 @@ define [ }] else if !@compiling @view.onCompiling() + @syncButtonsView?.hide() @compiling = true @ide.socket.emit "pdfProject", opts, (err, pdfExists, outputFiles) => @compiling = false @@ -142,6 +161,7 @@ define [ else @view.unsetPdf() @view.showLog() + @syncButtonsView?.hide() if outputFiles? @view.showOutputFileDownloadLinks(outputFiles) @@ -213,6 +233,13 @@ define [ }] syncToCode: (e) -> + if !e? + e = @view.getPdfPosition() + return if !e? + # It's not clear exactly where we should sync to if it was directly + # clicked on, but a little bit down from the very top seems best. + e.y = e.y + 80 + $.ajax { url: "/project/#{@ide.project_id}/sync/pdf" data: diff --git a/services/web/public/coffee/pdf/SyncButtonsView.coffee b/services/web/public/coffee/pdf/SyncButtonsView.coffee new file mode 100644 index 0000000000..3a4a425c4e --- /dev/null +++ b/services/web/public/coffee/pdf/SyncButtonsView.coffee @@ -0,0 +1,45 @@ +define [ + "libs/backbone" + "libs/mustache" +], () -> + SyncButtonsView = Backbone.View.extend + template: $("#syncButtonsTemplate").html() + + events: + "click .sync-code-to-pdf": () -> @trigger "click:sync-code-to-pdf" + "click .sync-pdf-to-code": () -> @trigger "click:sync-pdf-to-code" + + initialize: (options) -> + @render() + @ide = options.ide + @ide.editor.on "resize", => @repositionLeft() + @ide.editor.on "cursor:change", => @repositionTop() + + render: () -> + @setElement($(@template)) + return @ + + hide: () -> @$el.hide() + + show: () -> @$el.show() + + repositionLeft: () -> + state = @ide.editor.$splitter.layout().readState() + if state.east? + @$el.css({right: state.east.size - 8}) + + repositionTop: () -> + # The cursor hasn't actually moved yet. + setTimeout () => + cursor = @ide.editor.getCursorElement() + container = @ide.editor.getContainerElement() + top = cursor.offset().top - container.offset().top + top = top - 6 + + max = @ide.editor.getContainerElement().outerHeight() - @$el.outerHeight() + top = 0 if top < 0 + top = max if top > max + + @$el.css({top: top}) + , 10 + diff --git a/services/web/public/js/libs/pdfListView/PdfListView.js b/services/web/public/js/libs/pdfListView/PdfListView.js index 22991e852d..66d7d1ba37 100644 --- a/services/web/public/js/libs/pdfListView/PdfListView.js +++ b/services/web/public/js/libs/pdfListView/PdfListView.js @@ -369,12 +369,15 @@ ListView.prototype = { this.setPdfPosition(this.pdfPosition); }, - getPdfPosition: function() { + getPdfPosition: function(fromTop) { var pdfPosition = null; for (var i = 0; i < this.pageViews.length; i++) { var pageView = this.pageViews[i]; var pdfOffset = pageView.getUppermostVisiblePdfOffset(); if (pdfOffset !== null) { + if (fromTop) { + pdfOffset = pageView.normalHeight - pdfOffset; + } pdfPosition = { page: i, offset: { @@ -922,8 +925,8 @@ PDFListView.prototype = { this.renderController.onResize(); }, - getPdfPosition: function() { - return this.listView.getPdfPosition(); + getPdfPosition: function(fromTop) { + return this.listView.getPdfPosition(fromTop); }, setPdfPosition: function(pdfPosition, fromTop) { diff --git a/services/web/public/stylesheets/less/editor.less b/services/web/public/stylesheets/less/editor.less index 2235de881f..03f1d877d0 100644 --- a/services/web/public/stylesheets/less/editor.less +++ b/services/web/public/stylesheets/less/editor.less @@ -204,6 +204,25 @@ body.editor { width: 100%; height: 100%; } + .sync-buttons { + z-index: 3; + position: absolute; + top: 0; + right: 0; + padding: 2px; + background-color: #eee; + .border-radius(3px); + border: 1px solid #aaa; + button { + display: block; + padding: 3px; + font-size: 12px; + line-height: 12px; + } + button:first-child { + margin-bottom: 3px; + } + } } #undoConflictWarning { @@ -223,7 +242,7 @@ body.editor { #pdfArea { background-color: #eee; #pdfToolBar{ - padding: 5px 5px 3px 5px; + padding: 5px 10px 3px 10px; margin: 0; background-color: white; border-bottom: 1px solid #aaa;