a4422502577ca7f5e0c931699e3f29f1b0112589
[Plinn.git] / skins / ajax_scripts / javascript_events_api.js
1 // (c) BenoƮt PIN 2006-2009
2 // http://plinn.org
3 // Licence GPL
4 //
5 //
6 // Meta functions for events management.
7
8 var addListener; /* (ob, eventName, listenerFunction, group) add event listener eventName without "on" prefix.
9 * optionally, listeners can be grouped to make removing convenient.
10 */
11 var removeListener; // (ob, eventName, listenerFunction, group) remove event listener.
12 var removeGroupListeners; // (group) remove all listeners in group.
13 var raiseMouseEvent; // (ob, eventName) raise mouse event (without "on" prefix) on object.
14
15 var getTargetedObject; // (event) retrieves the object that fired the event. Event parameter is optional.
16 var getEventObject; // (event) return the event object. Event parameter is optional.
17 var disableDefault; // (event) disable default event's action. Event parameter is optional.
18 var disablePropagation; // (event) disable event propagation or bubbling.
19
20 // etc utils
21 var getWindowWidth; // returns browser's window width
22 var getWindowHeight; // returns browser's window height
23 var clearSelection; // clear current selection (useful on drag and drop)
24 var getCopyOfNode; /* (node) returns a clone of the given node.
25 * Useful when :
26 * the node came from a foreign document (eg. XmlHttpRequest xml reponse)
27 * to inject HMTL code inside tags where innerHtml is read only (IE)
28 */
29
30 var copyPrototype; // (descendant, parent) lightwheight javascript inheritance
31 if (!history.pushState) {
32 history.pushState = function(){};
33 }
34
35 (function(){
36
37 function buildMetaFunctions() {
38 addListener = _build_addListener();
39 removeListener = _build_removeListener();
40 raiseMouseEvent = _build_raiseMouseEvent();
41
42 getTargetedObject = _build_getTargetedObject();
43 getEventObject = _build_getEventObject();
44 disableDefault = _build_disableDefault();
45 disablePropagation = _build_disablePropagation();
46 getWindowWidth = _build_getWindowWidth();
47 getWindowHeight = _build_getWindowHeight();
48 clearSelection = _build_clearSelection();
49 }
50
51 var __groupListeners = {};
52
53 function _build_addListener() {
54 var _browserSpecific;
55 if (!browser.isDOM2Event) {
56 _browserSpecific = function(ob, eventName, listenerFunction) {
57 eventName = "on" + eventName;
58 ob.attachEvent(eventName, listenerFunction);
59 };
60 }
61 else {
62 _browserSpecific = function(ob, eventName, listenerFunction) {
63 ob.addEventListener(eventName, listenerFunction, false); // only bubbling events :-(
64 };
65 }
66 var common = function(ob, eventName, listenerFunction, group) {
67 _browserSpecific(ob, eventName, listenerFunction);
68 if (group) {
69 if(!__groupListeners[group]) {
70 __groupListeners[group] = [];}
71 __groupListeners[group].push([ob, eventName, listenerFunction]);
72 }
73 };
74 return common;
75 }
76
77 function _build_removeListener() {
78 if (!browser.isDOM2Event) {
79 var _ie_removeListener = function(ob, eventName, listenerFunction) {
80 eventName = "on" + eventName;
81 ob.detachEvent(eventName, listenerFunction);
82 };
83 return _ie_removeListener;
84 }
85 else {
86 var _dom2_removeListener = function(ob, eventName, listenerFunction) {
87 ob.removeEventListener(eventName, listenerFunction, false); // only bubbling events :-(
88 };
89 return _dom2_removeListener;
90 }
91 }
92
93 removeGroupListeners = function(group) {
94 var listeners = __groupListeners[group];
95 var l, i;
96 for (i=0 ; i<listeners.length ; i++){
97 l = listeners[i];
98 removeListener(l[0], l[1], l[2]);
99 }
100 __groupListeners[group] = null;
101
102 };
103
104 function _build_raiseMouseEvent() {
105 if (!browser.isDOM2Event) {
106 var _ie_raiseMouseEvent = function(ob, eventName) {
107 ob.fireEvent("on" + eventName);
108 };
109 return _ie_raiseMouseEvent;
110 }
111 else {
112 var _dom2_raiseMouseEvent = function(ob, eventName) {
113 var event = document.createEvent("MouseEvents");
114 event.initEvent(eventName, true, true);
115 ob.dispatchEvent(event);
116 };
117 return _dom2_raiseMouseEvent;
118 }
119 }
120
121 function _build_getTargetedObject(){
122 if (!browser.isDOM2Event) {
123 var _ie_getTargetedObject = function() {
124 return window.event.srcElement;
125 };
126 return _ie_getTargetedObject;
127 }
128 else {
129 var _appleWebKit_getTargetedeObject = function(evt) {
130 var target = evt.target;
131 // is it really safe ?...
132 return (target.nodeType === 3) ? target.parentNode : target;
133 };
134 var _dom2_getTargetedObject = function(evt) {
135 return evt.target;
136 };
137 return (browser.isAppleWebKit) ? _appleWebKit_getTargetedeObject : _dom2_getTargetedObject;
138 }
139 }
140
141 function _build_getEventObject(){
142 if (!browser.isDOM2Event) {
143 var _ie_getEventObject = function() {
144 return window.event;
145 };
146 return _ie_getEventObject;
147 }
148 else {
149 var _dom2_getEventObject = function(evt) {
150 return evt;
151 };
152 return _dom2_getEventObject;
153 }
154 }
155
156
157 function _build_disableDefault(){
158 if (!browser.isDOM2Event) {
159 var _ie_disableDefault = function() {
160 window.event.returnValue = false;
161 };
162 return _ie_disableDefault;
163 }
164 else {
165 var _dom2_disableDefault = function(evt) {
166 evt.preventDefault();
167 };
168 return _dom2_disableDefault;
169 }
170 }
171
172 function _build_disablePropagation() {
173 if (!browser.isDOM2Event) {
174 var _ie_disablePropagation = function() {
175 window.event.cancelBubble = true;
176 };
177 return _ie_disablePropagation;
178 }
179 else {
180 var _dom2_disablePropagation = function(evt) {
181 evt.stopPropagation();
182 };
183 return _dom2_disablePropagation;
184 }
185 }
186
187 function _build_getWindowWidth() {
188 if (window.innerWidth !== undefined){
189 return function(){
190 return window.innerWidth;
191 };
192 }
193 else {
194 return function(){
195 return document.documentElement.clientWidth;
196 };
197 }
198 }
199
200 function _build_getWindowHeight() {
201 if (window.innerHeight !== undefined) {
202 return function(){
203 return window.innerHeight;
204 };
205 }
206 else {
207 return function(){
208 return document.documentElement.clientHeight;
209 };
210 }
211 }
212
213 function _build_clearSelection() {
214 if (document.selection) {
215 return function() {
216 document.selection.clear();
217 };
218 }
219 else {
220 return function() {
221 window.getSelection().removeAllRanges();
222 };
223 }
224 }
225
226 buildMetaFunctions();
227
228 addListener(window, 'load', function(evt) {
229 // html5 facade
230 if (!document.body.classList) {
231 var nop = function(){};
232 var fakeDOMTokenList = {'length':0, 'item':nop, 'contains':nop, 'add':nop, 'remove':nop, 'toggle':nop};
233 Element.prototype.classList = fakeDOMTokenList;
234 }
235 });
236
237
238
239 var ELEMENT_NODE = 1;
240 var TEXT_NODE = 3;
241 var _setAttribute;
242 getCopyOfNode = function(node) {
243
244 switch(node.nodeType) {
245 case ELEMENT_NODE:
246 var attributes = node.attributes;
247 var childs = node.childNodes;
248
249 var e = document.createElement(node.nodeName);
250
251 var attribute, i;
252 for(i=0 ; i<attributes.length ; i++) {
253 attribute = attributes[i];
254 _setAttribute(e, attribute.name, attribute.value);
255 }
256
257 for(i=0 ; i<childs.length ; i++) {
258 e.appendChild(getCopyOfNode(childs[i]));}
259
260 return e;
261
262 case TEXT_NODE:
263 return document.createTextNode(node.nodeValue);
264 }
265 };
266
267 if (browser.isIE) {
268 _setAttribute = function(e, name, value) {
269 // workarround IE lack of dom implementation.
270 switch(name.toLowerCase()) {
271 case 'colspan' :
272 e.colSpan = value;
273 break;
274 case 'class' :
275 e.className = value;
276 break;
277 case 'style' :
278 loadCssText(e, value);
279 break;
280 default:
281 if (name.slice(0,2) === 'on') { // event handler
282 // A browser normaly eval text code attached to a onXyz attribute. Not IE.
283 /*jslint evil: true */
284 e[name] = function(){eval(value);};}
285 else {
286 e.setAttribute(name, value);}
287 }
288 };
289 var reCompoundPropName = /^\s*([^\-]+)\-([a-z])([a-z]+)\s*$/;
290 var _capitalizeCssPropName = function (s, g1, g2, g3) { // gN args match above regexp groups
291 if(g2) {
292 return g1 + g2.toUpperCase() + g3;}
293 else {
294 return s;}
295 };
296
297 var loadCssText = function (e, cssText) {
298 var pairs = cssText.split(';');
299 var pair, name, value, i;
300 var style = e.style;
301 for (i= 0; i < pairs.length; i++) {
302 pair = pairs[i].split(':');
303 if (pair.length === 2) {
304 name = _capitalizeCssPropName(pair[0]);
305 value = pair[1];
306 style[name] = value;
307 }
308 }
309 };
310 }
311 else {
312 _setAttribute = function(e, name, value) {e.setAttribute(name, value);};
313 }
314
315 /*
316 * http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/
317 */
318
319 copyPrototype = function (descendant, parent) {
320 var sConstructor = parent.toString();
321 var aMatch = sConstructor.match( /\s*function (.*)\(/ );
322 if ( aMatch !== null ) { descendant.prototype[aMatch[1]] = parent; }
323 var m;
324 for (m in parent.prototype) {
325 if (parent.prototype.hasOwnProperty(m)) {
326 descendant.prototype[m] = parent.prototype[m]; }
327 }
328 };
329
330 }());