mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 14:48:08 +02:00
Merge pull request #17967 from Snuffleupagus/eventBus-signal
Add `signal`-support in the `EventBus`, and utilize it in the viewer (PR 17964 follow-up)
This commit is contained in:
commit
bda98b91cb
7 changed files with 246 additions and 223 deletions
|
@ -143,6 +143,60 @@ describe("event_utils", function () {
|
|||
expect(onceCount).toEqual(1);
|
||||
});
|
||||
|
||||
it("dispatch event to handlers with/without 'signal' option, aborted *before* dispatch", function () {
|
||||
const eventBus = new EventBus();
|
||||
const ac = new AbortController();
|
||||
let multipleCount = 0,
|
||||
noneCount = 0;
|
||||
|
||||
eventBus.on("test", function () {
|
||||
multipleCount++;
|
||||
});
|
||||
eventBus.on(
|
||||
"test",
|
||||
function () {
|
||||
noneCount++;
|
||||
},
|
||||
{ signal: ac.signal }
|
||||
);
|
||||
|
||||
ac.abort();
|
||||
|
||||
eventBus.dispatch("test");
|
||||
eventBus.dispatch("test");
|
||||
eventBus.dispatch("test");
|
||||
|
||||
expect(multipleCount).toEqual(3);
|
||||
expect(noneCount).toEqual(0);
|
||||
});
|
||||
|
||||
it("dispatch event to handlers with/without 'signal' option, aborted *after* dispatch", function () {
|
||||
const eventBus = new EventBus();
|
||||
const ac = new AbortController();
|
||||
let multipleCount = 0,
|
||||
onceCount = 0;
|
||||
|
||||
eventBus.on("test", function () {
|
||||
multipleCount++;
|
||||
});
|
||||
eventBus.on(
|
||||
"test",
|
||||
function () {
|
||||
onceCount++;
|
||||
},
|
||||
{ signal: ac.signal }
|
||||
);
|
||||
|
||||
eventBus.dispatch("test");
|
||||
ac.abort();
|
||||
|
||||
eventBus.dispatch("test");
|
||||
eventBus.dispatch("test");
|
||||
|
||||
expect(multipleCount).toEqual(3);
|
||||
expect(onceCount).toEqual(1);
|
||||
});
|
||||
|
||||
it("should not re-dispatch to DOM", async function () {
|
||||
if (isNodeJS) {
|
||||
pending("Document is not supported in Node.js.");
|
||||
|
|
|
@ -50,7 +50,7 @@ import { PresentationModeState } from "./ui_utils.js";
|
|||
class AnnotationLayerBuilder {
|
||||
#onAppend = null;
|
||||
|
||||
#onPresentationModeChanged = null;
|
||||
#eventAbortController = null;
|
||||
|
||||
/**
|
||||
* @param {AnnotationLayerBuilderOptions} options
|
||||
|
@ -155,13 +155,15 @@ class AnnotationLayerBuilder {
|
|||
if (this.linkService.isInPresentationMode) {
|
||||
this.#updatePresentationModeState(PresentationModeState.FULLSCREEN);
|
||||
}
|
||||
if (!this.#onPresentationModeChanged) {
|
||||
this.#onPresentationModeChanged = evt => {
|
||||
this.#updatePresentationModeState(evt.state);
|
||||
};
|
||||
if (!this.#eventAbortController) {
|
||||
this.#eventAbortController = new AbortController();
|
||||
|
||||
this._eventBus?._on(
|
||||
"presentationmodechanged",
|
||||
this.#onPresentationModeChanged
|
||||
evt => {
|
||||
this.#updatePresentationModeState(evt.state);
|
||||
},
|
||||
{ signal: this.#eventAbortController.signal }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -169,13 +171,8 @@ class AnnotationLayerBuilder {
|
|||
cancel() {
|
||||
this._cancelled = true;
|
||||
|
||||
if (this.#onPresentationModeChanged) {
|
||||
this._eventBus?._off(
|
||||
"presentationmodechanged",
|
||||
this.#onPresentationModeChanged
|
||||
);
|
||||
this.#onPresentationModeChanged = null;
|
||||
}
|
||||
this.#eventAbortController?.abort();
|
||||
this.#eventAbortController = null;
|
||||
}
|
||||
|
||||
hide() {
|
||||
|
|
176
web/app.js
176
web/app.js
|
@ -157,7 +157,7 @@ const PDFViewerApplication = {
|
|||
url: "",
|
||||
baseUrl: "",
|
||||
_downloadUrl: "",
|
||||
_boundEvents: Object.create(null),
|
||||
_eventBusAbortController: null,
|
||||
_windowAbortController: null,
|
||||
documentInfo: null,
|
||||
metadata: null,
|
||||
|
@ -1832,75 +1832,87 @@ const PDFViewerApplication = {
|
|||
},
|
||||
|
||||
bindEvents() {
|
||||
const { eventBus, _boundEvents } = this;
|
||||
if (this._eventBusAbortController) {
|
||||
return;
|
||||
}
|
||||
this._eventBusAbortController = new AbortController();
|
||||
|
||||
_boundEvents.beforePrint = this.beforePrint.bind(this);
|
||||
_boundEvents.afterPrint = this.afterPrint.bind(this);
|
||||
const {
|
||||
eventBus,
|
||||
_eventBusAbortController: { signal },
|
||||
} = this;
|
||||
|
||||
eventBus._on("resize", webViewerResize);
|
||||
eventBus._on("hashchange", webViewerHashchange);
|
||||
eventBus._on("beforeprint", _boundEvents.beforePrint);
|
||||
eventBus._on("afterprint", _boundEvents.afterPrint);
|
||||
eventBus._on("pagerender", webViewerPageRender);
|
||||
eventBus._on("pagerendered", webViewerPageRendered);
|
||||
eventBus._on("updateviewarea", webViewerUpdateViewarea);
|
||||
eventBus._on("pagechanging", webViewerPageChanging);
|
||||
eventBus._on("scalechanging", webViewerScaleChanging);
|
||||
eventBus._on("rotationchanging", webViewerRotationChanging);
|
||||
eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged);
|
||||
eventBus._on("pagemode", webViewerPageMode);
|
||||
eventBus._on("namedaction", webViewerNamedAction);
|
||||
eventBus._on("presentationmodechanged", webViewerPresentationModeChanged);
|
||||
eventBus._on("presentationmode", webViewerPresentationMode);
|
||||
eventBus._on("resize", webViewerResize, { signal });
|
||||
eventBus._on("hashchange", webViewerHashchange, { signal });
|
||||
eventBus._on("beforeprint", this.beforePrint.bind(this), { signal });
|
||||
eventBus._on("afterprint", this.afterPrint.bind(this), { signal });
|
||||
eventBus._on("pagerender", webViewerPageRender, { signal });
|
||||
eventBus._on("pagerendered", webViewerPageRendered, { signal });
|
||||
eventBus._on("updateviewarea", webViewerUpdateViewarea, { signal });
|
||||
eventBus._on("pagechanging", webViewerPageChanging, { signal });
|
||||
eventBus._on("scalechanging", webViewerScaleChanging, { signal });
|
||||
eventBus._on("rotationchanging", webViewerRotationChanging, { signal });
|
||||
eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged, { signal });
|
||||
eventBus._on("pagemode", webViewerPageMode, { signal });
|
||||
eventBus._on("namedaction", webViewerNamedAction, { signal });
|
||||
eventBus._on("presentationmodechanged", webViewerPresentationModeChanged, {
|
||||
signal,
|
||||
});
|
||||
eventBus._on("presentationmode", webViewerPresentationMode, { signal });
|
||||
eventBus._on(
|
||||
"switchannotationeditormode",
|
||||
webViewerSwitchAnnotationEditorMode
|
||||
webViewerSwitchAnnotationEditorMode,
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on(
|
||||
"switchannotationeditorparams",
|
||||
webViewerSwitchAnnotationEditorParams
|
||||
webViewerSwitchAnnotationEditorParams,
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on("print", webViewerPrint);
|
||||
eventBus._on("download", webViewerDownload);
|
||||
eventBus._on("firstpage", webViewerFirstPage);
|
||||
eventBus._on("lastpage", webViewerLastPage);
|
||||
eventBus._on("nextpage", webViewerNextPage);
|
||||
eventBus._on("previouspage", webViewerPreviousPage);
|
||||
eventBus._on("zoomin", webViewerZoomIn);
|
||||
eventBus._on("zoomout", webViewerZoomOut);
|
||||
eventBus._on("zoomreset", webViewerZoomReset);
|
||||
eventBus._on("pagenumberchanged", webViewerPageNumberChanged);
|
||||
eventBus._on("scalechanged", webViewerScaleChanged);
|
||||
eventBus._on("rotatecw", webViewerRotateCw);
|
||||
eventBus._on("rotateccw", webViewerRotateCcw);
|
||||
eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig);
|
||||
eventBus._on("switchscrollmode", webViewerSwitchScrollMode);
|
||||
eventBus._on("scrollmodechanged", webViewerScrollModeChanged);
|
||||
eventBus._on("switchspreadmode", webViewerSwitchSpreadMode);
|
||||
eventBus._on("spreadmodechanged", webViewerSpreadModeChanged);
|
||||
eventBus._on("documentproperties", webViewerDocumentProperties);
|
||||
eventBus._on("findfromurlhash", webViewerFindFromUrlHash);
|
||||
eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount);
|
||||
eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState);
|
||||
eventBus._on("print", webViewerPrint, { signal });
|
||||
eventBus._on("download", webViewerDownload, { signal });
|
||||
eventBus._on("firstpage", webViewerFirstPage, { signal });
|
||||
eventBus._on("lastpage", webViewerLastPage, { signal });
|
||||
eventBus._on("nextpage", webViewerNextPage, { signal });
|
||||
eventBus._on("previouspage", webViewerPreviousPage, { signal });
|
||||
eventBus._on("zoomin", webViewerZoomIn, { signal });
|
||||
eventBus._on("zoomout", webViewerZoomOut, { signal });
|
||||
eventBus._on("zoomreset", webViewerZoomReset, { signal });
|
||||
eventBus._on("pagenumberchanged", webViewerPageNumberChanged, { signal });
|
||||
eventBus._on("scalechanged", webViewerScaleChanged, { signal });
|
||||
eventBus._on("rotatecw", webViewerRotateCw, { signal });
|
||||
eventBus._on("rotateccw", webViewerRotateCcw, { signal });
|
||||
eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig, {
|
||||
signal,
|
||||
});
|
||||
eventBus._on("switchscrollmode", webViewerSwitchScrollMode, { signal });
|
||||
eventBus._on("scrollmodechanged", webViewerScrollModeChanged, { signal });
|
||||
eventBus._on("switchspreadmode", webViewerSwitchSpreadMode, { signal });
|
||||
eventBus._on("spreadmodechanged", webViewerSpreadModeChanged, { signal });
|
||||
eventBus._on("documentproperties", webViewerDocumentProperties, { signal });
|
||||
eventBus._on("findfromurlhash", webViewerFindFromUrlHash, { signal });
|
||||
eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount, {
|
||||
signal,
|
||||
});
|
||||
eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState, {
|
||||
signal,
|
||||
});
|
||||
|
||||
if (AppOptions.get("pdfBug")) {
|
||||
_boundEvents.reportPageStatsPDFBug = reportPageStatsPDFBug;
|
||||
|
||||
eventBus._on("pagerendered", _boundEvents.reportPageStatsPDFBug);
|
||||
eventBus._on("pagechanging", _boundEvents.reportPageStatsPDFBug);
|
||||
eventBus._on("pagerendered", reportPageStatsPDFBug, { signal });
|
||||
eventBus._on("pagechanging", reportPageStatsPDFBug, { signal });
|
||||
}
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
eventBus._on("fileinputchange", webViewerFileInputChange);
|
||||
eventBus._on("openfile", webViewerOpenFile);
|
||||
eventBus._on("fileinputchange", webViewerFileInputChange, { signal });
|
||||
eventBus._on("openfile", webViewerOpenFile, { signal });
|
||||
}
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||
// The `unbindEvents` method is unused in MOZCENTRAL builds,
|
||||
// hence we don't need to unregister these event listeners.
|
||||
eventBus._on(
|
||||
"annotationeditorstateschanged",
|
||||
webViewerAnnotationEditorStatesChanged
|
||||
webViewerAnnotationEditorStatesChanged,
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on("reporttelemetry", webViewerReportTelemetry);
|
||||
eventBus._on("reporttelemetry", webViewerReportTelemetry, { signal });
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2049,62 +2061,8 @@ const PDFViewerApplication = {
|
|||
},
|
||||
|
||||
unbindEvents() {
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
|
||||
throw new Error("Not implemented: unbindEvents");
|
||||
}
|
||||
const { eventBus, _boundEvents } = this;
|
||||
|
||||
eventBus._off("resize", webViewerResize);
|
||||
eventBus._off("hashchange", webViewerHashchange);
|
||||
eventBus._off("beforeprint", _boundEvents.beforePrint);
|
||||
eventBus._off("afterprint", _boundEvents.afterPrint);
|
||||
eventBus._off("pagerender", webViewerPageRender);
|
||||
eventBus._off("pagerendered", webViewerPageRendered);
|
||||
eventBus._off("updateviewarea", webViewerUpdateViewarea);
|
||||
eventBus._off("pagechanging", webViewerPageChanging);
|
||||
eventBus._off("scalechanging", webViewerScaleChanging);
|
||||
eventBus._off("rotationchanging", webViewerRotationChanging);
|
||||
eventBus._off("sidebarviewchanged", webViewerSidebarViewChanged);
|
||||
eventBus._off("pagemode", webViewerPageMode);
|
||||
eventBus._off("namedaction", webViewerNamedAction);
|
||||
eventBus._off("presentationmodechanged", webViewerPresentationModeChanged);
|
||||
eventBus._off("presentationmode", webViewerPresentationMode);
|
||||
eventBus._off("print", webViewerPrint);
|
||||
eventBus._off("download", webViewerDownload);
|
||||
eventBus._off("firstpage", webViewerFirstPage);
|
||||
eventBus._off("lastpage", webViewerLastPage);
|
||||
eventBus._off("nextpage", webViewerNextPage);
|
||||
eventBus._off("previouspage", webViewerPreviousPage);
|
||||
eventBus._off("zoomin", webViewerZoomIn);
|
||||
eventBus._off("zoomout", webViewerZoomOut);
|
||||
eventBus._off("zoomreset", webViewerZoomReset);
|
||||
eventBus._off("pagenumberchanged", webViewerPageNumberChanged);
|
||||
eventBus._off("scalechanged", webViewerScaleChanged);
|
||||
eventBus._off("rotatecw", webViewerRotateCw);
|
||||
eventBus._off("rotateccw", webViewerRotateCcw);
|
||||
eventBus._off("optionalcontentconfig", webViewerOptionalContentConfig);
|
||||
eventBus._off("switchscrollmode", webViewerSwitchScrollMode);
|
||||
eventBus._off("scrollmodechanged", webViewerScrollModeChanged);
|
||||
eventBus._off("switchspreadmode", webViewerSwitchSpreadMode);
|
||||
eventBus._off("spreadmodechanged", webViewerSpreadModeChanged);
|
||||
eventBus._off("documentproperties", webViewerDocumentProperties);
|
||||
eventBus._off("findfromurlhash", webViewerFindFromUrlHash);
|
||||
eventBus._off("updatefindmatchescount", webViewerUpdateFindMatchesCount);
|
||||
eventBus._off("updatefindcontrolstate", webViewerUpdateFindControlState);
|
||||
|
||||
if (_boundEvents.reportPageStatsPDFBug) {
|
||||
eventBus._off("pagerendered", _boundEvents.reportPageStatsPDFBug);
|
||||
eventBus._off("pagechanging", _boundEvents.reportPageStatsPDFBug);
|
||||
|
||||
_boundEvents.reportPageStatsPDFBug = null;
|
||||
}
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
|
||||
eventBus._off("fileinputchange", webViewerFileInputChange);
|
||||
eventBus._off("openfile", webViewerOpenFile);
|
||||
}
|
||||
|
||||
_boundEvents.beforePrint = null;
|
||||
_boundEvents.afterPrint = null;
|
||||
this._eventBusAbortController?.abort();
|
||||
this._eventBusAbortController = null;
|
||||
},
|
||||
|
||||
unbindWindowEvents() {
|
||||
|
|
|
@ -44,29 +44,21 @@ async function waitOnEventOrTimeout({ target, name, delay = 0 }) {
|
|||
throw new Error("waitOnEventOrTimeout - invalid parameters.");
|
||||
}
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
const ac = new AbortController();
|
||||
|
||||
function handler(type) {
|
||||
if (target instanceof EventBus) {
|
||||
target._off(name, eventHandler);
|
||||
} else {
|
||||
target.removeEventListener(name, eventHandler);
|
||||
}
|
||||
ac.abort(); // Remove event listener.
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
resolve(type);
|
||||
}
|
||||
|
||||
const eventHandler = handler.bind(null, WaitOnType.EVENT);
|
||||
if (target instanceof EventBus) {
|
||||
target._on(name, eventHandler);
|
||||
} else {
|
||||
target.addEventListener(name, eventHandler);
|
||||
}
|
||||
const evtMethod = target instanceof EventBus ? "_on" : "addEventListener";
|
||||
target[evtMethod](name, handler.bind(null, WaitOnType.EVENT), {
|
||||
signal: ac.signal,
|
||||
});
|
||||
|
||||
const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT);
|
||||
const timeout = setTimeout(timeoutHandler, delay);
|
||||
const timeout = setTimeout(handler.bind(null, WaitOnType.TIMEOUT), delay);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
@ -87,6 +79,7 @@ class EventBus {
|
|||
this._on(eventName, listener, {
|
||||
external: true,
|
||||
once: options?.once,
|
||||
signal: options?.signal,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -96,10 +89,7 @@ class EventBus {
|
|||
* @param {Object} [options]
|
||||
*/
|
||||
off(eventName, listener, options = null) {
|
||||
this._off(eventName, listener, {
|
||||
external: true,
|
||||
once: options?.once,
|
||||
});
|
||||
this._off(eventName, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,11 +128,25 @@ class EventBus {
|
|||
* @ignore
|
||||
*/
|
||||
_on(eventName, listener, options = null) {
|
||||
let rmAbort = null;
|
||||
if (options?.signal instanceof AbortSignal) {
|
||||
const { signal } = options;
|
||||
if (signal.aborted) {
|
||||
console.error("Cannot use an `aborted` signal.");
|
||||
return;
|
||||
}
|
||||
const onAbort = () => this._off(eventName, listener);
|
||||
rmAbort = () => signal.removeEventListener("abort", onAbort);
|
||||
|
||||
signal.addEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
const eventListeners = (this.#listeners[eventName] ||= []);
|
||||
eventListeners.push({
|
||||
listener,
|
||||
external: options?.external === true,
|
||||
once: options?.once === true,
|
||||
rmAbort,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -155,7 +159,9 @@ class EventBus {
|
|||
return;
|
||||
}
|
||||
for (let i = 0, ii = eventListeners.length; i < ii; i++) {
|
||||
if (eventListeners[i].listener === listener) {
|
||||
const evt = eventListeners[i];
|
||||
if (evt.listener === listener) {
|
||||
evt.rmAbort?.(); // Ensure that the `AbortSignal` listener is removed.
|
||||
eventListeners.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ function getCurrentHash() {
|
|||
}
|
||||
|
||||
class PDFHistory {
|
||||
#eventAbortController = null;
|
||||
|
||||
/**
|
||||
* @param {PDFHistoryOptions} options
|
||||
*/
|
||||
|
@ -64,7 +66,6 @@ class PDFHistory {
|
|||
this._fingerprint = "";
|
||||
this.reset();
|
||||
|
||||
this._boundEvents = null;
|
||||
// Ensure that we don't miss a "pagesinit" event,
|
||||
// by registering the listener immediately.
|
||||
this.eventBus._on("pagesinit", () => {
|
||||
|
@ -679,29 +680,22 @@ class PDFHistory {
|
|||
}
|
||||
|
||||
#bindEvents() {
|
||||
if (this._boundEvents) {
|
||||
if (this.#eventAbortController) {
|
||||
return; // The event listeners were already added.
|
||||
}
|
||||
this._boundEvents = {
|
||||
updateViewarea: this.#updateViewarea.bind(this),
|
||||
popState: this.#popState.bind(this),
|
||||
pageHide: this.#pageHide.bind(this),
|
||||
};
|
||||
this.#eventAbortController = new AbortController();
|
||||
const { signal } = this.#eventAbortController;
|
||||
|
||||
this.eventBus._on("updateviewarea", this._boundEvents.updateViewarea);
|
||||
window.addEventListener("popstate", this._boundEvents.popState);
|
||||
window.addEventListener("pagehide", this._boundEvents.pageHide);
|
||||
this.eventBus._on("updateviewarea", this.#updateViewarea.bind(this), {
|
||||
signal,
|
||||
});
|
||||
window.addEventListener("popstate", this.#popState.bind(this), { signal });
|
||||
window.addEventListener("pagehide", this.#pageHide.bind(this), { signal });
|
||||
}
|
||||
|
||||
#unbindEvents() {
|
||||
if (!this._boundEvents) {
|
||||
return; // The event listeners were already removed.
|
||||
}
|
||||
this.eventBus._off("updateviewarea", this._boundEvents.updateViewarea);
|
||||
window.removeEventListener("popstate", this._boundEvents.popState);
|
||||
window.removeEventListener("pagehide", this._boundEvents.pageHide);
|
||||
|
||||
this._boundEvents = null;
|
||||
this.#eventAbortController?.abort();
|
||||
this.#eventAbortController = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ class PDFScriptingManager {
|
|||
|
||||
#docProperties = null;
|
||||
|
||||
#eventAbortController = null;
|
||||
|
||||
#eventBus = null;
|
||||
|
||||
#externalServices = null;
|
||||
|
@ -108,46 +110,66 @@ class PDFScriptingManager {
|
|||
await this.#destroyScripting();
|
||||
return;
|
||||
}
|
||||
const eventBus = this.#eventBus;
|
||||
|
||||
this._internalEvents.set("updatefromsandbox", event => {
|
||||
if (event?.source === window) {
|
||||
this.#updateFromSandbox(event.detail);
|
||||
}
|
||||
});
|
||||
this._internalEvents.set("dispatcheventinsandbox", event => {
|
||||
this.#scripting?.dispatchEventInSandbox(event.detail);
|
||||
});
|
||||
this.#eventAbortController = new AbortController();
|
||||
const { signal } = this.#eventAbortController;
|
||||
|
||||
this._internalEvents.set("pagechanging", ({ pageNumber, previous }) => {
|
||||
if (pageNumber === previous) {
|
||||
return; // The current page didn't change.
|
||||
}
|
||||
this.#dispatchPageClose(previous);
|
||||
this.#dispatchPageOpen(pageNumber);
|
||||
});
|
||||
this._internalEvents.set("pagerendered", ({ pageNumber }) => {
|
||||
if (!this._pageOpenPending.has(pageNumber)) {
|
||||
return; // No pending "PageOpen" event for the newly rendered page.
|
||||
}
|
||||
if (pageNumber !== this.#pdfViewer.currentPageNumber) {
|
||||
return; // The newly rendered page is no longer the current one.
|
||||
}
|
||||
this.#dispatchPageOpen(pageNumber);
|
||||
});
|
||||
this._internalEvents.set("pagesdestroy", async () => {
|
||||
await this.#dispatchPageClose(this.#pdfViewer.currentPageNumber);
|
||||
eventBus._on(
|
||||
"updatefromsandbox",
|
||||
event => {
|
||||
if (event?.source === window) {
|
||||
this.#updateFromSandbox(event.detail);
|
||||
}
|
||||
},
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on(
|
||||
"dispatcheventinsandbox",
|
||||
event => {
|
||||
this.#scripting?.dispatchEventInSandbox(event.detail);
|
||||
},
|
||||
{ signal }
|
||||
);
|
||||
|
||||
await this.#scripting?.dispatchEventInSandbox({
|
||||
id: "doc",
|
||||
name: "WillClose",
|
||||
});
|
||||
eventBus._on(
|
||||
"pagechanging",
|
||||
({ pageNumber, previous }) => {
|
||||
if (pageNumber === previous) {
|
||||
return; // The current page didn't change.
|
||||
}
|
||||
this.#dispatchPageClose(previous);
|
||||
this.#dispatchPageOpen(pageNumber);
|
||||
},
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on(
|
||||
"pagerendered",
|
||||
({ pageNumber }) => {
|
||||
if (!this._pageOpenPending.has(pageNumber)) {
|
||||
return; // No pending "PageOpen" event for the newly rendered page.
|
||||
}
|
||||
if (pageNumber !== this.#pdfViewer.currentPageNumber) {
|
||||
return; // The newly rendered page is no longer the current one.
|
||||
}
|
||||
this.#dispatchPageOpen(pageNumber);
|
||||
},
|
||||
{ signal }
|
||||
);
|
||||
eventBus._on(
|
||||
"pagesdestroy",
|
||||
async () => {
|
||||
await this.#dispatchPageClose(this.#pdfViewer.currentPageNumber);
|
||||
|
||||
this.#closeCapability?.resolve();
|
||||
});
|
||||
await this.#scripting?.dispatchEventInSandbox({
|
||||
id: "doc",
|
||||
name: "WillClose",
|
||||
});
|
||||
|
||||
for (const [name, listener] of this._internalEvents) {
|
||||
this.#eventBus._on(name, listener);
|
||||
}
|
||||
this.#closeCapability?.resolve();
|
||||
},
|
||||
{ signal }
|
||||
);
|
||||
|
||||
try {
|
||||
const docProperties = await this.#docProperties(pdfDocument);
|
||||
|
@ -168,7 +190,7 @@ class PDFScriptingManager {
|
|||
},
|
||||
});
|
||||
|
||||
this.#eventBus.dispatch("sandboxcreated", { source: this });
|
||||
eventBus.dispatch("sandboxcreated", { source: this });
|
||||
} catch (error) {
|
||||
console.error(`setDocument: "${error.message}".`);
|
||||
|
||||
|
@ -242,13 +264,6 @@ class PDFScriptingManager {
|
|||
return this.#ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
get _internalEvents() {
|
||||
return shadow(this, "_internalEvents", new Map());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
@ -466,10 +481,8 @@ class PDFScriptingManager {
|
|||
this.#willPrintCapability?.reject(new Error("Scripting destroyed."));
|
||||
this.#willPrintCapability = null;
|
||||
|
||||
for (const [name, listener] of this._internalEvents) {
|
||||
this.#eventBus._off(name, listener);
|
||||
}
|
||||
this._internalEvents.clear();
|
||||
this.#eventAbortController?.abort();
|
||||
this.#eventAbortController = null;
|
||||
|
||||
this._pageOpenPending.clear();
|
||||
this._visitedPages.clear();
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
* either the text layer or XFA layer depending on the type of document.
|
||||
*/
|
||||
class TextHighlighter {
|
||||
#eventAbortController = null;
|
||||
|
||||
/**
|
||||
* @param {TextHighlighterOptions} options
|
||||
*/
|
||||
|
@ -37,7 +39,6 @@ class TextHighlighter {
|
|||
this.matches = [];
|
||||
this.eventBus = eventBus;
|
||||
this.pageIdx = pageIndex;
|
||||
this._onUpdateTextLayerMatches = null;
|
||||
this.textDivs = null;
|
||||
this.textContentItemsStr = null;
|
||||
this.enabled = false;
|
||||
|
@ -69,15 +70,18 @@ class TextHighlighter {
|
|||
throw new Error("TextHighlighter is already enabled.");
|
||||
}
|
||||
this.enabled = true;
|
||||
if (!this._onUpdateTextLayerMatches) {
|
||||
this._onUpdateTextLayerMatches = evt => {
|
||||
if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) {
|
||||
this._updateMatches();
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.#eventAbortController) {
|
||||
this.#eventAbortController = new AbortController();
|
||||
|
||||
this.eventBus._on(
|
||||
"updatetextlayermatches",
|
||||
this._onUpdateTextLayerMatches
|
||||
evt => {
|
||||
if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) {
|
||||
this._updateMatches();
|
||||
}
|
||||
},
|
||||
{ signal: this.#eventAbortController.signal }
|
||||
);
|
||||
}
|
||||
this._updateMatches();
|
||||
|
@ -88,13 +92,10 @@ class TextHighlighter {
|
|||
return;
|
||||
}
|
||||
this.enabled = false;
|
||||
if (this._onUpdateTextLayerMatches) {
|
||||
this.eventBus._off(
|
||||
"updatetextlayermatches",
|
||||
this._onUpdateTextLayerMatches
|
||||
);
|
||||
this._onUpdateTextLayerMatches = null;
|
||||
}
|
||||
|
||||
this.#eventAbortController?.abort();
|
||||
this.#eventAbortController = null;
|
||||
|
||||
this._updateMatches(/* reset = */ true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue