/
Event.js
163 lines (146 loc) · 5.26 KB
/
Event.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import Check from './Check.js';
import defined from './defined.js';
import defineProperties from './defineProperties.js';
/**
* A generic utility class for managing subscribers for a particular event.
* This class is usually instantiated inside of a container class and
* exposed as a property for others to subscribe to.
*
* @alias Event
* @constructor
* @example
* MyObject.prototype.myListener = function(arg1, arg2) {
* this.myArg1Copy = arg1;
* this.myArg2Copy = arg2;
* }
*
* var myObjectInstance = new MyObject();
* var evt = new Cesium.Event();
* evt.addEventListener(MyObject.prototype.myListener, myObjectInstance);
* evt.raiseEvent('1', '2');
* evt.removeEventListener(MyObject.prototype.myListener);
*/
function Event() {
this._listeners = [];
this._scopes = [];
this._toRemove = [];
this._insideRaiseEvent = false;
}
defineProperties(Event.prototype, {
/**
* The number of listeners currently subscribed to the event.
* @memberof Event.prototype
* @type {Number}
* @readonly
*/
numberOfListeners : {
get : function() {
return this._listeners.length - this._toRemove.length;
}
}
});
/**
* Registers a callback function to be executed whenever the event is raised.
* An optional scope can be provided to serve as the <code>this</code> pointer
* in which the function will execute.
*
* @param {Function} listener The function to be executed when the event is raised.
* @param {Object} [scope] An optional object scope to serve as the <code>this</code>
* pointer in which the listener function will execute.
* @returns {Event~RemoveCallback} A function that will remove this event listener when invoked.
*
* @see Event#raiseEvent
* @see Event#removeEventListener
*/
Event.prototype.addEventListener = function(listener, scope) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.func('listener', listener);
//>>includeEnd('debug');
this._listeners.push(listener);
this._scopes.push(scope);
var event = this;
return function() {
event.removeEventListener(listener, scope);
};
};
/**
* Unregisters a previously registered callback.
*
* @param {Function} listener The function to be unregistered.
* @param {Object} [scope] The scope that was originally passed to addEventListener.
* @returns {Boolean} <code>true</code> if the listener was removed; <code>false</code> if the listener and scope are not registered with the event.
*
* @see Event#addEventListener
* @see Event#raiseEvent
*/
Event.prototype.removeEventListener = function(listener, scope) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.func('listener', listener);
//>>includeEnd('debug');
var listeners = this._listeners;
var scopes = this._scopes;
var index = -1;
for (var i = 0; i < listeners.length; i++) {
if (listeners[i] === listener && scopes[i] === scope) {
index = i;
break;
}
}
if (index !== -1) {
if (this._insideRaiseEvent) {
//In order to allow removing an event subscription from within
//a callback, we don't actually remove the items here. Instead
//remember the index they are at and undefined their value.
this._toRemove.push(index);
listeners[index] = undefined;
scopes[index] = undefined;
} else {
listeners.splice(index, 1);
scopes.splice(index, 1);
}
return true;
}
return false;
};
function compareNumber(a,b) {
return b - a;
}
/**
* Raises the event by calling each registered listener with all supplied arguments.
*
* @param {*} arguments This method takes any number of parameters and passes them through to the listener functions.
*
* @see Event#addEventListener
* @see Event#removeEventListener
*/
Event.prototype.raiseEvent = function() {
this._insideRaiseEvent = true;
var i;
var listeners = this._listeners;
var scopes = this._scopes;
var length = listeners.length;
for (i = 0; i < length; i++) {
var listener = listeners[i];
if (defined(listener)) {
listeners[i].apply(scopes[i], arguments);
}
}
//Actually remove items removed in removeEventListener.
var toRemove = this._toRemove;
length = toRemove.length;
if (length > 0) {
toRemove.sort(compareNumber);
for (i = 0; i < length; i++) {
var index = toRemove[i];
listeners.splice(index, 1);
scopes.splice(index, 1);
}
toRemove.length = 0;
}
this._insideRaiseEvent = false;
};
/**
* A function that removes a listener.
* @callback Event~RemoveCallback
*/
export default Event;