1 /** 2 * @fileOverview scalable event framework for kissy (refer DOM3 Events) 3 * how to fire event just like browser? 4 * @author yiminghe@gmail.com,lifesinger@gmail.com 5 */ 6 KISSY.add('event/base', function (S, DOM, EventObject, Utils, handle, _data, special) { 7 8 var isValidTarget = Utils.isValidTarget, 9 splitAndRun = Utils.splitAndRun, 10 getNodeName = DOM.nodeName, 11 trim = S.trim, 12 TRIGGERED_NONE = Utils.TRIGGERED_NONE; 13 14 /** 15 * @namespace The event utility provides functions to add and remove event listeners. 16 * @name Event 17 */ 18 var Event = 19 /** 20 * @lends Event 21 */ 22 { 23 24 _clone:function (src, dest) { 25 26 if (dest.nodeType !== DOM.ELEMENT_NODE || 27 !_data._hasData(src)) { 28 return; 29 } 30 var eventDesc = _data._data(src), 31 events = eventDesc.events; 32 S.each(events, function (handlers, type) { 33 S.each(handlers, function (handler) { 34 // scope undefined 时不能写死在 handlers 中,否则不能保证 clone 时的 this 35 Event.on(dest, type, { 36 data:handler.data, 37 fn:handler.fn, 38 groups:handler.groups, 39 last:handler.last, 40 originalType:handler.originalType, 41 scope:handler.scope, 42 selector:handler.selector 43 }); 44 }); 45 }); 46 }, 47 48 /** 49 * fire event,simulate bubble in browser. similar to dispatchEvent in DOM3 Events 50 * @memberOf Event 51 * @param targets html nodes 52 * @param {String|Event.Object} eventType event type 53 * @param [eventData] additional event data 54 * @param {Boolean} [onlyHandlers] only fire handlers 55 * @returns {Boolean} The return value of fire/dispatchEvent indicates 56 * whether any of the listeners which handled the event called preventDefault. 57 * If preventDefault was called the value is false, else the value is true. 58 */ 59 fire:function (targets, eventType, eventData, onlyHandlers/*internal usage*/) { 60 var ret = true, r; 61 // custom event firing moved to target.js 62 eventData = eventData || {}; 63 if (S.isString(eventType)) { 64 eventType = trim(eventType); 65 if (eventType.indexOf(" ") > -1) { 66 splitAndRun(eventType, function (t) { 67 r = Event.fire(targets, t, eventData, onlyHandlers); 68 if (ret !== false) { 69 ret = r; 70 } 71 }); 72 return ret; 73 } 74 // protect event type 75 eventData.type = eventType; 76 } else if (eventType instanceof EventObject) { 77 eventData = eventType; 78 eventType = eventData.type; 79 } 80 81 var typedGroups = Utils.getTypedGroups(eventType), 82 _ks_groups = typedGroups[1]; 83 84 if (_ks_groups) { 85 _ks_groups = Utils.getGroupsRe(_ks_groups); 86 } 87 88 eventType = typedGroups[0]; 89 90 S.mix(eventData, { 91 type:eventType, 92 _ks_groups:_ks_groups 93 }); 94 95 targets = DOM.query(targets); 96 for (var i = targets.length - 1; i >= 0; i--) { 97 r = fireDOMEvent(targets[i], eventType, eventData, onlyHandlers); 98 if (ret !== false) { 99 ret = r; 100 } 101 } 102 return ret; 103 }, 104 105 /** 106 * does not cause default behavior to occur 107 * does not bubble up the DOM hierarchy 108 * @param targets 109 * @param {Event.Object | String} eventType 110 * @param [eventData] 111 */ 112 fireHandler:function (targets, eventType, eventData) { 113 return Event.fire(targets, eventType, eventData, 1); 114 } 115 }; 116 117 /** 118 * fire dom event from bottom to up , emulate dispatchEvent in DOM3 Events 119 * @return {Boolean} The return value of dispatchEvent indicates 120 * whether any of the listeners which handled the event called preventDefault. 121 * If preventDefault was called the value is false, else the value is true. 122 */ 123 function fireDOMEvent(target, eventType, eventData, onlyHandlers) { 124 if (!isValidTarget(target)) { 125 return false; 126 } 127 var s = special[eventType]; 128 // TODO bug : when fire mouseenter , it also fire mouseover in firefox/chrome 129 if (s && s['onFix']) { 130 eventType = s['onFix']; 131 } 132 133 var event, 134 ret = true; 135 if (eventData instanceof EventObject) { 136 event = eventData; 137 } else { 138 event = new EventObject(target, undefined, eventType); 139 S.mix(event, eventData); 140 } 141 /** 142 * identify event as fired manually 143 */ 144 event._ks_fired = 1; 145 /* 146 The target of the event is the EventTarget on which dispatchEvent is called. 147 */ 148 // TODO: protect target , but incompatible 149 // event.target=target; 150 // protect type 151 event.type = eventType; 152 153 // onlyHandlers is equal to event.halt() 154 // but we can not call event.halt() 155 // because handle will check event.isPropagationStopped 156 157 var cur = target, 158 t, 159 win = DOM._getWin(cur.ownerDocument || cur), 160 ontype = "on" + eventType; 161 162 //bubble up dom tree 163 do { 164 event.currentTarget = cur; 165 t = handle(cur, event); 166 if (ret !== false) { 167 ret = t; 168 } 169 // Trigger an inline bound script 170 if (cur[ ontype ] && cur[ ontype ].call(cur) === false) { 171 event.preventDefault(); 172 } 173 // Bubble up to document, then to window 174 cur = cur.parentNode || 175 cur.ownerDocument || 176 (cur === target.ownerDocument) && win; 177 } while (!onlyHandlers && cur && !event.isPropagationStopped); 178 179 if (!onlyHandlers && !event.isDefaultPrevented) { 180 if (!(eventType === "click" && 181 getNodeName(target) == "a")) { 182 var old; 183 try { 184 // execute default action on dom node 185 // so exclude window 186 // exclude focus/blue on hidden element 187 if (ontype && 188 target[ eventType ] && 189 ( 190 (eventType !== "focus" && eventType !== "blur") || 191 target.offsetWidth !== 0 192 ) && 193 !S.isWindow(target)) { 194 // Don't re-trigger an onFOO event when we call its FOO() method 195 old = target[ ontype ]; 196 197 if (old) { 198 target[ ontype ] = null; 199 } 200 201 // 记录当前 trigger 触发 202 Utils.Event_Triggered = eventType; 203 204 // 只触发默认事件,而不要执行绑定的用户回调 205 // 同步触发 206 target[ eventType ](); 207 } 208 } catch (ieError) { 209 S.log("trigger action error : "); 210 S.log(ieError); 211 } 212 213 if (old) { 214 target[ ontype ] = old; 215 } 216 217 Utils.Event_Triggered = TRIGGERED_NONE; 218 } 219 } 220 return ret; 221 } 222 223 return Event; 224 }, { 225 requires:["dom", "./object", "./utils", './handle', './data', './special'] 226 }); 227 228 /** 229 * yiminghe@gmail.com : 2011-12-15 230 * - 重构,粒度更细,新的架构 231 * 232 * 2011-11-24 233 * - 自定义事件和 dom 事件操作彻底分离 234 * - TODO: group event from DOM3 Event 235 * 236 * 2011-06-07 237 * - refer : http://www.w3.org/TR/2001/WD-DOM-Level-3-Events-20010823/events.html 238 * - 重构 239 * - eventHandler 一个元素一个而不是一个元素一个事件一个,节省内存 240 * - 减少闭包使用,prevent ie 内存泄露? 241 * - 增加 fire ,模拟冒泡处理 dom 事件 242 */ 243