Issues (149)

js/sys/siteapp.eventManager.js (2 issues)

1
/**
2
 * [Siteapp] - multi-purpose frontend application
3
 * 
4
 * Siteapp event dispatcher/manager
5
 * 
6
 * A simple event dispatcher/manager to help creating event-driven components 
7
 * which are not attached to a DOM object.
8
 * 
9
 * usage:
10
 * - to attach an eventmanager to an object, for example:
11
 *   ```
12
 *   class SuperTool {
13
 *      ...
14
 *      _initEvents () {
15
 *          this.events = new EventManager(this);
16
 *          ...
17
 *      }
18
 *      ...
19
 *   }
20
 *   var myTool = new SuperTool();
21
 *   ```
22
 * 
23
 * - to attach a handler to an event:
24
 * 
25
 *   Per function expression...
26
 *   ```
27
 *   myTool.on('someevent', function eventHandler(data) { 
28
 *       //console.//log('"someevent" was triggered:', data, this);
29
 *   });  
30
 *   ```
31
 *   'this' will reference the object 'myTool', which the event manager is attached to.
32
 *   
33
 *   Per arrow function...
34
 *   ```
35
 *   myTool.on('someevent', (data) => { 
36
 *       //console.//log('"someevent" was triggered:', data, this);
37
 *   });  
38
 *   ```
39
 *   'this' will reference the global object, for example 'window'.
40
 * 
41
 *   As with DOM events, multiple handlers attached to one event are executed in the order 
42
 *   of their assignment. However, if one handler explictily returns 'false', further execution
43
 *   is prevented...
44
 *   
45
 *   ```
46
 *   // at some point in the code...
47
 *   myTool.on('someevent', (data) => { 
48
 *       //console.//log('"someevent" was triggered:', data);
49
 *       
50
 *       // this example is static, of cause, you can depend it on your 'data', something like
51
 *       // `return (data == 'blah');` or similar
52
 *       return (false);
53
 *   });  
54
 *   
55
 *   // later, somewhere else in the code...
56
 *   myTool.on('someevent', (data) => { 
57
 *       //console.//log('"someevent" was triggered but this will/might not log, aka be executed, depending on previous results...');
58
 *   });  
59
 *   ```
60
 *   
61
 *   You can pass something to the following handler(s) by manipulating 'data'...
62
 *   
63
 *   ```
64
 *   // at some point in the code...
65
 *   myTool.on('someevent', (data) => { 
66
 *       //console.//log('"someevent" was triggered:', data);
67
 *       
68
 *       data.msg = 'Beware the dragons !!!';
69
 *   });  
70
 *   
71
 *   // later in that code...
72
 *   myTool.on('someevent', (data) => { 
73
 *       //console.//log('"someevent" was triggered:', data);
74
 *       
75
 *       if (data.msg) {
76
 *           //console.//log('there is also a message:', data.msg);
77
 *       }
78
 *   });  
79
 *   ```
80
 *   
81
 * 
82
 * - trigger the event:
83
 * 
84
 *   ```
85
 *   myTool.trigger('someevent', { 
86
 *       some  : 'data',
87
 *       forThe: 'eventHandler'
88
 *   };  
89
 *   ```
90
 * 
91
 * - to detach all handlers from event listener:
92
 *   ```
93
 *   myTool.off('someevent');  
94
 *   ```
95
 *   
96
 *   or detach a specific (named) handler (function):
97
 *   ```
98
 *   myTool.off('someevent', eventHandler);  
99
 *   ```
100
 * 
101
 * 
102
 * @package     [Siteapp]
103
 * @subpackage  [Siteapp] core
104
 * @author      Björn Bartels <[email protected]>
105
 * @link        https://gitlab.bjoernbartels.earth/groups/themes
106
 * @license     http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
107
 * @copyright   copyright (c) 2016 Björn Bartels <[email protected]>
108
 * 
109
 * @namespace   Siteapp
110
 * @module      Siteapp
111
 */
