Преглед изворни кода

Merge pull request #146 from sharelatex/fix-pdfng-no-background-digests

Fix pdfng no background digests
James Allen пре 11 година
родитељ
комит
bd8311e1cf

+ 8 - 8
services/web/public/coffee/ide/directives/layout.coffee

@@ -105,12 +105,12 @@ define [
 
 					resetOpenStates()
 					onInternalResize()
-					
-					scope.$watch attrs.layoutDisabled, (value) ->
-						if value
-							element.layout().hide("east")
-						else
-							element.layout().show("east")
-							
+
+					if attrs.layoutDisabled?
+						scope.$watch attrs.layoutDisabled, (value) ->
+							if value
+								element.layout().hide("east")
+							else
+								element.layout().show("east")
 		}
-	]
+	]

+ 12 - 6
services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee

@@ -3,7 +3,7 @@ define [
 	"ide/editor/Document"
 ], (App, Document) ->
 	App.controller "SavingNotificationController", ["$scope", "$interval", "ide", ($scope, $interval, ide) ->
-		$interval () ->
+		setInterval () ->
 			pollSavedStatus()
 		, 1000
 
@@ -13,21 +13,27 @@ define [
 		$scope.docSavingStatus = {}
 		pollSavedStatus = () ->
 			oldStatus = $scope.docSavingStatus
-			$scope.docSavingStatus = {}
+			newStatus = {}
 
 			for doc_id, doc of Document.openDocs
 				saving = doc.pollSavedStatus()
 				if !saving
 					if oldStatus[doc_id]?
-						$scope.docSavingStatus[doc_id] = oldStatus[doc_id]
-						$scope.docSavingStatus[doc_id].unsavedSeconds += 1
+						newStatus[doc_id] = oldStatus[doc_id]
+						newStatus[doc_id].unsavedSeconds += 1
 					else
-						$scope.docSavingStatus[doc_id] = {
+						newStatus[doc_id] = {
 							unsavedSeconds: 0
 							doc: ide.fileTreeManager.findEntityById(doc_id)
 						}
 
+			# for performance, only update the display if the old or new
+			# statuses have any unsaved files
+			if _.size(newStatus) or _.size(oldStatus)
+				$scope.docSavingStatus = newStatus
+				$scope.$apply()
+
 		warnAboutUnsavedChanges = () ->
 			if Document.hasUnsavedChanges()
 				return "You have unsaved changes. If you leave now they will not be saved."
-	]
+	]

+ 5 - 2
services/web/public/coffee/ide/editor/directives/aceEditor/highlights/HighlightsManager.coffee

@@ -106,8 +106,11 @@ define [
 					labelToShow = label
 
 			if !labelToShow?
-				@$scope.$apply () =>
-					@$scope.annotationLabel.show = false
+				# this is the most common path, triggered on mousemove, so
+				# for performance only apply setting when it changes
+				if @$scope?.annotationLabel?.show != false
+					@$scope.$apply () =>
+						@$scope.annotationLabel.show = false
 			else
 				$ace = $(@editor.renderer.container).find(".ace_scroller")
 				# Move the label into the Ace content area so that offsets and positions are easy to calculate.

+ 5 - 2
services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee

@@ -86,8 +86,11 @@ define [
 				return false
 
 		closeContextMenu: (e) ->
-			@$scope.$apply () =>
-				@$scope.spellingMenu.open = false
+			# this is triggered on scroll, so for performance only apply
+			# setting when it changes
+			if @$scope?.spellingMenu?.open != false
+				@$scope.$apply () =>
+					@$scope.spellingMenu.open = false
 
 		replaceWord: (highlight, text) ->
 			@editor.getSession().replace(new Range(

+ 16 - 8
services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee

@@ -63,10 +63,11 @@ define [
 						$.localStorage "pdf.position.#{attrs.key}", scope.position
 
 				flashControls = () ->
-					scope.flashControls = true
-					$timeout () ->
-						scope.flashControls = false
-					, 1000
+					scope.$evalAsync () ->
+						scope.flashControls = true
+						$timeout () ->
+							scope.flashControls = false
+						, 1000
 
 				scope.$on 'pdfDoubleClick', (event, e) ->
 					scope.dblClickCallback?(page: e.page - 1, offset: { top: e.y, left: e.x })
@@ -80,7 +81,6 @@ define [
 						# console.log 'pdfSrc =', url
 						initializePosition()
 						flashControls()
-						scope.$broadcast 'layout-ready'
 						# pdfListView
 						#		.loadPdf(url, onProgress)
 						#		.then () ->
@@ -91,8 +91,12 @@ define [
 						#				flashControls()
 				
 				scope.$on "loaded", () ->
-					scope.loading = false
-					delete scope.progress
+					scope.progress = 100
+					scope.$apply()
+					$timeout () ->
+						scope.loading = false
+						delete scope.progress
+					, 250
 
 				#scope.$watch "highlights", (areas) ->
 					# console.log 'got HIGHLIGHTS in pdfJS', areas
@@ -155,8 +159,12 @@ define [
 
 				scope.$on 'progress', (event, progress) ->
 					scope.$apply () ->
-						#console.log 'progress', progress.loaded, progress.total, progress
 						scope.progress = Math.floor(progress.loaded/progress.total*100)
+						scope.progress = 100 if scope.progress > 100
+						scope.progress = 0 if scope.progress < 0
+
+				scope.$on '$destroy', () ->
+					# console.log 'pdfjs destroy event'
 
 			template: """
 				<div data-pdf-viewer class="pdfjs-viewer" pdf-src='pdfSrc' position='position' scale='scale' highlights='highlights' please-jump-to='pleaseJumpTo'></div>

+ 20 - 18
services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee

@@ -49,11 +49,11 @@ define [
 
 			getPdfViewport: (pageNum, scale) ->
 				scale ?= @scale
-				@document.then (pdfDocument) ->
+				@document.then (pdfDocument) =>
 					pdfDocument.getPage(pageNum).then (page) ->
 						viewport = page.getViewport scale
-					, (error) ->
-						console.log 'ERROR', error
+					, (error) =>
+						@errorCallback?(error)
 
 			getDestinations: () ->
 				@document.then (pdfDocument) ->
@@ -68,8 +68,8 @@ define [
 					pdfDocument.getDestinations()
 				return @destinations.then (all) ->
 					all[dest]
-				, (error) ->
-					console.log 'ERROR', error
+				, (error) =>
+					@errorCallback?(error)
 				# When we upgrade we can switch to using the following direct
 				# code.
 				# @document.then (pdfDocument) ->
@@ -78,11 +78,11 @@ define [
 				# 	console.log 'ERROR', error
 
 			getPageIndex: (ref) ->
-				@document.then (pdfDocument) ->
+				@document.then (pdfDocument) =>
 					pdfDocument.getPageIndex(ref).then (idx) ->
 						idx
-					, (error) ->
-						console.log 'ERROR', error
+					, (error) =>
+						@errorCallback?(error)
 
 			getScale: () ->
 				@scale
@@ -91,7 +91,8 @@ define [
 				@resetState()
 
 			triggerRenderQueue: (interval = @JOB_QUEUE_INTERVAL) ->
-				$timeout () =>
+				@queueTimer = setTimeout () =>
+					@queueTimer = null
 					@processRenderQueue()
 				, interval
 
@@ -134,7 +135,7 @@ define [
 				@jobs = @jobs + 1
 
 				element.canvas.addClass('pdfng-loading')
-				spinTimer = $timeout () =>
+				spinTimer = setTimeout () =>
 					@spinner.add(element.canvas)
 				, 100
 
@@ -144,14 +145,14 @@ define [
 
 				timedOut = false
 				timer = $timeout () =>
-					Raven.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
+					Raven?.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
 					# console.log 'page load timed out', pagenum
 					timedOut = true
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					@spinner.stop(element.canvas)
 					# @jobs = @jobs - 1
 					# @triggerRenderQueue(0)
-					this.errorCallback?('timeout')
+					@errorCallback?('timeout')
 				, @PAGE_LOAD_TIMEOUT
 
 				@pageLoad[pagenum] = @getPage(pagenum)
@@ -159,7 +160,7 @@ define [
 				@pageLoad[pagenum].then (pageObject) =>
 					# console.log 'in page load success', pagenum
 					$timeout.cancel(timer)
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					@renderTask[pagenum] = @doRender element, pagenum, pageObject
 					@renderTask[pagenum].then () =>
 						# complete
@@ -173,7 +174,7 @@ define [
 				.catch (error) ->
 					# console.log 'in page load error', pagenum, 'timedOut=', timedOut
 					$timeout.cancel(timer)
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					# console.log 'ERROR', error
 
 			doRender: (element, pagenum, page) ->
@@ -245,7 +246,7 @@ define [
 				timedOut = false
 
 				timer = $timeout () =>
-					Raven.captureMessage?('pdfng page render timed out after ' + @PAGE_RENDER_TIMEOUT + 'ms')
+					Raven?.captureMessage?('pdfng page render timed out after ' + @PAGE_RENDER_TIMEOUT + 'ms')
 					# console.log 'page render timed out', pagenum
 					timedOut = true
 					result.cancel()
@@ -258,11 +259,11 @@ define [
 					page.getTextContent().then (textContent) ->
 						textLayer.setTextContent textContent
 					, (error) ->
-						console.log 'ERROR', error
+						self.errorCallback?(error)
 					page.getAnnotations().then (annotations) ->
 						annotationsLayer.setAnnotations annotations
 					, (error) ->
-						console.log 'ERROR', error
+						self.errorCallback?(error)
 				.catch (error) ->
 					# console.log 'page render failed', pagenum, error
 					$timeout.cancel(timer)
@@ -278,6 +279,7 @@ define [
 			destroy: () ->
 				# console.log 'in pdf renderer destroy', @renderQueue
 				@shuttingDown = true
+				clearTimeout @queueTimer if @queueTimer?
 				@renderQueue = []
 				for task in @renderTask
 					task.cancel() if task?

+ 106 - 60
services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee

@@ -25,7 +25,7 @@ define [
 			# $scope.pages = []
 
 			$scope.document.destroy() if $scope.document?
-			$scope.loadCount = $scope.loadCount? ? $scope.loadCount + 1 : 1
+			$scope.loadCount = if $scope.loadCount? then $scope.loadCount + 1 else 1
 			# TODO need a proper url manipulation library to add to query string
 			$scope.document = new PDFRenderer($scope.pdfSrc + '&pdfng=true' , {
 				scale: 1,
@@ -38,7 +38,7 @@ define [
 				loadedCallback: () ->
 					$scope.$emit 'loaded'
 				errorCallback: (error) ->
-					Raven.captureMessage?('pdfng error ' + error)
+					Raven?.captureMessage?('pdfng error ' + error)
 					$scope.$emit 'pdf:error', error
 				pageSizeChangeCallback: (pageNum, deltaH) ->
 					$scope.$broadcast 'pdf:page:size-change', pageNum, deltaH
@@ -58,6 +58,9 @@ define [
 					]
 					# console.log 'resolved q.all, page size is', result
 					$scope.numPages = result.numPages
+				.catch (error) ->
+					$scope.$emit 'pdf:error', error
+					return $q.reject(error)
 
 		@setScale = (scale, containerHeight, containerWidth) ->
 			$scope.loaded.then () ->
@@ -85,6 +88,9 @@ define [
 					numScale * $scope.pdfPageSize[1]
 				]
 				# console.log 'in setScale result', $scope.scale.scale, $scope.defaultPageSize
+			.catch (error) ->
+				$scope.$emit 'pdf:error', error
+				return $q.reject(error)
 
 		@redraw = (position) ->
 			# console.log 'in redraw'
@@ -273,68 +279,107 @@ define [
 						extra.push scope.pages[lastVisiblePageIdx + 2]
 					return visiblePages.concat extra
 
+				rescaleTimer = null
+				queueRescale = (scale) ->
+					# console.log 'call to queueRescale'
+					return if rescaleTimer? or layoutTimer? or elementTimer?
+					# console.log 'adding to rescale queue'
+					rescaleTimer = setTimeout () ->
+						doRescale scale
+						rescaleTimer = null
+					, 0
+
 				doRescale = (scale) ->
 					# console.log 'doRescale', scale
+					return unless scale?
 					origposition = angular.copy scope.position
 					# console.log 'origposition', origposition
-					layoutReady.promise.then () ->
-						[h, w] = [element.innerHeight(), element.width()]
+					layoutReady.promise.then (parentSize) ->
+						[h, w] = parentSize
 						# console.log 'in promise', h, w
 						ctrl.setScale(scale, h, w).then () ->
-							spinner.remove(element)
-							ctrl.redraw(origposition)
-							setTimeout renderVisiblePages, 0
-
-				checkElementReady = () ->
+							# console.log 'in setscale then', scale, h, w
+							scope.$evalAsync () ->
+								if spinnerTimer
+									clearTimeout spinnerTimer
+								else
+									spinner.remove(element)
+								ctrl.redraw(origposition)
+								$timeout renderVisiblePages
+								scope.loadSuccess = true
+						.catch (error) ->
+							scope.$emit 'pdf:error', error
+
+				elementTimer = null
+				spinnerTimer = null
+				updateLayout = () ->
 					# if element is zero-sized keep checking until it is ready
+					# console.log 'checking element ready', element.height(), element.width()
 					if element.height() == 0 or element.width() == 0
-						$timeout () ->
-							checkElementReady()
-						, 250
+						return if elementTimer?
+						elementTimer = setTimeout () ->
+							elementTimer = null
+							updateLayout()
+						, 1000
 					else
-						scope.$broadcast 'layout-ready' if !scope.parentSize?
-
-				checkElementReady()
-
-				scope.$on 'layout-ready', () ->
-					# console.log 'GOT LAYOUT READY EVENT'
-					# console.log 'calling refresh'
-					# updateContainer()
-					spinner.add(element)
-					layoutReady.resolve 'layout is ready'
-					scope.parentSize = [
-						element.innerHeight(),
-						element.innerWidth()
-					]
-					scope.$emit 'flash-controls'
-					#scope.$apply()
+						scope.parentSize = [
+							element.innerHeight(),
+							element.innerWidth()
+						]
+						# console.log 'resolving layoutReady with', scope.parentSize
+						$timeout () ->
+							if not spinnerTimer?
+								spinnerTimer = setTimeout () ->
+									spinner.add(element)
+									spinnerTimer = null
+								, 100
+							layoutReady.resolve scope.parentSize
+							scope.$emit 'flash-controls'
+
+				layoutTimer = null
+				queueLayout = () ->
+					# console.log 'call to queue layout'
+					return if layoutTimer?
+					# console.log 'added to queue layoyt'
+					layoutReady = $q.defer()
+					layoutTimer = setTimeout () ->
+						# console.log 'calling update layout'
+						updateLayout()
+						# console.log 'setting layout timer to null'
+						layoutTimer = null
+					, 0
+
+				queueLayout()
+
+				#scope.$on 'layout:pdf:view', (e, args) ->
+				#	console.log 'pdf view change', element, e, args
+				#	queueLayout()
 
 				scope.$on 'layout:main:resize', () ->
 					# console.log 'GOT LAYOUT-MAIN-RESIZE EVENT'
-					scope.parentSize = [
-						element.innerHeight(),
-						element.innerWidth()
-					]
-					scope.$apply()
-
+					queueLayout()
 
 				scope.$on 'layout:pdf:resize', () ->
+					# FIXME we get this event twice
+					# also we need to start a new layout when we get it
 					# console.log 'GOT LAYOUT-PDF-RESIZE EVENT'
-					scope.parentSize = [
-						element.innerHeight(),
-						element.innerWidth()
-					]
-					#scope.$apply()
+					queueLayout()
 
 				scope.$on 'pdf:error', (event, error) ->
 					return if error == 'cancelled'
 					# check if too many retries or file is missing
-					if scope.loadCount > 3 || error.match(/^Missing PDF/i)
+					if scope.loadCount > 3 || error.match(/^Missing PDF/i) || error.match(/^loading/i)
+						scope.$emit 'pdf:error:display'
+						return
+					if scope.loadSuccess
+						ctrl.load().then () ->
+							# trigger a redraw
+							scope.scale = angular.copy (scope.scale)
+						.catch (error) ->
+							scope.$emit 'pdf:error:display'
+					else
 						scope.$emit 'pdf:error:display'
 						return
-					ctrl.load()
-					# trigger a redraw
-					scope.scale = angular.copy (scope.scale)
 
 				scope.$on 'pdf:page:size-change', (event, pageNum, delta) ->
 					#console.log 'page size change event', pageNum, delta
@@ -351,42 +396,40 @@ define [
 					#scope.scrollPosition = element.scrollTop()
 					if scope.adjustingScroll
 						renderVisiblePages()
-						# updateContainer()
-						scope.$apply()
 						scope.adjustingScroll = false
 						return
-					#scope.scrolled = true
 					if scope.scrollHandlerTimeout
 						clearTimeout(scope.scrollHandlerTimeout)
 					scope.scrollHandlerTimeout = setTimeout scrollHandler, 25
 
 				scrollHandler = () ->
 					renderVisiblePages()
-					#scope.$apply()
 					newPosition = ctrl.getPdfPosition()
 					if newPosition?
 						scope.position = newPosition
-					#scope.$apply()
 					scope.scrollHandlerTimeout = null
 
 				scope.$watch 'pdfSrc', (newVal, oldVal) ->
 					# console.log 'loading pdf', newVal, oldVal
 					return unless newVal?
 					scope.loadCount = 0; # new pdf, so reset load count
-					ctrl.load()
-					# trigger a redraw
-					scope.scale = angular.copy (scope.scale)
+					scope.loadSuccess = false
+					ctrl.load().then () ->
+						# trigger a redraw
+						scope.scale = angular.copy (scope.scale)
+					.catch (error) ->
+						scope.$emit 'pdf:error', error
 
 				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
+					queueRescale newVal
 
 				scope.$watch 'forceScale', (newVal, oldVal) ->
 					# console.log 'got change in numscale watcher', newVal, oldVal
 					return unless newVal?
-					doRescale newVal
+					queueRescale newVal
 
 #				scope.$watch 'position', (newVal, oldVal) ->
 #					console.log 'got change in position watcher', newVal, oldVal
@@ -395,16 +438,17 @@ define [
 					# console.log 'forceCheck', newVal, oldVal
 					return unless newVal?
 					scope.adjustingScroll = true  # temporarily disable scroll
-					doRescale scope.scale
+					queueRescale 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?
+					# return unless oldVal?
 					# console.log 'XXX calling setScale in parentSize watcher'
-					doRescale scope.scale
+					return unless newVal?
+					queueRescale scope.scale
 				, true)
 
 				# scope.$watch 'elementWidth', (newVal, oldVal) ->
@@ -477,9 +521,11 @@ define [
 						}
 						ctrl.setPdfPosition(scope.pages[first.page], position)
 
-				scope.$watch '$destroy', () ->
-					#console.log 'handle pdfng directive destroy'
-
-
+				scope.$on '$destroy', () ->
+					# console.log 'handle pdfng directive destroy'
+					clearTimeout elementTimer if elementTimer?
+					clearTimeout layoutTimer if layoutTimer?
+					clearTimeout rescaleTimer if rescaleTimer?
+					clearTimeout spinnerTimer if spinnerTimer?
 		}
 	]