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, tar; 148 149 // IE 8 doesn't have event bound to element 150 e = e || window.event; 151 152 // Get the live version of the target selector 153 t = $_.$(target, sel); 154 155 // Check each element to see if it matches the target 156 for(elem in t) 157 { 158 // IE 8 doesn't have target in the event object 159 tar = e.target || e.srcElement; 160 161 // Fire target callback when event bubbles from target 162 if(tar == t[elem]) 163 { 164 // Trigger the event callback 165 callback.call(t[elem], e); 166 167 // Stop event propegation 168 e.stopPropagation(); 169 } 170 } 171 172 }, true); 173 }; 174 175 176 177 // -------------------------------------------------------------------------- 178 179 /** 180 * Event Listener module 181 * 182 * @namespace 183 * @name event 184 * @memberOf $_ 185 */ 186 e = { 187 /** 188 * Adds an event that returns a callback when triggered on the selected 189 * event and selector 190 * 191 * @memberOf $_.event 192 * @name add 193 * @function 194 * @example Eg. $_("#selector").event.add("click", do_something()); 195 * @param string event 196 * @param function callback 197 */ 198 add: function (event, callback) 199 { 200 $_.each(function(e){ 201 _add_remove(e, event, callback, true); 202 }); 203 }, 204 /** 205 * Removes an event bound the the specified selector, event type, and callback 206 * 207 * @memberOf $_.event 208 * @name remove 209 * @function 210 * @example Eg. $_("#selector").event.remove("click", do_something()); 211 * @param string event 212 * @param string callback 213 */ 214 remove: function (event, callback) 215 { 216 $_.each(function(e){ 217 _add_remove(e, event, callback, false); 218 }); 219 }, 220 /** 221 * Binds a persistent event to the document 222 * 223 * @memberOf $_.event 224 * @name live 225 * @function 226 * @example Eg. $_.event.live(".button", "click", do_something()); 227 * @param string target 228 * @param string event 229 * @param function callback 230 */ 231 live: function (target, event, callback) 232 { 233 _attach_delegate(document.documentElement, target, event, callback); 234 }, 235 /** 236 * Binds an event to a parent object 237 * 238 * @memberOf $_.event 239 * @name delegate 240 * @function 241 * @example Eg. $_("#parent").delegate(".button", "click", do_something()); 242 * @param string target 243 * @param string event_type 244 * @param function callback 245 */ 246 delegate: function (target, event, callback) 247 { 248 $_.each(function(e){ 249 _attach_delegate(e, target, event, callback); 250 }); 251 } 252 }; 253 254 $_.ext('event', e); 255 256 }());