commit extjs-2.2.1
[extjs.git] / source / adapter / jquery-bridge.js
1 /*\r
2  * Ext JS Library 2.2.1\r
3  * Copyright(c) 2006-2009, Ext JS, LLC.\r
4  * licensing@extjs.com\r
5  * \r
6  * http://extjs.com/license\r
7  */\r
8 \r
9 if(typeof jQuery == "undefined"){\r
10     throw "Unable to load Ext, jQuery not found.";\r
11 }\r
12 \r
13 (function(){\r
14 var libFlyweight;\r
15 \r
16 Ext.lib.Dom = {\r
17     getViewWidth : function(full){\r
18         // jQuery doesn't report full window size on document query, so max both\r
19         return full ? Math.max(jQuery(document).width(),jQuery(window).width()) : jQuery(window).width();\r
20     },\r
21 \r
22     getViewHeight : function(full){\r
23         // jQuery doesn't report full window size on document query, so max both\r
24         return full ? Math.max(jQuery(document).height(),jQuery(window).height()) : jQuery(window).height();\r
25     },\r
26 \r
27     isAncestor : function(p, c){\r
28         p = Ext.getDom(p);\r
29         c = Ext.getDom(c);\r
30         if (!p || !c) {return false;}\r
31 \r
32         if(p.contains && !Ext.isSafari) {\r
33             return p.contains(c);\r
34         }else if(p.compareDocumentPosition) {\r
35             return !!(p.compareDocumentPosition(c) & 16);\r
36         }else{\r
37             var parent = c.parentNode;\r
38             while (parent) {\r
39                 if (parent == p) {\r
40                     return true;\r
41                 }\r
42                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {\r
43                     return false;\r
44                 }\r
45                 parent = parent.parentNode;\r
46             }\r
47             return false;\r
48         }\r
49     },\r
50 \r
51     getRegion : function(el){\r
52         return Ext.lib.Region.getRegion(el);\r
53     },\r
54 \r
55     //////////////////////////////////////////////////////////////////////////////////////\r
56     // Use of jQuery.offset() removed to promote consistent behavior across libs.\r
57     // JVS 05/23/07\r
58     //////////////////////////////////////////////////////////////////////////////////////\r
59 \r
60     getY : function(el){\r
61         return this.getXY(el)[1];\r
62     },\r
63 \r
64     getX : function(el){\r
65         return this.getXY(el)[0];\r
66     },\r
67 \r
68     getXY : function(el) {\r
69         var p, pe, b, scroll, bd = (document.body || document.documentElement);\r
70         el = Ext.getDom(el);\r
71 \r
72         if(el == bd){\r
73             return [0, 0];\r
74         }\r
75 \r
76         if (el.getBoundingClientRect) {\r
77             b = el.getBoundingClientRect();\r
78             scroll = fly(document).getScroll();\r
79             return [b.left + scroll.left, b.top + scroll.top];\r
80         }\r
81         var x = 0, y = 0;\r
82 \r
83         p = el;\r
84 \r
85         var hasAbsolute = fly(el).getStyle("position") == "absolute";\r
86 \r
87         while (p) {\r
88 \r
89             x += p.offsetLeft;\r
90             y += p.offsetTop;\r
91 \r
92             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {\r
93                 hasAbsolute = true;\r
94             }\r
95 \r
96             if (Ext.isGecko) {\r
97                 pe = fly(p);\r
98 \r
99                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;\r
100                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;\r
101 \r
102 \r
103                 x += bl;\r
104                 y += bt;\r
105 \r
106 \r
107                 if (p != el && pe.getStyle('overflow') != 'visible') {\r
108                     x += bl;\r
109                     y += bt;\r
110                 }\r
111             }\r
112             p = p.offsetParent;\r
113         }\r
114 \r
115         if (Ext.isSafari && hasAbsolute) {\r
116             x -= bd.offsetLeft;\r
117             y -= bd.offsetTop;\r
118         }\r
119 \r
120         if (Ext.isGecko && !hasAbsolute) {\r
121             var dbd = fly(bd);\r
122             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;\r
123             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;\r
124         }\r
125 \r
126         p = el.parentNode;\r
127         while (p && p != bd) {\r
128             if (!Ext.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {\r
129                 x -= p.scrollLeft;\r
130                 y -= p.scrollTop;\r
131             }\r
132             p = p.parentNode;\r
133         }\r
134         return [x, y];\r
135     },\r
136 \r
137     setXY : function(el, xy){\r
138         el = Ext.fly(el, '_setXY');\r
139         el.position();\r
140         var pts = el.translatePoints(xy);\r
141         if(xy[0] !== false){\r
142             el.dom.style.left = pts.left + "px";\r
143         }\r
144         if(xy[1] !== false){\r
145             el.dom.style.top = pts.top + "px";\r
146         }\r
147     },\r
148 \r
149     setX : function(el, x){\r
150         this.setXY(el, [x, false]);\r
151     },\r
152 \r
153     setY : function(el, y){\r
154         this.setXY(el, [false, y]);\r
155     }\r
156 };\r
157 \r
158 // all lib flyweight calls use their own flyweight to prevent collisions with developer flyweights\r
159 function fly(el){\r
160     if(!libFlyweight){\r
161         libFlyweight = new Ext.Element.Flyweight();\r
162     }\r
163     libFlyweight.dom = el;\r
164     return libFlyweight;\r
165 }\r
166 Ext.lib.Event = {\r
167     getPageX : function(e){\r
168         e = e.browserEvent || e;\r
169         return e.pageX;\r
170     },\r
171 \r
172     getPageY : function(e){\r
173         e = e.browserEvent || e;\r
174         return e.pageY;\r
175     },\r
176 \r
177     getXY : function(e){\r
178         e = e.browserEvent || e;\r
179         return [e.pageX, e.pageY];\r
180     },\r
181 \r
182     getTarget : function(e){\r
183         return e.target;\r
184     },\r
185 \r
186     // all Ext events will go through event manager which provides scoping\r
187     on : function(el, eventName, fn, scope, override){\r
188         jQuery(el).bind(eventName, fn);\r
189     },\r
190 \r
191     un : function(el, eventName, fn){\r
192         jQuery(el).unbind(eventName, fn);\r
193     },\r
194 \r
195     purgeElement : function(el){\r
196         jQuery(el).unbind();\r
197     },\r
198 \r
199     preventDefault : function(e){\r
200         e = e.browserEvent || e;\r
201         if(e.preventDefault){\r
202             e.preventDefault();\r
203         }else{\r
204             e.returnValue = false;\r
205         }\r
206     },\r
207 \r
208     stopPropagation : function(e){\r
209         e = e.browserEvent || e;\r
210         if(e.stopPropagation){\r
211             e.stopPropagation();\r
212         }else{\r
213             e.cancelBubble = true;\r
214         }\r
215     },\r
216 \r
217     stopEvent : function(e){\r
218         this.preventDefault(e);\r
219         this.stopPropagation(e);\r
220     },\r
221 \r
222     onAvailable : function(id, fn, scope){\r
223         var start = new Date();\r
224         var f = function(){\r
225             if(start.getElapsed() > 10000){\r
226                 clearInterval(iid);\r
227             }\r
228             var el = document.getElementById(id);\r
229             if(el){\r
230                 clearInterval(iid);\r
231                 fn.call(scope||window, el);\r
232             }\r
233         };\r
234         var iid = setInterval(f, 50);\r
235     },\r
236 \r
237     resolveTextNode: function(node) {\r
238         if (node && 3 == node.nodeType) {\r
239             return node.parentNode;\r
240         } else {\r
241             return node;\r
242         }\r
243     },\r
244 \r
245     getRelatedTarget: function(ev) {\r
246         ev = ev.browserEvent || ev;\r
247         var t = ev.relatedTarget;\r
248         if (!t) {\r
249             if (ev.type == "mouseout") {\r
250                 t = ev.toElement;\r
251             } else if (ev.type == "mouseover") {\r
252                 t = ev.fromElement;\r
253             }\r
254         }\r
255 \r
256         return this.resolveTextNode(t);\r
257     }\r
258 };\r
259 \r
260 Ext.lib.Ajax = function(){\r
261     var createComplete = function(cb){\r
262          return function(xhr, status){\r
263             if((status == 'error' || status == 'timeout') && cb.failure){\r
264                 cb.failure.call(cb.scope||window, {\r
265                     responseText: xhr.responseText,\r
266                     responseXML : xhr.responseXML,\r
267                     argument: cb.argument\r
268                 });\r
269             }else if(cb.success){\r
270                 cb.success.call(cb.scope||window, {\r
271                     responseText: xhr.responseText,\r
272                     responseXML : xhr.responseXML,\r
273                     argument: cb.argument\r
274                 });\r
275             }\r
276          };\r
277     };\r
278     return {\r
279         request : function(method, uri, cb, data, options){\r
280             var o = {\r
281                 type: method,\r
282                 url: uri,\r
283                 data: data,\r
284                 timeout: cb.timeout,\r
285                 complete: createComplete(cb)\r
286             };\r
287 \r
288             if(options){\r
289                 var hs = options.headers;\r
290                 if(options.xmlData){\r
291                     o.data = options.xmlData;\r
292                     o.processData = false;\r
293                     o.type = (method ? method : (options.method ? options.method : 'POST'));\r
294                     if (!hs || !hs['Content-Type']){\r
295                         o.contentType = 'text/xml';\r
296                     }\r
297                 }else if(options.jsonData){\r
298                     o.data = typeof options.jsonData == 'object' ? Ext.encode(options.jsonData) : options.jsonData;\r
299                     o.processData = false;\r
300                     o.type = (method ? method : (options.method ? options.method : 'POST'));\r
301                     if (!hs || !hs['Content-Type']){\r
302                         o.contentType = 'application/json';\r
303                     }\r
304                 }\r
305                 if(hs){\r
306                     o.beforeSend = function(xhr){\r
307                         for(var h in hs){\r
308                             if(hs.hasOwnProperty(h)){\r
309                                 xhr.setRequestHeader(h, hs[h]);\r
310                             }\r
311                         }\r
312                     }\r
313                 }\r
314             }\r
315             jQuery.ajax(o);\r
316         },\r
317 \r
318         formRequest : function(form, uri, cb, data, isUpload, sslUri){\r
319             jQuery.ajax({\r
320                 type: Ext.getDom(form).method ||'POST',\r
321                 url: uri,\r
322                 data: jQuery(form).serialize()+(data?'&'+data:''),\r
323                 timeout: cb.timeout,\r
324                 complete: createComplete(cb)\r
325             });\r
326         },\r
327 \r
328         isCallInProgress : function(trans){\r
329             return false;\r
330         },\r
331 \r
332         abort : function(trans){\r
333             return false;\r
334         },\r
335 \r
336         serializeForm : function(form){\r
337             return jQuery(form.dom||form).serialize();\r
338         }\r
339     };\r
340 }();\r
341 \r
342 Ext.lib.Anim = function(){\r
343     var createAnim = function(cb, scope){\r
344         var animated = true;\r
345         return {\r
346             stop : function(skipToLast){\r
347                 // do nothing\r
348             },\r
349 \r
350             isAnimated : function(){\r
351                 return animated;\r
352             },\r
353 \r
354             proxyCallback : function(){\r
355                 animated = false;\r
356                 Ext.callback(cb, scope);\r
357             }\r
358         };\r
359     };\r
360     return {\r
361         scroll : function(el, args, duration, easing, cb, scope){\r
362             // scroll anim not supported so just scroll immediately\r
363             var anim = createAnim(cb, scope);\r
364             el = Ext.getDom(el);\r
365             if(typeof args.scroll.to[0] == 'number'){\r
366                 el.scrollLeft = args.scroll.to[0];\r
367             }\r
368             if(typeof args.scroll.to[1] == 'number'){\r
369                 el.scrollTop = args.scroll.to[1];\r
370             }\r
371             anim.proxyCallback();\r
372             return anim;\r
373         },\r
374 \r
375         motion : function(el, args, duration, easing, cb, scope){\r
376             return this.run(el, args, duration, easing, cb, scope);\r
377         },\r
378 \r
379         color : function(el, args, duration, easing, cb, scope){\r
380             // color anim not supported, so execute callback immediately\r
381             var anim = createAnim(cb, scope);\r
382             anim.proxyCallback();\r
383             return anim;\r
384         },\r
385 \r
386         run : function(el, args, duration, easing, cb, scope, type){\r
387             var anim = createAnim(cb, scope), e = Ext.fly(el, '_animrun');\r
388             var o = {};\r
389             for(var k in args){\r
390                 if(args[k].from){\r
391                     if(k != 'points'){\r
392                         e.setStyle(k, args[k].from);\r
393                     }\r
394                 }\r
395                 switch(k){   // jquery doesn't support, so convert\r
396                     case 'points':\r
397                         var by, pts;\r
398                         e.position();\r
399                         if(by = args.points.by){\r
400                             var xy = e.getXY();\r
401                             pts = e.translatePoints([xy[0]+by[0], xy[1]+by[1]]);\r
402                         }else{\r
403                             pts = e.translatePoints(args.points.to);\r
404                         }\r
405                         o.left = pts.left;\r
406                         o.top = pts.top;\r
407                         if(!parseInt(e.getStyle('left'), 10)){ // auto bug\r
408                             e.setLeft(0);\r
409                         }\r
410                         if(!parseInt(e.getStyle('top'), 10)){\r
411                             e.setTop(0);\r
412                         }\r
413                         if(args.points.from){\r
414                             e.setXY(args.points.from);\r
415                         }\r
416                     break;\r
417                     case 'width':\r
418                         o.width = args.width.to;\r
419                     break;\r
420                     case 'height':\r
421                         o.height = args.height.to;\r
422                     break;\r
423                     case 'opacity':\r
424                         o.opacity = args.opacity.to;\r
425                     break;\r
426                     case 'left':\r
427                             o.left = args.left.to;\r
428                     break;\r
429                     case 'top':\r
430                             o.top = args.top.to;\r
431                     break;\r
432                     default:\r
433                         o[k] = args[k].to;\r
434                     break;\r
435                 }\r
436             }\r
437             // TODO: find out about easing plug in?\r
438             jQuery(el).animate(o, duration*1000, undefined, anim.proxyCallback);\r
439             return anim;\r
440         }\r
441     };\r
442 }();\r
443 \r
444 \r
445 Ext.lib.Region = function(t, r, b, l) {\r
446     this.top = t;\r
447     this[1] = t;\r
448     this.right = r;\r
449     this.bottom = b;\r
450     this.left = l;\r
451     this[0] = l;\r
452 };\r
453 \r
454 Ext.lib.Region.prototype = {\r
455     contains : function(region) {\r
456         return ( region.left   >= this.left   &&\r
457                  region.right  <= this.right  &&\r
458                  region.top    >= this.top    &&\r
459                  region.bottom <= this.bottom    );\r
460 \r
461     },\r
462 \r
463     getArea : function() {\r
464         return ( (this.bottom - this.top) * (this.right - this.left) );\r
465     },\r
466 \r
467     intersect : function(region) {\r
468         var t = Math.max( this.top,    region.top    );\r
469         var r = Math.min( this.right,  region.right  );\r
470         var b = Math.min( this.bottom, region.bottom );\r
471         var l = Math.max( this.left,   region.left   );\r
472 \r
473         if (b >= t && r >= l) {\r
474             return new Ext.lib.Region(t, r, b, l);\r
475         } else {\r
476             return null;\r
477         }\r
478     },\r
479     union : function(region) {\r
480         var t = Math.min( this.top,    region.top    );\r
481         var r = Math.max( this.right,  region.right  );\r
482         var b = Math.max( this.bottom, region.bottom );\r
483         var l = Math.min( this.left,   region.left   );\r
484 \r
485         return new Ext.lib.Region(t, r, b, l);\r
486     },\r
487 \r
488     constrainTo : function(r) {\r
489             this.top = this.top.constrain(r.top, r.bottom);\r
490             this.bottom = this.bottom.constrain(r.top, r.bottom);\r
491             this.left = this.left.constrain(r.left, r.right);\r
492             this.right = this.right.constrain(r.left, r.right);\r
493             return this;\r
494     },\r
495 \r
496     adjust : function(t, l, b, r){\r
497         this.top += t;\r
498         this.left += l;\r
499         this.right += r;\r
500         this.bottom += b;\r
501         return this;\r
502     }\r
503 };\r
504 \r
505 Ext.lib.Region.getRegion = function(el) {\r
506     var p = Ext.lib.Dom.getXY(el);\r
507 \r
508     var t = p[1];\r
509     var r = p[0] + el.offsetWidth;\r
510     var b = p[1] + el.offsetHeight;\r
511     var l = p[0];\r
512 \r
513     return new Ext.lib.Region(t, r, b, l);\r
514 };\r
515 \r
516 Ext.lib.Point = function(x, y) {\r
517    if (Ext.isArray(x)) {\r
518       y = x[1];\r
519       x = x[0];\r
520    }\r
521     this.x = this.right = this.left = this[0] = x;\r
522     this.y = this.top = this.bottom = this[1] = y;\r
523 };\r
524 \r
525 Ext.lib.Point.prototype = new Ext.lib.Region();\r
526 \r
527 // prevent IE leaks\r
528 if(Ext.isIE) {\r
529     function fnCleanUp() {\r
530         var p = Function.prototype;\r
531         delete p.createSequence;\r
532         delete p.defer;\r
533         delete p.createDelegate;\r
534         delete p.createCallback;\r
535         delete p.createInterceptor;\r
536 \r
537         window.detachEvent("onunload", fnCleanUp);\r
538     }\r
539     window.attachEvent("onunload", fnCleanUp);\r
540 }\r
541 })();