You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.4 KiB
JavaScript
163 lines
4.4 KiB
JavaScript
import Check from "./Check.js";
|
|
import defined from "./defined.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;
|
|
}
|
|
|
|
Object.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 {...Object} 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;
|