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(target, event, function(e){
146 		
147 			var i, t;
148 			
149 			//Get the live version of the target selector
150 			t = $_.$(target);
151 			
152 			console.log(t);
153 			
154 			//Check each element to see if it matches the target
155 			for(i in t)
156 			{
157 				if(t.hasOwnProperty(i))
158 				{
159 					//Fire target callback when event bubbles from target
160 					if(e.target == i)
161 					{
162 						//Trigger the event callback
163 						callback.call(i, e);
164 						
165 						//Stop event propegation
166 						e.stopPropagation();
167 					}
168 				}
169 			}
170 			
171 			
172 		}, true);
173 	};
174 	
175 	// --------------------------------------------------------------------------
176 
177 	/**
178 	 * @namespace
179 	 * @name event
180 	 * @memberOf $_
181 	 */
182 	e = {
183 		/**
184 		 * Adds an event that returns a callback when triggered on the selected
185 		 * event and selector
186 		 * 
187 		 * @memberOf $_.event
188 		 * @name add
189 		 * @function
190 		 * @example Eg. $_("#selector").event.add("click", do_something());
191 		 * @param string event
192 		 * @param function callback
193 		 * @return void
194 		 */
195 		add: function (event, callback)
196 		{
197 			$_.each(function(e){
198 				_add_remove(e, event, callback, true);
199 			});
200 		},
201 		/**
202 		 * Removes an event bound the the specified selector, event type, and callback
203 		 *
204 		 * @memberOf $_.event
205 		 * @name remove
206 		 * @function
207 		 * @example Eg. $_("#selector").event.remove("click", do_something());
208 		 * @param string event
209 		 * @param string callback
210 		 * @return void
211 		 */
212 		remove: function (event, callback)
213 		{
214 			$_.each(function(e){
215 				_add_remove(e, event, callback, false);
216 			});
217 		},
218 		/** 
219 		 * Binds a persistent, delegated event
220 		 * 
221 		 * @memberOf $_.event
222 		 * @name live
223 		 * @function
224 		 * @example Eg. $_.event.live(".button", "click", do_something());
225 		 * @param string target
226 		 * @param string event
227 		 * @param function callback
228 		 * @return void
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 		 * @parma function callback
244 		 * @return void
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 }());