From 05c331c2956b111ad3bedfc91fb3d2082c8b8f52 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 11 Jan 2014 12:57:33 +0100 Subject: [PATCH] Maintain the current position in the document when zooming --- web/page_view.js | 12 +++------ web/presentation_mode.js | 55 +++++++++++++++++++++++++++++++++++----- web/viewer.js | 53 +++++++++++++++++++++++++------------- 3 files changed, 87 insertions(+), 33 deletions(-) diff --git a/web/page_view.js b/web/page_view.js index 34c7be32a..822129d5a 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -400,16 +400,10 @@ var PageView = function pageView(container, id, scale, this.viewport.convertToViewportPoint(x, y), this.viewport.convertToViewportPoint(x + width, y + height) ]; - setTimeout(function pageViewScrollIntoViewRelayout() { - // letting page to re-layout before scrolling - var scale = PDFView.currentScale; - var x = Math.min(boundingRect[0][0], boundingRect[1][0]); - var y = Math.min(boundingRect[0][1], boundingRect[1][1]); - var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]); - var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]); + var left = Math.min(boundingRect[0][0], boundingRect[1][0]); + var top = Math.min(boundingRect[0][1], boundingRect[1][1]); - scrollIntoView(div, {left: x, top: y, width: width, height: height}); - }, 0); + scrollIntoView(div, { left: left, top: top }); }; this.getTextContent = function pageviewGetTextContent() { diff --git a/web/presentation_mode.js b/web/presentation_mode.js index 212887b22..d7c5d2945 100644 --- a/web/presentation_mode.js +++ b/web/presentation_mode.js @@ -20,6 +20,7 @@ var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms var SELECTOR = 'presentationControls'; +var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms var PresentationMode = { active: false, @@ -66,11 +67,38 @@ var PresentationMode = { document.msFullscreenElement); }, + /** + * Initialize a timeout that is used to reset PDFView.currentPosition when the + * browser transitions to fullscreen mode. Since resize events are triggered + * multiple times during the switch to fullscreen mode, this is necessary in + * order to prevent the page from being scrolled partially, or completely, + * out of view when Presentation Mode is enabled. + * Note: This is only an issue at certain zoom levels, e.g. 'page-width'. + */ + _setSwitchInProgress: function presentationMode_setSwitchInProgress() { + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + } + this.switchInProgress = setTimeout(function switchInProgressTimeout() { + delete this.switchInProgress; + }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); + + PDFView.currentPosition = null; + }, + + _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() { + if (this.switchInProgress) { + clearTimeout(this.switchInProgress); + delete this.switchInProgress; + } + }, + request: function presentationModeRequest() { if (!PDFView.supportsFullscreen || this.isFullscreen || !this.viewer.hasChildNodes()) { return false; } + this._setSwitchInProgress(); if (this.container.requestFullscreen) { this.container.requestFullscreen(); @@ -94,9 +122,15 @@ var PresentationMode = { enter: function presentationModeEnter() { this.active = true; + this._resetSwitchInProgress(); - PDFView.page = this.args.page; - PDFView.setScale('page-fit', true); + // Ensure that the correct page is scrolled into view when entering + // Presentation Mode, by waiting until fullscreen mode in enabled. + // Note: This is only necessary in non-Mozilla browsers. + setTimeout(function enterPresentationModeTimeout() { + PDFView.page = this.args.page; + PDFView.setScale('page-fit', true); + }.bind(this), 0); window.addEventListener('mousemove', this.mouseMove, false); window.addEventListener('mousedown', this.mouseDown, false); @@ -109,18 +143,25 @@ var PresentationMode = { }, exit: function presentationModeExit() { - this.active = false; - var page = PDFView.page; - PDFView.setScale(this.args.previousScale); - PDFView.page = page; + + // Ensure that the correct page is scrolled into view when exiting + // Presentation Mode, by waiting until fullscreen mode is disabled. + // Note: This is only necessary in non-Mozilla browsers. + setTimeout(function exitPresentationModeTimeout() { + PDFView.setScale(this.args.previousScale); + PDFView.page = page; + // Keep Presentation Mode active until the page is scrolled into view, + // to prevent issues in non-Mozilla browsers. + this.active = false; + this.args = null; + }.bind(this), 0); window.removeEventListener('mousemove', this.mouseMove, false); window.removeEventListener('mousedown', this.mouseDown, false); window.removeEventListener('contextmenu', this.contextMenu, false); this.hideControls(); - this.args = null; PDFView.clearMouseScrollState(); HandTool.exitPresentationMode(); this.container.removeAttribute('contextmenu'); diff --git a/web/viewer.js b/web/viewer.js index e89c8b923..afdf3f039 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -40,6 +40,7 @@ var SCALE_SELECT_PADDING = 22; var THUMBNAIL_SCROLL_MARGIN = -19; var USE_ONLY_CSS_ZOOM = false; var CLEANUP_TIMEOUT = 30000; +var IGNORE_CURRENT_POSITION_ON_ZOOM = false; //#if B2G //USE_ONLY_CSS_ZOOM = true; //#endif @@ -111,6 +112,7 @@ var PDFView = { previousPageNumber: 1, isViewerEmbedded: (window.parent !== window), idleTimeout: null, + currentPosition: null, // called once when the document is loaded initialize: function pdfViewInitialize() { @@ -219,7 +221,13 @@ var PDFView = { this.currentScale = newScale; if (!noScroll) { - this.pages[this.page - 1].scrollIntoView(); + var page = this.page, dest; + if (this.currentPosition && !IGNORE_CURRENT_POSITION_ON_ZOOM) { + page = this.currentPosition.page; + dest = [null, { name: 'XYZ' }, this.currentPosition.left, + this.currentPosition.top, null]; + } + this.pages[page - 1].scrollIntoView(dest); } var event = document.createEvent('UIEvents'); event.initUIEvent('scalechange', false, false, window, 0); @@ -1049,6 +1057,9 @@ var PDFView = { // Reset 'currentPageNumber', since otherwise the page's scale will be wrong // if 'currentPageNumber' is larger than the number of pages in the file. document.getElementById('pageNumber').value = currentPageNumber = 1; + // Reset the current position when loading a new file, + // to prevent displaying the wrong position in the document. + this.currentPosition = null; if (PDFHistory.initialDestination) { this.navigateTo(PDFHistory.initialDestination); @@ -1307,7 +1318,7 @@ var PDFView = { Math.max(0, currentHeight + viewHeight - bottom); percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; - visible.push({ id: view.id, y: currentHeight, + visible.push({ id: view.id, x: currentWidth, y: currentHeight, view: view, percent: percentHeight }); } @@ -1379,7 +1390,7 @@ var PDFView = { }, rotatePages: function pdfViewRotatePages(delta) { - + var currentPage = this.pages[this.page - 1]; this.pageRotation = (this.pageRotation + 360 + delta) % 360; for (var i = 0, l = this.pages.length; i < l; i++) { @@ -1392,19 +1403,13 @@ var PDFView = { thumb.update(this.pageRotation); } - this.setScale(this.currentScaleValue, true); + this.setScale(this.currentScaleValue, true, true); this.renderHighestPriority(); - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - - // Wait for presentation mode to take effect - setTimeout(function() { + if (currentPage) { currentPage.scrollIntoView(); - }, 0); + } }, /** @@ -1615,6 +1620,11 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { PDFJS.verbosity = hashParams['verbosity'] | 0; } + if ('ignoreCurrentPositionOnZoom' in hashParams) { + IGNORE_CURRENT_POSITION_ON_ZOOM = + (hashParams['ignoreCurrentPositionOnZoom'] === 'true'); + } + //#if !(FIREFOX || MOZCENTRAL) var locale = navigator.language; if ('locale' in hashParams) @@ -1812,17 +1822,26 @@ function updateViewarea() { var pdfOpenParams = '#page=' + pageNumber; pdfOpenParams += '&zoom=' + normalizedScaleValue; var currentPage = PDFView.pages[pageNumber - 1]; - var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft, - (PDFView.container.scrollTop - firstPage.y)); - pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]); + var container = PDFView.container; + var topLeft = currentPage.getPagePoint((container.scrollLeft - firstPage.x), + (container.scrollTop - firstPage.y)); + var intLeft = Math.round(topLeft[0]); + var intTop = Math.round(topLeft[1]); + pdfOpenParams += ',' + intLeft + ',' + intTop; + + if (PresentationMode.active || PresentationMode.switchInProgress) { + PDFView.currentPosition = null; + } else { + PDFView.currentPosition = { page: pageNumber, left: intLeft, top: intTop }; + } var store = PDFView.store; store.initializedPromise.then(function() { store.set('exists', true); store.set('page', pageNumber); store.set('zoom', normalizedScaleValue); - store.set('scrollLeft', Math.round(topLeft[0])); - store.set('scrollTop', Math.round(topLeft[1])); + store.set('scrollLeft', intLeft); + store.set('scrollTop', intTop); }); var href = PDFView.getAnchorUrl(pdfOpenParams); document.getElementById('viewBookmark').href = href;