Add general support for re-dispatching events, on EventBus
instances, to the DOM
This patch is the first step to be able to eventually get rid of the `attachDOMEventsToEventBus` function, by allowing `EventBus` instances to simply re-dispatch most[1] events to the DOM. Note that the re-dispatching is purposely implemented to occur *after* all registered `EventBus` listeners have been serviced, to prevent the ordering issues that necessitated the duplicated page/scale-change events. The DOM events are currently necessary for the `mozilla-central` tests, see https://hg.mozilla.org/mozilla-central/file/tip/browser/extensions/pdfjs/test, and perhaps also for custom deployments of the PDF.js default viewer. Once this have landed, and been successfully uplifted to `mozilla-central`, I intent to submit a patch to update the test-code to utilize the new preference. This will thus, eventually, make it possible to remove the `attachDOMEventsToEventBus` functionality. *Please note:* I've successfully ran all `mozilla-central` tests locally, with these patches applied. --- [1] The exception being events that originated on the `window` or `document`, since those are already globally available anyway.
This commit is contained in:
parent
7bc4bfcc8b
commit
0b1f41c5b3
@ -47,6 +47,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"eventBusDispatchToDOM": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"pdfBugEnabled": {
|
"pdfBugEnabled": {
|
||||||
"title": "Enable debugging tools",
|
"title": "Enable debugging tools",
|
||||||
"description": "Whether to enable debugging tools.",
|
"description": "Whether to enable debugging tools.",
|
||||||
|
@ -262,6 +262,45 @@ describe('ui_utils', function() {
|
|||||||
eventBus.dispatch('test');
|
eventBus.dispatch('test');
|
||||||
expect(count).toEqual(2);
|
expect(count).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not, by default, re-dispatch to DOM', function(done) {
|
||||||
|
if (isNodeJS()) {
|
||||||
|
pending('Document in not supported in Node.js.');
|
||||||
|
}
|
||||||
|
const eventBus = new EventBus();
|
||||||
|
let count = 0;
|
||||||
|
eventBus.on('test', function() {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
document.addEventListener('test', function() {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
eventBus.dispatch('test');
|
||||||
|
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
expect(count).toEqual(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should re-dispatch to DOM', function(done) {
|
||||||
|
if (isNodeJS()) {
|
||||||
|
pending('Document in not supported in Node.js.');
|
||||||
|
}
|
||||||
|
const eventBus = new EventBus({ dispatchToDOM: true, });
|
||||||
|
let count = 0;
|
||||||
|
eventBus.on('test', function() {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
document.addEventListener('test', function() {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
eventBus.dispatch('test');
|
||||||
|
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
expect(count).toEqual(2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isValidRotation', function() {
|
describe('isValidRotation', function() {
|
||||||
|
@ -288,7 +288,8 @@ let PDFViewerApplication = {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.overlayManager = new OverlayManager();
|
this.overlayManager = new OverlayManager();
|
||||||
|
|
||||||
let eventBus = appConfig.eventBus || getGlobalEventBus();
|
const dispatchToDOM = AppOptions.get('eventBusDispatchToDOM');
|
||||||
|
let eventBus = appConfig.eventBus || getGlobalEventBus(dispatchToDOM);
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
|
||||||
let pdfRenderingQueue = new PDFRenderingQueue();
|
let pdfRenderingQueue = new PDFRenderingQueue();
|
||||||
|
@ -68,6 +68,11 @@ const defaultOptions = {
|
|||||||
value: false,
|
value: false,
|
||||||
kind: OptionKind.VIEWER,
|
kind: OptionKind.VIEWER,
|
||||||
},
|
},
|
||||||
|
eventBusDispatchToDOM: {
|
||||||
|
/** @type {boolean} */
|
||||||
|
value: false,
|
||||||
|
kind: OptionKind.VIEWER,
|
||||||
|
},
|
||||||
externalLinkRel: {
|
externalLinkRel: {
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
value: 'noopener noreferrer nofollow',
|
value: 'noopener noreferrer nofollow',
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"sidebarViewOnLoad": 0,
|
"sidebarViewOnLoad": 0,
|
||||||
"cursorToolOnLoad": 0,
|
"cursorToolOnLoad": 0,
|
||||||
"enableWebGL": false,
|
"enableWebGL": false,
|
||||||
|
"eventBusDispatchToDOM": false,
|
||||||
"pdfBugEnabled": false,
|
"pdfBugEnabled": false,
|
||||||
"disableRange": false,
|
"disableRange": false,
|
||||||
"disableStream": false,
|
"disableStream": false,
|
||||||
|
@ -129,12 +129,13 @@ function attachDOMEventsToEventBus(eventBus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let globalEventBus = null;
|
let globalEventBus = null;
|
||||||
function getGlobalEventBus() {
|
function getGlobalEventBus(dispatchToDOM = false) {
|
||||||
if (globalEventBus) {
|
if (!globalEventBus) {
|
||||||
return globalEventBus;
|
globalEventBus = new EventBus({ dispatchToDOM, });
|
||||||
}
|
if (!dispatchToDOM) {
|
||||||
globalEventBus = new EventBus();
|
|
||||||
attachDOMEventsToEventBus(globalEventBus);
|
attachDOMEventsToEventBus(globalEventBus);
|
||||||
|
}
|
||||||
|
}
|
||||||
return globalEventBus;
|
return globalEventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,8 +683,9 @@ let animationStarted = new Promise(function (resolve) {
|
|||||||
* used.
|
* used.
|
||||||
*/
|
*/
|
||||||
class EventBus {
|
class EventBus {
|
||||||
constructor() {
|
constructor({ dispatchToDOM = false, } = {}) {
|
||||||
this._listeners = Object.create(null);
|
this._listeners = Object.create(null);
|
||||||
|
this._dispatchToDOM = dispatchToDOM === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
on(eventName, listener) {
|
on(eventName, listener) {
|
||||||
@ -708,6 +709,9 @@ class EventBus {
|
|||||||
dispatch(eventName) {
|
dispatch(eventName) {
|
||||||
let eventListeners = this._listeners[eventName];
|
let eventListeners = this._listeners[eventName];
|
||||||
if (!eventListeners || eventListeners.length === 0) {
|
if (!eventListeners || eventListeners.length === 0) {
|
||||||
|
if (this._dispatchToDOM) {
|
||||||
|
this._dispatchDOMEvent(eventName);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Passing all arguments after the eventName to the listeners.
|
// Passing all arguments after the eventName to the listeners.
|
||||||
@ -717,6 +721,35 @@ class EventBus {
|
|||||||
eventListeners.slice(0).forEach(function (listener) {
|
eventListeners.slice(0).forEach(function (listener) {
|
||||||
listener.apply(null, args);
|
listener.apply(null, args);
|
||||||
});
|
});
|
||||||
|
if (this._dispatchToDOM) {
|
||||||
|
this._dispatchDOMEvent(eventName, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_dispatchDOMEvent(eventName, args = null) {
|
||||||
|
if (!this._dispatchToDOM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const details = Object.create(null);
|
||||||
|
if (args && args.length > 0) {
|
||||||
|
const obj = args[0];
|
||||||
|
for (let 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user