Hey, was just trying to write a vanilla js solution to event binding. After looking at some examples online I came up with this script.
Some benefits of this:
- Can be passed either a node or a node list to attach handlers too
- It checks once to see if the addEventListener and removeEventListener are available and just wraps those if they are.
- If those methods are not available, it falls back to the Dean Edwards addEvent solution but without the Global pollution.
- Normalizes the event object passed to the handler a bit so as to ease event delegation and target checks
function BigAB(window, document) {
this.addEvent = (function( window, document ) {
if ( document.addEventListener ) {
return function( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.addEventListener(type, cb, false );
}
else if ( elem && elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
this.addEvent( elem[i], type, cb );
}
}
};
}
else if ( document.attachEvent ) {
return function ( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
if (!cb.$$guid) cb.$$guid = this.addEvent.guid++;
if (!elem.events) elem.events = {};
var cbs = elem.events[type];
if (!cbs) {
cbs = elem.events[type] = {};
if (elem['on' + type]) cbs[0] = elem['on' + type];
elem['on' + type] = handleEvent;
}
cbs[cb.$$guid] = cb;
}
else if ( elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
this.addEvent( elem[i], type, cb );
}
}
};
}
})( window, document );
this.addEvent.guid = 1;
this.removeEvent = (function( window, document ) {
if ( document.removeEventListener ) {
return function( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.removeEventListener(type, cb, false );
}
else if ( elem && elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
this.removeEvent( elem[i], type, cb );
}
}
};
}
else if ( document.detachEvent ) {
return function ( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
if (elem.removeEventListener) {
elem.removeEventListener(type, cb, false);
}
else if (elem.events && elem.events[type] && cb.$$guid) {
delete elem.events[type][cb.$$guid];
}
}
else if ( elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
this.removeEvent( elem[i], type, cb );
}
}
};
}
})( window, document );
function handleEvent(event) {
event = event || fixEvent(window.event, this);
var returnValue = true;
var handlers = this.events[event.type];
for (var i in handlers) {
if (!Object.prototype[i]) {
this.$$handler = handlers[i];
if (this.$$handler(event) === false) returnValue = false;
}
}
if (this.$$handler) this.$$handler = null;
return returnValue;
}
function fixEvent(event,currentTarget) {
event.currentTarget = currentTarget;
event.target = event.srcElement;
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
}
fixEvent.preventDefault = function() {
this.returnValue = false;
}
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
}
}
// example usage:
var lib = new BigAB(window,document),
listItems = document.getElementsByTagName('li');
lib.addEvent(listItems, 'click', function(e) { alert('clicked: '+this.id) });
Any comments or suggestinos would be appreciated.