From 374cf99ef2a7e20768498cfdc6db8b68127c69b9 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 8 Apr 2014 16:49:21 +0100 Subject: [PATCH 1/3] Double click on PDF syncs with code --- .../Features/Compile/CompileController.coffee | 3 ++ services/web/app/coffee/router.coffee | 3 ++ .../web/public/coffee/pdf/CompiledView.coffee | 1 + .../web/public/coffee/pdf/PDFjsView.coffee | 2 + .../web/public/coffee/pdf/PdfManager.coffee | 19 +++++++++ .../public/js/libs/pdfListView/PdfListView.js | 40 ++++++++++++++++++- .../js/libs/pdfListView/TextLayerBuilder.js | 7 ++++ 7 files changed, 74 insertions(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Compile/CompileController.coffee b/services/web/app/coffee/Features/Compile/CompileController.coffee index 3641398d18..5a6538cc8b 100644 --- a/services/web/app/coffee/Features/Compile/CompileController.coffee +++ b/services/web/app/coffee/Features/Compile/CompileController.coffee @@ -35,6 +35,9 @@ module.exports = CompileController = getFileFromClsi: (req, res, next = (error) ->) -> CompileController.proxyToClsi("/project/#{req.params.Project_id}/output/#{req.params.file}", req, res, next) + proxySync: (req, res, next = (error) ->) -> + CompileController.proxyToClsi(req.url, req, res, next) + proxyToClsi: (url, req, res, next = (error) ->) -> logger.log url: url, "proxying to CLSI" url = "#{Settings.apis.clsi.url}#{url}" diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index 01fd6cc489..e96ec5afed 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -108,6 +108,9 @@ module.exports = class Router next() ), SecurityManager.requestCanAccessProject, CompileController.getFileFromClsi app.del "/project/:Project_id/output", SecurityManager.requestCanAccessProject, CompileController.deleteAuxFiles + app.get "/project/:Project_id/sync/code", SecurityManager.requestCanAccessProject, CompileController.proxySync + app.get "/project/:Project_id/sync/pdf", SecurityManager.requestCanAccessProject, CompileController.proxySync + app.del '/Project/:Project_id', SecurityManager.requestIsOwner, Project.deleteProject app.post '/Project/:Project_id/clone', SecurityManager.requestCanAccessProject, Project.cloneProject diff --git a/services/web/public/coffee/pdf/CompiledView.coffee b/services/web/public/coffee/pdf/CompiledView.coffee index 770524f1ce..61d9b4ae5e 100644 --- a/services/web/public/coffee/pdf/CompiledView.coffee +++ b/services/web/public/coffee/pdf/CompiledView.coffee @@ -64,6 +64,7 @@ define [ PdfView = PdfjsView @pdfjs = true @pdfView = new PdfView(manager: @) + @pdfView.on "dblclick", (e) => @trigger "dblclick", e render: () -> @setElement(@templates.pdfPanel) diff --git a/services/web/public/coffee/pdf/PDFjsView.coffee b/services/web/public/coffee/pdf/PDFjsView.coffee index b913fbbc82..c7eab560fa 100644 --- a/services/web/public/coffee/pdf/PDFjsView.coffee +++ b/services/web/public/coffee/pdf/PDFjsView.coffee @@ -33,6 +33,8 @@ define [ @pdfListView = new PDFListView @$(".pdfjs-list-view")[0], textLayerBuilder: TextLayerBuilder annotationsLayerBuilder: AnnotationsLayerBuilder + ondblclick: (e) => + @trigger "dblclick", e #logLevel: PDFListView.Logger.DEBUG @pdfListView.listView.pageWidthOffset = 20 @pdfListView.listView.pageHeightOffset = 20 diff --git a/services/web/public/coffee/pdf/PdfManager.coffee b/services/web/public/coffee/pdf/PdfManager.coffee index 03daaddc32..e7dee888e3 100644 --- a/services/web/public/coffee/pdf/PdfManager.coffee +++ b/services/web/public/coffee/pdf/PdfManager.coffee @@ -24,6 +24,7 @@ define [ createPdfPanel: () -> @view = new CompiledView manager: @, ide: @ide + @view.on "dblclick", (e) => @syncToCode(e) @view.render() if $.localStorage("layout.pdf") == "flat" @switchToFlatView() @@ -210,3 +211,21 @@ define [ }) }] + + syncToCode: (e) -> + $.ajax { + url: "/project/#{@ide.project_id}/sync/pdf" + data: + page: e.page + 1 + h: e.x.toFixed(2) + v: e.y.toFixed(2) + type: "GET" + headers: + "X-CSRF-Token": window.csrfToken + success: (response) => + data = JSON.parse(response) + if data.code and data.code.length > 0 + file = data.code[0].file + line = data.code[0].line + @ide.fileTreeManager.openDocByPath(file, line) + } \ No newline at end of file diff --git a/services/web/public/js/libs/pdfListView/PdfListView.js b/services/web/public/js/libs/pdfListView/PdfListView.js index 539a574973..151f379fed 100644 --- a/services/web/public/js/libs/pdfListView/PdfListView.js +++ b/services/web/public/js/libs/pdfListView/PdfListView.js @@ -215,6 +215,16 @@ ListView.prototype = { // per pageContainer. this.pdfDoc.pages.map(function(page) { var pageView = new PageView(page, this); + + // TODO: Switch over to a proper event handler + var that = this; + var index = that.pageViews.length; + pageView.ondblclick = function(e) { + e.page = index; + if (that.ondblclick) { + that.ondblclick.call(that, e); + } + } this.pageViews.push(pageView); var container = new PageContainerView(this); @@ -462,6 +472,27 @@ function PageView(page, listView) { var dom = this.dom = document.createElement('div'); dom.className = "plv-page-view page-view"; + var that = this; + dom.ondblclick = function(e) { + var layerX = e.layerX; + var layerY = e.layerY; + var element = e.target; + while (element.offsetParent && element.offsetParent !== dom) { + layerX = layerX + element.offsetLeft; + layerY = layerY + element.offsetTop; + element = element.offsetParent; + } + + var pdfPoint = that.viewport.convertToPdfPoint(layerX, layerY); + var event = { + x: pdfPoint[0], + y: that.normalHeight - pdfPoint[1] + }; + + if (that.ondblclick) { + that.ondblclick.call(that.listView, event) + } + } this.createNewCanvas(); } @@ -560,6 +591,7 @@ PageView.prototype = { scaled: pixelRatio != 1 }; }, + createNewCanvas: function() { if (this.canvas) { this.dom.removeChild(this.canvas); @@ -766,13 +798,19 @@ function PDFListView(mainDiv, options) { } logger.logLevel = options.logLevel; + var self = this; + this.listView = new ListView(mainDiv, options); + this.listView.ondblclick = function(e) { + if (options.ondblclick) { + options.ondblclick.call(self, e); + } + } this.renderController = new RenderController(); this.renderController.addListView(this.listView); this.renderController.updateRenderList(); - var self = this; mainDiv.addEventListener('scroll', function() { // This will update the list AND start rendering if needed. diff --git a/services/web/public/js/libs/pdfListView/TextLayerBuilder.js b/services/web/public/js/libs/pdfListView/TextLayerBuilder.js index 61dda351ea..0b168e40f5 100644 --- a/services/web/public/js/libs/pdfListView/TextLayerBuilder.js +++ b/services/web/public/js/libs/pdfListView/TextLayerBuilder.js @@ -84,6 +84,13 @@ TextLayerBuilder.prototype = { textDiv.style.left = geom.x + 'px'; textDiv.style.top = (geom.y - fontHeight) + 'px'; + textDiv.ondblclick = function(e) { + if (window.getSelection) + window.getSelection().removeAllRanges(); + else if (document.selection) + document.selection.empty(); + } + // The content of the div is set in the `setTextContent` function. this.textDivs.push(textDiv); From 1444db4fd61288b496c6ae238064a63973b11428 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 8 Apr 2014 17:21:49 +0100 Subject: [PATCH 2/3] Implement code for syncing from editor to PDF --- .../web/public/coffee/editor/Editor.coffee | 6 +++++ .../web/public/coffee/pdf/CompiledView.coffee | 3 +++ .../web/public/coffee/pdf/PDFjsView.coffee | 8 ++++++ .../web/public/coffee/pdf/PdfManager.coffee | 26 ++++++++++++++++--- .../public/js/libs/pdfListView/PdfListView.js | 9 ++++--- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/services/web/public/coffee/editor/Editor.coffee b/services/web/public/coffee/editor/Editor.coffee index b0909e1ac3..2b46df5ab2 100644 --- a/services/web/public/coffee/editor/Editor.coffee +++ b/services/web/public/coffee/editor/Editor.coffee @@ -304,6 +304,12 @@ define [ gotoLine: (line) -> @aceEditor.gotoLine(line) + getCurrentLine: () -> + @aceEditor.selection?.getCursor()?.row + + getCurrentColumn: () -> + @aceEditor.selection?.getCursor()?.column + getLines: (from, to) -> if from? and to? @getSession().doc.getLines(from, to) diff --git a/services/web/public/coffee/pdf/CompiledView.coffee b/services/web/public/coffee/pdf/CompiledView.coffee index 61d9b4ae5e..fceb9e3b7a 100644 --- a/services/web/public/coffee/pdf/CompiledView.coffee +++ b/services/web/public/coffee/pdf/CompiledView.coffee @@ -215,4 +215,7 @@ define [ Backbone.View::undelegateEvents.apply(this, arguments) @pdfView.undelegateEvents() + setPdfPosition: (args...) -> + @pdfView.setPdfPosition?(args...) + diff --git a/services/web/public/coffee/pdf/PDFjsView.coffee b/services/web/public/coffee/pdf/PDFjsView.coffee index c7eab560fa..4747ea23fd 100644 --- a/services/web/public/coffee/pdf/PDFjsView.coffee +++ b/services/web/public/coffee/pdf/PDFjsView.coffee @@ -123,3 +123,11 @@ define [ onResize: () -> @pdfListView.onResize() + setPdfPosition: (page, top, left) -> + @pdfListView.setPdfPosition({ + page: page + offset: + left: left + top: top + }, true) + diff --git a/services/web/public/coffee/pdf/PdfManager.coffee b/services/web/public/coffee/pdf/PdfManager.coffee index e7dee888e3..6bef9ced07 100644 --- a/services/web/public/coffee/pdf/PdfManager.coffee +++ b/services/web/public/coffee/pdf/PdfManager.coffee @@ -220,12 +220,32 @@ define [ h: e.x.toFixed(2) v: e.y.toFixed(2) type: "GET" - headers: - "X-CSRF-Token": window.csrfToken success: (response) => data = JSON.parse(response) if data.code and data.code.length > 0 file = data.code[0].file line = data.code[0].line @ide.fileTreeManager.openDocByPath(file, line) - } \ No newline at end of file + } + + syncToPdf: () -> + entity_id = @ide.editor.getCurrentDocId() + file = @ide.fileTreeManager.getPathOfEntityId(entity_id) + line = @ide.editor.getCurrentLine() + column = @ide.editor.getCurrentColumn() + + $.ajax { + url: "/project/#{@ide.project_id}/sync/code" + data: + file: file + line: line + 1 + column: column + type: "GET" + success: (response) => + data = JSON.parse(response) + if data.pdf and data.pdf.length > 0 + page = data.pdf[0].page - 1 + h = data.pdf[0].h + v = data.pdf[0].v + @view.setPdfPosition page, v - 100, h + } diff --git a/services/web/public/js/libs/pdfListView/PdfListView.js b/services/web/public/js/libs/pdfListView/PdfListView.js index 151f379fed..91deed63b9 100644 --- a/services/web/public/js/libs/pdfListView/PdfListView.js +++ b/services/web/public/js/libs/pdfListView/PdfListView.js @@ -388,11 +388,14 @@ ListView.prototype = { return pdfPosition; }, - setPdfPosition: function(pdfPosition) { + setPdfPosition: function(pdfPosition, fromTop) { if (typeof pdfPosition !== "undefined" && pdfPosition != null) { var offset = pdfPosition.offset; var page_index = pdfPosition.page; var pageView = this.pageViews[page_index]; + if (fromTop) { + offset.top = pageView.normalHeight - offset.top; + } var position = pageView.getPdfPositionInViewer(offset.left, offset.top); this.dom.scrollTop = position.top; } @@ -882,8 +885,8 @@ PDFListView.prototype = { return this.listView.getPdfPosition(); }, - setPdfPosition: function(pdfPosition) { - this.listView.setPdfPosition(pdfPosition) + setPdfPosition: function(pdfPosition, fromTop) { + this.listView.setPdfPosition(pdfPosition, fromTop) } }; PDFListView.Logger = Logger; From ef7a3788b407f1ce7070e471a5958df725fc89cf Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 8 Apr 2014 18:21:44 +0100 Subject: [PATCH 3/3] Add highlighting when syncing from code to pdf --- .../web/public/coffee/pdf/CompiledView.coffee | 4 +- .../web/public/coffee/pdf/PDFjsView.coffee | 45 ++++++++++++---- .../web/public/coffee/pdf/PdfManager.coffee | 6 +-- .../js/libs/pdfListView/HighlightsLayer.css | 16 ++++++ .../pdfListView/HighlightsLayerBuilder.js | 39 ++++++++++++++ .../public/js/libs/pdfListView/PdfListView.js | 51 ++++++++++++++++++- 6 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 services/web/public/js/libs/pdfListView/HighlightsLayer.css create mode 100644 services/web/public/js/libs/pdfListView/HighlightsLayerBuilder.js diff --git a/services/web/public/coffee/pdf/CompiledView.coffee b/services/web/public/coffee/pdf/CompiledView.coffee index fceb9e3b7a..6b6478d520 100644 --- a/services/web/public/coffee/pdf/CompiledView.coffee +++ b/services/web/public/coffee/pdf/CompiledView.coffee @@ -215,7 +215,7 @@ define [ Backbone.View::undelegateEvents.apply(this, arguments) @pdfView.undelegateEvents() - setPdfPosition: (args...) -> - @pdfView.setPdfPosition?(args...) + highlightInPdf: (args...) -> + @pdfView.highlightInPdf?(args...) diff --git a/services/web/public/coffee/pdf/PDFjsView.coffee b/services/web/public/coffee/pdf/PDFjsView.coffee index 4747ea23fd..1c3fd0b3ef 100644 --- a/services/web/public/coffee/pdf/PDFjsView.coffee +++ b/services/web/public/coffee/pdf/PDFjsView.coffee @@ -2,16 +2,18 @@ define [ "libs/pdfListView/PdfListView" "libs/pdfListView/TextLayerBuilder" "libs/pdfListView/AnnotationsLayerBuilder" + "libs/pdfListView/HighlightsLayerBuilder" "text!libs/pdfListView/TextLayer.css" "text!libs/pdfListView/AnnotationsLayer.css" + "text!libs/pdfListView/HighlightsLayer.css" "libs/backbone" "libs/jquery.storage" -], (PDFListView, TextLayerBuilder, AnnotationsLayerBuilder, textLayerCss, annotationsLayerCss) -> +], (PDFListView, TextLayerBuilder, AnnotationsLayerBuilder, HighlightsLayerBuilder, textLayerCss, annotationsLayerCss, highlightsLayerCss) -> if PDFJS? PDFJS.workerSrc = "#{window.sharelatex.pdfJsWorkerPath}" style = $("