Rename Array.from to Array.convert, keep as is in compat layer
[mootools.git] / Source / Element / Element.Event.js
blob919a8d4a384c2fbc5ee23f1536127aa03e38a2ba
1 /*
2 ---
4 name: Element.Event
6 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
8 license: MIT-style license.
10 requires: [Element, Event]
12 provides: Element.Event
14 ...
17 (function(){
19 Element.Properties.events = {set: function(events){
20         this.addEvents(events);
21 }};
23 [Element, Window, Document].invoke('implement', {
25         addEvent: function(type, fn){
26                 var events = this.retrieve('events', {});
27                 if (!events[type]) events[type] = {keys: [], values: []};
28                 if (events[type].keys.contains(fn)) return this;
29                 events[type].keys.push(fn);
30                 var realType = type,
31                         custom = Element.Events[type],
32                         condition = fn,
33                         self = this;
34                 if (custom){
35                         if (custom.onAdd) custom.onAdd.call(this, fn, type);
36                         if (custom.condition){
37                                 condition = function(event){
38                                         if (custom.condition.call(this, event, type)) return fn.call(this, event);
39                                         return true;
40                                 };
41                         }
42                         if (custom.base) realType = Function.from(custom.base).call(this, type);
43                 }
44                 var defn = function(){
45                         return fn.call(self);
46                 };
47                 var nativeEvent = Element.NativeEvents[realType];
48                 if (nativeEvent){
49                         if (nativeEvent == 2){
50                                 defn = function(event){
51                                         event = new DOMEvent(event, self.getWindow());
52                                         if (condition.call(self, event) === false) event.stop();
53                                 };
54                         }
55                         this.addListener(realType, defn, arguments[2]);
56                 }
57                 events[type].values.push(defn);
58                 return this;
59         },
61         removeEvent: function(type, fn){
62                 var events = this.retrieve('events');
63                 if (!events || !events[type]) return this;
64                 var list = events[type];
65                 var index = list.keys.indexOf(fn);
66                 if (index == -1) return this;
67                 var value = list.values[index];
68                 delete list.keys[index];
69                 delete list.values[index];
70                 var custom = Element.Events[type];
71                 if (custom){
72                         if (custom.onRemove) custom.onRemove.call(this, fn, type);
73                         if (custom.base) type = Function.from(custom.base).call(this, type);
74                 }
75                 return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
76         },
78         addEvents: function(events){
79                 for (var event in events) this.addEvent(event, events[event]);
80                 return this;
81         },
83         removeEvents: function(events){
84                 var type;
85                 if (typeOf(events) == 'object'){
86                         for (type in events) this.removeEvent(type, events[type]);
87                         return this;
88                 }
89                 var attached = this.retrieve('events');
90                 if (!attached) return this;
91                 if (!events){
92                         for (type in attached) this.removeEvents(type);
93                         this.eliminate('events');
94                 } else if (attached[events]){
95                         attached[events].keys.each(function(fn){
96                                 this.removeEvent(events, fn);
97                         }, this);
98                         delete attached[events];
99                 }
100                 return this;
101         },
103         fireEvent: function(type, args, delay){
104                 var events = this.retrieve('events');
105                 if (!events || !events[type]) return this;
106                 args = Array.convert(args);
108                 events[type].keys.each(function(fn){
109                         if (delay) fn.delay(delay, this, args);
110                         else fn.apply(this, args);
111                 }, this);
112                 return this;
113         },
115         cloneEvents: function(from, type){
116                 from = document.id(from);
117                 var events = from.retrieve('events');
118                 if (!events) return this;
119                 if (!type){
120                         for (var eventType in events) this.cloneEvents(from, eventType);
121                 } else if (events[type]){
122                         events[type].keys.each(function(fn){
123                                 this.addEvent(type, fn);
124                         }, this);
125                 }
126                 return this;
127         }
131 Element.NativeEvents = {
132         click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
133         wheel: 2, mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
134         mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
135         keydown: 2, keypress: 2, keyup: 2, //keyboard
136         orientationchange: 2, // mobile
137         touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
138         gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
139         focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
140         load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
141         hashchange: 1, popstate: 2, pageshow: 2, pagehide: 2, // history
142         error: 1, abort: 1, scroll: 1, message: 2 //misc
145 Element.Events = {
146         mousewheel: {
147                 base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll'
148         }
151 var check = function(event){
152         var related = event.relatedTarget;
153         if (related == null) return true;
154         if (!related) return false;
155         return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
158 if ('onmouseenter' in document.documentElement){
159         Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
160         Element.MouseenterCheck = check;
161 } else {
162         Element.Events.mouseenter = {
163                 base: 'mouseover',
164                 condition: check
165         };
167         Element.Events.mouseleave = {
168                 base: 'mouseout',
169                 condition: check
170         };
173 /*<ltIE9>*/
174 if (!window.addEventListener){
175         Element.NativeEvents.propertychange = 2;
176         Element.Events.change = {
177                 base: function(){
178                         var type = this.type;
179                         return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change';
180                 },
181                 condition: function(event){
182                         return event.type != 'propertychange' || event.event.propertyName == 'checked';
183                 }
184         };
186 /*</ltIE9>*/
188 //<1.2compat>
190 Element.Events = new Hash(Element.Events);
192 //</1.2compat>
194 })();