//Element¼setteraddEventsĿݷʽ

Element.Properties.events = {set: function(events){

 this.addEvents(events);

}};


//ElementWindow  Document¼չ

Native.implement([Element, Window, Document], {


 //¼бaddListenerʹԶ¼

 addEvent: function(type, fn){
  //ȡʱעṩĬֵ

  var events = this.retrieve('events', {});
  //ָ͵¼б

  events[type] = events[type] || {'keys': [], 'values': []};
  //Ѿ˸ü

  if (events[type].keys.contains(fn)) return this;
  //ӵ¼б

  events[type].keys.push(fn);

  var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
  //Զ¼

  if (custom){
   //Զ¼
ʱĴ
   if (custom.onAdd) custom.onAdd.call(this, fn);
   //Զ¼

   if (custom.condition){

    condition = function(event){

     if (custom.condition.call(this, event)) return fn.call(this, event);

     return false;

    };

   }

   realType = custom.base || realType;

  }

  var defn = function(){

   return fn.call(self);

  };
  //¼ʹ

  var nativeEvent = Element.NativeEvents[realType] || 0;
  //õ¼

  if (nativeEvent){
   //ǽ¼

   if (nativeEvent == 2){
    //հ

    defn = function(event){
     //󴫸ĲǾװEvent

     event = new Event(event, self.getWindow());
     //չ¼

     if (condition.call(self, event) === false) event.stop();

    };

   }
   //ջǵaddListener

   this.addListener(realType, defn);

  }
  //ӵб

  events[type].values.push(defn);

  return this;

 },


 //Ƴ¼

 removeEvent: function(type, fn){

  //ȡʱ󣬲ṩĬֵ
  var events = this.retrieve('events');

  //ʱ󲻴ڣ˵ڣֱӷ
  if (!events || !events[type]) return this;

  //Ƿӱ
  var pos = events[type].keys.indexOf(fn);

  //û򷵻
  if (pos == -1) return this;
  

  //ӶƳ
  var key = events[type].keys.splice(pos, 1)[0];

  var value = events[type].values.splice(pos, 1)[0];

  //Զ¼

  var custom = Element.Events.get(type);

  //Զ¼

  if (custom){
   //Զ¼Ƴ

   if (custom.onRemove) custom.onRemove.call(this, fn);

   type = custom.base || type;

  }
  //¼ҪremoveListener

  return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;

 },


 //¼

 addEvents: function(events){

  for (var event in events) this.addEvent(event, events[event]);

  return this;

 },

 

 //Ƴ¼

 removeEvents: function(type){

  //ȡʱ󣬲ṩĬֵ
  var events = this.retrieve('events');
  //û¼ֱӷ

  if (!events) return this;
  //ṩtypeƳ͵¼

  if (!type){

   for (var evType in events) this.removeEvents(evType);

   events = null;

  } else if (events[type]){
   //Ƴָ͵¼

   while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);

   events[type] = null;

  }

  return this;

 },

 

 //¼
֪ͨ
 fireEvent: function(type, args, delay){

  //ȡʱ󣬲ṩĬֵ
  var events = this.retrieve('events');
  //û¼

  if (!events || !events[type]) return this;

  events[type].keys.each(function(fn){
   //ע¼ĺthisĬ
ָǰElement
   fn.create({'bind': this, 'delay': delay, 'arguments': args})();

  }, this);

  return this;

 },

 

 //¼

 cloneEvents: function(from, type){
  //¼
Դ
  from = $(from);

  var fevents = from.retrieve('events');

  if (!fevents) return this;
  //ṩtype¼

  if (!type){

   for (var evType in fevents) this.cloneEvents(from, evType);

  } else if (fevents[type]){
   //ָ͵¼

   fevents[type].keys.each(function(fn){

    this.addEvent(type, fn);

   }, this);

  }

  return this;

 }

 

});


//¼

Element.NativeEvents = {

 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons

 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel

 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement

 keydown: 2, keypress: 2, keyup: 2, //keyboard

 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements

 load: 1, unload: 1, beforeunload: 1, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window

 error: 1, abort: 1, scroll: 1 //misc

};


//͵ִе

(function(){

 

var $check = function(event){

 var related = event.relatedTarget;

 if (related == undefined) return true;

 if (related === false) return false;

 return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));

};


//ԭ¼չԶ¼

Element.Events = new Hash({


 //¼

 mouseenter: {

  base: 'mouseover',

  condition: $check

 },

 

 //뿪¼

 mouseleave: {

  base: 'mouseout',

  condition: $check

 },

 

 //¼

 mousewheel: {

  base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'

 }

 

});

 

})();