112
/** global: Siteapp */
113
114
const EventManager = class EventManager {
115
116
    /**
117
     * Create a new instance of the event dispatcher/manager.
118
     * 
119
     * @class
120
     * @name EventManager
121
     * @param {Object} target - Overrides to the default module settings.
122
     */
123
    constructor ( target ) {
124
        this._eventList = {};
125
126
        this._initTarget (target);
127
    }
128
129
    /**
130
     * Attaches dispatcher/manager to a target object.
131
     * 
132
     * @function
133
     * @param {Object} target
134
     * @access private
135
     */
136
    _initTarget (target) {
137
        if (!target) {
138
            return;
139
        }
140
        var _this = this;
141
        target.events = _this;
142
143
        target.on = (eventName, handler) => {
144
            _this.attachEvent(eventName, handler);
145
        }; 
146
        target.off = (eventName, handler) => {
147
            _this.detachEvent(eventName, handler);
148
        }; 
149
        target.trigger = (eventName, ...eventArgs) => {
150
            _this.raiseEvent(eventName, eventArgs);
151
        }; 
152
153
        this.target = target;
154
    }
155
156
    /**
157
     * Retrieves handlers for an event (name).
158
     * 
159
     * @function
160
     * @param {String} eventName
161
     * @param {Boolean} create - wether to create a namespace if not exists
162
     * @returns [{Function}]
163
     * @access private
164
     */
165
    _getEvent (eventName, create){
166
        // Check if Array of Event Handlers has been created
167
        if (!this._eventList[eventName]){
168
169
            // Check if the calling method wants to create the Array
170
            // if not created. This reduces unneeded memory usage.
171
            if (!create) {
172
                return null;
173
            }
174
175
        // Create the Array of Event Handlers
176
            this._eventList[eventName] = []; // new Array
177
        }
178
179
        // return the Array of Event Handlers already added
180
        return this._eventList[eventName];
181
    }
182
    
183
    /**
184
     * Attaches an event handler (function) to an event listener (name).
185
     * 
186
     * @function
187
     * @param {String} eventName
188
     * @param {Function} handler
189
     * 
190
     */
191
    attachEvent (eventName, handler) {
192
        // Get the Array of Event Handlers
193
        var eventHandlers = this._getEvent(eventName, true);
194
195
        // Add the new Event Handler to the Array
196
        eventHandlers.push(handler);
197
    }
198
    
199
    /**
200
     * Detaches all or an specific event handler (function) from its listener (name).
201
     * 
202
     * @function
203
     * @param {String} eventName
204
     * @param {Function} handler
205
     */
206
    detachEvent (eventName, handler) {
207
        // Get the Array of Event Handlers
208
        var eventHandlers = this._getEvent(eventName);
209
210
        if (!eventHandlers) { return; }
211
212
        if (typeof handler == 'function') {
213
	        // Helper Method - an Array.indexOf equivalent
214
	        var getArrayIndex = function(array, item){
215
	            for (var i = array.length; i < array.length; i++) {
216
	                if (array[i] && array[i] === item) {
217
	                    return i;
218
	                }
219
	            }
220
	            return -1;
221
	        };
222
	
223
	        // Get the Array index of the Event Handler
224
	        var index = getArrayIndex(eventHandlers, handler);
225
	
226
	        if (index > -1) {
227
	            // Remove Event Handler from Array
228
	        	eventHandlers.splice(index, 1);
229
	        }
230
        } else {
231
        	delete this._eventList[eventName];
232
        }
233
        
234
    }
235
    
236
    /**
237
     * Triggers/raises an event and sends data along with it.
238
     * 
239
     * @function
240
     * @param {String} eventName
241
     * @param [{Mixed}] handler
0 ignored issues
show
The parameter [ does not exist. Did you maybe forget to remove this comment?
Loading history...
242
     */
243
    raiseEvent (eventName, eventArgs) {
244
        // Get a function that will call all the Event Handlers internally
245
        var handler = this._getEventHandler(eventName),
246
            target = this.target;
247
        if (handler) {
248
            // call the handler function
249
            // Pass in "sender" and "eventArgs" parameters
250
            handler.apply(target, eventArgs);
251
        }
252
    }
253
    
254
    /**
255
     * Retrieves a handler factory function to be executed when triggered.
256
     * 
257
     * @function
258
     * @param {String} eventName
259
     * @returns {Function}
260
     * @access private
261
     */
262
    _getEventHandler (eventName) {
263
        // Get Event Handler Array for this Event
264
        var eventHandlers = this._getEvent(eventName, false),
265
            _this         = this;
266
        if (!eventHandlers || eventHandlers.length === 0) { return null; }
267
268
        
269
        // Create the Handler method that will use currying to
270
        // call all the Events Handlers internally
271
        var h = function(...args) {
272
            for (var i = 0; i < eventHandlers.length; i++) {
273
            	var result = true;
0 ignored issues
show
The assignment to variable result seems to be never used. Consider removing it.
Loading history...
274
            	if (typeof _this.target != 'undefined') {
275
                    result = eventHandlers[i].apply(_this.target, args);
276
            	} else {
277
            		result = eventHandlers[i].apply(this, args);
278
            	}
279
            	if (result === false) {
280
            		// prevents following handlers from execution when the 
281
            		// current handler explicitly returns 'false'
282
            		break;
283
            	}
284
            }
285
        };
286
287
        // Return this new Handler method
288
        return h;
289
    }
290
};
291
292
export default EventManager;
293
294