Hilo/docs/api-en/code/event/EventMixin.js
2016-12-14 14:40:55 +08:00

141 lines
4.5 KiB
JavaScript

/**
* Hilo
* Copyright 2015 alibaba.com
* Licensed under the MIT License
*/
/**
* @class EventMixin is a mixin on event related functions. Use Class.mix(target, EventMixin) to add event function onto target.
* @static
* @mixin
* @module hilo/event/EventMixin
* @requires hilo/core/Class
*/
var EventMixin = /** @lends EventMixin# */{
_listeners: null,
/**
* Add an event listenser.
* @param {String} type Event type to listen.
* @param {Function} listener Callback function of event listening.
* @param {Boolean} once Listen on event only once and no more response after the first response?
* @returns {Object} The Event itself. Functions chain call supported.
*/
on: function(type, listener, once){
var listeners = (this._listeners = this._listeners || {});
var eventListeners = (listeners[type] = listeners[type] || []);
for(var i = 0, len = eventListeners.length; i < len; i++){
var el = eventListeners[i];
if(el.listener === listener) return;
}
eventListeners.push({listener:listener, once:once});
return this;
},
/**
* Remove one event listener. Remove all event listeners if no parameter provided, and remove all event listeners on one type which is provided as the only parameter.
* @param {String} type The type of event listener that want to remove.
* @param {Function} listener Event listener callback function to be removed.
* @returns {Object} The Event itself. Functions chain call supported.
*/
off: function(type, listener){
//remove all event listeners
if(arguments.length == 0){
this._listeners = null;
return this;
}
var eventListeners = this._listeners && this._listeners[type];
if(eventListeners){
//remove event listeners by specified type
if(arguments.length == 1){
delete this._listeners[type];
return this;
}
for(var i = 0, len = eventListeners.length; i < len; i++){
var el = eventListeners[i];
if(el.listener === listener){
eventListeners.splice(i, 1);
if(eventListeners.length === 0) delete this._listeners[type];
break;
}
}
}
return this;
},
/**
* Send events. If the first parameter is an Object, take it as an Event Object.
* @param {String} type Event type to send.
* @param {Object} detail The detail (parameters go with the event) of Event to send.
* @returns {Boolean} Whether Event call successfully.
*/
fire: function(type, detail){
var event, eventType;
if(typeof type === 'string'){
eventType = type;
}else{
event = type;
eventType = type.type;
}
var listeners = this._listeners;
if(!listeners) return false;
var eventListeners = listeners[eventType];
if(eventListeners){
var eventListenersCopy = eventListeners.slice(0);
event = event || new EventObject(eventType, this, detail);
if(event._stopped) return false;
for(var i = 0; i < eventListenersCopy.length; i++){
var el = eventListenersCopy[i];
el.listener.call(this, event);
if(el.once) {
var index = eventListeners.indexOf(el);
if(index > -1){
eventListeners.splice(index, 1);
}
}
}
if(eventListeners.length == 0) delete listeners[eventType];
return true;
}
return false;
}
};
/**
* Event Object class. It's an private class now, but maybe will become a public class if needed.
*/
var EventObject = Class.create({
constructor: function EventObject(type, target, detail){
this.type = type;
this.target = target;
this.detail = detail;
this.timeStamp = +new Date();
},
type: null,
target: null,
detail: null,
timeStamp: 0,
stopImmediatePropagation: function(){
this._stopped = true;
}
});
//Trick: `stopImmediatePropagation` compatibility
var RawEvent = window.Event;
if(RawEvent){
var proto = RawEvent.prototype,
stop = proto.stopImmediatePropagation;
proto.stopImmediatePropagation = function(){
stop && stop.call(this);
this._stopped = true;
};
}