/** * Tab-/Fenster-übergreifendes Event-System * * @example * EventListener attachen (für Events aus eigenem Fenster/Tab): * EventManager.on('notification.send', function () { * alert('huhu self'); * }); * * @example * EventListener attachen (für Events aus anderen Fenstern/Tabs): * EventManager.onReceive('notification.send', function () { * alert('huhu received'); * }); * * @example * Event auslösen: * EventManager.fire('notification.send'); */ var EventManager = function() { 'use strict'; var me = { /** LocalStorage-Key */ storageKey: 'xentral_event_marker', /** Eindeutige ID pro Tab/Fenster */ windowIdentifier: null, /** Event-Warteschlange */ ownQueue: {}, receiveQueue: {}, /** LocalStorage-Cache */ storageCache: { name: null, data: {}, index: 0, origin: null, isOwnEvent: true }, init: function() { me.windowIdentifier = 'window_' + Math.floor(Math.random() * Math.floor(9999999999)); me.storageCache.origin = me.windowIdentifier; // storageCache aus LocalStorage wiederherstellen var value = localStorage.getItem(me.storageKey); if (typeof value !== 'undefined' && value !== null) { me.storageCache = JSON.parse(value); } // Auf Änderungen im LocalStorage horchen window.addEventListener('storage', me.storageHandler, false); }, /** * Event wurde ausgelöst > Event ausführen und andere Tabs/Fenster informieren * * @param {string} eventName * @param {object} eventData */ fire: function(eventName, eventData) { me.execute(me.ownQueue, eventName, eventData); me.send(eventName, eventData); }, /** * Event ausführen * * @param {object} eventQueue * @param {string} eventName * @param {object} eventData */ execute: function(eventQueue, eventName, eventData) { var queue = eventQueue[eventName]; // Event existiert nicht if (typeof queue === 'undefined') { return; } if (typeof eventData === 'undefined') { eventData = {}; } // EventListener ausführen queue.forEach(function(callback) { callback(eventData); }); }, /** * Event an andere Tabs senden * * @param {string} eventName * @param {object} eventData */ send: function(eventName, eventData) { me.storageCache.name = eventName; me.storageCache.data = eventData; // // Index hochzählen me.storageCache.index++; if (me.storageCache.index > 9999999) { me.storageCache.index = 1; } // Herkunft setzen me.storageCache.origin = me.windowIdentifier; // LocalStorage updaten > Andere Fenster informieren localStorage.setItem(me.storageKey, JSON.stringify(me.storageCache)); }, /** * EventListener auf Events im eigenen Tab binden * * @param {string} eventName * @param {function} listener */ on: function(eventName, listener) { if (typeof me.ownQueue[eventName] === 'undefined') { me.ownQueue[eventName] = []; } // Listener in Warteschlange speichern me.ownQueue[eventName].push(listener); }, /** * EventListener auf Events aus fremden Tabs/Fenstern binden * * @param {string} eventName * @param {function} listener */ onReceive: function(eventName, listener) { if (typeof me.receiveQueue[eventName] === 'undefined') { me.receiveQueue[eventName] = []; } // Listener in Warteschlange speichern me.receiveQueue[eventName].push(listener); }, /** * Horcht auf Änderungen im LocalStorage * * @param {StorageEvent} e */ storageHandler: function(e) { // Nur auf bestimmten Key horchen if (e.key !== me.storageKey) { return; } // LocalStorage(-Key) wurde gelöscht if (e.newValue === null) { return; } var received = JSON.parse(e.newValue); if (received === null) { return; } // Eigene Änderungen ignorieren if (received.origin === me.windowIdentifier && received.index === me.storageCache.index) { return; } // Event wurde hier schon ausgeführt if (received.index <= me.storageCache.index) { return; } // EventListener ausführen me.execute(me.receiveQueue, received.name, received.data); me.storageCache = received; } }; me.init(); return { fire: me.fire, on: me.on, onReceive: me.onReceive }; }();