Re-factor the EventBus and isInAutomation handling (PR 11655 follow-up)

Rather than forcing the "regular" `EventBus` to check and handle `isInAutomation` for every `dispatch` call, we can take advantage of subclassing instead.
Hence this PR introduces a new `AutomationEventBus` class, which extends `EventBus`, and is used by the default viewer when `isInAutomation === true`.
This commit is contained in:
Jonas Jenwald 2021-09-17 18:17:40 +02:00
parent 7082ff9bf8
commit 0e92f995c9
3 changed files with 45 additions and 51 deletions

View File

@ -6,7 +6,7 @@ class MainTest {
task: ReturnType<typeof getDocument> | undefined; task: ReturnType<typeof getDocument> | undefined;
constructor(public file: string) { constructor(public file: string) {
this.eventBus = new EventBus({}); this.eventBus = new EventBus();
} }
loadPdf() { loadPdf() {

View File

@ -18,6 +18,7 @@ import {
animationStarted, animationStarted,
apiPageLayoutToSpreadMode, apiPageLayoutToSpreadMode,
apiPageModeToSidebarView, apiPageModeToSidebarView,
AutomationEventBus,
AutoPrintRegExp, AutoPrintRegExp,
DEFAULT_SCALE_VALUE, DEFAULT_SCALE_VALUE,
EventBus, EventBus,
@ -458,11 +459,16 @@ const PDFViewerApplication = {
* @private * @private
*/ */
async _initializeViewerComponents() { async _initializeViewerComponents() {
const appConfig = this.appConfig; const { appConfig, externalServices } = this;
const eventBus = let eventBus;
appConfig.eventBus || if (appConfig.eventBus) {
new EventBus({ isInAutomation: this.externalServices.isInAutomation }); eventBus = appConfig.eventBus;
} else if (externalServices.isInAutomation) {
eventBus = new AutomationEventBus();
} else {
eventBus = new EventBus();
}
this.eventBus = eventBus; this.eventBus = eventBus;
this.overlayManager = new OverlayManager(); this.overlayManager = new OverlayManager();
@ -479,7 +485,7 @@ const PDFViewerApplication = {
}); });
this.pdfLinkService = pdfLinkService; this.pdfLinkService = pdfLinkService;
const downloadManager = this.externalServices.createDownloadManager(); const downloadManager = externalServices.createDownloadManager();
this.downloadManager = downloadManager; this.downloadManager = downloadManager;
const findController = new PDFFindController({ const findController = new PDFFindController({
@ -495,7 +501,7 @@ const PDFViewerApplication = {
PDFJSDev.test("!PRODUCTION || GENERIC || CHROME") PDFJSDev.test("!PRODUCTION || GENERIC || CHROME")
? AppOptions.get("sandboxBundleSrc") ? AppOptions.get("sandboxBundleSrc")
: null, : null,
scriptingFactory: this.externalServices, scriptingFactory: externalServices,
docPropertiesLookup: this._scriptingDocProperties.bind(this), docPropertiesLookup: this._scriptingDocProperties.bind(this),
}); });
this.pdfScriptingManager = pdfScriptingManager; this.pdfScriptingManager = pdfScriptingManager;

View File

@ -708,43 +708,13 @@ const animationStarted = new Promise(function (resolve) {
window.requestAnimationFrame(resolve); window.requestAnimationFrame(resolve);
}); });
/**
* NOTE: Only used to support various PDF viewer tests in `mozilla-central`.
*/
function dispatchDOMEvent(eventName, args = null) {
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("MOZCENTRAL")) {
throw new Error("Not implemented: dispatchDOMEvent");
}
const details = Object.create(null);
if (args?.length > 0) {
const obj = args[0];
for (const key in obj) {
const value = obj[key];
if (key === "source") {
if (value === window || value === document) {
return; // No need to re-dispatch (already) global events.
}
continue; // Ignore the `source` property.
}
details[key] = value;
}
}
const event = document.createEvent("CustomEvent");
event.initCustomEvent(eventName, true, true, details);
document.dispatchEvent(event);
}
/** /**
* Simple event bus for an application. Listeners are attached using the `on` * Simple event bus for an application. Listeners are attached using the `on`
* and `off` methods. To raise an event, the `dispatch` method shall be used. * and `off` methods. To raise an event, the `dispatch` method shall be used.
*/ */
class EventBus { class EventBus {
constructor(options) { constructor() {
this._listeners = Object.create(null); this._listeners = Object.create(null);
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL")) {
this._isInAutomation = options?.isInAutomation === true;
}
} }
/** /**
@ -774,13 +744,6 @@ class EventBus {
dispatch(eventName) { dispatch(eventName) {
const eventListeners = this._listeners[eventName]; const eventListeners = this._listeners[eventName];
if (!eventListeners || eventListeners.length === 0) { if (!eventListeners || eventListeners.length === 0) {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL")) &&
this._isInAutomation
) {
const args = Array.prototype.slice.call(arguments, 1);
dispatchDOMEvent(eventName, args);
}
return; return;
} }
// Passing all arguments after the eventName to the listeners. // Passing all arguments after the eventName to the listeners.
@ -806,12 +769,6 @@ class EventBus {
} }
externalListeners = null; externalListeners = null;
} }
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("MOZCENTRAL")) &&
this._isInAutomation
) {
dispatchDOMEvent(eventName, args);
}
} }
/** /**
@ -843,6 +800,36 @@ class EventBus {
} }
} }
/**
* NOTE: Only used to support various PDF viewer tests in `mozilla-central`.
*/
class AutomationEventBus extends EventBus {
dispatch(eventName) {
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("MOZCENTRAL")) {
throw new Error("Not implemented: AutomationEventBus.dispatch");
}
super.dispatch(...arguments);
const details = Object.create(null);
if (arguments.length > 1) {
const obj = arguments[1];
for (const key in obj) {
const value = obj[key];
if (key === "source") {
if (value === window || value === document) {
return; // No need to re-dispatch (already) global events.
}
continue; // Ignore the `source` property.
}
details[key] = value;
}
}
const event = document.createEvent("CustomEvent");
event.initCustomEvent(eventName, true, true, details);
document.dispatchEvent(event);
}
}
function clamp(v, min, max) { function clamp(v, min, max) {
return Math.min(Math.max(v, min), max); return Math.min(Math.max(v, min), max);
} }
@ -1012,6 +999,7 @@ export {
apiPageLayoutToSpreadMode, apiPageLayoutToSpreadMode,
apiPageModeToSidebarView, apiPageModeToSidebarView,
approximateFraction, approximateFraction,
AutomationEventBus,
AutoPrintRegExp, AutoPrintRegExp,
backtrackBeforeAllVisibleElements, // only exported for testing backtrackBeforeAllVisibleElements, // only exported for testing
binarySearchFirstItem, binarySearchFirstItem,