From 5657d082c73864b9468bc092ab6048c32d35768d Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 12 Mar 2016 13:07:43 +0100 Subject: [PATCH 1/2] Dispatch a `sidebarviewchanged` event in `PDFSidebar` when the view changes We cannot piggy-back on the `updateviewarea` event in order to update the stored sidebar state, since there're a number of cases where opening/switching the sidebar view won't fire a `updateviewarea` event. Note that `updateviewarea` only fires when the position changes in the *viewer*, which means that it won't fire if e.g. the viewer is narrow, such that the sidebar overlays the document transparently; or when switching views, without the document position also changing. This patch also moves the handling of `forceOpen` parameter in `PDFSidebar_switchView`, to prevent triggering back-to-back rendering and dispatching of events. --- web/app.js | 43 ++++++++++++++++++++++++++++++------------- web/pdf_sidebar.js | 45 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/web/app.js b/web/app.js index 9d03cc234..505eeb469 100644 --- a/web/app.js +++ b/web/app.js @@ -150,6 +150,8 @@ var PDFViewerApplication = { pdfOutlineViewer: null, /** @type {PDFAttachmentViewer} */ pdfAttachmentViewer: null, + /** @type {ViewHistory} */ + store: null, pageRotation: 0, isInitialViewSet: false, animationStartedPromise: null, @@ -603,6 +605,8 @@ var PDFViewerApplication = { this.pdfViewer.setDocument(null); this.pdfLinkService.setDocument(null, null); } + this.store = null; + this.isInitialViewSet = false; this.pdfSidebar.reset(); this.pdfOutlineViewer.reset(); @@ -925,7 +929,6 @@ var PDFViewerApplication = { var onePageRendered = pdfViewer.onePageRendered; this.pageRotation = 0; - this.isInitialViewSet = false; this.pdfThumbnailViewer.setDocument(pdfDocument); @@ -1002,7 +1005,7 @@ var PDFViewerApplication = { self.initialBookmark = initialParams.bookmark; self.pdfViewer.currentScaleValue = self.pdfViewer.currentScaleValue; - self.setInitialView(initialParams.hash, scale); + self.setInitialView(initialParams.hash); }); }); @@ -1682,23 +1685,37 @@ window.addEventListener('presentationmodechanged', function (e) { active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL; }); +window.addEventListener('sidebarviewchanged', function (evt) { + if (!PDFViewerApplication.initialized) { + return; + } + PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = + PDFViewerApplication.pdfSidebar.isThumbnailViewVisible; + + var store = PDFViewerApplication.store; + if (!store || !PDFViewerApplication.isInitialViewSet) { + // Only update the storage when the document has been loaded *and* rendered. + return; + } +}, true); + window.addEventListener('updateviewarea', function (evt) { if (!PDFViewerApplication.initialized) { return; } - var location = evt.location; + var location = evt.location, store = PDFViewerApplication.store; - PDFViewerApplication.store.initializedPromise.then(function() { - PDFViewerApplication.store.setMultiple({ - 'exists': true, - 'page': location.pageNumber, - 'zoom': location.scale, - 'scrollLeft': location.left, - 'scrollTop': location.top - }).catch(function() { - // unable to write to storage + if (store) { + store.initializedPromise.then(function() { + store.setMultiple({ + 'exists': true, + 'page': location.pageNumber, + 'zoom': location.scale, + 'scrollLeft': location.left, + 'scrollTop': location.top, + }).catch(function() { /* unable to write to storage */ }); }); - }); + } var href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); document.getElementById('viewBookmark').href = href; diff --git a/web/pdf_sidebar.js b/web/pdf_sidebar.js index c28b4db49..0cbae2c50 100644 --- a/web/pdf_sidebar.js +++ b/web/pdf_sidebar.js @@ -37,9 +37,9 @@ var SidebarView = { /** * @typedef {Object} PDFSidebarOptions - * @property {PDFViewer} - The document viewer. - * @property {PDFThumbnailViewer} - The thumbnail viewer. - * @property {PDFOutlineViewer} - The outline viewer. + * @property {PDFViewer} pdfViewer - The document viewer. + * @property {PDFThumbnailViewer} pdfThumbnailViewer - The thumbnail viewer. + * @property {PDFOutlineViewer} pdfOutlineViewer - The outline viewer. * @property {HTMLDivElement} mainContainer - The main container * (in which the viewer element is placed). * @property {HTMLDivElement} outerContainer - The outer container @@ -139,17 +139,25 @@ var PDFSidebar = (function PDFSidebarClosure() { this.isInitialViewSet = true; if (this.isOpen && view === SidebarView.NONE) { + this._dispatchEvent(); // If the user has already manually opened the sidebar, // immediately closing it would be bad UX. return; } - this.switchView(view, true); + var isViewPreserved = (view === this.visibleView); + this.switchView(view, /* forceOpen */ true); + + if (isViewPreserved) { + // Prevent dispatching two back-to-back `sidebarviewchanged` events, + // since `this.switchView` dispatched the event if the view changed. + this._dispatchEvent(); + } }, /** * @param {number} view - The sidebar view that should be switched to, * must be one of the values in {SidebarView}. - * @param {boolean} forceOpen - Ensure that the sidebar is opened. + * @param {boolean} forceOpen - (optional) Ensure that the sidebar is open. * The default value is false. */ switchView: function PDFSidebar_switchView(view, forceOpen) { @@ -157,9 +165,7 @@ var PDFSidebar = (function PDFSidebarClosure() { this.close(); return; } - if (forceOpen) { - this.open(); - } + var isViewChanged = (view !== this.active); var shouldForceRendering = false; switch (view) { @@ -172,7 +178,7 @@ var PDFSidebar = (function PDFSidebarClosure() { this.outlineView.classList.add('hidden'); this.attachmentsView.classList.add('hidden'); - if (this.isOpen && view !== this.active) { + if (this.isOpen && isViewChanged) { this._updateThumbnailViewer(); shouldForceRendering = true; } @@ -210,9 +216,17 @@ var PDFSidebar = (function PDFSidebarClosure() { // in order to prevent setting it to an invalid state. this.active = view | 0; + if (forceOpen && !this.isOpen) { + this.open(); + // NOTE: `this.open` will trigger rendering, and dispatch the event. + return; + } if (shouldForceRendering) { this._forceRendering(); } + if (isViewChanged) { + this._dispatchEvent(); + } }, open: function PDFSidebar_open() { @@ -229,6 +243,7 @@ var PDFSidebar = (function PDFSidebarClosure() { this._updateThumbnailViewer(); } this._forceRendering(); + this._dispatchEvent(); }, close: function PDFSidebar_close() { @@ -242,6 +257,7 @@ var PDFSidebar = (function PDFSidebarClosure() { this.outerContainer.classList.remove('sidebarOpen'); this._forceRendering(); + this._dispatchEvent(); }, toggle: function PDFSidebar_toggle() { @@ -252,6 +268,17 @@ var PDFSidebar = (function PDFSidebarClosure() { } }, + /** + * @private + */ + _dispatchEvent: function PDFSidebar_dispatchEvent() { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('sidebarviewchanged', true, true, { + view: this.visibleView, + }); + this.outerContainer.dispatchEvent(event); + }, + /** * @private */ From 6ceda3f29079d9df12c26239e792bcb5cc56da16 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 13 Apr 2016 18:58:53 +0530 Subject: [PATCH 2/2] web/viewer.js: Persist the state of sidebar Persist the state of content sidebar while browsing away from viewer and initializing the same on returning back to the viewer. The state is saved in persistent store preferences and used upon viewer initialization. Fixes #6935 --- web/app.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/web/app.js b/web/app.js index 505eeb469..9b54fcd2c 100644 --- a/web/app.js +++ b/web/app.js @@ -963,7 +963,7 @@ var PDFViewerApplication = { }; store.initializedPromise.then(function resolved() { - var storedHash = null; + var storedHash = null, sidebarView = null; if (self.preferenceShowPreviousViewOnLoad && store.get('exists', false)) { var pageNum = store.get('page', '1'); @@ -974,10 +974,13 @@ var PDFViewerApplication = { storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + left + ',' + top; + + sidebarView = store.get('sidebarView', SidebarView.NONE); } else if (self.preferenceDefaultZoomValue) { storedHash = 'page=1&zoom=' + self.preferenceDefaultZoomValue; } - self.setInitialView(storedHash, scale); + self.setInitialView(storedHash, + { scale: scale, sidebarView: sidebarView }); initialParams.hash = storedHash; @@ -988,7 +991,7 @@ var PDFViewerApplication = { } }, function rejected(reason) { console.error(reason); - self.setInitialView(null, scale); + self.setInitialView(null, { scale: scale }); }); // For documents with different page sizes, @@ -1112,7 +1115,10 @@ var PDFViewerApplication = { }); }, - setInitialView: function pdfViewSetInitialView(storedHash, scale) { + setInitialView: function pdfViewSetInitialView(storedHash, options) { + var scale = options && options.scale; + var sidebarView = options && options.sidebarView; + this.isInitialViewSet = true; // When opening a new file, when one is already loaded in the viewer, @@ -1120,7 +1126,8 @@ var PDFViewerApplication = { document.getElementById('pageNumber').value = this.pdfViewer.currentPageNumber; - this.pdfSidebar.setInitialView(this.preferenceSidebarViewOnLoad); + this.pdfSidebar.setInitialView(this.preferenceSidebarViewOnLoad || + (sidebarView | 0)); if (this.initialDestination) { this.pdfLinkService.navigateTo(this.initialDestination); @@ -1697,6 +1704,9 @@ window.addEventListener('sidebarviewchanged', function (evt) { // Only update the storage when the document has been loaded *and* rendered. return; } + store.initializedPromise.then(function() { + store.set('sidebarView', evt.detail.view).catch(function() {}); + }); }, true); window.addEventListener('updateviewarea', function (evt) {