Merge pull request #12793 from Snuffleupagus/Eventbus-once

Support the `once` option, when registering `EventBus` listeners
This commit is contained in:
Tim van der Meij 2020-12-30 13:32:31 +01:00 committed by GitHub
commit 57bec090ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 26 deletions

View File

@ -312,6 +312,30 @@ describe("ui_utils", function () {
expect(count).toEqual(2); expect(count).toEqual(2);
}); });
it("dispatch event to handlers with/without 'once' option", function () {
const eventBus = new EventBus();
let multipleCount = 0,
onceCount = 0;
eventBus.on("test", function () {
multipleCount++;
});
eventBus.on(
"test",
function () {
onceCount++;
},
{ once: true }
);
eventBus.dispatch("test");
eventBus.dispatch("test");
eventBus.dispatch("test");
expect(multipleCount).toEqual(3);
expect(onceCount).toEqual(1);
});
it("should not re-dispatch to DOM", function (done) { it("should not re-dispatch to DOM", function (done) {
if (isNodeJS) { if (isNodeJS) {
pending("Document in not supported in Node.js."); pending("Document in not supported in Node.js.");

View File

@ -1497,11 +1497,13 @@ const PDFViewerApplication = {
// It should be *extremely* rare for metadata to not have been resolved // It should be *extremely* rare for metadata to not have been resolved
// when this code runs, but ensure that we handle that case here. // when this code runs, but ensure that we handle that case here.
await new Promise(resolve => { await new Promise(resolve => {
const metadataLoaded = () => { this.eventBus._on(
this.eventBus._off("metadataloaded", metadataLoaded); "metadataloaded",
resolve(); evt => {
}; resolve();
this.eventBus._on("metadataloaded", metadataLoaded); },
{ once: true }
);
}); });
if (pdfDocument !== this.pdfDocument) { if (pdfDocument !== this.pdfDocument) {
return; // The document was closed while the metadata resolved. return; // The document was closed while the metadata resolved.

View File

@ -76,11 +76,13 @@ class PDFHistory {
this.eventBus._on("pagesinit", () => { this.eventBus._on("pagesinit", () => {
this._isPagesLoaded = false; this._isPagesLoaded = false;
const onPagesLoaded = evt => { this.eventBus._on(
this.eventBus._off("pagesloaded", onPagesLoaded); "pagesloaded",
this._isPagesLoaded = !!evt.pagesCount; evt => {
}; this._isPagesLoaded = !!evt.pagesCount;
this.eventBus._on("pagesloaded", onPagesLoaded); },
{ once: true }
);
}); });
} }

View File

@ -804,24 +804,32 @@ class EventBus {
this._listeners = Object.create(null); this._listeners = Object.create(null);
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL")) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL")) {
this._isInAutomation = (options && options.isInAutomation) === true; this._isInAutomation = options?.isInAutomation === true;
} }
} }
/** /**
* @param {string} eventName * @param {string} eventName
* @param {function} listener * @param {function} listener
* @param {Object} [options]
*/ */
on(eventName, listener) { on(eventName, listener, options = null) {
this._on(eventName, listener, { external: true }); this._on(eventName, listener, {
external: true,
once: options?.once,
});
} }
/** /**
* @param {string} eventName * @param {string} eventName
* @param {function} listener * @param {function} listener
* @param {Object} [options]
*/ */
off(eventName, listener) { off(eventName, listener, options = null) {
this._off(eventName, listener, { external: true }); this._off(eventName, listener, {
external: true,
once: options?.once,
});
} }
dispatch(eventName) { dispatch(eventName) {
@ -841,12 +849,12 @@ class EventBus {
let externalListeners; let externalListeners;
// Making copy of the listeners array in case if it will be modified // Making copy of the listeners array in case if it will be modified
// during dispatch. // during dispatch.
eventListeners.slice(0).forEach(function ({ listener, external }) { eventListeners.slice(0).forEach(({ listener, external, once }) => {
if (once) {
this._off(eventName, listener);
}
if (external) { if (external) {
if (!externalListeners) { (externalListeners ||= []).push(listener);
externalListeners = [];
}
externalListeners.push(listener);
return; return;
} }
listener.apply(null, args); listener.apply(null, args);
@ -854,7 +862,7 @@ class EventBus {
// Dispatch any "external" listeners *after* the internal ones, to give the // Dispatch any "external" listeners *after* the internal ones, to give the
// viewer components time to handle events and update their state first. // viewer components time to handle events and update their state first.
if (externalListeners) { if (externalListeners) {
externalListeners.forEach(function (listener) { externalListeners.forEach(listener => {
listener.apply(null, args); listener.apply(null, args);
}); });
externalListeners = null; externalListeners = null;
@ -871,13 +879,11 @@ class EventBus {
* @ignore * @ignore
*/ */
_on(eventName, listener, options = null) { _on(eventName, listener, options = null) {
let eventListeners = this._listeners[eventName]; const eventListeners = (this._listeners[eventName] ||= []);
if (!eventListeners) {
this._listeners[eventName] = eventListeners = [];
}
eventListeners.push({ eventListeners.push({
listener, listener,
external: (options && options.external) === true, external: options?.external === true,
once: options?.once === true,
}); });
} }