UNPKG

bugcore

Version:

bugcore is a JavaScript library that provides a foundational architecture for object oriented JS

361 lines (302 loc) 12.5 kB
/* * Copyright (c) 2016 airbug Inc. http://airbug.com * * bugcore may be freely distributed under the MIT license. */ //------------------------------------------------------------------------------- // Annotations //------------------------------------------------------------------------------- //@Export('EventReceiver') //@Require('Class') //@Require('EventListener') //@Require('EventPropagator') //@Require('EventQueryBuilder') //@Require('IEventReceiver') //@Require('MultiListMap') //@Require('TypeUtil') //------------------------------------------------------------------------------- // Context //------------------------------------------------------------------------------- require('bugpack').context("*", function(bugpack) { //------------------------------------------------------------------------------- // BugPack //------------------------------------------------------------------------------- var Class = bugpack.require('Class'); var EventListener = bugpack.require('EventListener'); var EventPropagator = bugpack.require('EventPropagator'); var EventQueryBuilder = bugpack.require('EventQueryBuilder'); var IEventReceiver = bugpack.require('IEventReceiver'); var MultiListMap = bugpack.require('MultiListMap'); var TypeUtil = bugpack.require('TypeUtil'); //------------------------------------------------------------------------------- // Declare Class //------------------------------------------------------------------------------- /** * @class * @extends {EventPropagator} * @implements {IEventReceiver} */ var EventReceiver = Class.extend(EventPropagator, /** @lends {EventReceiver.prototype} */{ _name: "EventReceiver", //------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------- /** * @constructs * @param {*} target */ _constructor: function(target) { this._super(target); //------------------------------------------------------------------------------- // Private Properties //------------------------------------------------------------------------------- /** * @private * @type {MultiListMap.<string, EventListener>} */ this.eventTypeListenerMap = new MultiListMap(); /** * @private * @type {IEventPropagator} */ this.parentPropagator = null; }, //------------------------------------------------------------------------------- // IEventReceiver Implementation //------------------------------------------------------------------------------- /** * @return {IEventPropagator} */ getParentPropagator: function() { return this.parentPropagator; }, /** * @param {IEventPropagator} parentPropagator */ setParentPropagator: function(parentPropagator) { this.parentPropagator = parentPropagator; }, /** * @param {(string | Array.<string>)} eventTypes * @param {function(Event)=} listenerFunction * @param {Object=} listenerContext (optional) * @param {boolean=} once (optional) * @return {(undefined | EventQueryBuilder)} */ addEventListener: function(eventTypes, listenerFunction, listenerContext, once) { if (eventTypes && !listenerFunction) { return this.generateEventQueryBuilder(eventTypes); } else { this.buildEventListener(eventTypes, listenerFunction, listenerContext, once); } }, /** * @param {string} eventType * @param {function(Event)} listenerFunction * @param {?Object=} listenerContext (optional) */ hasEventListener: function(eventType, listenerFunction, listenerContext) { var eventTypeListenerList = this.eventTypeListenerMap.get(eventType); if (eventTypeListenerList) { var eventListener = this.factoryEventListener(listenerFunction, listenerContext); return eventTypeListenerList.contains(eventListener); } return false; }, /** * @param {string} eventType * @return {boolean} */ isListening: function(eventType) { return this.eventTypeListenerMap.containsKey(eventType); }, /** * @param {(string | Array.<string>)} eventTypes * @param {function(Event)} listenerFunction * @param {Object} listenerContext * @return {(undefined | EventQuery)} */ onceOn: function(eventTypes, listenerFunction, listenerContext) { return this.addEventListener(eventTypes, listenerFunction, listenerContext, true); }, /** * @param {(string | Array.<string>)} eventTypes * @param {function(Event)} listenerFunction * @param {?Object=} listenerContext */ removeEventListener: function(eventTypes, listenerFunction, listenerContext) { var eventListener = this.factoryEventListener(listenerFunction, listenerContext); this.detachEventListenerFromTypes(eventTypes, eventListener); }, /** * */ removeAllListeners: function() { this.eventTypeListenerMap.clear(); }, //------------------------------------------------------------------------------- // EventPropagator Methods //------------------------------------------------------------------------------- /** * @override * @param {Event} event */ propagateEvent: function(event) { if (!event.isPropagationStopped()) { event.setCurrentTarget(this.getTarget()); this.propagateEventToListeners(event); this.propagateEventToPropagators(event); if (event.getBubbles()) { this.bubbleEvent(event); } } }, //------------------------------------------------------------------------------- // Public Methods //------------------------------------------------------------------------------- /** * @param {string} eventType * @param {EventListener} eventListener */ attachEventListener: function(eventType, eventListener) { var eventTypeListenerList = this.eventTypeListenerMap.get(eventType); if (!eventTypeListenerList) { this.eventTypeListenerMap.put(eventType, eventListener); } else if (!eventTypeListenerList.contains(eventListener)) { eventTypeListenerList.add(eventListener); } }, /** * @param {(string | Array.<string>)} eventTypes * @param {EventListener} eventListener */ attachEventListenerToTypes: function(eventTypes, eventListener) { var _this = this; if (TypeUtil.isArray(eventTypes)) { eventTypes.forEach(function(eventType) { _this.attachEventListener(eventType, eventListener); }); } else { this.attachEventListener(eventTypes, eventListener); } }, /** * @param {string} eventType * @param {EventListener} eventListener */ detachEventListener: function(eventType, eventListener) { this.eventTypeListenerMap.removeKeyValuePair(eventType, eventListener); }, /** * @param {(string | Array.<string>)} eventTypes * @param {EventListener} eventListener */ detachEventListenerFromTypes: function(eventTypes, eventListener) { var _this = this; if (TypeUtil.isArray(eventTypes)) { eventTypes.forEach(function(eventType) { _this.detachEventListener(eventType, eventListener); }); } else { this.detachEventListener(eventTypes, eventListener); } }, /** * */ off: function() { return this.removeEventListener.apply(this, arguments); }, /** * */ on: function() { return this.addEventListener.apply(this, arguments); }, //------------------------------------------------------------------------------- // Private Methods //------------------------------------------------------------------------------- /** * @private * @param {Event} event */ bubbleEvent: function(event) { var parentPropagator = this.getParentPropagator(); if (parentPropagator) { parentPropagator.propagateEvent(event); } }, /** * @private * @param {(string | Array.<string>)} eventTypes * @param {function(Event)} listenerFunction * @param {(Object | boolean)=} listenerContext * @param {boolean=} once */ buildEventListener: function(eventTypes, listenerFunction, listenerContext, once) { var eventListener = this.factoryEventListener(listenerFunction, listenerContext, once); this.attachEventListenerToTypes(eventTypes, eventListener); }, /** * @private * @param listenerFunction * @param {(Object | boolean)=} listenerContext * @param {boolean=} once * @return {EventListener} */ factoryEventListener: function(listenerFunction, listenerContext, once) { if (!TypeUtil.isBoolean(once)) { once = false; if (TypeUtil.isBoolean(listenerContext)) { once = listenerContext; } } return new EventListener(listenerFunction, listenerContext, once); }, /** * @private * @param {(string | Array.<string>)} eventTypes * @return {EventQueryBuilder} */ generateEventQueryBuilder: function(eventTypes) { return new EventQueryBuilder(this, eventTypes); }, /** * @private * @param {Event} event */ propagateEventToListeners: function(event) { var _this = this; var eventTypeListenerList = this.eventTypeListenerMap.get(event.getType()); if (eventTypeListenerList) { // NOTE BRN: Clone the event listener list so that if the list is changed during execution of the listeners // we still execute all of the listeners. var cloneEventTypeListenerList = eventTypeListenerList.clone(); cloneEventTypeListenerList.forEach(function(eventListener) { eventListener.hearEvent(event); if (eventListener.isOnce()) { _this.removeEventListener(event.getType(), eventListener.getListenerFunction(), eventListener.getListenerContext()); } }); } }, /** * @private * @param {Event} event */ propagateEventToPropagators: function(event) { var cloneEventPropagatorList = this.getEventPropagatorList().clone(); cloneEventPropagatorList.forEach(function(eventPropagator) { eventPropagator.propagateEvent(event); }); } }); //------------------------------------------------------------------------------- // Interfaces //------------------------------------------------------------------------------- Class.implement(EventReceiver, IEventReceiver); //------------------------------------------------------------------------------- // Exports //------------------------------------------------------------------------------- bugpack.export('EventReceiver', EventReceiver); });