/*
  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;
};
