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.
This commit is contained in:
Jonas Jenwald 2021-01-12 13:38:49 +01:00
parent 1de1ae0be6
commit a882a85446
2 changed files with 47 additions and 25 deletions

View File

@ -1588,7 +1588,7 @@ const PDFViewerApplication = {
} }
} }
this._scriptingInstance?.scripting.dispatchEventInSandbox({ await this._scriptingInstance?.scripting.dispatchEventInSandbox({
id: "page", id: "page",
name: "PageOpen", name: "PageOpen",
pageNumber, pageNumber,
@ -1612,7 +1612,7 @@ const PDFViewerApplication = {
return; // The document was closed while the actions resolved. return; // The document was closed while the actions resolved.
} }
this._scriptingInstance?.scripting.dispatchEventInSandbox({ await this._scriptingInstance?.scripting.dispatchEventInSandbox({
id: "page", id: "page",
name: "PageClose", name: "PageClose",
pageNumber, pageNumber,
@ -1678,8 +1678,7 @@ const PDFViewerApplication = {
id: "doc", id: "doc",
name: "Open", name: "Open",
}); });
await this.pdfViewer.initializeScriptingEvents();
await pageOpen({ pageNumber: this.pdfViewer.currentPageNumber });
// Used together with the integration-tests, see the `scriptingReady` // Used together with the integration-tests, see the `scriptingReady`
// getter, to enable awaiting full initialization of the scripting/sandbox. // getter, to enable awaiting full initialization of the scripting/sandbox.

View File

@ -215,7 +215,6 @@ class BaseViewer {
if (this.removePageBorders) { if (this.removePageBorders) {
this.viewer.classList.add("removePageBorders"); this.viewer.classList.add("removePageBorders");
} }
this._initializeScriptingEvents();
// Defer the dispatching of this event, to give other viewer components // Defer the dispatching of this event, to give other viewer components
// time to initialize *and* register 'baseviewerinit' event listeners. // time to initialize *and* register 'baseviewerinit' event listeners.
Promise.resolve().then(() => { Promise.resolve().then(() => {
@ -654,7 +653,6 @@ class BaseViewer {
this._pagesCapability = createPromiseCapability(); this._pagesCapability = createPromiseCapability();
this._scrollMode = ScrollMode.VERTICAL; this._scrollMode = ScrollMode.VERTICAL;
this._spreadMode = SpreadMode.NONE; this._spreadMode = SpreadMode.NONE;
this._pageOpenPendingSet?.clear();
if (this._onBeforeDraw) { if (this._onBeforeDraw) {
this.eventBus._off("pagerender", this._onBeforeDraw); this.eventBus._off("pagerender", this._onBeforeDraw);
@ -664,6 +662,8 @@ class BaseViewer {
this.eventBus._off("pagerendered", this._onAfterDraw); this.eventBus._off("pagerendered", this._onAfterDraw);
this._onAfterDraw = null; this._onAfterDraw = null;
} }
this._resetScriptingEvents();
// Remove the pages from the DOM... // Remove the pages from the DOM...
this.viewer.textContent = ""; this.viewer.textContent = "";
// ... and reset the Scroll mode CSS class(es) afterwards. // ... and reset the Scroll mode CSS class(es) afterwards.
@ -1507,15 +1507,13 @@ class BaseViewer {
this.update(); this.update();
} }
/** initializeScriptingEvents() {
* @private if (!this.enableScripting || this._pageOpenPendingSet) {
*/
_initializeScriptingEvents() {
if (!this.enableScripting) {
return; return;
} }
const eventBus = this.eventBus, const eventBus = this.eventBus,
pageOpenPendingSet = (this._pageOpenPendingSet ||= new Set()); pageOpenPendingSet = (this._pageOpenPendingSet = new Set()),
scriptingEvents = (this._scriptingEvents ||= Object.create(null));
const dispatchPageClose = pageNumber => { const dispatchPageClose = pageNumber => {
if (pageOpenPendingSet.has(pageNumber)) { if (pageOpenPendingSet.has(pageNumber)) {
@ -1523,9 +1521,9 @@ class BaseViewer {
} }
eventBus.dispatch("pageclose", { source: this, pageNumber }); eventBus.dispatch("pageclose", { source: this, pageNumber });
}; };
const dispatchPageOpen = (pageNumber, force = false) => { const dispatchPageOpen = pageNumber => {
const pageView = this._pages[pageNumber - 1]; const pageView = this._pages[pageNumber - 1];
if (force || pageView?.renderingState === RenderingStates.FINISHED) { if (pageView?.renderingState === RenderingStates.FINISHED) {
pageOpenPendingSet.delete(pageNumber); pageOpenPendingSet.delete(pageNumber);
eventBus.dispatch("pageopen", { source: this, 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) { if (pageNumber === previous) {
return; // The active page didn't change. return; // The active page didn't change.
} }
dispatchPageClose(previous); dispatchPageClose(previous);
dispatchPageOpen(pageNumber); dispatchPageOpen(pageNumber);
}); };
eventBus._on("pagechanging", scriptingEvents.onPageChanging);
eventBus._on("pagerendered", ({ pageNumber }) => { scriptingEvents.onPageRendered = ({ pageNumber }) => {
if (!pageOpenPendingSet.has(pageNumber)) { if (!pageOpenPendingSet.has(pageNumber)) {
return; // No pending "pageopen" event for the newly rendered page. return; // No pending "pageopen" event for the newly rendered page.
} }
if (pageNumber !== this._currentPageNumber) { if (pageNumber !== this._currentPageNumber) {
return; // The newly rendered page is no longer the current one. 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", () => { scriptingEvents.onPagesDestroy = () => {
dispatchPageOpen(this._currentPageNumber);
});
eventBus._on("pagesdestroy", () => {
dispatchPageClose(this._currentPageNumber); 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;
} }
} }