+ /**
+ * Event
+ *
+ * Event api wrapper
+ * @todo Add method for triggering events
+ */
+(function (undefined){
+
+ "use strict";
+
+ var _add_remove, e, _attach_delegate;
+
+ _add_remove = function (sel, event, callback, add)
+ {
+ var i, len;
+
+ // Multiple events? Run recursively!
+ if ( ! event.match(/^([\w\-]+)$/))
+ {
+ event = event.split(" ");
+
+ len = event.length;
+
+ for (i = 0; i < len; i++)
+ {
+ _add_remove(sel, event[i], callback, add);
+ }
+
+ return;
+ }
+
+ // Bind the event
+ (add === true)
+ ? sel.addEventListener(event, callback, false)
+ : sel.removeEventListener(event, callback, false);
+ };
+
+ _attach_delegate = function(sel, target, event, callback)
+ {
+ // attach the listener to the parent object
+ _add_remove(sel, event, function(e){
+
+ var elem, t;
+
+ // Get the live version of the target selector
+ t = $_.$(target, sel);
+
+ // Check each element to see if it matches the target
+ for(elem in t)
+ {
+ // Fire target callback when event bubbles from target
+ if(e.target == t[elem])
+ {
+ // Trigger the event callback
+ callback.call(t[elem], e);
+
+ // Stop event propegation
+ e.stopPropagation();
+ }
+ }
+
+ }, true);
+ };
+
+ // --------------------------------------------------------------------------
+
+ /**
+ * Event Listener module
+ *
+ * @namespace
+ * @name event
+ * @memberOf $_
+ */
+ e = {
+ /**
+ * Create a custom event
+ *
+ * @memberOf $_.event
+ * @name create
+ * @function
+ * @example Eg. var event = $_("#selector").event.create('foo', {});
+ * @param {string} name
+ * @param {object} [data]
+ * @return {Object}
+ */
+ create: function(name, data)
+ {
+ // Do a terrible browser-sniffic hack because I don't know of a good
+ // feature test
+ if (/MSIE|Trident/i.test(navigator.userAgent))
+ {
+ // Okay, I guess we have to do this the hard way... :(
+ // Microsoft, your browser still sucks
+ var e = document.createEvent('CustomEvent');
+ e.initCustomEvent(name, true, true, data);
+
+ return e;
+ }
+ else
+ {
+ return new CustomEvent(name, data);
+ }
+ },
+ /**
+ * Adds an event that returns a callback when triggered on the selected
+ * event and selector
+ *
+ * @memberOf $_.event
+ * @name add
+ * @function
+ * @example Eg. $_("#selector").event.add("click", do_something());
+ * @param {string} event
+ * @param {function} callback
+ */
+ add: function (event, callback)
+ {
+ $_.each(function(e){
+ _add_remove(e, event, callback, true);
+ });
+ },
+ /**
+ * Removes an event bound the the specified selector, event type, and callback
+ *
+ * @memberOf $_.event
+ * @name remove
+ * @function
+ * @example Eg. $_("#selector").event.remove("click", do_something());
+ * @param {string} event
+ * @param {string} callback
+ */
+ remove: function (event, callback)
+ {
+ $_.each(function(e){
+ _add_remove(e, event, callback, false);
+ });
+ },
+ /**
+ * Binds a persistent event to the document
+ *
+ * @memberOf $_.event
+ * @name live
+ * @function
+ * @example Eg. $_.event.live(".button", "click", do_something());
+ * @param {string} target
+ * @param {string} event
+ * @param {function} callback
+ */
+ live: function (target, event, callback)
+ {
+ _attach_delegate(document.documentElement, target, event, callback);
+ },
+ /**
+ * Binds an event to a parent object
+ *
+ * @memberOf $_.event
+ * @name delegate
+ * @function
+ * @example Eg. $_("#parent").delegate(".button", "click", do_something());
+ * @param {string} target
+ * @param {string} event
+ * @param {function} callback
+ */
+ delegate: function (target, event, callback)
+ {
+ $_.each(function(e){
+ _attach_delegate(e, target, event, callback);
+ });
+ },
+ /**
+ * Trigger an event to fire
+ *
+ * @memberOf $_.event
+ * @name trigger
+ * @function
+ * @example Eg. $_("#my_id").trigger('click');
+ * @param {object} event
+ * @return {boolean}
+ */
+ trigger: function(event)
+ {
+ var target = this.el;
+ return target.dispatchEvent(event);
+ }
+ };
+
+ $_.ext('event', e);
+
+}());
+
+