moved new pdf viewer under base App module

This commit is contained in:
Brian Gough 2014-12-01 10:42:47 +00:00
parent 175de30967
commit ff04e1662a
8 changed files with 841 additions and 829 deletions

View file

@ -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

View file

@ -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
]

View file

@ -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 = []
]

View file

@ -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

View file

@ -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: '''
<div class="plv-page-view page-view">
<div class="pdf-canvas"></div>
<div class="plv-text-layer text-layer"></div>
<div class="plv-annotations-layer annotations-layer"></div>
<div class="plv-highlights-layer highlights-layer"></div>
</div>
'''
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: '''
<div class="plv-page-view page-view">
<div class="pdf-canvas"></div>
<div class="plv-text-layer text-layer"></div>
<div class="plv-annotations-layer annotations-layer"></div>
<div class="plv-highlights-layer highlights-layer"></div>
</div>
'''
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'
}
]
}
]

View file

@ -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 class="pdf-canvas-new"></canvas>')
canvas = $('<canvas class="pdf-canvas-new"></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 = $('<div style="position: absolute; top: 50%; left:50%; transform: translateX(-50%) translateY(50%);"><i class="fa fa-spinner fa-spin" style="color: #999"></i></div>')
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 = $('<div style="position: absolute; top: 50%; left:50%; transform: translateX(-50%) translateY(50%);"><i class="fa fa-spinner fa-spin" style="color: #999"></i></div>')
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')
]
]

View file

@ -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
]

View file

@ -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: """
<div data-pdf-page class='pdf-page-container page-container' ng-repeat='page in pages'></div>
"""
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: """
<div data-pdf-page class='pdf-page-container page-container' ng-repeat='page in pages'></div>
"""
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)
}
]
}
]