From ff04e1662ad77431cca5841139e09ccd8a5a5614 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 1 Dec 2014 10:42:47 +0000 Subject: [PATCH] moved new pdf viewer under base App module --- services/web/public/coffee/base.coffee | 8 - .../pdfng/directives/pdfAnnotations.coffee | 74 +- .../ide/pdfng/directives/pdfHighlights.coffee | 47 +- .../coffee/ide/pdfng/directives/pdfJs.coffee | 12 - .../ide/pdfng/directives/pdfPage.coffee | 193 ++--- .../ide/pdfng/directives/pdfRenderer.coffee | 295 ++++---- .../ide/pdfng/directives/pdfTextLayer.coffee | 375 +++++----- .../ide/pdfng/directives/pdfViewer.coffee | 666 +++++++++--------- 8 files changed, 841 insertions(+), 829 deletions(-) diff --git a/services/web/public/coffee/base.coffee b/services/web/public/coffee/base.coffee index 9e1e59b49a..b050b45802 100644 --- a/services/web/public/coffee/base.coffee +++ b/services/web/public/coffee/base.coffee @@ -2,13 +2,6 @@ define [ "libs" "modules/recursionHelper" "utils/underscore" - # TODo move these into a separate definition - "ide/pdfng/directives/pdfViewer" - "ide/pdfng/directives/pdfPage" - "ide/pdfng/directives/pdfRenderer" - "ide/pdfng/directives/pdfTextLayer" - "ide/pdfng/directives/pdfAnnotations" - "ide/pdfng/directives/pdfHighlights" ], () -> App = angular.module("SharelatexApp", [ "ui.bootstrap" @@ -18,7 +11,6 @@ define [ "underscore" "ngSanitize" "ipCookie" - "pdfViewerApp" ]) return App diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee index a2d9d1751a..99c37aca09 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee @@ -1,42 +1,44 @@ -app = angular.module 'pdfAnnotations', [] +define [ + "base" +], (App) -> + # App = angular.module 'pdfAnnotations', [] + App.factory 'pdfAnnotations', [ () -> + class pdfAnnotations -app.factory 'pdfAnnotations', [ () -> - class pdfAnnotations + @EXTERNAL_LINK_TARGET = "_blank"; - @EXTERNAL_LINK_TARGET = "_blank"; + constructor: (options) -> + @annotationsLayerDiv = options.annotations; + @viewport = options.viewport + @navigateFn = options.navigateFn - constructor: (options) -> - @annotationsLayerDiv = options.annotations; - @viewport = options.viewport - @navigateFn = options.navigateFn + setAnnotations: (annotations) -> + for annotation in annotations + switch annotation.subtype + when 'Link' then @addLink(annotation); + when 'Text' then continue - setAnnotations: (annotations) -> - for annotation in annotations - switch annotation.subtype - when 'Link' then @addLink(annotation); - when 'Text' then continue + addLink: (link) -> + element = @buildLinkElementFromRect(link.rect); + @setLinkTarget(element, link); + @annotationsLayerDiv.appendChild(element); - addLink: (link) -> - element = @buildLinkElementFromRect(link.rect); - @setLinkTarget(element, link); - @annotationsLayerDiv.appendChild(element); + buildLinkElementFromRect: (rect) -> + rect = @viewport.convertToViewportRectangle(rect); + rect = PDFJS.Util.normalizeRect(rect); + element = document.createElement("a"); + element.style.left = Math.floor(rect[0]) + 'px'; + element.style.top = Math.floor(rect[1]) + 'px'; + element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; + element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + element - buildLinkElementFromRect: (rect) -> - rect = @viewport.convertToViewportRectangle(rect); - rect = PDFJS.Util.normalizeRect(rect); - element = document.createElement("a"); - element.style.left = Math.floor(rect[0]) + 'px'; - element.style.top = Math.floor(rect[1]) + 'px'; - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; - element - - setLinkTarget: (element, link) -> - if link.url - element.href = link.url; - element.target = @EXTERNAL_LINK_TARGET; - else if (link.dest) - element.href = "#" + link.dest; - element.onclick = (e) => - @navigateFn link -] + setLinkTarget: (element, link) -> + if link.url + element.href = link.url; + element.target = @EXTERNAL_LINK_TARGET; + else if (link.dest) + element.href = "#" + link.dest; + element.onclick = (e) => + @navigateFn link + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee index 2c93e8bef5..fc2b72bd79 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee @@ -1,26 +1,29 @@ -app = angular.module 'pdfHighlights', [] +define [ + "base" +], (App) -> + #app = angular.module 'pdfHighlights', [] -app.factory 'pdfHighlights', [ () -> - class pdfHighlights + App.factory 'pdfHighlights', [ () -> + class pdfHighlights - constructor: (options) -> - @highlightsLayerDiv = options.highlights[0] - @highlightElements = [] + constructor: (options) -> + @highlightsLayerDiv = options.highlights[0] + @highlightElements = [] - addHighlight: (viewport, left, top, width, height) -> - rect = viewport.convertToViewportRectangle([left, top, left + width, top + height]) - rect = PDFJS.Util.normalizeRect(rect) - element = document.createElement("div") - element.style.left = Math.floor(rect[0]) + 'px' - element.style.top = Math.floor(rect[1]) + 'px' - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px' - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px' - @highlightElements.push(element) - @highlightsLayerDiv.appendChild(element) - element + addHighlight: (viewport, left, top, width, height) -> + rect = viewport.convertToViewportRectangle([left, top, left + width, top + height]) + rect = PDFJS.Util.normalizeRect(rect) + element = document.createElement("div") + element.style.left = Math.floor(rect[0]) + 'px' + element.style.top = Math.floor(rect[1]) + 'px' + element.style.width = Math.ceil(rect[2] - rect[0]) + 'px' + element.style.height = Math.ceil(rect[3] - rect[1]) + 'px' + @highlightElements.push(element) + @highlightsLayerDiv.appendChild(element) + element - clearHighlights: () -> - for h in @highlightElements - h.remove() - @highlightElements = [] -] + clearHighlights: () -> + for h in @highlightElements + h.remove() + @highlightElements = [] + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee index 41e91fbd66..8deba7548a 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee @@ -1,24 +1,12 @@ define [ "base" - "ide/pdfng/directives/pdfTextLayer" - "ide/pdfng/directives/pdfAnnotations" - "ide/pdfng/directives/pdfHighlights" - "ide/pdfng/directives/pdfRenderer" - "ide/pdfng/directives/pdfPage" "ide/pdfng/directives/pdfViewer" - "libs/pdfjs-1.0.712/pdf" "text!libs/pdfListView/TextLayer.css" "text!libs/pdfListView/AnnotationsLayer.css" "text!libs/pdfListView/HighlightsLayer.css" ], ( App pdfViewer - pdfPage - pdfRenderer - pdfTextLayer - pdfAnnotations - pdfHighlights - pdf textLayerCss annotationsLayerCss highlightsLayerCss diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee index fcfad6b9c0..f28f09d2dc 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfPage.coffee @@ -1,104 +1,107 @@ -app = angular.module 'pdfPage', ['pdfHighlights'] +define [ + "base" +], (App) -> + # App = angular.module 'pdfPage', ['pdfHighlights'] -app.directive 'pdfPage', ['$timeout', 'pdfHighlights', ($timeout, pdfHighlights) -> - { - require: '^pdfViewer', - template: ''' -
-
-
-
-
-
- ''' - link: (scope, element, attrs, ctrl) -> - canvasElement = $(element).find('.pdf-canvas') - textElement = $(element).find('.text-layer') - annotationsElement = $(element).find('.annotations-layer') - highlightsElement = $(element).find('.highlights-layer') + App.directive 'pdfPage', ['$timeout', 'pdfHighlights', ($timeout, pdfHighlights) -> + { + require: '^pdfViewer', + template: ''' +
+
+
+
+
+
+ ''' + link: (scope, element, attrs, ctrl) -> + canvasElement = $(element).find('.pdf-canvas') + textElement = $(element).find('.text-layer') + annotationsElement = $(element).find('.annotations-layer') + highlightsElement = $(element).find('.highlights-layer') - updatePageSize = (size) -> - element.height(Math.floor(size[0])) - element.width(Math.floor(size[1])) - scope.page.sized = true + updatePageSize = (size) -> + element.height(Math.floor(size[0])) + element.width(Math.floor(size[1])) + scope.page.sized = true - isVisible = (containerSize) -> - elemTop = element.offset().top - containerSize[2] - elemBottom = elemTop + element.innerHeight() - visible = (elemTop < containerSize[1] and elemBottom > 0) - scope.page.visible = visible - scope.page.elemTop = elemTop - scope.page.elemBottom = elemBottom - return visible + isVisible = (containerSize) -> + elemTop = element.offset().top - containerSize[2] + elemBottom = elemTop + element.innerHeight() + visible = (elemTop < containerSize[1] and elemBottom > 0) + scope.page.visible = visible + scope.page.elemTop = elemTop + scope.page.elemBottom = elemBottom + return visible - renderPage = () -> - scope.document.renderPage { - canvas: canvasElement, - text: textElement - annotations: annotationsElement + renderPage = () -> + scope.document.renderPage { + canvas: canvasElement, + text: textElement + annotations: annotationsElement + highlights: highlightsElement + }, scope.page.pageNum + + pausePage = () -> + scope.document.pause { + canvas: canvasElement, + text: textElement + }, scope.page.pageNum + + # keep track of our page element, so we can access it in the + # parent with scope.pages[i].element + scope.page.element = element + + if (!scope.page.sized && scope.defaultPageSize) + updatePageSize scope.defaultPageSize + + if scope.page.current + console.log 'we must scroll to this page', scope.page.pageNum, + 'at position', scope.page.position + renderPage() + # this is the current page, we want to scroll it into view + scope.document.getPdfViewport(scope.page.pageNum).then (viewport) -> + scope.page.viewport = viewport + ctrl.setPdfPosition(scope.page, scope.page.position) + + scope.$watch 'defaultPageSize', (defaultPageSize) -> + return unless defaultPageSize? + updatePageSize defaultPageSize + + watchHandle = scope.$watch 'containerSize', (containerSize, oldVal) -> + return unless containerSize? + return unless scope.page.sized + oldVisible = scope.page.visible + newVisible = isVisible containerSize + scope.page.visible = newVisible + if newVisible && !oldVisible + renderPage() + # TODO deregister this listener after the page is rendered + #watchHandle() + else if !newVisible && oldVisible + pausePage() + + highlightsLayer = new pdfHighlights({ highlights: highlightsElement - }, scope.page.pageNum + }) - pausePage = () -> - scope.document.pause { - canvas: canvasElement, - text: textElement - }, scope.page.pageNum - - # keep track of our page element, so we can access it in the - # parent with scope.pages[i].element - scope.page.element = element - - if (!scope.page.sized && scope.defaultPageSize) - updatePageSize scope.defaultPageSize - - if scope.page.current - console.log 'we must scroll to this page', scope.page.pageNum, - 'at position', scope.page.position - renderPage() - # this is the current page, we want to scroll it into view + scope.$watch 'highlights', (highlights, oldVal) -> + return unless highlights? + return unless highlights.length > 0 + console.log 'got highlight watch in pdfPage', scope.page + pageHighlights = (h for h in highlights when h.page == scope.page.pageNum) + return unless pageHighlights.length scope.document.getPdfViewport(scope.page.pageNum).then (viewport) -> - scope.page.viewport = viewport - ctrl.setPdfPosition(scope.page, scope.page.position) + for hl in pageHighlights + console.log 'adding highlight', h, viewport + top = viewport.viewBox[3] - hl.v + highlightsLayer.addHighlight viewport, hl.h, top, hl.width, hl.height + $timeout () -> + highlightsLayer.clearHighlights() + , 1000 - scope.$watch 'defaultPageSize', (defaultPageSize) -> - return unless defaultPageSize? - updatePageSize defaultPageSize + scope.$on "$destroy", () -> + console.log 'in destroy handler, TODO need to clean up timeout/highlights' - watchHandle = scope.$watch 'containerSize', (containerSize, oldVal) -> - return unless containerSize? - return unless scope.page.sized - oldVisible = scope.page.visible - newVisible = isVisible containerSize - scope.page.visible = newVisible - if newVisible && !oldVisible - renderPage() - # TODO deregister this listener after the page is rendered - #watchHandle() - else if !newVisible && oldVisible - pausePage() - - highlightsLayer = new pdfHighlights({ - highlights: highlightsElement - }) - - scope.$watch 'highlights', (highlights, oldVal) -> - return unless highlights? - return unless highlights.length > 0 - console.log 'got highlight watch in pdfPage', scope.page - pageHighlights = (h for h in highlights when h.page == scope.page.pageNum) - return unless pageHighlights.length - scope.document.getPdfViewport(scope.page.pageNum).then (viewport) -> - for hl in pageHighlights - console.log 'adding highlight', h, viewport - top = viewport.viewBox[3] - hl.v - highlightsLayer.addHighlight viewport, hl.h, top, hl.width, hl.height - $timeout () -> - highlightsLayer.clearHighlights() - , 1000 - - scope.$on "$destroy", () -> - console.log 'in destroy handler, TODO need to clean up timeout/highlights' - - } -] + } + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee index 8957fd83c9..eaad381577 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee @@ -1,185 +1,188 @@ -app = angular.module 'PDFRenderer', ['pdfAnnotations', 'pdfTextLayer'] +define [ + "base" +], (App) -> + # App = angular.module 'PDFRenderer', ['pdfAnnotations', 'pdfTextLayer'] -console.log 'hello from Renderer' + console.log 'hello from Renderer' -app.factory 'PDFRenderer', ['$q', '$timeout', 'pdfAnnotations', 'pdfTextLayer', ($q, $timeout, pdfAnnotations, pdfTextLayer) -> + App.factory 'PDFRenderer', ['$q', '$timeout', 'pdfAnnotations', 'pdfTextLayer', ($q, $timeout, pdfAnnotations, pdfTextLayer) -> - class PDFRenderer - @JOB_QUEUE_INTERVAL: 100 + class PDFRenderer + @JOB_QUEUE_INTERVAL: 100 - constructor: (@url, @options) -> - @scale = @options.scale || 1 - @document = $q.when(PDFJS.getDocument @url) - @navigateFn = @options.navigateFn - @resetState() + constructor: (@url, @options) -> + @scale = @options.scale || 1 + @document = $q.when(PDFJS.getDocument @url) + @navigateFn = @options.navigateFn + @resetState() - resetState: () -> - console.log 'reseting renderer state' - @page = [] - @complete = [] - @timeout = [] - @renderTask = [] - @renderQueue = [] - @jobs = 0 + resetState: () -> + console.log 'reseting renderer state' + @page = [] + @complete = [] + @timeout = [] + @renderTask = [] + @renderQueue = [] + @jobs = 0 - getNumPages: () -> - @document.then (pdfDocument) -> - pdfDocument.numPages + getNumPages: () -> + @document.then (pdfDocument) -> + pdfDocument.numPages - getPage: (pageNum) -> - # with promise caching - return @page[pageNum] if @page[pageNum]? - @page[pageNum] = @document.then (pdfDocument) -> - pdfDocument.getPage(pageNum) + getPage: (pageNum) -> + # with promise caching + return @page[pageNum] if @page[pageNum]? + @page[pageNum] = @document.then (pdfDocument) -> + pdfDocument.getPage(pageNum) - getPdfViewport: (pageNum, scale) -> - scale ?= @scale - @document.then (pdfDocument) -> - pdfDocument.getPage(pageNum).then (page) -> - viewport = page.getViewport scale + getPdfViewport: (pageNum, scale) -> + scale ?= @scale + @document.then (pdfDocument) -> + pdfDocument.getPage(pageNum).then (page) -> + viewport = page.getViewport scale - getDestinations: () -> - @document.then (pdfDocument) -> - pdfDocument.getDestinations() + getDestinations: () -> + @document.then (pdfDocument) -> + pdfDocument.getDestinations() - getPageIndex: (ref) -> - @document.then (pdfDocument) -> - pdfDocument.getPageIndex(ref).then (idx) -> - idx + getPageIndex: (ref) -> + @document.then (pdfDocument) -> + pdfDocument.getPageIndex(ref).then (idx) -> + idx - getScale: () -> - @scale + getScale: () -> + @scale - setScale: (@scale) -> - @resetState() + setScale: (@scale) -> + @resetState() - pause: (element, pagenum) -> - return if @complete[pagenum] - @renderQueue = @renderQueue.filter (q) -> - q.pagenum != pagenum - @stopSpinner (element.canvas) + pause: (element, pagenum) -> + return if @complete[pagenum] + @renderQueue = @renderQueue.filter (q) -> + q.pagenum != pagenum + @stopSpinner (element.canvas) - triggerRenderQueue: () -> - $timeout () => - @processRenderQueue() - , @JOB_QUEUE_INTERVAL + triggerRenderQueue: () -> + $timeout () => + @processRenderQueue() + , @JOB_QUEUE_INTERVAL - removeCompletedJob: (pagenum) -> - # may need to clean up deferred object here - delete @renderTask[pagenum] - @jobs = @jobs - 1 - @triggerRenderQueue() + removeCompletedJob: (pagenum) -> + # may need to clean up deferred object here + delete @renderTask[pagenum] + @jobs = @jobs - 1 + @triggerRenderQueue() - renderPage: (element, pagenum) -> - viewport = $q.defer() - current = { - 'element': element - 'pagenum': pagenum - } - @renderQueue.push(current) - @triggerRenderQueue() + renderPage: (element, pagenum) -> + viewport = $q.defer() + current = { + 'element': element + 'pagenum': pagenum + } + @renderQueue.push(current) + @triggerRenderQueue() - processRenderQueue: () -> - return if @jobs > 0 - current = @renderQueue.pop() - return unless current? - [element, pagenum] = [current.element, current.pagenum] - return if @complete[pagenum] - return if @renderTask[pagenum] - @jobs = @jobs + 1 + processRenderQueue: () -> + return if @jobs > 0 + current = @renderQueue.pop() + return unless current? + [element, pagenum] = [current.element, current.pagenum] + return if @complete[pagenum] + return if @renderTask[pagenum] + @jobs = @jobs + 1 - @addSpinner(element.canvas) + @addSpinner(element.canvas) - pageLoad = @getPage(pagenum) + pageLoad = @getPage(pagenum) - @renderTask[pagenum] = pageLoad.then (pageObject) => - @doRender element, pagenum, pageObject + @renderTask[pagenum] = pageLoad.then (pageObject) => + @doRender element, pagenum, pageObject - @renderTask[pagenum].then () => - # complete - @complete[pagenum] = true - @removeCompletedJob pagenum - , () => - # rejected - @removeCompletedJob pagenum + @renderTask[pagenum].then () => + # complete + @complete[pagenum] = true + @removeCompletedJob pagenum + , () => + # rejected + @removeCompletedJob pagenum - doRender: (element, pagenum, page) -> - self = this - scale = @scale + doRender: (element, pagenum, page) -> + self = this + scale = @scale - if (not scale?) - console.log 'scale is undefined, returning' - return + if (not scale?) + console.log 'scale is undefined, returning' + return - canvas = $('') + canvas = $('') - viewport = page.getViewport (scale) + viewport = page.getViewport (scale) - devicePixelRatio = window.devicePixelRatio || 1 + devicePixelRatio = window.devicePixelRatio || 1 - ctx = canvas[0].getContext '2d' - backingStoreRatio = ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1 - pixelRatio = devicePixelRatio / backingStoreRatio + ctx = canvas[0].getContext '2d' + backingStoreRatio = ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || 1 + pixelRatio = devicePixelRatio / backingStoreRatio - scaledWidth = (Math.floor(viewport.width) * pixelRatio) | 0 - scaledHeight = (Math.floor(viewport.height) * pixelRatio) | 0 + scaledWidth = (Math.floor(viewport.width) * pixelRatio) | 0 + scaledHeight = (Math.floor(viewport.height) * pixelRatio) | 0 - newWidth = Math.floor(viewport.width) - newHeight = Math.floor(viewport.height) + newWidth = Math.floor(viewport.width) + newHeight = Math.floor(viewport.height) - canvas[0].height = scaledHeight - canvas[0].width = scaledWidth + canvas[0].height = scaledHeight + canvas[0].width = scaledWidth - canvas.height(newHeight + 'px') - canvas.width(newWidth + 'px') + canvas.height(newHeight + 'px') + canvas.width(newWidth + 'px') - element.canvas[0].height = newHeight - element.canvas[0].width = newWidth + element.canvas[0].height = newHeight + element.canvas[0].width = newWidth - if pixelRatio != 1 - ctx.scale(pixelRatio, pixelRatio) + if pixelRatio != 1 + ctx.scale(pixelRatio, pixelRatio) - textLayer = new pdfTextLayer({ - textLayerDiv: element.text[0] - viewport: viewport - }) - page.getTextContent().then (textContent) -> - console.log 'text content is', textContent - window.RENDER_DELAY = 0 - textLayer.setTextContent textContent + textLayer = new pdfTextLayer({ + textLayerDiv: element.text[0] + viewport: viewport + }) + page.getTextContent().then (textContent) -> + console.log 'text content is', textContent + window.RENDER_DELAY = 0 + textLayer.setTextContent textContent - annotationsLayer = new pdfAnnotations({ - annotations: element.annotations[0] - viewport: viewport - navigateFn: @navigateFn - }) - page.getAnnotations().then (annotations) -> - console.log 'annotations are', annotations - window.RENDER_DELAY = 0 - annotationsLayer.setAnnotations annotations + annotationsLayer = new pdfAnnotations({ + annotations: element.annotations[0] + viewport: viewport + navigateFn: @navigateFn + }) + page.getAnnotations().then (annotations) -> + console.log 'annotations are', annotations + window.RENDER_DELAY = 0 + annotationsLayer.setAnnotations annotations - return @renderTask = page.render { - canvasContext: ctx - viewport: viewport - } - .then () -> - element.canvas.replaceWith(canvas) - canvas.removeClass('pdf-canvas-new') + return @renderTask = page.render { + canvasContext: ctx + viewport: viewport + } + .then () -> + element.canvas.replaceWith(canvas) + canvas.removeClass('pdf-canvas-new') - addSpinner: (element) -> - element.css({position: 'relative'}) - h = element.parent().height() - w = element.parent().width() - size = Math.floor(0.5 * Math.min(h, w)) - spinner = $('
') - spinner.css({'font-size' : size + 'px'}) - element.append(spinner) + addSpinner: (element) -> + element.css({position: 'relative'}) + h = element.parent().height() + w = element.parent().width() + size = Math.floor(0.5 * Math.min(h, w)) + spinner = $('
') + spinner.css({'font-size' : size + 'px'}) + element.append(spinner) - stopSpinner: (element) -> - element.find('.fa-spin').removeClass('fa-spin') + stopSpinner: (element) -> + element.find('.fa-spin').removeClass('fa-spin') - ] + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfTextLayer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfTextLayer.coffee index 8bbeffa5fd..f863d6a2b2 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfTextLayer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfTextLayer.coffee @@ -1,207 +1,210 @@ -app = angular.module 'pdfTextLayer', [] +define [ + "base" +], (App) -> + # App = angular.module 'pdfTextLayer', [] -app.factory 'pdfTextLayer', [ () -> + App.factory 'pdfTextLayer', [ () -> -# TRANSLATED FROM pdf.js-1.0.712 -# pdf.js-1.0.712/web/ui_utils.js -# pdf.js-1.0.712/web/text_layer_builder.js + # TRANSLATED FROM pdf.js-1.0.712 + # pdf.js-1.0.712/web/ui_utils.js + # pdf.js-1.0.712/web/text_layer_builder.js -# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + # -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- -# Copyright 2012 Mozilla Foundation -# * -# * Licensed under the Apache License, Version 2.0 (the "License"); -# * you may not use this file except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.apache.org/licenses/LICENSE-2.0 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# + # Copyright 2012 Mozilla Foundation + # * + # * Licensed under the Apache License, Version 2.0 (the "License"); + # * you may not use this file except in compliance with the License. + # * You may obtain a copy of the License at + # * + # * http://www.apache.org/licenses/LICENSE-2.0 + # * + # * Unless required by applicable law or agreed to in writing, software + # * distributed under the License is distributed on an "AS IS" BASIS, + # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # * See the License for the specific language governing permissions and + # * limitations under the License. + # -# globals CustomStyle, scrollIntoView, PDFJS -# ms + # globals CustomStyle, scrollIntoView, PDFJS + # ms -# optimised CSS custom property getter/setter + # optimised CSS custom property getter/setter - CustomStyle = (CustomStyleClosure = -> + CustomStyle = (CustomStyleClosure = -> - # As noted on: http://www.zachstronaut.com/posts/2009/02/17/ - # animate-css-transforms-firefox-webkit.html - # in some versions of IE9 it is critical that ms appear in this list - # before Moz - CustomStyle = -> - prefixes = [ - 'ms' - 'Moz' - 'Webkit' - 'O' - ] - _cache = {} - CustomStyle.getProp = get = (propName, element) -> + # As noted on: http://www.zachstronaut.com/posts/2009/02/17/ + # animate-css-transforms-firefox-webkit.html + # in some versions of IE9 it is critical that ms appear in this list + # before Moz + CustomStyle = -> + prefixes = [ + 'ms' + 'Moz' + 'Webkit' + 'O' + ] + _cache = {} + CustomStyle.getProp = get = (propName, element) -> - # check cache only when no element is given - return _cache[propName] if arguments.length is 1 and typeof _cache[propName] is 'string' - element = element or document.documentElement - style = element.style - prefixed = undefined - uPropName = undefined + # check cache only when no element is given + return _cache[propName] if arguments.length is 1 and typeof _cache[propName] is 'string' + element = element or document.documentElement + style = element.style + prefixed = undefined + uPropName = undefined - # test standard property first - return (_cache[propName] = propName) if typeof style[propName] is 'string' + # test standard property first + return (_cache[propName] = propName) if typeof style[propName] is 'string' - # capitalize - uPropName = propName.charAt(0).toUpperCase() + propName.slice(1) + # capitalize + uPropName = propName.charAt(0).toUpperCase() + propName.slice(1) - # test vendor specific properties - i = 0 - l = prefixes.length + # test vendor specific properties + i = 0 + l = prefixes.length - while i < l - prefixed = prefixes[i] + uPropName - return (_cache[propName] = prefixed) if typeof style[prefixed] is 'string' - i++ + while i < l + prefixed = prefixes[i] + uPropName + return (_cache[propName] = prefixed) if typeof style[prefixed] is 'string' + i++ - #if all fails then set to undefined - _cache[propName] = 'undefined' + #if all fails then set to undefined + _cache[propName] = 'undefined' - CustomStyle.setProp = set = (propName, element, str) -> - prop = @getProp(propName) - element.style[prop] = str if prop isnt 'undefined' - return - - CustomStyle - )() - - ################################# - - isAllWhitespace = (str) -> - not NonWhitespaceRegexp.test(str) - 'use strict' - FIND_SCROLL_OFFSET_TOP = -50 - FIND_SCROLL_OFFSET_LEFT = -400 - MAX_TEXT_DIVS_TO_RENDER = 100000 - RENDER_DELAY = 200 - NonWhitespaceRegexp = /\S/ - - ###* - TextLayerBuilder provides text-selection functionality for the PDF. - It does this by creating overlay divs over the PDF text. These divs - contain text that matches the PDF text they are overlaying. This object - also provides a way to highlight text that is being searched for. - ### - - class pdfTextLayer - - constructor: (options) -> - @textLayerDiv = options.textLayerDiv - @layoutDone = false - @divContentDone = false - @pageIdx = options.pageIndex - @matches = [] - @lastScrollSource = options.lastScrollSource or null - @viewport = options.viewport - @isViewerInPresentationMode = options.isViewerInPresentationMode - @textDivs = [] - @findController = options.findController or null - - renderLayer: () -> - textLayerFrag = document.createDocumentFragment() - textDivs = @textDivs - textDivsLength = textDivs.length - canvas = document.createElement('canvas') - ctx = canvas.getContext('2d') - - # No point in rendering many divs as it would make the browser - # unusable even after the divs are rendered. - return if textDivsLength > MAX_TEXT_DIVS_TO_RENDER - lastFontSize = undefined - lastFontFamily = undefined - i = 0 - - while i < textDivsLength - textDiv = textDivs[i] - continue if textDiv.dataset.isWhitespace - fontSize = textDiv.style.fontSize - fontFamily = textDiv.style.fontFamily - - # Only build font string and set to context if different from last. - if fontSize isnt lastFontSize or fontFamily isnt lastFontFamily - ctx.font = fontSize + ' ' + fontFamily - lastFontSize = fontSize - lastFontFamily = fontFamily - width = ctx.measureText(textDiv.textContent).width - if width > 0 - textLayerFrag.appendChild textDiv - - # Dataset values come of type string. - textScale = textDiv.dataset.canvasWidth / width - rotation = textDiv.dataset.angle - transform = 'scale(' + textScale + ', 1)' - transform = 'rotate(' + rotation + 'deg) ' + transform if rotation - CustomStyle.setProp 'transform', textDiv, transform - CustomStyle.setProp 'transformOrigin', textDiv, '0% 0%' - i++ - @textLayerDiv.appendChild textLayerFrag - return - - appendText: (geom, styles) -> - style = styles[geom.fontName] - textDiv = document.createElement('div') - @textDivs.push textDiv - if isAllWhitespace(geom.str) - textDiv.dataset.isWhitespace = true + CustomStyle.setProp = set = (propName, element, str) -> + prop = @getProp(propName) + element.style[prop] = str if prop isnt 'undefined' return - tx = PDFJS.Util.transform(@viewport.transform, geom.transform) - angle = Math.atan2(tx[1], tx[0]) - angle += Math.PI / 2 if style.vertical - fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3])) - fontAscent = fontHeight - if style.ascent - fontAscent = style.ascent * fontAscent - else fontAscent = (1 + style.descent) * fontAscent if style.descent - left = undefined - top = undefined - if angle is 0 - left = tx[4] - top = tx[5] - fontAscent - else - left = tx[4] + (fontAscent * Math.sin(angle)) - top = tx[5] - (fontAscent * Math.cos(angle)) - textDiv.style.left = left + 'px' - textDiv.style.top = top + 'px' - textDiv.style.fontSize = fontHeight + 'px' - textDiv.style.fontFamily = style.fontFamily - textDiv.textContent = geom.str - # |fontName| is only used by the Font Inspector. This test will succeed - # when e.g. the Font Inspector is off but the Stepper is on, but it's - # not worth the effort to do a more accurate test. - textDiv.dataset.fontName = geom.fontName if PDFJS.pdfBug + CustomStyle + )() - # Storing into dataset will convert number into string. - textDiv.dataset.angle = angle * (180 / Math.PI) if angle isnt 0 - if style.vertical - textDiv.dataset.canvasWidth = geom.height * @viewport.scale - else - textDiv.dataset.canvasWidth = geom.width * @viewport.scale - return + ################################# - setTextContent: (textContent) -> - @textContent = textContent - textItems = textContent.items - i = 0 - len = textItems.length + isAllWhitespace = (str) -> + not NonWhitespaceRegexp.test(str) + 'use strict' + FIND_SCROLL_OFFSET_TOP = -50 + FIND_SCROLL_OFFSET_LEFT = -400 + MAX_TEXT_DIVS_TO_RENDER = 100000 + RENDER_DELAY = 200 + NonWhitespaceRegexp = /\S/ - while i < len - @appendText textItems[i], textContent.styles - i++ - @divContentDone = true - @renderLayer() - return + ###* + TextLayerBuilder provides text-selection functionality for the PDF. + It does this by creating overlay divs over the PDF text. These divs + contain text that matches the PDF text they are overlaying. This object + also provides a way to highlight text that is being searched for. + ### -] + class pdfTextLayer + + constructor: (options) -> + @textLayerDiv = options.textLayerDiv + @layoutDone = false + @divContentDone = false + @pageIdx = options.pageIndex + @matches = [] + @lastScrollSource = options.lastScrollSource or null + @viewport = options.viewport + @isViewerInPresentationMode = options.isViewerInPresentationMode + @textDivs = [] + @findController = options.findController or null + + renderLayer: () -> + textLayerFrag = document.createDocumentFragment() + textDivs = @textDivs + textDivsLength = textDivs.length + canvas = document.createElement('canvas') + ctx = canvas.getContext('2d') + + # No point in rendering many divs as it would make the browser + # unusable even after the divs are rendered. + return if textDivsLength > MAX_TEXT_DIVS_TO_RENDER + lastFontSize = undefined + lastFontFamily = undefined + i = 0 + + while i < textDivsLength + textDiv = textDivs[i] + continue if textDiv.dataset.isWhitespace + fontSize = textDiv.style.fontSize + fontFamily = textDiv.style.fontFamily + + # Only build font string and set to context if different from last. + if fontSize isnt lastFontSize or fontFamily isnt lastFontFamily + ctx.font = fontSize + ' ' + fontFamily + lastFontSize = fontSize + lastFontFamily = fontFamily + width = ctx.measureText(textDiv.textContent).width + if width > 0 + textLayerFrag.appendChild textDiv + + # Dataset values come of type string. + textScale = textDiv.dataset.canvasWidth / width + rotation = textDiv.dataset.angle + transform = 'scale(' + textScale + ', 1)' + transform = 'rotate(' + rotation + 'deg) ' + transform if rotation + CustomStyle.setProp 'transform', textDiv, transform + CustomStyle.setProp 'transformOrigin', textDiv, '0% 0%' + i++ + @textLayerDiv.appendChild textLayerFrag + return + + appendText: (geom, styles) -> + style = styles[geom.fontName] + textDiv = document.createElement('div') + @textDivs.push textDiv + if isAllWhitespace(geom.str) + textDiv.dataset.isWhitespace = true + return + tx = PDFJS.Util.transform(@viewport.transform, geom.transform) + angle = Math.atan2(tx[1], tx[0]) + angle += Math.PI / 2 if style.vertical + fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3])) + fontAscent = fontHeight + if style.ascent + fontAscent = style.ascent * fontAscent + else fontAscent = (1 + style.descent) * fontAscent if style.descent + left = undefined + top = undefined + if angle is 0 + left = tx[4] + top = tx[5] - fontAscent + else + left = tx[4] + (fontAscent * Math.sin(angle)) + top = tx[5] - (fontAscent * Math.cos(angle)) + textDiv.style.left = left + 'px' + textDiv.style.top = top + 'px' + textDiv.style.fontSize = fontHeight + 'px' + textDiv.style.fontFamily = style.fontFamily + textDiv.textContent = geom.str + + # |fontName| is only used by the Font Inspector. This test will succeed + # when e.g. the Font Inspector is off but the Stepper is on, but it's + # not worth the effort to do a more accurate test. + textDiv.dataset.fontName = geom.fontName if PDFJS.pdfBug + + # Storing into dataset will convert number into string. + textDiv.dataset.angle = angle * (180 / Math.PI) if angle isnt 0 + if style.vertical + textDiv.dataset.canvasWidth = geom.height * @viewport.scale + else + textDiv.dataset.canvasWidth = geom.width * @viewport.scale + return + + setTextContent: (textContent) -> + @textContent = textContent + textItems = textContent.items + i = 0 + len = textItems.length + + while i < len + @appendText textItems[i], textContent.styles + i++ + @divContentDone = true + @renderLayer() + return + + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index 556e1c7d47..3b8a625da8 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee @@ -1,359 +1,377 @@ -app = angular.module 'pdfViewerApp', ['pdfPage', 'PDFRenderer', 'pdfHighlights'] +define [ + "base" + "ide/pdfng/directives/pdfTextLayer" + "ide/pdfng/directives/pdfAnnotations" + "ide/pdfng/directives/pdfHighlights" + "ide/pdfng/directives/pdfRenderer" + "ide/pdfng/directives/pdfPage" + "libs/pdfjs-1.0.712/pdf" +], ( + App + pdfTextLayer + pdfAnnotations + pdfHighlights + pdfRenderer + pdfPage + pdf +) -> -app.controller 'pdfViewerController', ['$scope', '$q', 'PDFRenderer', '$element', 'pdfHighlights', ($scope, $q, PDFRenderer, $element, pdfHighlights) -> - @load = () -> - $scope.document = new PDFRenderer($scope.pdfSrc, { - scale: 1, - navigateFn: (ref) -> - # this function captures clicks on the annotation links - $scope.navigateTo = ref - $scope.$apply() - }) + # App = angular.module 'pdfViewerApp', ['pdfPage', 'PDFRenderer', 'pdfHighlights'] - # we will have all the main information needed to start display - # after the following promise is resolved - $scope.loaded = $q.all({ - numPages: $scope.document.getNumPages() - destinations: $scope.document.getDestinations() - # get size of first page as default @ scale 1 - pdfViewport: $scope.document.getPdfViewport 1, 1 - }).then (result) -> - $scope.pdfViewport = result.pdfViewport - $scope.pdfPageSize = [ - result.pdfViewport.height, - result.pdfViewport.width + App.controller 'pdfViewerController', ['$scope', '$q', 'PDFRenderer', '$element', 'pdfHighlights', ($scope, $q, PDFRenderer, $element, pdfHighlights) -> + @load = () -> + $scope.document = new PDFRenderer($scope.pdfSrc, { + scale: 1, + navigateFn: (ref) -> + # this function captures clicks on the annotation links + $scope.navigateTo = ref + $scope.$apply() + }) + + # we will have all the main information needed to start display + # after the following promise is resolved + $scope.loaded = $q.all({ + numPages: $scope.document.getNumPages() + destinations: $scope.document.getDestinations() + # get size of first page as default @ scale 1 + pdfViewport: $scope.document.getPdfViewport 1, 1 + }).then (result) -> + $scope.pdfViewport = result.pdfViewport + $scope.pdfPageSize = [ + result.pdfViewport.height, + result.pdfViewport.width + ] + $scope.destinations = result.destinations + console.log 'resolved q.all, page size is', result + $scope.numPages = result.numPages + + @setScale = (scale, containerHeight, containerWidth) -> + $scope.loaded.then () -> + scale = {} if not scale? + if scale.scaleMode == 'scale_mode_fit_width' + # TODO make this dynamic + numScale = (containerWidth - 40) / ($scope.pdfPageSize[1]) + else if scale.scaleMode == 'scale_mode_fit_height' + # TODO magic numbers for jquery ui layout + numScale = (containerHeight - 20) / ($scope.pdfPageSize[0]) + else if scale.scaleMode == 'scale_mode_value' + numScale = scale.scale + else if scale.scaleMode == 'scale_mode_auto' + # TODO + else + scale.scaleMode = 'scale_mode_fit_width' + numScale = (containerWidth - 40) / ($scope.pdfPageSize[1]) + # TODO + $scope.scale.scale = numScale + $scope.document.setScale(numScale) + $scope.defaultPageSize = [ + numScale * $scope.pdfPageSize[0], + numScale * $scope.pdfPageSize[1] ] - $scope.destinations = result.destinations - console.log 'resolved q.all, page size is', result - $scope.numPages = result.numPages + console.log 'in setScale result', $scope.scale.scale, $scope.defaultPageSize - @setScale = (scale, containerHeight, containerWidth) -> - $scope.loaded.then () -> - scale = {} if not scale? - if scale.scaleMode == 'scale_mode_fit_width' - # TODO make this dynamic - numScale = (containerWidth - 40) / ($scope.pdfPageSize[1]) - else if scale.scaleMode == 'scale_mode_fit_height' - # TODO magic numbers for jquery ui layout - numScale = (containerHeight - 20) / ($scope.pdfPageSize[0]) - else if scale.scaleMode == 'scale_mode_value' - numScale = scale.scale - else if scale.scaleMode == 'scale_mode_auto' - # TODO - else - scale.scaleMode = 'scale_mode_fit_width' - numScale = (containerWidth - 40) / ($scope.pdfPageSize[1]) - # TODO - $scope.scale.scale = numScale - $scope.document.setScale(numScale) - $scope.defaultPageSize = [ - numScale * $scope.pdfPageSize[0], - numScale * $scope.pdfPageSize[1] + @redraw = (position) -> + console.log 'in redraw' + console.log 'reseting pages array for', $scope.numPages + console.log 'position is', position.page, position.offset + $scope.pages = ({ + pageNum: i + 1 + } for i in [0 .. $scope.numPages-1]) + if position? && position.page? + console.log 'setting current page', position.page + pagenum = position.page + $scope.pages[pagenum].current = true + $scope.pages[pagenum].position = position + + @zoomIn = () -> + console.log 'zoom in' + newScale = $scope.scale.scale * 1.2 + $scope.forceScale = { scaleMode: 'scale_mode_value', scale: newScale } + + @zoomOut = () -> + console.log 'zoom out' + newScale = $scope.scale.scale / 1.2 + $scope.forceScale = { scaleMode: 'scale_mode_value', scale: newScale } + + @fitWidth = () -> + console.log 'fit width' + $scope.forceScale = { scaleMode: 'scale_mode_fit_width' } + + @fitHeight = () -> + console.log 'fit height' + $scope.forceScale = { scaleMode: 'scale_mode_fit_height' } + + @checkPosition = () -> + console.log 'check position' + $scope.forceCheck = ($scope.forceCheck || 0) + 1 + + @showRandomHighlights = () -> + console.log 'show highlights' + $scope.highlights = [ + { + page: 3 + h: 100 + v: 100 + height: 30 + width: 200 + } ] - console.log 'in setScale result', $scope.scale.scale, $scope.defaultPageSize - @redraw = (position) -> - console.log 'in redraw' - console.log 'reseting pages array for', $scope.numPages - console.log 'position is', position.page, position.offset - $scope.pages = ({ - pageNum: i + 1 - } for i in [0 .. $scope.numPages-1]) - if position? && position.page? - console.log 'setting current page', position.page - pagenum = position.page - $scope.pages[pagenum].current = true - $scope.pages[pagenum].position = position + # we work with (pagenumber, % of height down page from top) + # pdfListView works with (pagenumber, vertical position up page from + # bottom measured in pts) - @zoomIn = () -> - console.log 'zoom in' - newScale = $scope.scale.scale * 1.2 - $scope.forceScale = { scaleMode: 'scale_mode_value', scale: newScale } + @getPdfPosition = () -> + console.log 'in getPdfPosition' + topPageIdx = 0 + topPage = $scope.pages[0] + # find first visible page + visible = $scope.pages.some (page, i) -> + [topPageIdx, topPage] = [i, page] if page.visible + if visible + console.log 'found it', topPageIdx + else + console.log 'CANNOT FIND TOP PAGE' - @zoomOut = () -> - console.log 'zoom out' - newScale = $scope.scale.scale / 1.2 - $scope.forceScale = { scaleMode: 'scale_mode_value', scale: newScale } - - @fitWidth = () -> - console.log 'fit width' - $scope.forceScale = { scaleMode: 'scale_mode_fit_width' } - - @fitHeight = () -> - console.log 'fit height' - $scope.forceScale = { scaleMode: 'scale_mode_fit_height' } - - @checkPosition = () -> - console.log 'check position' - $scope.forceCheck = ($scope.forceCheck || 0) + 1 - - @showRandomHighlights = () -> - console.log 'show highlights' - $scope.highlights = [ - { - page: 3 - h: 100 - v: 100 - height: 30 - width: 200 + console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage + top = topPage.elemTop + bottom = topPage.elemBottom + viewportTop = 0 + viewportHeight = $element.height() + topVisible = (top >= viewportTop && top < viewportTop + viewportHeight) + someContentVisible = (top < viewportTop && bottom > viewportTop) + console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop + if topVisible + canvasOffset = 0 + else if someContentVisible + canvasOffset = viewportTop - top + else + canvasOffset = null + console.log 'pdfListview position = ', canvasOffset + # instead of using promise, check if size is known and revert to + # default otherwise + console.log 'looking up viewport', topPage.viewport, $scope.pdfViewport + if topPage.viewport + viewport = topPage.viewport + pdfOffset = viewport.convertToPdfPoint(0, canvasOffset); + else + console.log 'WARNING: had to default to global page size' + viewport = $scope.pdfViewport + scaledOffset = canvasOffset / $scope.scale.scale + pdfOffset = viewport.convertToPdfPoint(0, scaledOffset); + console.log 'converted to offset = ', pdfOffset + newPosition = { + "page": topPageIdx, + "offset" : { "top" : pdfOffset[1], "left": 0 } } - ] + return newPosition - # we work with (pagenumber, % of height down page from top) - # pdfListView works with (pagenumber, vertical position up page from - # bottom measured in pts) + @computeOffset = (page, position) -> + console.log 'computing offset for', page, position + element = page.element + pageTop = $(element).offset().top - $(element).parent().offset().top + console.log('top of page scroll is', pageTop, 'vs', page.elemTop) + console.log('inner height is', $(element).innerHeight()) + currentScroll = $(element).parent().scrollTop() + offset = position.offset + # convert offset to pixels + return $scope.document.getPdfViewport(page.pageNum).then (viewport) -> + page.viewport = viewport + pageOffset = viewport.convertToViewportPoint(offset.left, offset.top) + console.log 'addition offset =', pageOffset + console.log 'total', pageTop + pageOffset[1] + Math.round(pageTop + pageOffset[1] + currentScroll) ## 10 is margin - @getPdfPosition = () -> - console.log 'in getPdfPosition' - topPageIdx = 0 - topPage = $scope.pages[0] - # find first visible page - visible = $scope.pages.some (page, i) -> - [topPageIdx, topPage] = [i, page] if page.visible - if visible - console.log 'found it', topPageIdx - else - console.log 'CANNOT FIND TOP PAGE' + @setPdfPosition = (page, position) -> + console.log 'required pdf Position is', position + @computeOffset(page, position).then (offset) -> + $scope.pleaseScrollTo = offset + $scope.position = position - console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage - top = topPage.elemTop - bottom = topPage.elemBottom - viewportTop = 0 - viewportHeight = $element.height() - topVisible = (top >= viewportTop && top < viewportTop + viewportHeight) - someContentVisible = (top < viewportTop && bottom > viewportTop) - console.log 'in PdfListView', top, topVisible, someContentVisible, viewportTop - if topVisible - canvasOffset = 0 - else if someContentVisible - canvasOffset = viewportTop - top - else - canvasOffset = null - console.log 'pdfListview position = ', canvasOffset - # instead of using promise, check if size is known and revert to - # default otherwise - console.log 'looking up viewport', topPage.viewport, $scope.pdfViewport - if topPage.viewport - viewport = topPage.viewport - pdfOffset = viewport.convertToPdfPoint(0, canvasOffset); - else - console.log 'WARNING: had to default to global page size' - viewport = $scope.pdfViewport - scaledOffset = canvasOffset / $scope.scale.scale - pdfOffset = viewport.convertToPdfPoint(0, scaledOffset); - console.log 'converted to offset = ', pdfOffset - newPosition = { - "page": topPageIdx, - "offset" : { "top" : pdfOffset[1], "left": 0 } - } - return newPosition + return this - @computeOffset = (page, position) -> - console.log 'computing offset for', page, position - element = page.element - pageTop = $(element).offset().top - $(element).parent().offset().top - console.log('top of page scroll is', pageTop, 'vs', page.elemTop) - console.log('inner height is', $(element).innerHeight()) - currentScroll = $(element).parent().scrollTop() - offset = position.offset - # convert offset to pixels - return $scope.document.getPdfViewport(page.pageNum).then (viewport) -> - page.viewport = viewport - pageOffset = viewport.convertToViewportPoint(offset.left, offset.top) - console.log 'addition offset =', pageOffset - console.log 'total', pageTop + pageOffset[1] - Math.round(pageTop + pageOffset[1] + currentScroll) ## 10 is margin + ] - @setPdfPosition = (page, position) -> - console.log 'required pdf Position is', position - @computeOffset(page, position).then (offset) -> - $scope.pleaseScrollTo = offset - $scope.position = position - - return this - -] - -app.directive 'pdfViewer', ['$q', '$timeout', ($q, $timeout) -> - { - controller: 'pdfViewerController' - controllerAs: 'ctrl' - scope: { - "pdfSrc": "=" - "highlights": "=" - "position": "=" - "scale": "=" - "dblClickCallback": "=" - "pleaseJumpTo": "=" - } - template: """ -
- """ - link: (scope, element, attrs, ctrl) -> - console.log 'in pdfViewer element is', element - console.log 'attrs', attrs - layoutReady = $q.defer() - layoutReady.notify 'waiting for layout' - layoutReady.promise.then () -> - console.log 'layoutReady was resolved' - - # TODO can we combine this with scope.parentSize, need to finalize boxes - updateContainer = () -> - scope.containerSize = [ - element.innerWidth() - element.innerHeight() - element.offset().top - ] - - doRescale = (scale) -> - console.log 'doRescale', scale - origposition = angular.copy scope.position - console.log 'origposition', origposition + App.directive 'pdfViewer', ['$q', '$timeout', ($q, $timeout) -> + { + controller: 'pdfViewerController' + controllerAs: 'ctrl' + scope: { + "pdfSrc": "=" + "highlights": "=" + "position": "=" + "scale": "=" + "dblClickCallback": "=" + "pleaseJumpTo": "=" + } + template: """ +
+ """ + link: (scope, element, attrs, ctrl) -> + console.log 'in pdfViewer element is', element + console.log 'attrs', attrs + layoutReady = $q.defer() + layoutReady.notify 'waiting for layout' layoutReady.promise.then () -> - [h, w] = [element.innerHeight(), element.width()] - console.log 'in promise', h, w - ctrl.setScale(scale, h, w).then () -> - ctrl.redraw(origposition) + console.log 'layoutReady was resolved' - scope.$on 'layout-ready', () -> - console.log 'GOT LAYOUT READY EVENT' - console.log 'calling refresh' - updateContainer() - layoutReady.resolve 'layout is ready' - scope.parentSize = [ - element.innerHeight(), - element.innerWidth() - ] - #scope.$apply() + # TODO can we combine this with scope.parentSize, need to finalize boxes + updateContainer = () -> + scope.containerSize = [ + element.innerWidth() + element.innerHeight() + element.offset().top + ] - scope.$on 'layout:pdf:resize', () -> - console.log 'GOT LAYOUT-RESIZE EVENT' - scope.parentSize = [ - element.innerHeight(), - element.innerWidth() - ] - #scope.$apply() + doRescale = (scale) -> + console.log 'doRescale', scale + origposition = angular.copy scope.position + console.log 'origposition', origposition + layoutReady.promise.then () -> + [h, w] = [element.innerHeight(), element.width()] + console.log 'in promise', h, w + ctrl.setScale(scale, h, w).then () -> + ctrl.redraw(origposition) - element.on 'scroll', () -> - console.log 'scroll detected', scope.adjustingScroll - updateContainer() - scope.$apply() - #console.log 'pdfposition', element.parent().scrollTop() - if scope.adjustingScroll - scope.adjustingScroll = false - return - #console.log 'not from auto scroll' - scope.position = ctrl.getPdfPosition() - console.log 'position is', scope.position.page, scope.position.offset - scope.$apply() + scope.$on 'layout-ready', () -> + console.log 'GOT LAYOUT READY EVENT' + console.log 'calling refresh' + updateContainer() + layoutReady.resolve 'layout is ready' + scope.parentSize = [ + element.innerHeight(), + element.innerWidth() + ] + #scope.$apply() - scope.$watch 'pdfSrc', (newVal, oldVal) -> - console.log 'loading pdf', newVal, oldVal - return unless newVal? - ctrl.load() - # trigger a redraw - scope.scale = angular.copy (scope.scale) + scope.$on 'layout:pdf:resize', () -> + console.log 'GOT LAYOUT-RESIZE EVENT' + scope.parentSize = [ + element.innerHeight(), + element.innerWidth() + ] + #scope.$apply() - scope.$watch 'scale', (newVal, oldVal) -> - # no need to set scale when initialising, done in pdfSrc - return if newVal == oldVal - console.log 'XXX calling Setscale in scale watch' - doRescale newVal + element.on 'scroll', () -> + console.log 'scroll detected', scope.adjustingScroll + updateContainer() + scope.$apply() + #console.log 'pdfposition', element.parent().scrollTop() + if scope.adjustingScroll + scope.adjustingScroll = false + return + #console.log 'not from auto scroll' + scope.position = ctrl.getPdfPosition() + console.log 'position is', scope.position.page, scope.position.offset + scope.$apply() - scope.$watch 'forceScale', (newVal, oldVal) -> - console.log 'got change in numscale watcher', newVal, oldVal - return unless newVal? - doRescale newVal + scope.$watch 'pdfSrc', (newVal, oldVal) -> + console.log 'loading pdf', newVal, oldVal + return unless newVal? + ctrl.load() + # trigger a redraw + scope.scale = angular.copy (scope.scale) - scope.$watch 'position', (newVal, oldVal) -> - console.log 'got change in position watcher', newVal, oldVal + scope.$watch 'scale', (newVal, oldVal) -> + # no need to set scale when initialising, done in pdfSrc + return if newVal == oldVal + console.log 'XXX calling Setscale in scale watch' + doRescale newVal - scope.$watch 'forceCheck', (newVal, oldVal) -> - console.log 'forceCheck', newVal, oldVal - return unless newVal? - scope.adjustingScroll = true # temporarily disable scroll - doRescale scope.scale + scope.$watch 'forceScale', (newVal, oldVal) -> + console.log 'got change in numscale watcher', newVal, oldVal + return unless newVal? + doRescale newVal - scope.$watch('parentSize', (newVal, oldVal) -> - console.log 'XXX in parentSize watch', newVal, oldVal - if newVal == oldVal - console.log 'returning because old and new are the same' - return - return unless oldVal? - console.log 'XXX calling setScale in parentSize watcher' - doRescale scope.scale - , true) + scope.$watch 'position', (newVal, oldVal) -> + console.log 'got change in position watcher', newVal, oldVal - scope.$watch 'elementWidth', (newVal, oldVal) -> - console.log '*** watch INTERVAL element width is', newVal, oldVal + scope.$watch 'forceCheck', (newVal, oldVal) -> + console.log 'forceCheck', newVal, oldVal + return unless newVal? + scope.adjustingScroll = true # temporarily disable scroll + doRescale scope.scale - scope.$watch 'pleaseScrollTo', (newVal, oldVal) -> - console.log 'got request to ScrollTo', newVal, 'oldVal', oldVal - return unless newVal? - scope.adjustingScroll = true # temporarily disable scroll - # handler while we reposition - $(element).scrollTop(newVal) - scope.pleaseScrollTo = undefined + scope.$watch('parentSize', (newVal, oldVal) -> + console.log 'XXX in parentSize watch', newVal, oldVal + if newVal == oldVal + console.log 'returning because old and new are the same' + return + return unless oldVal? + console.log 'XXX calling setScale in parentSize watcher' + doRescale scope.scale + , true) - scope.$watch 'pleaseJumpTo', (newPosition, oldPosition) -> - console.log 'in pleaseJumpTo', newPosition, oldPosition - return unless newPosition? - ctrl.setPdfPosition scope.pages[newPosition.page-1], newPosition + scope.$watch 'elementWidth', (newVal, oldVal) -> + console.log '*** watch INTERVAL element width is', newVal, oldVal - scope.$watch 'navigateTo', (newVal, oldVal) -> - return unless newVal? - console.log 'got request to navigate to', newVal, 'oldVal', oldVal - scope.navigateTo = undefined - console.log 'navigate to', newVal - console.log 'look up page num' - scope.loaded.then () -> - console.log 'destinations are', scope.destinations - r = scope.destinations[newVal.dest] - console.log 'need to go to', r - console.log 'page ref is', r[0] - scope.document.getPageIndex(r[0]).then (pidx) -> - console.log 'page num is', pidx - page = scope.pages[pidx] - scope.document.getPdfViewport(page.pageNum).then (viewport) -> - console.log 'got viewport', viewport - coords = viewport.convertToViewportPoint r[2], r[3] - console.log 'viewport position', coords - console.log 'r is', r, 'r[1]', r[1], 'r[1].name', r[1].name - if r[1].name == 'XYZ' - console.log 'XYZ:', r[2], r[3] - newPosition = {page: pidx, offset: {top: r[3], left: r[2]}} - ctrl.setPdfPosition scope.pages[pidx], newPosition # XXX? + scope.$watch 'pleaseScrollTo', (newVal, oldVal) -> + console.log 'got request to ScrollTo', newVal, 'oldVal', oldVal + return unless newVal? + scope.adjustingScroll = true # temporarily disable scroll + # handler while we reposition + $(element).scrollTop(newVal) + scope.pleaseScrollTo = undefined - scope.$watch "highlights", (areas) -> - console.log 'got HIGHLIGHTS in pdfViewer', areas - return if !areas? - console.log 'areas are', areas - highlights = for area in areas or [] - { - page: area.page - 1 - highlight: - left: area.h - top: area.v - height: area.height - width: area.width - } - console.log 'highlights', highlights + scope.$watch 'pleaseJumpTo', (newPosition, oldPosition) -> + console.log 'in pleaseJumpTo', newPosition, oldPosition + return unless newPosition? + ctrl.setPdfPosition scope.pages[newPosition.page-1], newPosition - return if !highlights.length + scope.$watch 'navigateTo', (newVal, oldVal) -> + return unless newVal? + console.log 'got request to navigate to', newVal, 'oldVal', oldVal + scope.navigateTo = undefined + console.log 'navigate to', newVal + console.log 'look up page num' + scope.loaded.then () -> + console.log 'destinations are', scope.destinations + r = scope.destinations[newVal.dest] + console.log 'need to go to', r + console.log 'page ref is', r[0] + scope.document.getPageIndex(r[0]).then (pidx) -> + console.log 'page num is', pidx + page = scope.pages[pidx] + scope.document.getPdfViewport(page.pageNum).then (viewport) -> + console.log 'got viewport', viewport + coords = viewport.convertToViewportPoint r[2], r[3] + console.log 'viewport position', coords + console.log 'r is', r, 'r[1]', r[1], 'r[1].name', r[1].name + if r[1].name == 'XYZ' + console.log 'XYZ:', r[2], r[3] + newPosition = {page: pidx, offset: {top: r[3], left: r[2]}} + ctrl.setPdfPosition scope.pages[pidx], newPosition # XXX? - first = highlights[0] + scope.$watch "highlights", (areas) -> + console.log 'got HIGHLIGHTS in pdfViewer', areas + return if !areas? + console.log 'areas are', areas + highlights = for area in areas or [] + { + page: area.page - 1 + highlight: + left: area.h + top: area.v + height: area.height + width: area.width + } + console.log 'highlights', highlights - pageNum = scope.pages[first.page].pageNum + return if !highlights.length - scope.document.getPdfViewport(pageNum).then (viewport) -> - position = { - page: first.page - offset: - left: first.highlight.left - top: viewport.viewBox[3] - first.highlight.top + first.highlight.height + 72 - } - ctrl.setPdfPosition(scope.pages[first.page], position) + first = highlights[0] + + pageNum = scope.pages[first.page].pageNum + + scope.document.getPdfViewport(pageNum).then (viewport) -> + position = { + page: first.page + offset: + left: first.highlight.left + top: viewport.viewBox[3] - first.highlight.top + first.highlight.height + 72 + } + ctrl.setPdfPosition(scope.pages[first.page], position) - } -] + } + ]