diff --git a/services/web/public/coffee/ide/directives/layout.coffee b/services/web/public/coffee/ide/directives/layout.coffee index 94a4343b49..836d0ae591 100644 --- a/services/web/public/coffee/ide/directives/layout.coffee +++ b/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") } - ] \ No newline at end of file + ] diff --git a/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee b/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee index edefe07ea9..3629939798 100644 --- a/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee +++ b/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." - ] \ No newline at end of file + ] diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/highlights/HighlightsManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/highlights/HighlightsManager.coffee index 6173e053f7..d1f520d8f1 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/highlights/HighlightsManager.coffee +++ b/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. diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee index bdddb2ab20..7af794e867 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee +++ b/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( diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee index 8656abd8f9..7a2e1d472a 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee +++ b/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: """
diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee index 31880b83ca..7875faf886 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee +++ b/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? diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index 73bd907a6f..0f6c6d9bac 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/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 + # 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 - checkElementReady = () -> + 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? + 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' - checkElementReady() + 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 - 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() + 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? } ]