      1 /**
      2  * Hilo
      3  * Copyright 2015 alibaba.com
      4  * Licensed under the MIT License
      5  */
      6
      7 /**
      8  * @class EventMixin是一个包含事件相关功能的mixin。可以通过 Class.mix(target, EventMixin) 来为target增加事件功能。
      9  * @static
     10  * @mixin
     11  * @module hilo/event/EventMixin
     12  * @requires hilo/core/Class
     13  */
     14 var EventMixin = /** @lends EventMixin# */{
     15     _listeners: null,
     16
     17     /**
     18      * 增加一个事件监听。
     19      * @param {String} type 要监听的事件类型。
     20      * @param {Function} listener 事件监听回调函数。
     21      * @param {Boolean} once 是否是一次性监听，即回调函数响应一次后即删除，不再响应。
     22      * @returns {Object} 对象本身。链式调用支持。
     23      */
     24     on: function(type, listener, once){
     25         var listeners = (this._listeners = this._listeners || {});
     26         var eventListeners = (listeners[type] = listeners[type] || []);
     27         for(var i = 0, len = eventListeners.length; i < len; i++){
     28             var el = eventListeners[i];
     29             if(el.listener === listener) return;
     30         }
     31         eventListeners.push({listener:listener, once:once});
     32         return this;
     33     },
     34
     35     /**
     36      * 删除一个事件监听。如果不传入任何参数，则删除所有的事件监听；如果不传入第二个参数，则删除指定类型的所有事件监听。
     37      * @param {String} type 要删除监听的事件类型。
     38      * @param {Function} listener 要删除监听的回调函数。
     39      * @returns {Object} 对象本身。链式调用支持。
     40      */
     41     off: function(type, listener){
     42         //remove all event listeners
     43         if(arguments.length == 0){
     44             this._listeners = null;
     45             return this;
     46         }
     47
     48         var eventListeners = this._listeners && this._listeners[type];
     49         if(eventListeners){
     50             //remove event listeners by specified type
     51             if(arguments.length == 1){
     52                 delete this._listeners[type];
     53                 return this;
     54             }
     55
     56             for(var i = 0, len = eventListeners.length; i < len; i++){
     57                 var el = eventListeners[i];
     58                 if(el.listener === listener){
     59                     eventListeners.splice(i, 1);
     60                     if(eventListeners.length === 0) delete this._listeners[type];
     61                     break;
     62                 }
     63             }
     64         }
     65         return this;
     66     },
     67
     68     /**
     69      * 发送事件。当第一个参数类型为Object时，则把它作为一个整体事件对象。
     70      * @param {String} type 要发送的事件类型。
     71      * @param {Object} detail 要发送的事件的具体信息，即事件随带参数。
     72      * @returns {Boolean} 是否成功调度事件。
     73      */
     74     fire: function(type, detail){
     75         var event, eventType;
     76         if(typeof type === 'string'){
     77             eventType = type;
     78         }else{
     79             event = type;
     80             eventType = type.type;
     81         }
     82
     83         var listeners = this._listeners;
     84         if(!listeners) return false;
     85
     86         var eventListeners = listeners[eventType];
     87         if(eventListeners){
     88             var eventListenersCopy = eventListeners.slice(0);
     89             event = event || new EventObject(eventType, this, detail);
     90             if(event._stopped) return false;
     91
     92             for(var i = 0; i < eventListenersCopy.length; i++){
     93                 var el = eventListenersCopy[i];
     94                 el.listener.call(this, event);
     95                 if(el.once) {
     96                     var index = eventListeners.indexOf(el);
     97                     if(index > -1){
     98                         eventListeners.splice(index, 1);
     99                     }
    100                 }
    101             }
    102
    103             if(eventListeners.length == 0) delete listeners[eventType];
    104             return true;
    105         }
    106         return false;
    107     }
    108 };
    109
    110 /**
    111  * 事件对象类。当前仅为内部类，以后有需求的话可能会考虑独立为公开类。
    112  */
    113 var EventObject = Class.create({
    114     constructor: function EventObject(type, target, detail){
    115         this.type = type;
    116         this.target = target;
    117         this.detail = detail;
    118         this.timeStamp = +new Date();
    119     },
    120
    121     type: null,
    122     target: null,
    123     detail: null,
    124     timeStamp: 0,
    125
    126     stopImmediatePropagation: function(){
    127         this._stopped = true;
    128     }
    129 });
    130
    131 //Trick: `stopImmediatePropagation` compatibility
    132 var RawEvent = window.Event;
    133 if(RawEvent){
    134     var proto = RawEvent.prototype,
    135         stop = proto.stopImmediatePropagation;
    136     proto.stopImmediatePropagation = function(){
    137         stop && stop.call(this);
    138         this._stopped = true;
    139     };
    140 }
    141