diff --git a/themes/bootstrap3/js/cart.js b/themes/bootstrap3/js/cart.js index 14c37733087..849c18bf726 100644 --- a/themes/bootstrap3/js/cart.js +++ b/themes/bootstrap3/js/cart.js @@ -312,4 +312,4 @@ function cartFormHandler(event, data) { } } -document.addEventListener('VuFind.lightbox.closed', VuFind.cart.updateCount, false); +VuFind.listen('lightbox.closed', VuFind.cart.updateCount); diff --git a/themes/bootstrap3/js/common.js b/themes/bootstrap3/js/common.js index 99743de9bbb..288e40075b7 100644 --- a/themes/bootstrap3/js/common.js +++ b/themes/bootstrap3/js/common.js @@ -15,21 +15,35 @@ var VuFind = (function VuFind() { var _elementBase; var _iconsCache = {}; - // Emit a custom event - // Recommendation: prefix with vf- - var emit = function emit(name, detail) { - if (typeof detail === 'undefined') { - document.dispatchEvent(new Event(name)); - } else { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent(name, true, true, detail); // name, canBubble, cancelable, detail - document.dispatchEvent(event); + // Event controls + + let listeners = {}; + function unlisten(event, fn) { + const index = listeners[event].indexOf(fn); + + if (index > -1) { + listeners[event].splice(index, 1); } - }; - // Listen shortcut to put everyone on the same element - var listen = function listen(name, func) { - document.addEventListener(name, func, false); - }; + } + + function listen(event, fn, { once = false } = {}) { + if (typeof listeners[event] === "undefined") { + listeners[event] = []; + } + + listeners[event].push(fn); + return () => unlisten(event, fn); + } + + function emit(event, ...args) { + if (typeof listeners[event] === "undefined") { + return; + } + + listeners[event].forEach((fn) => fn(...args)); + } + + // Module control var register = function register(name, module) { if (_submodules.indexOf(name) === -1) { @@ -340,11 +354,12 @@ var VuFind = (function VuFind() { addTranslations: addTranslations, init: init, emit: emit, + listen: listen, + unlisten: unlisten, evalCallback: evalCallback, getCspNonce: getCspNonce, icon: icon, isPrinting: isPrinting, - listen: listen, refreshPage: refreshPage, register: register, setCspNonce: setCspNonce, diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js index 2397e6e09a7..1c2ac9d0d55 100644 --- a/themes/bootstrap3/js/lightbox.js +++ b/themes/bootstrap3/js/lightbox.js @@ -32,22 +32,6 @@ VuFind.register('lightbox', function Lightbox() { _lightboxTitle = false; _modal.modal('handleUpdate'); } - function _emit(msg, _details) { - var details = _details || {}; - var event; - try { - event = new CustomEvent(msg, { - detail: details, - bubbles: true, - cancelable: true - }); - } catch (e) { - // Fallback to document.createEvent() if creating a new CustomEvent fails (e.g. IE 11) - event = document.createEvent('CustomEvent'); - event.initCustomEvent(msg, true, true, details); - } - return document.dispatchEvent(event); - } function _addQueryParameters(url, params) { let fragmentSplit = url.split('#'); @@ -220,7 +204,7 @@ VuFind.register('lightbox', function Lightbox() { || obj.url.match(/MyResearch\/(?!Bulk|Delete|Recover)/) ) && flashMessages.length === 0 ) { - var eventResult = _emit('VuFind.lightbox.login', { + var eventResult = VuFind.emit('lightbox.login', { originalUrl: _originalUrl, formUrl: obj.url }); @@ -338,10 +322,10 @@ VuFind.register('lightbox', function Lightbox() { } // onclose behavior if ('string' === typeof $(form).data('lightboxOnclose')) { - document.addEventListener('VuFind.lightbox.closed', function lightboxClosed(e) { - this.removeEventListener('VuFind.lightbox.closed', arguments.callee); - VuFind.evalCallback($(form).data('lightboxOnclose'), e, form); - }, false); + VuFind.listen('lightbox.closed', function lightboxClosed() { + VuFind.unlisten('lightbox.closed', arguments.callee); // only once + VuFind.evalCallback($(form).data('lightboxOnclose'), null, form); + }); } // Prevent multiple submission of submit button in lightbox if (submit.closest(_modal).length > 0) { @@ -523,12 +507,12 @@ VuFind.register('lightbox', function Lightbox() { } unbindFocus(); this.setAttribute('aria-hidden', true); - _emit('VuFind.lightbox.closing'); + VuFind.emit('lightbox.closing'); } }); _modal.on('hidden.bs.modal', function lightboxHidden() { VuFind.lightbox.reset(); - _emit('VuFind.lightbox.closed'); + VuFind.emit('lightbox.closed'); }); _modal.on("shown.bs.modal", function lightboxShown() { bindFocus();