1 /** 2 * Event 3 * 4 * Event api wrapper 5 */ 6 (function (){ 7 8 "use strict"; 9 10 // Property name for expandos on DOM objects 11 var kis_expando = "KIS_0_5_0"; 12 13 var _attach, _remove, _add_remove, e, _attach_delegate; 14 15 // Define the proper _attach and _remove functions 16 // based on browser support 17 if(typeof document.addEventListener !== "undefined") 18 { 19 /** 20 * @private 21 */ 22 _attach = function (sel, event, callback) 23 { 24 if(typeof sel.addEventListener !== "undefined") 25 { 26 //Duplicated events are dropped, per the specification 27 sel.addEventListener(event, callback, false); 28 } 29 }; 30 /** 31 * @private 32 */ 33 _remove = function (sel, event, callback) 34 { 35 if(typeof sel.removeEventListener !== "undefined") 36 { 37 sel.removeEventListener(event, callback, false); 38 } 39 }; 40 } 41 //typeof function doesn't work in IE where attachEvent is available: brute force it 42 else if(typeof document.attachEvent !== "undefined") 43 { 44 /** 45 * @private 46 */ 47 _attach = function (sel, event, callback) 48 { 49 function listener () { 50 // Internet Explorer fails to correctly set the 'this' object 51 // for event listeners, so we need to set it ourselves. 52 callback.apply(arguments[0]); 53 } 54 55 if (typeof sel.attachEvent !== "undefined") 56 { 57 _remove(event, callback); // Make sure we don't have duplicate listeners 58 59 sel.attachEvent("on" + event, listener); 60 // Store our listener so we can remove it later 61 var expando = sel[kis_expando] = sel[kis_expando] || {}; 62 expando.listeners = expando.listeners || {}; 63 expando.listeners[event] = expando.listeners[event] || []; 64 expando.listeners[event].push({ 65 callback: callback, 66 listener: listener 67 }); 68 } 69 else 70 { 71 console.log("Failed to _attach event:"+event+" on "+sel); 72 } 73 }; 74 /** 75 * @private 76 */ 77 _remove = function (sel, event, callback) 78 { 79 if(typeof sel.detachEvent !== "undefined") 80 { 81 var expando = sel[kis_expando]; 82 if (expando && expando.listeners 83 && expando.listeners[event]) 84 { 85 var listeners = expando.listeners[event]; 86 var len = listeners.length; 87 for (var i=0; i<len; i++) 88 { 89 if (listeners[i].callback === callback) 90 { 91 sel.detachEvent("on" + event, listeners[i].listener); 92 listeners.splice(i, 1); 93 if(listeners.length === 0) 94 { 95 delete expando.listeners[event]; 96 } 97 return; 98 } 99 } 100 } 101 } 102 }; 103 } 104 105 _add_remove = function (sel, event, callback, add) 106 { 107 var i, len; 108 109 if(typeof sel === "undefined") 110 { 111 console.log(arguments); 112 console.log(event); 113 return false; 114 } 115 116 //Multiple events? Run recursively! 117 if (!event.match(/^([\w\-]+)$/)) 118 { 119 event = event.split(" "); 120 121 len = event.length; 122 123 for (i = 0; i < len; i++) 124 { 125 _add_remove(sel, event[i], callback, add); 126 } 127 128 return; 129 } 130 131 132 if(add === true) 133 { 134 _attach(sel, event, callback); 135 } 136 else 137 { 138 _remove(sel, event, callback); 139 } 140 }; 141 142 _attach_delegate = function(sel, target, event, callback) 143 { 144 //_attach the listener to the parent object 145 _add_remove(sel, event, function(e){ 146 147 var elem, t; 148 149 //Get the live version of the target selector 150 t = $_.$(target); 151 152 //Check each element to see if it matches the target 153 for(elem in t) 154 { 155 //Fire target callback when event bubbles from target 156 if(e.target == t[elem]) 157 { 158 //Trigger the event callback 159 callback.call(t[elem], e); 160 161 //Stop event propegation 162 e.stopPropagation(); 163 } 164 } 165 166 167 }, true); 168 }; 169 170 171 172 // -------------------------------------------------------------------------- 173 174 /** 175 * @namespace 176 * @name event 177 * @memberOf $_ 178 */ 179 e = { 180 /** 181 * Adds an event that returns a callback when triggered on the selected 182 * event and selector 183 * 184 * @memberOf $_.event 185 * @name add 186 * @function 187 * @example Eg. $_("#selector").event.add("click", do_something()); 188 * @param string event 189 * @param function callback 190 * @return void 191 */ 192 add: function (event, callback) 193 { 194 $_.each(function(e){ 195 _add_remove(e, event, callback, true); 196 }); 197 }, 198 /** 199 * Removes an event bound the the specified selector, event type, and callback 200 * 201 * @memberOf $_.event 202 * @name remove 203 * @function 204 * @example Eg. $_("#selector").event.remove("click", do_something()); 205 * @param string event 206 * @param string callback 207 * @return void 208 */ 209 remove: function (event, callback) 210 { 211 $_.each(function(e){ 212 _add_remove(e, event, callback, false); 213 }); 214 }, 215 /** 216 * Binds a persistent, delegated event 217 * 218 * @memberOf $_.event 219 * @name live 220 * @function 221 * @example Eg. $_.event.live(".button", "click", do_something()); 222 * @param string target 223 * @param string event 224 * @param function callback 225 * @return void 226 */ 227 live: function (target, event, callback) 228 { 229 _attach_delegate(document.documentElement, target, event, callback); 230 }, 231 /** 232 * Binds an event to a parent object 233 * 234 * @memberOf $_.event 235 * @name delegate 236 * @function 237 * @example Eg. $_("#parent").delegate(".button", "click", do_something()); 238 * @param string target 239 * @param string event_type 240 * @parma function callback 241 * @return void 242 */ 243 delegate: function(target, event, callback) 244 { 245 $_.each(function(e){ 246 _attach_delegate(e, target, event, callback); 247 }); 248 } 249 }; 250 251 $_.ext('event', e); 252 253 }());