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