1 /**
  2  * @fileOverview responsible for handling event from browser to KISSY Event
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("event/handle", function (S, DOM, _data, special) {
  6 
  7     function getEvents(target) {
  8         // 获取事件描述
  9         var eventDesc = _data._data(target);
 10         return eventDesc && eventDesc.events;
 11     }
 12 
 13     function getHandlers(target, type) {
 14         var events = getEvents(target) || {};
 15         return events[type] || [];
 16     }
 17 
 18     return function (currentTarget, event) {
 19         /*
 20          As some listeners may remove themselves from the
 21          event, the original array length is dynamic. So,
 22          let's make a copy of all listeners, so we are
 23          sure we'll call all of them.
 24          */
 25         /**
 26          * DOM3 Events: EventListenerList objects in the DOM are live. ??
 27          */
 28         var handlers = getHandlers(currentTarget, event.type),
 29             target = event.target,
 30             currentTarget0,
 31             allHandlers = [],
 32             ret,
 33             gRet,
 34             handlerObj,
 35             i,
 36             j,
 37             delegateCount = handlers.delegateCount || 0,
 38             len,
 39             currentTargetHandlers,
 40             currentTargetHandler,
 41             handler;
 42 
 43         // collect delegated handlers and corresponding element
 44         if (delegateCount &&
 45             // by jq
 46             // Avoid disabled elements in IE (#6911)
 47             // non-left-click bubbling in Firefox (#3861),firefox 8 fix it
 48             !target.disabled) {
 49             while (target != currentTarget) {
 50                 currentTargetHandlers = [];
 51                 for (i = 0; i < delegateCount; i++) {
 52                     handler = handlers[i];
 53                     if (DOM.test(target, handler.selector)) {
 54                         currentTargetHandlers.push(handler);
 55                     }
 56                 }
 57                 if (currentTargetHandlers.length) {
 58                     allHandlers.push({
 59                         currentTarget:target,
 60                         currentTargetHandlers:currentTargetHandlers
 61                     });
 62                 }
 63                 target = target.parentNode || currentTarget;
 64             }
 65         }
 66 
 67         // root node's handlers is placed at end position of add handlers
 68         // in case child node stopPropagation of root node's handlers
 69         allHandlers.push({
 70             currentTarget:currentTarget,
 71             currentTargetHandlers:handlers.slice(delegateCount)
 72         });
 73 
 74         // backup eventType
 75         var eventType = event.type,
 76             s,
 77             t,
 78             _ks_groups = event._ks_groups;
 79         for (i = 0, len = allHandlers.length;
 80              !event.isPropagationStopped && i < len;
 81              ++i) {
 82 
 83             handlerObj = allHandlers[i];
 84             currentTargetHandlers = handlerObj.currentTargetHandlers;
 85             currentTarget0 = handlerObj.currentTarget;
 86             event.currentTarget = currentTarget0;
 87             for (j = 0; !event.isImmediatePropagationStopped &&
 88                 j < currentTargetHandlers.length;
 89                  j++) {
 90 
 91                 currentTargetHandler = currentTargetHandlers[j];
 92 
 93                 // handler's group does not match specified groups (at fire step)
 94                 if (_ks_groups &&
 95                     (!currentTargetHandler.groups ||
 96                         !(currentTargetHandler.groups.match(_ks_groups)))) {
 97                     continue;
 98                 }
 99 
100                 var data = currentTargetHandler.data;
101 
102                 // restore originalType if involving delegate/onFix handlers
103                 event.type = currentTargetHandler.originalType || eventType;
104 
105                 // scope undefined 时不能写死在 listener 中,否则不能保证 clone 时的 this
106                 if ((s = special[event.type]) && s.handle) {
107                     t = s.handle(event, currentTargetHandler, data);
108                     // can handle
109                     if (t.length > 0) {
110                         ret = t[0];
111                     }
112                 } else {
113                     ret = currentTargetHandler.fn.call(
114                         currentTargetHandler.scope || currentTarget,
115                         event, data
116                     );
117                 }
118                 // 和 jQuery 逻辑保持一致
119                 // 有一个 false,最终结果就是 false
120                 // 否则等于最后一个返回值
121                 if (gRet !== false) {
122                     gRet = ret;
123                 }
124                 // return false 等价 preventDefault + stopProgation
125                 if (ret === false) {
126                     event.halt();
127                 }
128             }
129         }
130 
131         // fire 时判断如果 preventDefault,则返回 false 否则返回 true
132         // 这里返回值意义不同
133         return gRet;
134     }
135 }, {
136     requires:['dom', './data', './special']
137 });