/* Javascript: Browser Compatibility: Event Listener Wrappers Copyright © Yudhi Seymour (http://penagate.com) 2006-2007. Licenced under the GPL (http://gnu.org/copyleft/gpl.html). Latest revision: http://dev.penagate.com/js/event-listeners.js This revision on Thursday, February 1st, 2007. -- Changelog (Y/M/D): * 07/02/01: Fixed context/property issues with IE. -- Notes: * MSIE doesn't support various DOM Level 2 types such as Node; Element; or EventTarget; so the addEHandler and removeEHandler functions must be global, to avoid modifying Object.prototype. -- Documentation: * void addEHandler(EventTarget obj, string event_name, EventListener handler); Attaches an event listener to the event target. * void removeEHandler(EventTarget obj, string event_name, EventListener handler); Removes an event listener that was attached using the same parameters. * EventContextWrapper: Class that wraps an event listener and allows supplementary properties and a (manually set) context reference. Useful for event listeners that need access to a related object. * IEventContext: Virtual interface specifying: * Function $callback(Event evt); Event listener function to call. * object $context; Reference to the context object. * object $props; Optional hashtable of name/value pair properties. * void EventContextWrapper.create(object p_contextobj, IEventContext p_interface, object props); Creates an event listener wrapper object. Use this method instead of the new operator as a function, rather than an object, must be returned for MSIE compatibility. * static void EventContextWrapper::handleEvent(Event evt); Implements EventListener::handleEvent. * static void EventContextWrapper::invoke_event(Event evt); Manually invoke the event. Example usage: 1. Simple event listener function: -- addEHandler(window, 'load', function() { addEHandler(document.body, 'click', function(evt) { alert('Event type: ' + evt.type); }); }); -- 2. Event listener object using context wrapper: -- function MyClass() { this.name = 'MyClass'; addEHandler(document.body, 'click', EventContextWrapper.create( this, { $callback: function(evt) { alert('Event type: ' + evt.type + '; Context: ' + this.$context.name); } } )); } addEHandler(window, 'load', function() { var myobj = new MyClass(); }); -- 3. Event listener object with property baggage: -- function MyClass() { this.name = 'MyClass'; addEHandler(document.body, 'click', EventContextWrapper.create( this, { $callback: function(evt) { alert('Event type: ' + evt.type + '; Context: ' + this.$context.name); for (var key in this.$props) alert('Property "' + key + '": "' + this.$props[key] + '"'); }, }, { fruit: 'Banana', vegetable: 'Carrot' } )); } addEHandler(window, 'load', function() { var myobj = new MyClass(); }); -- */ if (typeof(EventListener) != 'undefined') { var addEHandler = function(obj, event_name, handler) { obj.addEventListener(event_name, handler, false); }; var removeEHandler = function(obj, event_name, handler) { obj.removeEventListener(event_name, handler, false); }; } else if (typeof(attachEvent) != 'undefined') { var addEHandler = function(obj, event_name, handler) { obj.attachEvent('on' + event_name, handler); }; var removeEHandler = function(obj, event_name, handler) { obj.detachEvent('on' + event_name, handler); }; } function EventContextWrapper() {}; EventContextWrapper.prototype = { handleEvent: function(evt) // implements DOM::EventListener::handleEvent { this.callback(evt); }, invoke_event: function(evt) { this.handleEvent(evt); } }; EventContextWrapper.create = function(p_contextobj, p_interface, props) { if (typeof(EventListener) != 'undefined') var wrapper = new EventContextWrapper(); else if (typeof(window.attachEvent) != 'undefined') { var wrapper = function(evt) { arguments.callee.callback(evt); }; wrapper.invoke_event = function(evt) { this(evt); }; } wrapper.$context = p_contextobj; wrapper.$props = props != undefined && props instanceof Object ? props : null; wrapper.callback = p_interface.$callback; return wrapper; };