if (typeof IS != 'object') { alert('Il faut insérer browser.js avant events.js'); }
EVT = { };
EVT.is_ie = IS.ie();
EVT._eventFlushers = [ ];
EVT.flushEvents = function()
{
  var x = 0;
  var e = null;
  while(e = EVT._eventFlushers.pop())
  {
    try
    {
      if(e.length == 3)
      {
        EVT.removeEvent(e[0], e[1], e[2]);
        x++;
      }
      else if (e.length == 2)
      {
        e[0]['on' + e[1]] = null;
        e[0].__dom0Events[e[1]] = null;
        x++;
      }
    }
    catch(e)
    {
      // Do Nothing
    }
  }
  // alert('Flushed ' + x + ' events.');
};

EVT._addEvent = function(el, evname, func) {
  if (EVT.is_ie) {
    el.attachEvent("on" + evname, func);
  } else {
    el.addEventListener(evname, func, true);
  }
  EVT._eventFlushers.push([el, evname, func]);
};

EVT._addEvents = function(el, evs, func) {
  for (var i = evs.length; --i >= 0;) {
    EVT._addEvent(el, evs[i], func);
  }
};

EVT._removeEvent = function(el, evname, func) {
  if (EVT.is_ie) {
    el.detachEvent("on" + evname, func);
  } else {
    el.removeEventListener(evname, func, true);
  }
};

EVT._removeEvents = function(el, evs, func) {
  for (var i = evs.length; --i >= 0;) {
    EVT._removeEvent(el, evs[i], func);
  }
};

EVT._stopEvent = function(ev) {
  if (EVT.is_ie) {
    try{
      ev.cancelBubble = true;
      ev.returnValue = false;
    } catch(e){}
  } else {
    ev.preventDefault();
    ev.stopPropagation();
  }
};

/**
 * Adds a standard "DOM-0" event listener to an element.
 * The DOM-0 events are those applied directly as attributes to
 * an element - eg element.onclick = stuff;
 *
 * By using this function instead of simply overwriting any existing
 * DOM-0 event by the same name on the element it will trigger as well
 * as the existing ones.  Handlers are triggered one after the other
 * in the order they are added.
 *
 * Remember to return true/false from your handler, this will determine
 * whether subsequent handlers will be triggered (ie that the event will
 * continue or be canceled).
 *
 */
EVT.addDom0Event = function(el, ev, fn)
{
  EVT._prepareForDom0Events(el, ev);
  el.__dom0Events[ev].unshift(fn);
};


/**
 * See addDom0Event, the difference is that handlers registered using
 * prependDom0Event will be triggered before existing DOM-0 events of the
 * same name on the same element.
 */
EVT.prependDom0Event = function(el, ev, fn)
{
  EVT._prepareForDom0Events(el, ev);
  el.__dom0Events[ev].push(fn);
};

/**
 * Prepares an element to receive more than one DOM-0 event handler
 * when handlers are added via addDom0Event and prependDom0Event.
 */
EVT._prepareForDom0Events = function(el, ev)
{
  // Create a structure to hold our lists of event handlers
  if(typeof el.__dom0Events == 'undefined')
  {
    el.__dom0Events = { };
    EVT.freeLater(el, '__dom0Events');
  }

  // Create a list of handlers for this event type
  if(typeof el.__dom0Events[ev] == 'undefined')
  {
    el.__dom0Events[ev] = [ ];
    if(typeof el['on'+ev] == 'function')
    {
      el.__dom0Events[ev].push(el['on'+ev]);
    }

    // Make the actual event handler, which runs through
    // each of the handlers in the list and executes them
    // in the correct context.
    el['on'+ev] = function(event)
    {
      var a = el.__dom0Events[ev];
      // call previous submit methods if they were there.
      var allOK = true;
      for (var i = a.length; --i >= 0;)
      {
        // We want the handler to be a member of the form, not the array, so that "this" will work correctly
        el.__tempEventHandler = a[i];
        if(el.__tempEventHandler(event) === false)
        {
          el.__tempEventHandler = null;
          allOK = false;
          break;
        }
        el.__tempEventHandler = null;
      }
      return allOK;
    };

    EVT._eventFlushers.push([el, ev]);
  }
};

EVT.toFree = [ ];
EVT.freeLater = function(obj,prop)
{
  EVT.toFree.push({o:obj,p:prop});
};

EVT.free = function(obj, prop)
{
  if(obj && !prop)
  {
    for(var p in obj)
    {
      EVT.free(obj, p);
    }
  }
  else if (obj)
  {
    try{ obj[prop] = null; } catch(e){ }
  }
};

/** IE's Garbage Collector is broken very badly.  We will do our best to
 *   do it's job for it, but we can't be perfect.
 */
EVT.collectGarbageForIE = function()
{
  EVT.flushEvents();
  for (var x = 0; x < EVT.toFree.length; x++)
  {
    if(!EVT.toFree[x].o) { alert("What is " + x + ' ' + EVT.toFree[x].o); }
    EVT.free(EVT.toFree[x].o, EVT.toFree[x].p);
  }
};

/* compatibilité avec anciennes versions, a DEPRECATED, utiliser plutot la syntaxe EVT.methode(); } */
//_flushAllEvents = function() { EVT.flushEvents(); };
//_addEvent = function(el, evname, func) { EVT._addEvent(el, evname, func); };
//_addEvents = function(el, evs, func) { EVT._addEvents(el, evs, func); };
//_removeEvent = function(el, evname, func) { EVT._removeEvent(el, evname, func); };
//_removeEvents = function(el, evs, func) { EVT._removeEvents(el, evs, func); };
//_stopEvent = function(ev) { EVT._stopEvent(ev); };
//_addDom0Event = function(el, ev, fn) { EVT.addDom0Event(el, ev, fn); };
//_prependDom0Event = function(el, ev, fn) { EVT.prependDom0Event(el, ev, fn); };
//_prepareForDom0Events = function(el, ev) { EVT._prepareForDom0Events(el, ev); };
//freeLater = function(obj,prop) { EVT.freeLater(obj, prop); };
//free = function(obj, prop) { EVT.free(obj, prop); };
//IE_GarbageCollector = function() { EVT.collectGarbageForIE(); };

/* garbage collector est lancé sur le onunload */
// EVT.addDom0Event(window,'unload', EVT.collectGarbageForIE);