1 /** 2 * @fileOverview responsible for registering event 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("event/add", function (S, Event, DOM, Utils, EventObject, handle, _data, specials) { 6 var simpleAdd = Utils.simpleAdd, 7 isValidTarget = Utils.isValidTarget, 8 isIdenticalHandler = Utils.isIdenticalHandler; 9 10 /** 11 * dom node need eventHandler attached to dom node 12 */ 13 function addDomEvent(target, type, eventHandler, handlers, handleObj) { 14 var special = specials[type] || {}; 15 // 第一次注册该事件,dom 节点才需要注册 dom 事件 16 if (!handlers.length && 17 (!special.setup || special.setup.call(target) === false)) { 18 simpleAdd(target, type, eventHandler) 19 } 20 if (special.add) { 21 special.add.call(target, handleObj); 22 } 23 } 24 25 /** 26 * @exports Event as Event 27 */ 28 29 S.mix(Event, 30 /** 31 * @lends Event 32 */ 33 { 34 // single type , single target , fixed native 35 __add:function (isNativeTarget, target, type, fn, scope) { 36 var typedGroups = Utils.getTypedGroups(type); 37 type = typedGroups[0]; 38 var groups = typedGroups[1], 39 eventDesc, 40 data, 41 s = specials[type], 42 // in case overwrite by delegateFix/onFix in specials events 43 // (mouseenter/leave,focusin/out) 44 originalType, 45 last, 46 selector; 47 if (S.isObject(fn)) { 48 last = fn.last; 49 scope = fn.scope; 50 data = fn.data; 51 selector = fn.selector; 52 // in case provided by clone 53 originalType = fn.originalType; 54 fn = fn.fn; 55 if (selector && !originalType) { 56 if (s && s['delegateFix']) { 57 originalType = type; 58 type = s['delegateFix']; 59 } 60 } 61 } 62 if (!selector && !originalType) { 63 // when on mouseenter , it's actually on mouseover , and handlers is saved with mouseover! 64 // TODO need evaluate! 65 if (s && s['onFix']) { 66 originalType = type; 67 type = s['onFix']; 68 } 69 } 70 // 不是有效的 target 或 参数不对 71 if (!type || 72 !target || 73 !S.isFunction(fn) || 74 (isNativeTarget && !isValidTarget(target))) { 75 return; 76 } 77 // 获取事件描述 78 eventDesc = Event._data(target); 79 if (!eventDesc) { 80 _data._data(target, eventDesc = {}); 81 } 82 //事件 listeners , similar to eventListeners in DOM3 Events 83 var events = eventDesc.events = eventDesc.events || {}, 84 handlers = events[type] = events[type] || [], 85 handleObj = { 86 fn:fn, 87 scope:scope, 88 selector:selector, 89 last:last, 90 data:data, 91 groups:groups, 92 originalType:originalType 93 }, 94 eventHandler = eventDesc.handler; 95 // 该元素没有 handler ,并且该元素是 dom 节点时才需要注册 dom 事件 96 if (!eventHandler) { 97 eventHandler = eventDesc.handler = function (event, data) { 98 // 是经过 fire 手动调用而浏览器同步触发导致的,就不要再次触发了, 99 // 已经在 fire 中 bubble 过一次了 100 // incase after page has unloaded 101 if (typeof KISSY == "undefined" || 102 event && event.type == Utils.Event_Triggered) { 103 return; 104 } 105 var currentTarget = eventHandler.target, type; 106 if (!event || !event.fixed) { 107 event = new EventObject(currentTarget, event); 108 } 109 type = event.type; 110 if (S.isPlainObject(data)) { 111 S.mix(event, data); 112 } 113 // protect type 114 if (type) { 115 event.type = type; 116 } 117 return handle(currentTarget, event); 118 }; 119 // as for native dom event , this represents currentTarget ! 120 eventHandler.target = target; 121 } 122 123 for (var i = handlers.length - 1; i >= 0; --i) { 124 /** 125 * If multiple identical EventListeners are registered on the same EventTarget 126 * with the same parameters the duplicate instances are discarded. 127 * They do not cause the EventListener to be called twice 128 * and since they are discarded 129 * they do not need to be removed with the removeEventListener method. 130 */ 131 if (isIdenticalHandler(handlers[i], handleObj, target)) { 132 return; 133 } 134 } 135 136 if (isNativeTarget) { 137 addDomEvent(target, type, eventHandler, handlers, handleObj); 138 //nullify to prevent memory leak in ie ? 139 target = null; 140 } 141 142 // 增加 listener 143 if (selector) { 144 var delegateIndex = handlers.delegateCount 145 = handlers.delegateCount || 0; 146 handlers.splice(delegateIndex, 0, handleObj); 147 handlers.delegateCount++; 148 } else { 149 handlers.lastCount = handlers.lastCount || 0; 150 if (last) { 151 handlers.push(handleObj); 152 handlers.lastCount++; 153 } else { 154 handlers.splice(handlers.length - handlers.lastCount, 155 0, handleObj); 156 } 157 } 158 }, 159 160 /** 161 * Adds an event listener.similar to addEventListener in DOM3 Events 162 * @param targets KISSY selector 163 * @param type {String} The type of event to append.use space to separate multiple event types. 164 * @param fn {Function} The event handler/listener. 165 * @param {Object} [scope] The scope (this reference) in which the handler function is executed. 166 */ 167 add:function (targets, type, fn, scope) { 168 type = S.trim(type); 169 // data : 附加在回调后面的数据,delegate 检查使用 170 // remove 时 data 相等(指向同一对象或者定义了 equals 比较函数) 171 if (Utils.batchForType(Event.add, targets, type, fn, scope)) { 172 return targets; 173 } 174 targets = DOM.query(targets); 175 for (var i = targets.length - 1; i >= 0; i--) { 176 Event.__add(true, targets[i], type, fn, scope); 177 } 178 return targets; 179 } 180 }); 181 }, { 182 requires:['./base', 'dom', './utils', './object', './handle', './data', './special'] 183 });