Sfoglia il codice sorgente

moved new pdf viewer under base App module

Brian Gough 12 anni fa
parent
commit
ff04e1662a

+ 0 - 8
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

+ 38 - 36
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
+	]

+ 25 - 22
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 = []
+	]

+ 0 - 12
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

+ 93 - 90
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: '''
-		<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
-					highlights: highlightsElement
-				}, scope.page.pageNum
+				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
+				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
+				# 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.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)
+				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
+				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()
+				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
-			})
+				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.$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'
+				scope.$on "$destroy", () ->
+					console.log 'in destroy handler, TODO need to clean up timeout/highlights'
 
-	}
-]
+		}
+	]

+ 188 - 185
services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee

@@ -1,185 +1,188 @@
-app = angular.module 'PDFRenderer', ['pdfAnnotations', 'pdfTextLayer']
-
-console.log 'hello from Renderer'
-
-app.factory 'PDFRenderer', ['$q', '$timeout', 'pdfAnnotations', 'pdfTextLayer', ($q, $timeout, pdfAnnotations, pdfTextLayer) ->
-
-	class PDFRenderer
-		@JOB_QUEUE_INTERVAL: 100
-
-		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
-
-		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)
-
-		getPdfViewport: (pageNum, scale) ->
-			scale ?= @scale
-			@document.then (pdfDocument) ->
-				pdfDocument.getPage(pageNum).then (page) ->
-					viewport = page.getViewport scale
-
-		getDestinations: () ->
-			@document.then (pdfDocument) ->
-				pdfDocument.getDestinations()
-
-		getPageIndex: (ref) ->
-			@document.then (pdfDocument) ->
-				pdfDocument.getPageIndex(ref).then (idx) ->
-					idx
-
-		getScale: () ->
-			@scale
-
-		setScale: (@scale) ->
-			@resetState()
-
-		pause: (element, pagenum) ->
-			return if @complete[pagenum]
-			@renderQueue = @renderQueue.filter (q) ->
-				q.pagenum != pagenum
-			@stopSpinner (element.canvas)
-
-		triggerRenderQueue: () ->
-			$timeout () =>
-				@processRenderQueue()
-			, @JOB_QUEUE_INTERVAL
-
-		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()
-
-		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)
-
-			pageLoad = @getPage(pagenum)
-
-			@renderTask[pagenum] = pageLoad.then (pageObject) =>
-				@doRender element, pagenum, pageObject
-
-			@renderTask[pagenum].then () =>
-				# complete
-				@complete[pagenum] = true
-				@removeCompletedJob pagenum
-			, () =>
-				# rejected
-				@removeCompletedJob pagenum
-
-		doRender: (element, pagenum, page) ->
-			self = this
-			scale = @scale
-
-			if (not scale?)
-				console.log 'scale is undefined, returning'
-				return
-
-			canvas = $('<canvas class="pdf-canvas-new"></canvas>')
-
-			viewport = page.getViewport (scale)
-
-			devicePixelRatio = window.devicePixelRatio || 1
-
-			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
-
-			newWidth = Math.floor(viewport.width)
-			newHeight = Math.floor(viewport.height)
-
-			canvas[0].height = scaledHeight
-			canvas[0].width = scaledWidth
-
-			canvas.height(newHeight + 'px')
-			canvas.width(newWidth + 'px')
-
-			element.canvas[0].height = newHeight
-			element.canvas[0].width = newWidth
-
-			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
-
-			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')
-
-		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')
-
-	]
+define [
+	"base"
+], (App) ->
+	# App = angular.module 'PDFRenderer', ['pdfAnnotations', 'pdfTextLayer']
+
+	console.log 'hello from Renderer'
+
+	App.factory 'PDFRenderer', ['$q', '$timeout', 'pdfAnnotations', 'pdfTextLayer', ($q, $timeout, pdfAnnotations, pdfTextLayer) ->
+
+		class PDFRenderer
+			@JOB_QUEUE_INTERVAL: 100
+
+			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
+
+			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)
+
+			getPdfViewport: (pageNum, scale) ->
+				scale ?= @scale
+				@document.then (pdfDocument) ->
+					pdfDocument.getPage(pageNum).then (page) ->
+						viewport = page.getViewport scale
+
+			getDestinations: () ->
+				@document.then (pdfDocument) ->
+					pdfDocument.getDestinations()
+
+			getPageIndex: (ref) ->
+				@document.then (pdfDocument) ->
+					pdfDocument.getPageIndex(ref).then (idx) ->
+						idx
+
+			getScale: () ->
+				@scale
+
+			setScale: (@scale) ->
+				@resetState()
+
+			pause: (element, pagenum) ->
+				return if @complete[pagenum]
+				@renderQueue = @renderQueue.filter (q) ->
+					q.pagenum != pagenum
+				@stopSpinner (element.canvas)
+
+			triggerRenderQueue: () ->
+				$timeout () =>
+					@processRenderQueue()
+				, @JOB_QUEUE_INTERVAL
+
+			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()
+
+			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)
+
+				pageLoad = @getPage(pagenum)
+
+				@renderTask[pagenum] = pageLoad.then (pageObject) =>
+					@doRender element, pagenum, pageObject
+
+				@renderTask[pagenum].then () =>
+					# complete
+					@complete[pagenum] = true
+					@removeCompletedJob pagenum
+				, () =>
+					# rejected
+					@removeCompletedJob pagenum
+
+			doRender: (element, pagenum, page) ->
+				self = this
+				scale = @scale
+
+				if (not scale?)
+					console.log 'scale is undefined, returning'
+					return
+
+				canvas = $('<canvas class="pdf-canvas-new"></canvas>')
+
+				viewport = page.getViewport (scale)
+
+				devicePixelRatio = window.devicePixelRatio || 1
+
+				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
+
+				newWidth = Math.floor(viewport.width)
+				newHeight = Math.floor(viewport.height)
+
+				canvas[0].height = scaledHeight
+				canvas[0].width = scaledWidth
+
+				canvas.height(newHeight + 'px')
+				canvas.width(newWidth + 'px')
+
+				element.canvas[0].height = newHeight
+				element.canvas[0].width = newWidth
+
+				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
+
+				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')
+
+			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')
+
+		]

+ 209 - 206
services/web/public/coffee/ide/pdfng/directives/pdfTextLayer.coffee

@@ -1,207 +1,210 @@
-app = angular.module '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
-
-# -*- 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.
-#
-
-# globals CustomStyle, scrollIntoView, PDFJS
-# ms
-
-# optimised CSS custom property getter/setter
-
-	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) ->
-
-			# 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'
-
-			# capitalize
-			uPropName = propName.charAt(0).toUpperCase() + propName.slice(1)
-
-			# 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++
-
-			#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
+define [
+	"base"
+], (App) ->
+	# App = angular.module '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
+
+	# -*- 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.
+	#
+
+	# globals CustomStyle, scrollIntoView, PDFJS
+	# ms
+
+	# optimised CSS custom property getter/setter
+
+		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) ->
+
+				# 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'
+
+				# capitalize
+				uPropName = propName.charAt(0).toUpperCase() + propName.slice(1)
+
+				# 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++
+
+				#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
-			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
-
-]
+
+			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
+					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
+
+	]

+ 372 - 354
services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee

@@ -1,359 +1,377 @@
-app = angular.module 'pdfViewerApp', ['pdfPage', 'PDFRenderer', 'pdfHighlights']
-
-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
+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 = angular.module 'pdfViewerApp', ['pdfPage', 'PDFRenderer', 'pdfHighlights']
+
+	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
-
-	@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]
+				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
+
+		@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
-
-	@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
-			}
-		]
-
-	# we work with (pagenumber, % of height down page from top)
-	# pdfListView works with (pagenumber, vertical position up page from
-	# bottom measured in pts)
-
-	@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'
-
-		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
-
-	@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
+		# we work with (pagenumber, % of height down page from top)
+		# pdfListView works with (pagenumber, vertical position up page from
+		# bottom measured in pts)
+
+		@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'
+
+			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
+
+		@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 () ->
-					[h, w] = [element.innerHeight(), element.width()]
-					console.log 'in promise', h, w
-					ctrl.setScale(scale, h, w).then () ->
-						ctrl.redraw(origposition)
-
-			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()
+					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
+					layoutReady.promise.then () ->
+						[h, w] = [element.innerHeight(), element.width()]
+						console.log 'in promise', h, w
+						ctrl.setScale(scale, h, w).then () ->
+							ctrl.redraw(origposition)
+
+				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.$on 'layout:pdf:resize', () ->
+					console.log 'GOT LAYOUT-RESIZE EVENT'
+					scope.parentSize = [
+						element.innerHeight(),
+						element.innerWidth()
+					]
+					#scope.$apply()
+
+				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 '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 '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 'forceScale', (newVal, oldVal) ->
+					console.log 'got change in numscale watcher', newVal, oldVal
+					return unless newVal?
+					doRescale newVal
+
+				scope.$watch 'position', (newVal, oldVal) ->
+					console.log 'got change in position watcher', 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('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 'elementWidth', (newVal, oldVal) ->
+					console.log '*** watch INTERVAL element width is', newVal, oldVal
+
+				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 'pleaseJumpTo', (newPosition, oldPosition) ->
+					console.log 'in pleaseJumpTo', newPosition, oldPosition
+					return unless newPosition?
+					ctrl.setPdfPosition scope.pages[newPosition.page-1], newPosition
+
+				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 "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
+
+					return if !highlights.length
+
+					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)
 
-			scope.$on 'layout:pdf:resize', () ->
-				console.log 'GOT LAYOUT-RESIZE EVENT'
-				scope.parentSize = [
-					element.innerHeight(),
-					element.innerWidth()
-				]
-				#scope.$apply()
-
-			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 '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 '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 'forceScale', (newVal, oldVal) ->
-				console.log 'got change in numscale watcher', newVal, oldVal
-				return unless newVal?
-				doRescale newVal
-
-			scope.$watch 'position', (newVal, oldVal) ->
-				console.log 'got change in position watcher', 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('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 'elementWidth', (newVal, oldVal) ->
-				console.log '*** watch INTERVAL element width is', newVal, oldVal
-
-			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 'pleaseJumpTo', (newPosition, oldPosition) ->
-				console.log 'in pleaseJumpTo', newPosition, oldPosition
-				return unless newPosition?
-				ctrl.setPdfPosition scope.pages[newPosition.page-1], newPosition
-
-			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 "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
-
-				return if !highlights.length
-
-				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)
-
-
-	}
-]
+
+		}
+	]