From a882a854461a60a3a38654a6d925c33ecf3cd979 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 12 Jan 2021 13:38:49 +0100 Subject: [PATCH] Fix the initialization/resetting of scripting-related events in the `BaseViewer` The "pageopen"/"pageclose"-events are only necessary if, and only if, there's actually a sandbox to dispatch the events in. Hence we shouldn't dispatch those events unconditionally, as soon as `enableScripting` is set, but rather initialize that functionality only when needed. Furthermore, in `web/app.js`, there's currently a bug since we're attempting to *manually* simulate a "pageopen"-event for a page that may not actually have been rendered at the time. With the modified `BaseViewer.initializeScriptingEvents` method, we'll now dispatch a correct "pageopen"-event here. --- web/app.js | 7 +++-- web/base_viewer.js | 65 +++++++++++++++++++++++++++++++--------------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/web/app.js b/web/app.js index 825b3eda9..e36e5f1a8 100644 --- a/web/app.js +++ b/web/app.js @@ -1588,7 +1588,7 @@ const PDFViewerApplication = { } } - this._scriptingInstance?.scripting.dispatchEventInSandbox({ + await this._scriptingInstance?.scripting.dispatchEventInSandbox({ id: "page", name: "PageOpen", pageNumber, @@ -1612,7 +1612,7 @@ const PDFViewerApplication = { return; // The document was closed while the actions resolved. } - this._scriptingInstance?.scripting.dispatchEventInSandbox({ + await this._scriptingInstance?.scripting.dispatchEventInSandbox({ id: "page", name: "PageClose", pageNumber, @@ -1678,8 +1678,7 @@ const PDFViewerApplication = { id: "doc", name: "Open", }); - - await pageOpen({ pageNumber: this.pdfViewer.currentPageNumber }); + await this.pdfViewer.initializeScriptingEvents(); // Used together with the integration-tests, see the `scriptingReady` // getter, to enable awaiting full initialization of the scripting/sandbox. diff --git a/web/base_viewer.js b/web/base_viewer.js index 60cfbcb2e..c9935ec1b 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -215,7 +215,6 @@ class BaseViewer { if (this.removePageBorders) { this.viewer.classList.add("removePageBorders"); } - this._initializeScriptingEvents(); // Defer the dispatching of this event, to give other viewer components // time to initialize *and* register 'baseviewerinit' event listeners. Promise.resolve().then(() => { @@ -654,7 +653,6 @@ class BaseViewer { this._pagesCapability = createPromiseCapability(); this._scrollMode = ScrollMode.VERTICAL; this._spreadMode = SpreadMode.NONE; - this._pageOpenPendingSet?.clear(); if (this._onBeforeDraw) { this.eventBus._off("pagerender", this._onBeforeDraw); @@ -664,6 +662,8 @@ class BaseViewer { this.eventBus._off("pagerendered", this._onAfterDraw); this._onAfterDraw = null; } + this._resetScriptingEvents(); + // Remove the pages from the DOM... this.viewer.textContent = ""; // ... and reset the Scroll mode CSS class(es) afterwards. @@ -1507,15 +1507,13 @@ class BaseViewer { this.update(); } - /** - * @private - */ - _initializeScriptingEvents() { - if (!this.enableScripting) { + initializeScriptingEvents() { + if (!this.enableScripting || this._pageOpenPendingSet) { return; } const eventBus = this.eventBus, - pageOpenPendingSet = (this._pageOpenPendingSet ||= new Set()); + pageOpenPendingSet = (this._pageOpenPendingSet = new Set()), + scriptingEvents = (this._scriptingEvents ||= Object.create(null)); const dispatchPageClose = pageNumber => { if (pageOpenPendingSet.has(pageNumber)) { @@ -1523,9 +1521,9 @@ class BaseViewer { } eventBus.dispatch("pageclose", { source: this, pageNumber }); }; - const dispatchPageOpen = (pageNumber, force = false) => { + const dispatchPageOpen = pageNumber => { const pageView = this._pages[pageNumber - 1]; - if (force || pageView?.renderingState === RenderingStates.FINISHED) { + if (pageView?.renderingState === RenderingStates.FINISHED) { pageOpenPendingSet.delete(pageNumber); eventBus.dispatch("pageopen", { source: this, pageNumber }); @@ -1534,31 +1532,56 @@ class BaseViewer { } }; - eventBus._on("pagechanging", ({ pageNumber, previous }) => { + scriptingEvents.onPageChanging = ({ pageNumber, previous }) => { if (pageNumber === previous) { return; // The active page didn't change. } dispatchPageClose(previous); dispatchPageOpen(pageNumber); - }); + }; + eventBus._on("pagechanging", scriptingEvents.onPageChanging); - eventBus._on("pagerendered", ({ pageNumber }) => { + scriptingEvents.onPageRendered = ({ pageNumber }) => { if (!pageOpenPendingSet.has(pageNumber)) { return; // No pending "pageopen" event for the newly rendered page. } if (pageNumber !== this._currentPageNumber) { return; // The newly rendered page is no longer the current one. } - dispatchPageOpen(pageNumber, /* force = */ true); - }); + dispatchPageOpen(pageNumber); + }; + eventBus._on("pagerendered", scriptingEvents.onPageRendered); - eventBus._on("pagesinit", () => { - dispatchPageOpen(this._currentPageNumber); - }); - - eventBus._on("pagesdestroy", () => { + scriptingEvents.onPagesDestroy = () => { dispatchPageClose(this._currentPageNumber); - }); + }; + eventBus._on("pagesdestroy", scriptingEvents.onPagesDestroy); + + // Ensure that a "pageopen" event is dispatched for the initial page. + dispatchPageOpen(this._currentPageNumber); + } + + /** + * @private + */ + _resetScriptingEvents() { + if (!this.enableScripting || !this._pageOpenPendingSet) { + return; + } + const eventBus = this.eventBus, + scriptingEvents = this._scriptingEvents; + + // Remove the event listeners. + eventBus._off("pagechanging", scriptingEvents.onPageChanging); + scriptingEvents.onPageChanging = null; + + eventBus._off("pagerendered", scriptingEvents.onPageRendered); + scriptingEvents.onPageRendered = null; + + eventBus._off("pagesdestroy", scriptingEvents.onPagesDestroy); + scriptingEvents.onPagesDestroy = null; + + this._pageOpenPendingSet = null; } }