Event Handling
When doing Ajax event handling is necessary. Most (or actually all) Ajax libraries support browser-abstracted event handling. I took from many of these and made my own with nice features from all of them.
I will list the features here later, but here's the code now:
//////////// EVENT /////////////// var addEvent; var removeEvent; var getEvent; (function() { var curId = 0; var delayedListeners = []; var listeners = {}; var windowLoaded = false; function getObjId(object) { if (!object.__eventId) object.__eventId = ++curId; return object.__eventId; } function getEventId(element, event, listener) { var listener = listener.length == 2 ? getObjId(listener[0]) + '_' + getObjId(listener[1]) : getObjId(listener); return getObjId(element) + "_" + event + "_" + listener; } function addListener(element, event, listener) { if (typeof element == 'string' && !windowLoaded) { delayedListeners.push(arguments); return true; } if (typeof element == "string") element = document.getElementById(element); if (!element) return false; var obj = listener.length == 2 ? listener[0] : element; var func = listener.length == 2 ? listener[1] : listener; var args = Array.prototype.splice.call(arguments, 3, arguments.length); var proxy = function(event) { args.push(event); func.apply(obj, args); } listeners[getEventId(element, event, listener)] = {listener: listener, proxy: proxy}; if (element.addEventListener) element.addEventListener(event, proxy, false); else if (element.attachEvent) element.attachEvent('on' + event, proxy); return true; } function removeListener(element, event, listener) { if (typeof element == "string") element = document.getElementById(element); var eventId = getEventId(element, event, listener); if (!eventId in listeners) return false var proxy = listeners[eventId].proxy; delete listeners[eventId]; if (element.removeEventListener) element.removeEventListener(event, proxy, false); else if (element.detachEvent) element.detachEvent('on' + event, proxy); return true; } addEvent = function(element, event, listener) { if (element.length && typeof element != 'string') { var args = Array.prototype.splice.call(arguments, 0, arguments.length); for (var i = 0; i < element.length; i++) { args[0] = element[i]; addListener.apply(this, args); } } else addListener.apply(this, arguments); }; removeEvent = function(element, event, listener) { if (element.length && typeof element != 'string') { for (var i = 0; i < element.length; i++) removeListener(element, event, listener); } else removeListener(element, event, listener); }; function stop() { this.stopPropagation(); this.preventDefault(); } function find(nodeName, useRelatedTarget) { nodeName = nodeName.toUpperCase(); var node = useRelatedTarget ? this.relatedTarget : this.target; while (node.nodeName != nodeName && node.parentNode) node = node.parentNode; if (node.nodeName == nodeName) return node; } getEvent = function(event, property) { if (event.isSetup) return event; if (isIE) { event = window.event; event.stopPropagation = new Function("this.cancelBubble = true"); event.preventDefault = new Function("this.returnValue = false"); event.target = event.srcElement; if ("fromElement" in event) event.relatedTarget = event.fromElement; else if ("toElement" in event) event.relatedTarget = event.toElement; if (!("layerX" in event) && "offsetX" in event) { event.layerX = event.offsetX; event.layerY = event.offsetY; } } else { if (event.target.nodeType == 3) event.target = event.target.parentNode; } if ("button" in event) event.mouseButton = event.button != 2 ? 1 : 2; if (!("pageX" in event) && "clientX" in event) { event.pageX = event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft); event.pageY = event.clientY + (document.documentElement.scrollTop || document.body.scrollTop); } event.stop = stop; event.find = find; event.isSetup = true; return event; }; function onWindowUnload() { if (!listeners) return; for (var i = 0; i < listeners.length; i++) { var element = listeners[i][0]; var event = listeners[i][1]; var proxy = listeners[i][4]; try { // if the element no longer exists, don't throw an error if (element.removeEventListener) element.removeEventListener(event, proxy, false); else if (element.detachEvent) element.detachEvent('on' + event, proxy); } catch(e) {} delete listeners[i]; } delete listeners; } function onWindowLoad() { windowLoaded = true; for (var i = 0; i < delayedListeners.length; i++) { addListener.apply(this, delayedListeners[i]); } } addEvent(window, 'unload', onWindowUnload); addEvent(window, 'load', onWindowLoad); })();