Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / adapter / prototype / ext-prototype-adapter-debug.js
1 /*!
2  * Ext JS Library 3.0.0
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 \r
8 // for old browsers\r
9 window.undefined = window.undefined;\r
10 \r
11 /**\r
12  * @class Ext\r
13  * Ext core utilities and functions.\r
14  * @singleton\r
15  */\r
16 \r
17 Ext = {\r
18     /**\r
19      * The version of the framework\r
20      * @type String\r
21      */\r
22     version : '3.0'\r
23 };\r
24 \r
25 /**\r
26  * Copies all the properties of config to obj.\r
27  * @param {Object} obj The receiver of the properties\r
28  * @param {Object} config The source of the properties\r
29  * @param {Object} defaults A different object that will also be applied for default values\r
30  * @return {Object} returns obj\r
31  * @member Ext apply\r
32  */\r
33 Ext.apply = function(o, c, defaults){\r
34     // no "this" reference for friendly out of scope calls\r
35     if(defaults){\r
36         Ext.apply(o, defaults);\r
37     }\r
38     if(o && c && typeof c == 'object'){\r
39         for(var p in c){\r
40             o[p] = c[p];\r
41         }\r
42     }\r
43     return o;\r
44 };\r
45 \r
46 (function(){\r
47     var idSeed = 0,\r
48         toString = Object.prototype.toString,\r
49         //assume it's not null and not an array\r
50         isIterable = function(v){\r
51             //check for array or arguments\r
52             if(Ext.isArray(v) || v.callee){\r
53                 return true;\r
54             }\r
55             //check for node list type\r
56             if(/NodeList|HTMLCollection/.test(toString.call(v))){\r
57                 return true;\r
58             }\r
59             //NodeList has an item and length property\r
60             //IXMLDOMNodeList has nextNode method, needs to be checked first.\r
61             return ((v.nextNode || v.item) && Ext.isNumber(v.length));\r
62         },\r
63         ua = navigator.userAgent.toLowerCase(),\r
64         check = function(r){\r
65             return r.test(ua);\r
66         },\r
67         DOC = document,\r
68         isStrict = DOC.compatMode == "CSS1Compat",\r
69         isOpera = check(/opera/),\r
70         isChrome = check(/chrome/),\r
71         isWebKit = check(/webkit/),\r
72         isSafari = !isChrome && check(/safari/),\r
73         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2\r
74         isSafari3 = isSafari && check(/version\/3/),\r
75         isSafari4 = isSafari && check(/version\/4/),\r
76         isIE = !isOpera && check(/msie/),\r
77         isIE7 = isIE && check(/msie 7/),\r
78         isIE8 = isIE && check(/msie 8/),\r
79         isIE6 = isIE && !isIE7 && !isIE8,\r
80         isGecko = !isWebKit && check(/gecko/),\r
81         isGecko2 = isGecko && check(/rv:1\.8/),\r
82         isGecko3 = isGecko && check(/rv:1\.9/),\r
83         isBorderBox = isIE && !isStrict,\r
84         isWindows = check(/windows|win32/),\r
85         isMac = check(/macintosh|mac os x/),\r
86         isAir = check(/adobeair/),\r
87         isLinux = check(/linux/),\r
88         isSecure = /^https/i.test(window.location.protocol);\r
89 \r
90     // remove css image flicker\r
91     if(isIE6){\r
92         try{\r
93             DOC.execCommand("BackgroundImageCache", false, true);\r
94         }catch(e){}\r
95     }\r
96 \r
97     Ext.apply(Ext, {\r
98         /**\r
99          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent\r
100          * the IE insecure content warning (defaults to javascript:false).\r
101          * @type String\r
102          */\r
103         SSL_SECURE_URL : 'javascript:false',\r
104         /**\r
105          * True if the browser is in strict (standards-compliant) mode, as opposed to quirks mode\r
106          * @type Boolean\r
107          */\r
108         isStrict : isStrict,\r
109         /**\r
110          * True if the page is running over SSL\r
111          * @type Boolean\r
112          */\r
113         isSecure : isSecure,\r
114         /**\r
115          * True when the document is fully initialized and ready for action\r
116          * @type Boolean\r
117          */\r
118         isReady : false,\r
119 \r
120         /**\r
121          * True if the {@link Ext.Fx} Class is available\r
122          * @type Boolean\r
123          * @property enableFx\r
124          */\r
125 \r
126         /**\r
127          * True to automatically uncache orphaned Ext.Elements periodically (defaults to true)\r
128          * @type Boolean\r
129          */\r
130         enableGarbageCollector : true,\r
131 \r
132         /**\r
133          * True to automatically purge event listeners after uncaching an element (defaults to false).\r
134          * Note: this only happens if {@link #enableGarbageCollector} is true.\r
135          * @type Boolean\r
136          */\r
137         enableListenerCollection : false,\r
138 \r
139         /**\r
140          * Indicates whether to use native browser parsing for JSON methods.\r
141          * This option is ignored if the browser does not support native JSON methods.\r
142          * <b>Note: Native JSON methods will not work with objects that have functions.\r
143          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)\r
144          * @type Boolean\r
145          */\r
146         USE_NATIVE_JSON : false,\r
147 \r
148         /**\r
149          * Copies all the properties of config to obj if they don't already exist.\r
150          * @param {Object} obj The receiver of the properties\r
151          * @param {Object} config The source of the properties\r
152          * @return {Object} returns obj\r
153          */\r
154         applyIf : function(o, c){\r
155             if(o){\r
156                 for(var p in c){\r
157                     if(Ext.isEmpty(o[p])){\r
158                         o[p] = c[p];\r
159                     }\r
160                 }\r
161             }\r
162             return o;\r
163         },\r
164 \r
165         /**\r
166          * Generates unique ids. If the element already has an id, it is unchanged\r
167          * @param {Mixed} el (optional) The element to generate an id for\r
168          * @param {String} prefix (optional) Id prefix (defaults "ext-gen")\r
169          * @return {String} The generated Id.\r
170          */\r
171         id : function(el, prefix){\r
172             return (el = Ext.getDom(el) || {}).id = el.id || (prefix || "ext-gen") + (++idSeed);\r
173         },\r
174 \r
175         /**\r
176          * Extends one class with another class and optionally overrides members with the passed literal. This class\r
177          * also adds the function "override()" to the class that can be used to override\r
178          * members on an instance.\r
179          * * <p>\r
180          * This function also supports a 2-argument call in which the subclass's constructor is\r
181          * not passed as an argument. In this form, the parameters are as follows:</p><p>\r
182          * <div class="mdetail-params"><ul>\r
183          * <li><code>superclass</code>\r
184          * <div class="sub-desc">The class being extended</div></li>\r
185          * <li><code>overrides</code>\r
186          * <div class="sub-desc">A literal with members which are copied into the subclass's\r
187          * prototype, and are therefore shared among all instances of the new class.<p>\r
188          * This may contain a special member named <tt><b>constructor</b></tt>. This is used\r
189          * to define the constructor of the new class, and is returned. If this property is\r
190          * <i>not</i> specified, a constructor is generated and returned which just calls the\r
191          * superclass's constructor passing on its parameters.</p></div></li>\r
192          * </ul></div></p><p>\r
193          * For example, to create a subclass of the Ext GridPanel:\r
194          * <pre><code>\r
195 MyGridPanel = Ext.extend(Ext.grid.GridPanel, {\r
196     constructor: function(config) {\r
197         // Your preprocessing here\r
198         MyGridPanel.superclass.constructor.apply(this, arguments);\r
199         // Your postprocessing here\r
200     },\r
201 \r
202     yourMethod: function() {\r
203         // etc.\r
204     }\r
205 });\r
206 </code></pre>\r
207          * </p>\r
208          * @param {Function} subclass The class inheriting the functionality\r
209          * @param {Function} superclass The class being extended\r
210          * @param {Object} overrides (optional) A literal with members which are copied into the subclass's\r
211          * prototype, and are therefore shared between all instances of the new class.\r
212          * @return {Function} The subclass constructor.\r
213          * @method extend\r
214          */\r
215         extend : function(){\r
216             // inline overrides\r
217             var io = function(o){\r
218                 for(var m in o){\r
219                     this[m] = o[m];\r
220                 }\r
221             };\r
222             var oc = Object.prototype.constructor;\r
223 \r
224             return function(sb, sp, overrides){\r
225                 if(Ext.isObject(sp)){\r
226                     overrides = sp;\r
227                     sp = sb;\r
228                     sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};\r
229                 }\r
230                 var F = function(){},\r
231                     sbp,\r
232                     spp = sp.prototype;\r
233 \r
234                 F.prototype = spp;\r
235                 sbp = sb.prototype = new F();\r
236                 sbp.constructor=sb;\r
237                 sb.superclass=spp;\r
238                 if(spp.constructor == oc){\r
239                     spp.constructor=sp;\r
240                 }\r
241                 sb.override = function(o){\r
242                     Ext.override(sb, o);\r
243                 };\r
244                 sbp.superclass = sbp.supr = (function(){\r
245                     return spp;\r
246                 });\r
247                 sbp.override = io;\r
248                 Ext.override(sb, overrides);\r
249                 sb.extend = function(o){Ext.extend(sb, o);};\r
250                 return sb;\r
251             };\r
252         }(),\r
253 \r
254         /**\r
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.\r
256          * Usage:<pre><code>\r
257 Ext.override(MyClass, {\r
258     newMethod1: function(){\r
259         // etc.\r
260     },\r
261     newMethod2: function(foo){\r
262         // etc.\r
263     }\r
264 });\r
265 </code></pre>\r
266          * @param {Object} origclass The class to override\r
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal\r
268          * containing one or more methods.\r
269          * @method override\r
270          */\r
271         override : function(origclass, overrides){\r
272             if(overrides){\r
273                 var p = origclass.prototype;\r
274                 Ext.apply(p, overrides);\r
275                 if(Ext.isIE && overrides.toString != origclass.toString){\r
276                     p.toString = overrides.toString;\r
277                 }\r
278             }\r
279         },\r
280 \r
281         /**\r
282          * Creates namespaces to be used for scoping variables and classes so that they are not global.\r
283          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:\r
284          * <pre><code>\r
285 Ext.namespace('Company', 'Company.data');\r
286 Ext.namespace('Company.data'); // equivalent and preferable to above syntax\r
287 Company.Widget = function() { ... }\r
288 Company.data.CustomStore = function(config) { ... }\r
289 </code></pre>\r
290          * @param {String} namespace1\r
291          * @param {String} namespace2\r
292          * @param {String} etc\r
293          * @method namespace\r
294          */\r
295         namespace : function(){\r
296             var o, d;\r
297             Ext.each(arguments, function(v) {\r
298                 d = v.split(".");\r
299                 o = window[d[0]] = window[d[0]] || {};\r
300                 Ext.each(d.slice(1), function(v2){\r
301                     o = o[v2] = o[v2] || {};\r
302                 });\r
303             });\r
304             return o;\r
305         },\r
306 \r
307         /**\r
308          * Takes an object and converts it to an encoded URL. e.g. Ext.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.\r
309          * @param {Object} o\r
310          * @param {String} pre (optional) A prefix to add to the url encoded string\r
311          * @return {String}\r
312          */\r
313         urlEncode: function(o, pre){\r
314             var undef, buf = [], key, e = encodeURIComponent;\r
315 \r
316             for(key in o){\r
317                 undef = !Ext.isDefined(o[key]);\r
318                 Ext.each(undef ? key : o[key], function(val, i){\r
319                     buf.push("&", e(key), "=", (val != key || !undef) ? e(val) : "");\r
320                 });\r
321             }\r
322             if(!pre){\r
323                 buf.shift();\r
324                 pre = "";\r
325             }\r
326             return pre + buf.join('');\r
327         },\r
328 \r
329         /**\r
330          * Takes an encoded URL and and converts it to an object. Example: <pre><code>\r
331 Ext.urlDecode("foo=1&bar=2"); // returns {foo: "1", bar: "2"}\r
332 Ext.urlDecode("foo=1&bar=2&bar=3&bar=4", false); // returns {foo: "1", bar: ["2", "3", "4"]}\r
333 </code></pre>\r
334          * @param {String} string\r
335          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).\r
336          * @return {Object} A literal with members\r
337          */\r
338         urlDecode : function(string, overwrite){\r
339             var obj = {},\r
340                 pairs = string.split('&'),\r
341                 d = decodeURIComponent,\r
342                 name,\r
343                 value;\r
344             Ext.each(pairs, function(pair) {\r
345                 pair = pair.split('=');\r
346                 name = d(pair[0]);\r
347                 value = d(pair[1]);\r
348                 obj[name] = overwrite || !obj[name] ? value :\r
349                             [].concat(obj[name]).concat(value);\r
350             });\r
351             return obj;\r
352         },\r
353 \r
354         /**\r
355          * Appends content to the query string of a URL, which handles logic for whether to place\r
356          * a question mark or ampersand.\r
357          * @param {String} url The url to append to.\r
358          * @@param {String} s The content to append to the url.\r
359          * @return (String) The appended string\r
360          */\r
361         urlAppend : function(url, s){\r
362             if(!Ext.isEmpty(s)){\r
363                 return url + (url.indexOf('?') === -1 ? '?' : '&') + s;\r
364             }\r
365             return url;\r
366         },\r
367 \r
368         /**\r
369          * Converts any iterable (numeric indices and a length property) into a true array\r
370          * Don't use this on strings. IE doesn't support "abc"[0] which this implementation depends on.\r
371          * For strings, use this instead: "abc".match(/./g) => [a,b,c];\r
372          * @param {Iterable} the iterable object to be turned into a true Array.\r
373          * @return (Array) array\r
374          */\r
375         toArray : function(){\r
376             return isIE ?\r
377                 function(a, i, j, res){\r
378                     res = [];\r
379                     Ext.each(a, function(v) {\r
380                         res.push(v);\r
381                     });\r
382                     return res.slice(i || 0, j || res.length);\r
383                 } :\r
384                 function(a, i, j){\r
385                     return Array.prototype.slice.call(a, i || 0, j || a.length);\r
386                 }\r
387         }(),\r
388 \r
389         /**\r
390          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the\r
391          * passed array is not really an array, your function is called once with it.\r
392          * The supplied function is called with (Object item, Number index, Array allItems).\r
393          * @param {Array/NodeList/Mixed} array\r
394          * @param {Function} fn\r
395          * @param {Object} scope\r
396          */\r
397         each: function(array, fn, scope){\r
398             if(Ext.isEmpty(array, true)){\r
399                 return;\r
400             }\r
401             if(!isIterable(array) || Ext.isPrimitive(array)){\r
402                 array = [array];\r
403             }\r
404             for(var i = 0, len = array.length; i < len; i++){\r
405                 if(fn.call(scope || array[i], array[i], i, array) === false){\r
406                     return i;\r
407                 };\r
408             }\r
409         },\r
410 \r
411         /**\r
412          * Iterates either the elements in an array, or each of the properties in an object.\r
413          * <b>Note</b>: If you are only iterating arrays, it is better to call {@link #each}.\r
414          * @param {Object/Array} object The object or array to be iterated\r
415          * @param {Function} fn The function to be called for each iteration.\r
416          * The iteration will stop if the supplied function returns false, or\r
417          * all array elements / object properties have been covered. The signature\r
418          * varies depending on the type of object being interated:\r
419          * <div class="mdetail-params"><ul>\r
420          * <li>Arrays : <tt>(Object item, Number index, Array allItems)</tt>\r
421          * <div class="sub-desc">\r
422          * When iterating an array, the supplied function is called with each item.</div></li>\r
423          * <li>Objects : <tt>(String key, Object value)</tt>\r
424          * <div class="sub-desc">\r
425          * When iterating an object, the supplied function is called with each key-value pair in\r
426          * the object.</div></li>\r
427          * </ul></div>\r
428          * @param {Object} scope The scope to call the supplied function with, defaults to\r
429          * the specified <tt>object</tt>\r
430          */\r
431         iterate : function(obj, fn, scope){\r
432             if(isIterable(obj)){\r
433                 Ext.each(obj, fn, scope);\r
434                 return;\r
435             }else if(Ext.isObject(obj)){\r
436                 for(var prop in obj){\r
437                     if(obj.hasOwnProperty(prop)){\r
438                         if(fn.call(scope || obj, prop, obj[prop]) === false){\r
439                             return;\r
440                         };\r
441                     }\r
442                 }\r
443             }\r
444         },\r
445 \r
446         /**\r
447          * Return the dom node for the passed String (id), dom node, or Ext.Element.\r
448          * Here are some examples:\r
449          * <pre><code>\r
450 // gets dom node based on id\r
451 var elDom = Ext.getDom('elId');\r
452 // gets dom node based on the dom node\r
453 var elDom1 = Ext.getDom(elDom);\r
454 \r
455 // If we don&#39;t know if we are working with an\r
456 // Ext.Element or a dom node use Ext.getDom\r
457 function(el){\r
458     var dom = Ext.getDom(el);\r
459     // do something with the dom node\r
460 }\r
461          * </code></pre>\r
462          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)\r
463          * when this method is called to be successful.\r
464          * @param {Mixed} el\r
465          * @return HTMLElement\r
466          */\r
467         getDom : function(el){\r
468             if(!el || !DOC){\r
469                 return null;\r
470             }\r
471             return el.dom ? el.dom : (Ext.isString(el) ? DOC.getElementById(el) : el);\r
472         },\r
473 \r
474         /**\r
475          * Returns the current document body as an {@link Ext.Element}.\r
476          * @return Ext.Element The document body\r
477          */\r
478         getBody : function(){\r
479             return Ext.get(DOC.body || DOC.documentElement);\r
480         },\r
481 \r
482         /**\r
483          * Removes a DOM node from the document.  The body node will be ignored if passed in.\r
484          * @param {HTMLElement} node The node to remove\r
485          */\r
486         removeNode : isIE ? function(){\r
487             var d;\r
488             return function(n){\r
489                 if(n && n.tagName != 'BODY'){\r
490                     d = d || DOC.createElement('div');\r
491                     d.appendChild(n);\r
492                     d.innerHTML = '';\r
493                 }\r
494             }\r
495         }() : function(n){\r
496             if(n && n.parentNode && n.tagName != 'BODY'){\r
497                 n.parentNode.removeChild(n);\r
498             }\r
499         },\r
500 \r
501         /**\r
502          * <p>Returns true if the passed value is empty.</p>\r
503          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>\r
504          * <li>null</li>\r
505          * <li>undefined</li>\r
506          * <li>an empty array</li>\r
507          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>\r
508          * </ul></div>\r
509          * @param {Mixed} value The value to test\r
510          * @param {Boolean} allowBlank (optional) true to allow empty strings (defaults to false)\r
511          * @return {Boolean}\r
512          */\r
513         isEmpty : function(v, allowBlank){\r
514             return v === null || v === undefined || ((Ext.isArray(v) && !v.length)) || (!allowBlank ? v === '' : false);\r
515         },\r
516 \r
517         /**\r
518          * Returns true if the passed object is a JavaScript array, otherwise false.\r
519          * @param {Object} object The object to test\r
520          * @return {Boolean}\r
521          */\r
522         isArray : function(v){\r
523             return toString.apply(v) === '[object Array]';\r
524         },\r
525 \r
526         /**\r
527          * Returns true if the passed object is a JavaScript Object, otherwise false.\r
528          * @param {Object} object The object to test\r
529          * @return {Boolean}\r
530          */\r
531         isObject : function(v){\r
532             return v && typeof v == "object";\r
533         },\r
534 \r
535         /**\r
536          * Returns true if the passed object is a JavaScript 'primitive', a string, number or boolean.\r
537          * @param {Mixed} value The value to test\r
538          * @return {Boolean}\r
539          */\r
540         isPrimitive : function(v){\r
541             return Ext.isString(v) || Ext.isNumber(v) || Ext.isBoolean(v);\r
542         },\r
543 \r
544         /**\r
545          * Returns true if the passed object is a JavaScript Function, otherwise false.\r
546          * @param {Object} object The object to test\r
547          * @return {Boolean}\r
548          */\r
549         isFunction : function(v){\r
550             return toString.apply(v) === '[object Function]';\r
551         },\r
552 \r
553         /**\r
554          * Returns true if the passed object is a number. Returns false for non-finite numbers.\r
555          * @param {Object} v The object to test\r
556          * @return {Boolean}\r
557          */\r
558         isNumber: function(v){\r
559             return typeof v === 'number' && isFinite(v);\r
560         },\r
561 \r
562         /**\r
563          * Returns true if the passed object is a string.\r
564          * @param {Object} v The object to test\r
565          * @return {Boolean}\r
566          */\r
567         isString: function(v){\r
568             return typeof v === 'string';\r
569         },\r
570 \r
571         /**\r
572          * Returns true if the passed object is a boolean.\r
573          * @param {Object} v The object to test\r
574          * @return {Boolean}\r
575          */\r
576         isBoolean: function(v){\r
577             return typeof v === 'boolean';\r
578         },\r
579 \r
580         /**\r
581          * Returns true if the passed object is not undefined.\r
582          * @param {Object} v The object to test\r
583          * @return {Boolean}\r
584          */\r
585         isDefined: function(v){\r
586             return typeof v !== 'undefined';\r
587         },\r
588 \r
589         /**\r
590          * True if the detected browser is Opera.\r
591          * @type Boolean\r
592          */\r
593         isOpera : isOpera,\r
594         /**\r
595          * True if the detected browser uses WebKit.\r
596          * @type Boolean\r
597          */\r
598         isWebKit: isWebKit,\r
599         /**\r
600          * True if the detected browser is Chrome.\r
601          * @type Boolean\r
602          */\r
603         isChrome : isChrome,\r
604         /**\r
605          * True if the detected browser is Safari.\r
606          * @type Boolean\r
607          */\r
608         isSafari : isSafari,\r
609         /**\r
610          * True if the detected browser is Safari 3.x.\r
611          * @type Boolean\r
612          */\r
613         isSafari3 : isSafari3,\r
614         /**\r
615          * True if the detected browser is Safari 4.x.\r
616          * @type Boolean\r
617          */\r
618         isSafari4 : isSafari4,\r
619         /**\r
620          * True if the detected browser is Safari 2.x.\r
621          * @type Boolean\r
622          */\r
623         isSafari2 : isSafari2,\r
624         /**\r
625          * True if the detected browser is Internet Explorer.\r
626          * @type Boolean\r
627          */\r
628         isIE : isIE,\r
629         /**\r
630          * True if the detected browser is Internet Explorer 6.x.\r
631          * @type Boolean\r
632          */\r
633         isIE6 : isIE6,\r
634         /**\r
635          * True if the detected browser is Internet Explorer 7.x.\r
636          * @type Boolean\r
637          */\r
638         isIE7 : isIE7,\r
639         /**\r
640          * True if the detected browser is Internet Explorer 8.x.\r
641          * @type Boolean\r
642          */\r
643         isIE8 : isIE8,\r
644         /**\r
645          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).\r
646          * @type Boolean\r
647          */\r
648         isGecko : isGecko,\r
649         /**\r
650          * True if the detected browser uses a pre-Gecko 1.9 layout engine (e.g. Firefox 2.x).\r
651          * @type Boolean\r
652          */\r
653         isGecko2 : isGecko2,\r
654         /**\r
655          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).\r
656          * @type Boolean\r
657          */\r
658         isGecko3 : isGecko3,\r
659         /**\r
660          * True if the detected browser is Internet Explorer running in non-strict mode.\r
661          * @type Boolean\r
662          */\r
663         isBorderBox : isBorderBox,\r
664         /**\r
665          * True if the detected platform is Linux.\r
666          * @type Boolean\r
667          */\r
668         isLinux : isLinux,\r
669         /**\r
670          * True if the detected platform is Windows.\r
671          * @type Boolean\r
672          */\r
673         isWindows : isWindows,\r
674         /**\r
675          * True if the detected platform is Mac OS.\r
676          * @type Boolean\r
677          */\r
678         isMac : isMac,\r
679         /**\r
680          * True if the detected platform is Adobe Air.\r
681          * @type Boolean\r
682          */\r
683         isAir : isAir\r
684     });\r
685 \r
686     /**\r
687      * Creates namespaces to be used for scoping variables and classes so that they are not global.\r
688      * Specifying the last node of a namespace implicitly creates all other nodes. Usage:\r
689      * <pre><code>\r
690 Ext.namespace('Company', 'Company.data');\r
691 Ext.namespace('Company.data'); // equivalent and preferable to above syntax\r
692 Company.Widget = function() { ... }\r
693 Company.data.CustomStore = function(config) { ... }\r
694 </code></pre>\r
695      * @param {String} namespace1\r
696      * @param {String} namespace2\r
697      * @param {String} etc\r
698      * @method namespace\r
699      */\r
700     Ext.ns = Ext.namespace;\r
701 })();\r
702 \r
703 Ext.ns("Ext", "Ext.util", "Ext.lib", "Ext.data");\r
704 \r
705 \r
706 /**\r
707  * @class Function\r
708  * These functions are available on every Function object (any JavaScript function).\r
709  */\r
710 Ext.apply(Function.prototype, {\r
711      /**\r
712      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false,\r
713      * the original one is not called. The resulting function returns the results of the original function.\r
714      * The passed fcn is called with the parameters of the original function. Example usage:\r
715      * <pre><code>\r
716 var sayHi = function(name){\r
717     alert('Hi, ' + name);\r
718 }\r
719 \r
720 sayHi('Fred'); // alerts "Hi, Fred"\r
721 \r
722 // create a new function that validates input without\r
723 // directly modifying the original function:\r
724 var sayHiToFriend = sayHi.createInterceptor(function(name){\r
725     return name == 'Brian';\r
726 });\r
727 \r
728 sayHiToFriend('Fred');  // no alert\r
729 sayHiToFriend('Brian'); // alerts "Hi, Brian"\r
730 </code></pre>\r
731      * @param {Function} fcn The function to call before the original\r
732      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)\r
733      * @return {Function} The new function\r
734      */\r
735     createInterceptor : function(fcn, scope){\r
736         var method = this;\r
737         return !Ext.isFunction(fcn) ?\r
738                 this :\r
739                 function() {\r
740                     var me = this,\r
741                         args = arguments;\r
742                     fcn.target = me;\r
743                     fcn.method = method;\r
744                     return (fcn.apply(scope || me || window, args) !== false) ?\r
745                             method.apply(me || window, args) :\r
746                             null;\r
747                 };\r
748     },\r
749 \r
750      /**\r
751      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...\r
752      * Call directly on any function. Example: <code>myFunction.createCallback(arg1, arg2)</code>\r
753      * Will create a function that is bound to those 2 args. <b>If a specific scope is required in the\r
754      * callback, use {@link #createDelegate} instead.</b> The function returned by createCallback always\r
755      * executes in the window scope.\r
756      * <p>This method is required when you want to pass arguments to a callback function.  If no arguments\r
757      * are needed, you can simply pass a reference to the function as a callback (e.g., callback: myFn).\r
758      * However, if you tried to pass a function with arguments (e.g., callback: myFn(arg1, arg2)) the function\r
759      * would simply execute immediately when the code is parsed. Example usage:\r
760      * <pre><code>\r
761 var sayHi = function(name){\r
762     alert('Hi, ' + name);\r
763 }\r
764 \r
765 // clicking the button alerts "Hi, Fred"\r
766 new Ext.Button({\r
767     text: 'Say Hi',\r
768     renderTo: Ext.getBody(),\r
769     handler: sayHi.createCallback('Fred')\r
770 });\r
771 </code></pre>\r
772      * @return {Function} The new function\r
773     */\r
774     createCallback : function(/*args...*/){\r
775         // make args available, in function below\r
776         var args = arguments,\r
777             method = this;\r
778         return function() {\r
779             return method.apply(window, args);\r
780         };\r
781     },\r
782 \r
783     /**\r
784      * Creates a delegate (callback) that sets the scope to obj.\r
785      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this, [arg1, arg2])</code>\r
786      * Will create a function that is automatically scoped to obj so that the <tt>this</tt> variable inside the\r
787      * callback points to obj. Example usage:\r
788      * <pre><code>\r
789 var sayHi = function(name){\r
790     // Note this use of "this.text" here.  This function expects to\r
791     // execute within a scope that contains a text property.  In this\r
792     // example, the "this" variable is pointing to the btn object that\r
793     // was passed in createDelegate below.\r
794     alert('Hi, ' + name + '. You clicked the "' + this.text + '" button.');\r
795 }\r
796 \r
797 var btn = new Ext.Button({\r
798     text: 'Say Hi',\r
799     renderTo: Ext.getBody()\r
800 });\r
801 \r
802 // This callback will execute in the scope of the\r
803 // button instance. Clicking the button alerts\r
804 // "Hi, Fred. You clicked the "Say Hi" button."\r
805 btn.on('click', sayHi.createDelegate(btn, ['Fred']));\r
806 </code></pre>\r
807      * @param {Object} obj (optional) The object for which the scope is set\r
808      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)\r
809      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,\r
810      *                                             if a number the args are inserted at the specified position\r
811      * @return {Function} The new function\r
812      */\r
813     createDelegate : function(obj, args, appendArgs){\r
814         var method = this;\r
815         return function() {\r
816             var callArgs = args || arguments;\r
817             if (appendArgs === true){\r
818                 callArgs = Array.prototype.slice.call(arguments, 0);\r
819                 callArgs = callArgs.concat(args);\r
820             }else if (Ext.isNumber(appendArgs)){\r
821                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first\r
822                 var applyArgs = [appendArgs, 0].concat(args); // create method call params\r
823                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in\r
824             }\r
825             return method.apply(obj || window, callArgs);\r
826         };\r
827     },\r
828 \r
829     /**\r
830      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:\r
831      * <pre><code>\r
832 var sayHi = function(name){\r
833     alert('Hi, ' + name);\r
834 }\r
835 \r
836 // executes immediately:\r
837 sayHi('Fred');\r
838 \r
839 // executes after 2 seconds:\r
840 sayHi.defer(2000, this, ['Fred']);\r
841 \r
842 // this syntax is sometimes useful for deferring\r
843 // execution of an anonymous function:\r
844 (function(){\r
845     alert('Anonymous');\r
846 }).defer(100);\r
847 </code></pre>\r
848      * @param {Number} millis The number of milliseconds for the setTimeout call (if less than or equal to 0 the function is executed immediately)\r
849      * @param {Object} obj (optional) The object for which the scope is set\r
850      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)\r
851      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,\r
852      *                                             if a number the args are inserted at the specified position\r
853      * @return {Number} The timeout id that can be used with clearTimeout\r
854      */\r
855     defer : function(millis, obj, args, appendArgs){\r
856         var fn = this.createDelegate(obj, args, appendArgs);\r
857         if(millis > 0){\r
858             return setTimeout(fn, millis);\r
859         }\r
860         fn();\r
861         return 0;\r
862     }\r
863 });\r
864 \r
865 /**\r
866  * @class String\r
867  * These functions are available on every String object.\r
868  */\r
869 Ext.applyIf(String, {\r
870     /**\r
871      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each\r
872      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:\r
873      * <pre><code>\r
874 var cls = 'my-class', text = 'Some text';\r
875 var s = String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);\r
876 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'\r
877      * </code></pre>\r
878      * @param {String} string The tokenized string to be formatted\r
879      * @param {String} value1 The value to replace token {0}\r
880      * @param {String} value2 Etc...\r
881      * @return {String} The formatted string\r
882      * @static\r
883      */\r
884     format : function(format){\r
885         var args = Ext.toArray(arguments, 1);\r
886         return format.replace(/\{(\d+)\}/g, function(m, i){\r
887             return args[i];\r
888         });\r
889     }\r
890 });\r
891 \r
892 /**\r
893  * @class Array\r
894  */\r
895 Ext.applyIf(Array.prototype, {\r
896     /**\r
897      * Checks whether or not the specified object exists in the array.\r
898      * @param {Object} o The object to check for\r
899      * @return {Number} The index of o in the array (or -1 if it is not found)\r
900      */\r
901     indexOf : function(o){\r
902         for (var i = 0, len = this.length; i < len; i++){\r
903             if(this[i] == o){\r
904                 return i;\r
905             }\r
906         }\r
907         return -1;\r
908     },\r
909 \r
910     /**\r
911      * Removes the specified object from the array.  If the object is not found nothing happens.\r
912      * @param {Object} o The object to remove\r
913      * @return {Array} this array\r
914      */\r
915     remove : function(o){\r
916         var index = this.indexOf(o);\r
917         if(index != -1){\r
918             this.splice(index, 1);\r
919         }\r
920         return this;\r
921     }\r
922 });\r
923 /**
924  * @class Ext
925  */
926
927 Ext.ns("Ext.grid", "Ext.dd", "Ext.tree", "Ext.form", "Ext.menu",
928        "Ext.state", "Ext.layout", "Ext.app", "Ext.ux", "Ext.chart", "Ext.direct");
929     /**
930      * Namespace alloted for extensions to the framework.
931      * @property ux
932      * @type Object
933      */
934
935 Ext.apply(Ext, function(){
936     var E = Ext, idSeed = 0;
937
938     return {
939         /**
940         * A reusable empty function
941         * @property
942         * @type Function
943         */
944         emptyFn : function(){},
945
946         /**
947          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images. 
948          * In older versions of IE, this defaults to "http://extjs.com/s.gif" and you should change this to a URL on your server.
949          * For other browsers it uses an inline data URL.
950          * @type String
951          */
952         BLANK_IMAGE_URL : Ext.isIE6 || Ext.isIE7 ?
953                             'http:/' + '/extjs.com/s.gif' :
954                             'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
955
956         extendX : function(supr, fn){
957             return Ext.extend(supr, fn(supr.prototype));
958         },
959
960         /**
961          * Returns the current HTML document object as an {@link Ext.Element}.
962          * @return Ext.Element The document
963          */
964         getDoc : function(){
965             return Ext.get(document);
966         },
967
968         /**
969          * Returns true if the passed object is a JavaScript date object, otherwise false.
970          * @param {Object} object The object to test
971          * @return {Boolean}
972          */
973         isDate : function(v){
974             return Object.prototype.toString.apply(v) === '[object Date]';
975         },
976
977         /**
978          * Utility method for validating that a value is numeric, returning the specified default value if it is not.
979          * @param {Mixed} value Should be a number, but any type will be handled appropriately
980          * @param {Number} defaultValue The value to return if the original value is non-numeric
981          * @return {Number} Value, if numeric, else defaultValue
982          */
983         num : function(v, defaultValue){
984             v = Number(v === null || typeof v == 'boolean'? NaN : v);
985             return isNaN(v)? defaultValue : v;
986         },
987
988         /**
989          * <p>Utility method for returning a default value if the passed value is empty.</p>
990          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
991          * <li>null</li>
992          * <li>undefined</li>
993          * <li>an empty array</li>
994          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
995          * </ul></div>
996          * @param {Mixed} value The value to test
997          * @param {Mixed} defaultValue The value to return if the original value is empty
998          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
999          * @return {Mixed} value, if non-empty, else defaultValue
1000          */
1001         value : function(v, defaultValue, allowBlank){
1002             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
1003         },
1004
1005         /**
1006          * Escapes the passed string for use in a regular expression
1007          * @param {String} str
1008          * @return {String}
1009          */
1010         escapeRe : function(s) {
1011             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
1012         },
1013
1014         sequence : function(o, name, fn, scope){
1015             o[name] = o[name].createSequence(fn, scope);
1016         },
1017
1018         /**
1019          * Applies event listeners to elements by selectors when the document is ready.
1020          * The event name is specified with an <tt>&#64;</tt> suffix.
1021          * <pre><code>
1022 Ext.addBehaviors({
1023     // add a listener for click on all anchors in element with id foo
1024     '#foo a&#64;click' : function(e, t){
1025         // do something
1026     },
1027     
1028     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
1029     '#foo a, #bar span.some-class&#64;mouseover' : function(){
1030         // do something
1031     }
1032 });
1033          * </code></pre> 
1034          * @param {Object} obj The list of behaviors to apply
1035          */
1036         addBehaviors : function(o){
1037             if(!Ext.isReady){
1038                 Ext.onReady(function(){
1039                     Ext.addBehaviors(o);
1040                 });
1041             } else {
1042                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
1043                     parts,
1044                     b,
1045                     s;
1046                 for (b in o) {
1047                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
1048                         s = parts[0];
1049                         if(!cache[s]){
1050                             cache[s] = Ext.select(s);
1051                         }
1052                         cache[s].on(parts[1], o[b]);
1053                     }
1054                 }
1055                 cache = null;
1056             }
1057         },
1058
1059
1060         // deprecated
1061         combine : function(){
1062             var as = arguments, l = as.length, r = [];
1063             for(var i = 0; i < l; i++){
1064                 var a = as[i];
1065                 if(Ext.isArray(a)){
1066                     r = r.concat(a);
1067                 }else if(a.length !== undefined && !a.substr){
1068                     r = r.concat(Array.prototype.slice.call(a, 0));
1069                 }else{
1070                     r.push(a);
1071                 }
1072             }
1073             return r;
1074         },
1075
1076         /**
1077          * Copies a set of named properties fom the source object to the destination object.
1078          * <p>example:<pre><code>
1079 ImageComponent = Ext.extend(Ext.BoxComponent, {
1080     initComponent: function() {
1081         this.autoEl = { tag: 'img' };
1082         MyComponent.superclass.initComponent.apply(this, arguments);
1083         this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
1084     }
1085 });
1086          * </code></pre> 
1087          * @param {Object} The destination object.
1088          * @param {Object} The source object.
1089          * @param {Array/String} Either an Array of property names, or a comma-delimited list
1090          * of property names to copy.
1091          * @return {Object} The modified object.
1092         */
1093         copyTo : function(dest, source, names){
1094             if(typeof names == 'string'){
1095                 names = names.split(/[,;\s]/);
1096             }
1097             Ext.each(names, function(name){
1098                 if(source.hasOwnProperty(name)){
1099                     dest[name] = source[name];
1100                 }
1101             }, this);
1102             return dest;
1103         },
1104
1105         /**
1106          * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
1107          * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
1108          * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
1109          * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
1110          * passed into this function in a single call as separate arguments.
1111          * @param {Mixed} arg1 An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
1112          * @param {Mixed} arg2 (optional)
1113          * @param {Mixed} etc... (optional)
1114          */
1115         destroy : function(){
1116             Ext.each(arguments, function(arg){
1117                 if(arg){
1118                     if(Ext.isArray(arg)){
1119                         this.destroy.apply(this, arg);
1120                     }else if(Ext.isFunction(arg.destroy)){
1121                         arg.destroy();
1122                     }else if(arg.dom){
1123                         arg.remove();
1124                     }    
1125                 }
1126             }, this);
1127         },
1128
1129         /**
1130          * Attempts to destroy and then remove a set of named properties of the passed object.
1131          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
1132          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
1133          * @param {Mixed} etc... More property names to destroy and remove.
1134          */
1135         destroyMembers : function(o, arg1, arg2, etc){
1136             for(var i = 1, a = arguments, len = a.length; i < len; i++) {
1137                 Ext.destroy(o[a[i]]);
1138                 delete o[a[i]];
1139             }
1140         },
1141
1142         /**
1143          * Creates a copy of the passed Array with falsy values removed.
1144          * @param {Array/NodeList} arr The Array from which to remove falsy values.
1145          * @return {Array} The new, compressed Array.
1146          */
1147         clean : function(arr){
1148             var ret = [];
1149             Ext.each(arr, function(v){
1150                 if(!!v){
1151                     ret.push(v);
1152                 }
1153             });
1154             return ret;
1155         },
1156
1157         /**
1158          * Creates a copy of the passed Array, filtered to contain only unique values.
1159          * @param {Array} arr The Array to filter
1160          * @return {Array} The new Array containing unique values.
1161          */
1162         unique : function(arr){
1163             var ret = [],
1164                 collect = {};
1165
1166             Ext.each(arr, function(v) {
1167                 if(!collect[v]){
1168                     ret.push(v);
1169                 }
1170                 collect[v] = true;
1171             });
1172             return ret;
1173         },
1174
1175         /**
1176          * Recursively flattens into 1-d Array. Injects Arrays inline.
1177          * @param {Array} arr The array to flatten
1178          * @return {Array} The new, flattened array.
1179          */
1180         flatten : function(arr){
1181             var worker = [];
1182             function rFlatten(a) {
1183                 Ext.each(a, function(v) {
1184                     if(Ext.isArray(v)){
1185                         rFlatten(v);
1186                     }else{
1187                         worker.push(v);
1188                     }
1189                 });
1190                 return worker;
1191             }
1192             return rFlatten(arr);
1193         },
1194
1195         /**
1196          * Returns the minimum value in the Array.
1197          * @param {Array|NodeList} arr The Array from which to select the minimum value.
1198          * @param {Function} comp (optional) a function to perform the comparision which determines minimization.
1199          *                   If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
1200          * @return {Object} The minimum value in the Array.
1201          */
1202         min : function(arr, comp){
1203             var ret = arr[0];
1204             comp = comp || function(a,b){ return a < b ? -1 : 1; };
1205             Ext.each(arr, function(v) {
1206                 ret = comp(ret, v) == -1 ? ret : v;
1207             });
1208             return ret;
1209         },
1210
1211         /**
1212          * Returns the maximum value in the Array
1213          * @param {Array|NodeList} arr The Array from which to select the maximum value.
1214          * @param {Function} comp (optional) a function to perform the comparision which determines maximization.
1215          *                   If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
1216          * @return {Object} The maximum value in the Array.
1217          */
1218         max : function(arr, comp){
1219             var ret = arr[0];
1220             comp = comp || function(a,b){ return a > b ? 1 : -1; };
1221             Ext.each(arr, function(v) {
1222                 ret = comp(ret, v) == 1 ? ret : v;
1223             });
1224             return ret;
1225         },
1226
1227         /**
1228          * Calculates the mean of the Array
1229          * @param {Array} arr The Array to calculate the mean value of.
1230          * @return {Number} The mean.
1231          */
1232         mean : function(arr){
1233            return Ext.sum(arr) / arr.length;
1234         },
1235
1236         /**
1237          * Calculates the sum of the Array
1238          * @param {Array} arr The Array to calculate the sum value of.
1239          * @return {Number} The sum.
1240          */
1241         sum : function(arr){
1242            var ret = 0;
1243            Ext.each(arr, function(v) {
1244                ret += v;
1245            });
1246            return ret;
1247         },
1248
1249         /**
1250          * Partitions the set into two sets: a true set and a false set.
1251          * Example: 
1252          * Example2: 
1253          * <pre><code>
1254 // Example 1:
1255 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
1256
1257 // Example 2:
1258 Ext.partition(
1259     Ext.query("p"),
1260     function(val){
1261         return val.className == "class1"
1262     }
1263 );
1264 // true are those paragraph elements with a className of "class1",
1265 // false set are those that do not have that className.
1266          * </code></pre>
1267          * @param {Array|NodeList} arr The array to partition
1268          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
1269          *                   itself must be able to be evaluated for its truthfulness.
1270          * @return {Array} [true<Array>,false<Array>]
1271          */
1272         partition : function(arr, truth){
1273             var ret = [[],[]];
1274             Ext.each(arr, function(v, i, a) {
1275                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
1276             });
1277             return ret;
1278         },
1279
1280         /**
1281          * Invokes a method on each item in an Array.
1282          * <pre><code>
1283 // Example:
1284 Ext.invoke(Ext.query("p"), "getAttribute", "id");
1285 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
1286          * </code></pre>
1287          * @param {Array|NodeList} arr The Array of items to invoke the method on.
1288          * @param {String} methodName The method name to invoke.
1289          * @param {Anything} ... Arguments to send into the method invocation.
1290          * @return {Array} The results of invoking the method on each item in the array.
1291          */
1292         invoke : function(arr, methodName){
1293             var ret = [],
1294                 args = Array.prototype.slice.call(arguments, 2);
1295             Ext.each(arr, function(v,i) {
1296                 if (v && typeof v[methodName] == "function") {
1297                     ret.push(v[methodName].apply(v, args));
1298                 } else {
1299                     ret.push(undefined);
1300                 }
1301             });
1302             return ret;
1303         },
1304
1305         /**
1306          * Plucks the value of a property from each item in the Array
1307          * <pre><code>
1308 // Example:
1309 Ext.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1310          * </code></pre>
1311          * @param {Array|NodeList} arr The Array of items to pluck the value from.
1312          * @param {String} prop The property name to pluck from each element.
1313          * @return {Array} The value from each item in the Array.
1314          */
1315         pluck : function(arr, prop){
1316             var ret = [];
1317             Ext.each(arr, function(v) {
1318                 ret.push( v[prop] );
1319             });
1320             return ret;
1321         },
1322
1323         /**
1324          * <p>Zips N sets together.</p>
1325          * <pre><code>
1326 // Example 1:
1327 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
1328 // Example 2:
1329 Ext.zip(
1330     [ "+", "-", "+"],
1331     [  12,  10,  22],
1332     [  43,  15,  96],
1333     function(a, b, c){
1334         return "$" + a + "" + b + "." + c
1335     }
1336 ); // ["$+12.43", "$-10.15", "$+22.96"]
1337          * </code></pre>
1338          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
1339          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
1340          * @return {Array} The zipped set.
1341          */
1342         zip : function(){
1343             var parts = Ext.partition(arguments, function( val ){ return !Ext.isFunction(val); }),
1344                 arrs = parts[0],
1345                 fn = parts[1][0],
1346                 len = Ext.max(Ext.pluck(arrs, "length")),
1347                 ret = [];
1348
1349             for (var i = 0; i < len; i++) {
1350                 ret[i] = [];
1351                 if(fn){
1352                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
1353                 }else{
1354                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
1355                         ret[i].push( arrs[j][i] );
1356                     }
1357                 }
1358             }
1359             return ret;
1360         },
1361
1362         /**
1363          * This is shorthand reference to {@link Ext.ComponentMgr#get}.
1364          * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
1365          * @param {String} id The component {@link Ext.Component#id id}
1366          * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
1367          * Class was found.
1368         */
1369         getCmp : function(id){
1370             return Ext.ComponentMgr.get(id);
1371         },
1372
1373         /**
1374          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
1375          * you may want to set this to true.
1376          * @type Boolean
1377          */
1378         useShims: E.isIE6 || (E.isMac && E.isGecko2),
1379
1380         // inpired by a similar function in mootools library
1381         /**
1382          * Returns the type of object that is passed in. If the object passed in is null or undefined it
1383          * return false otherwise it returns one of the following values:<div class="mdetail-params"><ul>
1384          * <li><b>string</b>: If the object passed is a string</li>
1385          * <li><b>number</b>: If the object passed is a number</li>
1386          * <li><b>boolean</b>: If the object passed is a boolean value</li>
1387          * <li><b>date</b>: If the object passed is a Date object</li>
1388          * <li><b>function</b>: If the object passed is a function reference</li>
1389          * <li><b>object</b>: If the object passed is an object</li>
1390          * <li><b>array</b>: If the object passed is an array</li>
1391          * <li><b>regexp</b>: If the object passed is a regular expression</li>
1392          * <li><b>element</b>: If the object passed is a DOM Element</li>
1393          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
1394          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
1395          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
1396          * </ul></div>
1397          * @param {Mixed} object
1398          * @return {String}
1399          */
1400         type : function(o){
1401             if(o === undefined || o === null){
1402                 return false;
1403             }
1404             if(o.htmlElement){
1405                 return 'element';
1406             }
1407             var t = typeof o;
1408             if(t == 'object' && o.nodeName) {
1409                 switch(o.nodeType) {
1410                     case 1: return 'element';
1411                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
1412                 }
1413             }
1414             if(t == 'object' || t == 'function') {
1415                 switch(o.constructor) {
1416                     case Array: return 'array';
1417                     case RegExp: return 'regexp';
1418                     case Date: return 'date';
1419                 }
1420                 if(typeof o.length == 'number' && typeof o.item == 'function') {
1421                     return 'nodelist';
1422                 }
1423             }
1424             return t;
1425         },
1426
1427         intercept : function(o, name, fn, scope){
1428             o[name] = o[name].createInterceptor(fn, scope);
1429         },
1430
1431         // internal
1432         callback : function(cb, scope, args, delay){
1433             if(Ext.isFunction(cb)){
1434                 if(delay){
1435                     cb.defer(delay, scope, args || []);
1436                 }else{
1437                     cb.apply(scope, args || []);
1438                 }
1439             }
1440         }
1441     };
1442 }());
1443
1444 /**
1445  * @class Function
1446  * These functions are available on every Function object (any JavaScript function).
1447  */
1448 Ext.apply(Function.prototype, {
1449     /**
1450      * Create a combined function call sequence of the original function + the passed function.
1451      * The resulting function returns the results of the original function.
1452      * The passed fcn is called with the parameters of the original function. Example usage:
1453      * <pre><code>
1454 var sayHi = function(name){
1455     alert('Hi, ' + name);
1456 }
1457
1458 sayHi('Fred'); // alerts "Hi, Fred"
1459
1460 var sayGoodbye = sayHi.createSequence(function(name){
1461     alert('Bye, ' + name);
1462 });
1463
1464 sayGoodbye('Fred'); // both alerts show
1465 </code></pre>
1466      * @param {Function} fcn The function to sequence
1467      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
1468      * @return {Function} The new function
1469      */
1470     createSequence : function(fcn, scope){
1471         var method = this;
1472         return !Ext.isFunction(fcn) ?
1473                 this :
1474                 function(){
1475                     var retval = method.apply(this || window, arguments);
1476                     fcn.apply(scope || this || window, arguments);
1477                     return retval;
1478                 };
1479     }
1480 });
1481
1482
1483 /**
1484  * @class String
1485  * These functions are available as static methods on the JavaScript String object.
1486  */
1487 Ext.applyIf(String, {
1488
1489     /**
1490      * Escapes the passed string for ' and \
1491      * @param {String} string The string to escape
1492      * @return {String} The escaped string
1493      * @static
1494      */
1495     escape : function(string) {
1496         return string.replace(/('|\\)/g, "\\$1");
1497     },
1498
1499     /**
1500      * Pads the left side of a string with a specified character.  This is especially useful
1501      * for normalizing number and date strings.  Example usage:
1502      * <pre><code>
1503 var s = String.leftPad('123', 5, '0');
1504 // s now contains the string: '00123'
1505      * </code></pre>
1506      * @param {String} string The original string
1507      * @param {Number} size The total length of the output string
1508      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
1509      * @return {String} The padded string
1510      * @static
1511      */
1512     leftPad : function (val, size, ch) {
1513         var result = String(val);
1514         if(!ch) {
1515             ch = " ";
1516         }
1517         while (result.length < size) {
1518             result = ch + result;
1519         }
1520         return result;
1521     }
1522 });
1523
1524 /**
1525  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1526  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1527  * they are already different, the first value passed in is returned.  Note that this method returns the new value
1528  * but does not change the current string.
1529  * <pre><code>
1530 // alternate sort directions
1531 sort = sort.toggle('ASC', 'DESC');
1532
1533 // instead of conditional logic:
1534 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1535 </code></pre>
1536  * @param {String} value The value to compare to the current string
1537  * @param {String} other The new value to use if the string already equals the first value passed in
1538  * @return {String} The new value
1539  */
1540 String.prototype.toggle = function(value, other){
1541     return this == value ? other : value;
1542 };
1543
1544 /**
1545  * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
1546  * <pre><code>
1547 var s = '  foo bar  ';
1548 alert('-' + s + '-');         //alerts "- foo bar -"
1549 alert('-' + s.trim() + '-');  //alerts "-foo bar-"
1550 </code></pre>
1551  * @return {String} The trimmed string
1552  */
1553 String.prototype.trim = function(){
1554     var re = /^\s+|\s+$/g;
1555     return function(){ return this.replace(re, ""); };
1556 }();
1557
1558 // here to prevent dependency on Date.js
1559 /**
1560  Returns the number of milliseconds between this date and date
1561  @param {Date} date (optional) Defaults to now
1562  @return {Number} The diff in milliseconds
1563  @member Date getElapsed
1564  */
1565 Date.prototype.getElapsed = function(date) {
1566     return Math.abs((date || new Date()).getTime()-this.getTime());
1567 };
1568
1569
1570 /**
1571  * @class Number
1572  */
1573 Ext.applyIf(Number.prototype, {
1574     /**
1575      * Checks whether or not the current number is within a desired range.  If the number is already within the
1576      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1577      * exceeded.  Note that this method returns the constrained value but does not change the current number.
1578      * @param {Number} min The minimum number in the range
1579      * @param {Number} max The maximum number in the range
1580      * @return {Number} The constrained value if outside the range, otherwise the current value
1581      */
1582     constrain : function(min, max){
1583         return Math.min(Math.max(this, min), max);
1584     }
1585 });
1586 /**
1587  * @class Ext.util.TaskRunner
1588  * Provides the ability to execute one or more arbitrary tasks in a multithreaded
1589  * manner.  Generally, you can use the singleton {@link Ext.TaskMgr} instead, but
1590  * if needed, you can create separate instances of TaskRunner.  Any number of
1591  * separate tasks can be started at any time and will run independently of each
1592  * other. Example usage:
1593  * <pre><code>
1594 // Start a simple clock task that updates a div once per second
1595 var updateClock = function(){
1596     Ext.fly('clock').update(new Date().format('g:i:s A'));
1597
1598 var task = {
1599     run: updateClock,
1600     interval: 1000 //1 second
1601 }
1602 var runner = new Ext.util.TaskRunner();
1603 runner.start(task);
1604
1605 // equivalent using TaskMgr
1606 Ext.TaskMgr.start({
1607     run: updateClock,
1608     interval: 1000
1609 });
1610
1611  * </code></pre>
1612  * Also see {@link Ext.util.DelayedTask}. 
1613  * 
1614  * @constructor
1615  * @param {Number} interval (optional) The minimum precision in milliseconds supported by this TaskRunner instance
1616  * (defaults to 10)
1617  */
1618 Ext.util.TaskRunner = function(interval){
1619     interval = interval || 10;
1620     var tasks = [], 
1621         removeQueue = [],
1622         id = 0,
1623         running = false,
1624
1625         // private
1626         stopThread = function(){
1627                 running = false;
1628                 clearInterval(id);
1629                 id = 0;
1630             },
1631
1632         // private
1633         startThread = function(){
1634                 if(!running){
1635                     running = true;
1636                     id = setInterval(runTasks, interval);
1637                 }
1638             },
1639
1640         // private
1641         removeTask = function(t){
1642                 removeQueue.push(t);
1643                 if(t.onStop){
1644                     t.onStop.apply(t.scope || t);
1645                 }
1646             },
1647             
1648         // private
1649         runTasks = function(){
1650                 var rqLen = removeQueue.length,
1651                         now = new Date().getTime();                                             
1652             
1653                 if(rqLen > 0){
1654                     for(var i = 0; i < rqLen; i++){
1655                         tasks.remove(removeQueue[i]);
1656                     }
1657                     removeQueue = [];
1658                     if(tasks.length < 1){
1659                         stopThread();
1660                         return;
1661                     }
1662                 }               
1663                 for(var i = 0, t, itime, rt, len = tasks.length; i < len; ++i){
1664                     t = tasks[i];
1665                     itime = now - t.taskRunTime;
1666                     if(t.interval <= itime){
1667                         rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
1668                         t.taskRunTime = now;
1669                         if(rt === false || t.taskRunCount === t.repeat){
1670                             removeTask(t);
1671                             return;
1672                         }
1673                     }
1674                     if(t.duration && t.duration <= (now - t.taskStartTime)){
1675                         removeTask(t);
1676                     }
1677                 }
1678             };
1679
1680     /**
1681      * Starts a new task.
1682      * @method start
1683      * @param {Object} task A config object that supports the following properties:<ul>
1684      * <li><code>run</code> : Function<div class="sub-desc">The function to execute each time the task is run. The
1685      * function will be called at each interval and passed the <code>args</code> argument if specified.  If a
1686      * particular scope is required, be sure to specify it using the <code>scope</code> argument.</div></li>
1687      * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
1688      * should be executed.</div></li>
1689      * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
1690      * specified by <code>run</code>.</div></li>
1691      * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
1692      * <code>run</code> function. Defaults to the task config object.</div></li>
1693      * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to execute
1694      * the task before stopping automatically (defaults to indefinite).</div></li>
1695      * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to execute the task before
1696      * stopping automatically (defaults to indefinite).</div></li>
1697      * </ul>
1698      * @return {Object} The task
1699      */
1700     this.start = function(task){
1701         tasks.push(task);
1702         task.taskStartTime = new Date().getTime();
1703         task.taskRunTime = 0;
1704         task.taskRunCount = 0;
1705         startThread();
1706         return task;
1707     };
1708
1709     /**
1710      * Stops an existing running task.
1711      * @method stop
1712      * @param {Object} task The task to stop
1713      * @return {Object} The task
1714      */
1715     this.stop = function(task){
1716         removeTask(task);
1717         return task;
1718     };
1719
1720     /**
1721      * Stops all tasks that are currently running.
1722      * @method stopAll
1723      */
1724     this.stopAll = function(){
1725         stopThread();
1726         for(var i = 0, len = tasks.length; i < len; i++){
1727             if(tasks[i].onStop){
1728                 tasks[i].onStop();
1729             }
1730         }
1731         tasks = [];
1732         removeQueue = [];
1733     };
1734 };
1735
1736 /**
1737  * @class Ext.TaskMgr
1738  * @extends Ext.util.TaskRunner
1739  * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks.  See
1740  * {@link Ext.util.TaskRunner} for supported methods and task config properties.
1741  * <pre><code>
1742 // Start a simple clock task that updates a div once per second
1743 var task = {
1744     run: function(){
1745         Ext.fly('clock').update(new Date().format('g:i:s A'));
1746     },
1747     interval: 1000 //1 second
1748 }
1749 Ext.TaskMgr.start(task);
1750 </code></pre>
1751  * @singleton
1752  */
1753 Ext.TaskMgr = new Ext.util.TaskRunner();(function(){
1754
1755 var libFlyweight,
1756     version = Prototype.Version.split('.'),
1757     mouseEnterSupported = (parseInt(version[0]) >= 2) || (parseInt(version[1]) >= 7) || (parseInt(version[2]) >= 1),
1758     mouseCache = {},
1759     isXUL = Ext.isGecko ? function(node){ 
1760         return Object.prototype.toString.call(node) == '[object XULElement]';
1761     } : function(){},
1762     isTextNode = Ext.isGecko ? function(node){
1763         try{
1764             return node.nodeType == 3;
1765         }catch(e) {
1766             return false;
1767         }
1768
1769     } : function(node){
1770         return node.nodeType == 3;
1771     },
1772     elContains = function(parent, child) {
1773        if(parent && parent.firstChild){  
1774          while(child) {
1775             if(child === parent) {
1776                 return true;
1777             }
1778             try {
1779                 child = child.parentNode;
1780             } catch(e) {
1781                 // In FF if you mouseout an text input element
1782                 // thats inside a div sometimes it randomly throws
1783                 // Permission denied to get property HTMLDivElement.parentNode
1784                 // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
1785                 return false;
1786             }                
1787             if(child && (child.nodeType != 1)) {
1788                 child = null;
1789             }
1790           }
1791         }
1792         return false;
1793     },
1794     checkRelatedTarget = function(e) {
1795         var related = Ext.lib.Event.getRelatedTarget(e);
1796         return !(isXUL(related) || elContains(e.currentTarget,related));
1797     };
1798
1799 Ext.lib.Dom = {
1800     getViewWidth : function(full){
1801         return full ? this.getDocumentWidth() : this.getViewportWidth();
1802     },
1803
1804     getViewHeight : function(full){
1805         return full ? this.getDocumentHeight() : this.getViewportHeight();
1806     },
1807
1808     getDocumentHeight: function() { // missing from prototype?
1809         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810         return Math.max(scrollHeight, this.getViewportHeight());
1811     },
1812
1813     getDocumentWidth: function() { // missing from prototype?
1814         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815         return Math.max(scrollWidth, this.getViewportWidth());
1816     },
1817
1818     getViewportHeight: function() { // missing from prototype?
1819         var height = self.innerHeight;
1820         var mode = document.compatMode;
1821
1822         if ( (mode || Ext.isIE) && !Ext.isOpera ) {
1823             height = (mode == "CSS1Compat") ?
1824                     document.documentElement.clientHeight : // Standards
1825                     document.body.clientHeight; // Quirks
1826         }
1827
1828         return height;
1829     },
1830
1831     getViewportWidth: function() { // missing from prototype?
1832         var width = self.innerWidth;  // Safari
1833         var mode = document.compatMode;
1834
1835         if (mode || Ext.isIE) { // IE, Gecko, Opera
1836             width = (mode == "CSS1Compat") ?
1837                     document.documentElement.clientWidth : // Standards
1838                     document.body.clientWidth; // Quirks
1839         }
1840         return width;
1841     },
1842
1843     isAncestor : function(p, c){ // missing from prototype?
1844         p = Ext.getDom(p);
1845         c = Ext.getDom(c);
1846         if (!p || !c) {return false;}
1847
1848         if(p.contains && !Ext.isSafari) {
1849             return p.contains(c);
1850         }else if(p.compareDocumentPosition) {
1851             return !!(p.compareDocumentPosition(c) & 16);
1852         }else{
1853             var parent = c.parentNode;
1854             while (parent) {
1855                 if (parent == p) {
1856                     return true;
1857                 }
1858                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1859                     return false;
1860                 }
1861                 parent = parent.parentNode;
1862             }
1863             return false;
1864         }
1865     },
1866
1867     getRegion : function(el){
1868         return Ext.lib.Region.getRegion(el);
1869     },
1870
1871     getY : function(el){
1872         return this.getXY(el)[1];
1873     },
1874
1875     getX : function(el){
1876         return this.getXY(el)[0];
1877     },
1878
1879     getXY : function(el){ // this initially used Position.cumulativeOffset but it is not accurate enough
1880         var p, pe, b, scroll, bd = (document.body || document.documentElement);
1881         el = Ext.getDom(el);
1882
1883         if(el == bd){
1884             return [0, 0];
1885         }
1886
1887         if (el.getBoundingClientRect) {
1888             b = el.getBoundingClientRect();
1889             scroll = fly(document).getScroll();
1890             return [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
1891         }
1892         var x = 0, y = 0;
1893
1894         p = el;
1895
1896         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1897
1898         while (p) {
1899
1900             x += p.offsetLeft;
1901             y += p.offsetTop;
1902
1903             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1904                 hasAbsolute = true;
1905             }
1906
1907             if (Ext.isGecko) {
1908                 pe = fly(p);
1909
1910                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1911                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1912
1913
1914                 x += bl;
1915                 y += bt;
1916
1917
1918                 if (p != el && pe.getStyle('overflow') != 'visible') {
1919                     x += bl;
1920                     y += bt;
1921                 }
1922             }
1923             p = p.offsetParent;
1924         }
1925
1926         if (Ext.isSafari && hasAbsolute) {
1927             x -= bd.offsetLeft;
1928             y -= bd.offsetTop;
1929         }
1930
1931         if (Ext.isGecko && !hasAbsolute) {
1932             var dbd = fly(bd);
1933             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1934             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1935         }
1936
1937         p = el.parentNode;
1938         while (p && p != bd) {
1939             if (!Ext.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1940                 x -= p.scrollLeft;
1941                 y -= p.scrollTop;
1942             }
1943             p = p.parentNode;
1944         }
1945         return [x, y];
1946     },
1947
1948     setXY : function(el, xy){ // this initially used Position.cumulativeOffset but it is not accurate enough
1949         el = Ext.fly(el, '_setXY');
1950         el.position();
1951         var pts = el.translatePoints(xy);
1952         if(xy[0] !== false){
1953             el.dom.style.left = pts.left + "px";
1954         }
1955         if(xy[1] !== false){
1956             el.dom.style.top = pts.top + "px";
1957         }
1958     },
1959
1960     setX : function(el, x){
1961         this.setXY(el, [x, false]);
1962     },
1963
1964     setY : function(el, y){
1965         this.setXY(el, [false, y]);
1966     }
1967 };
1968
1969 Ext.lib.Event = {
1970     getPageX : function(e){
1971         return Event.pointerX(e.browserEvent || e);
1972     },
1973
1974     getPageY : function(e){
1975         return Event.pointerY(e.browserEvent || e);
1976     },
1977
1978     getXY : function(e){
1979         e = e.browserEvent || e;
1980         return [Event.pointerX(e), Event.pointerY(e)];
1981     },
1982
1983     getTarget : function(e){
1984         return Event.element(e.browserEvent || e);
1985     },
1986
1987     resolveTextNode: function(node) {
1988         return node && !isXUL(node) && isTextNode(node) ? node.parentNode : node;
1989     },
1990
1991     getRelatedTarget: function(ev) { // missing from prototype?
1992         ev = ev.browserEvent || ev;
1993         var t = ev.relatedTarget;
1994         if (!t) {
1995             if (ev.type == "mouseout") {
1996                 t = ev.toElement;
1997             } else if (ev.type == "mouseover") {
1998                 t = ev.fromElement;
1999             }
2000         }
2001
2002         return this.resolveTextNode(t);
2003     },
2004
2005     on : function(el, eventName, fn){
2006         if((eventName == 'mouseenter' || eventName == 'mouseleave') && !mouseEnterSupported){
2007             var item = mouseCache[el.id] || (mouseCache[el.id] = {});
2008             item[eventName] = fn;
2009             fn = fn.createInterceptor(checkRelatedTarget);
2010             eventName = (eventName == 'mouseenter') ? 'mouseover' : 'mouseout';
2011         }
2012         Event.observe(el, eventName, fn, false);
2013     },
2014
2015     un : function(el, eventName, fn){
2016         if((eventName == 'mouseenter' || eventName == 'mouseleave') && !mouseEnterSupported){
2017             var item = mouseCache[el.id], 
2018                 ev = item && item[eventName];
2019
2020             if(ev){
2021                 fn = ev.fn;
2022                 delete item[eventName];
2023                 eventName = (eventName == 'mouseenter') ? 'mouseover' : 'mouseout';
2024             }
2025         }
2026         Event.stopObserving(el, eventName, fn, false);
2027     },
2028
2029     purgeElement : function(el){
2030         // no equiv?
2031     },
2032
2033     preventDefault : function(e){   // missing from prototype?
2034         e = e.browserEvent || e;
2035         if(e.preventDefault) {
2036             e.preventDefault();
2037         } else {
2038             e.returnValue = false;
2039         }
2040     },
2041
2042     stopPropagation : function(e){   // missing from prototype?
2043         e = e.browserEvent || e;
2044         if(e.stopPropagation) {
2045             e.stopPropagation();
2046         } else {
2047             e.cancelBubble = true;
2048         }
2049     },
2050
2051     stopEvent : function(e){
2052         Event.stop(e.browserEvent || e);
2053     },
2054
2055     onAvailable : function(id, fn, scope){  // no equiv
2056         var start = new Date(), iid;
2057         var f = function(){
2058             if(start.getElapsed() > 10000){
2059                 clearInterval(iid);
2060             }
2061             var el = document.getElementById(id);
2062             if(el){
2063                 clearInterval(iid);
2064                 fn.call(scope||window, el);
2065             }
2066         };
2067         iid = setInterval(f, 50);
2068     }
2069 };
2070
2071 Ext.lib.Ajax = function(){
2072     var createSuccess = function(cb){
2073          return cb.success ? function(xhr){
2074             cb.success.call(cb.scope||window, {
2075                 responseText: xhr.responseText,
2076                 responseXML : xhr.responseXML,
2077                 argument: cb.argument
2078             });
2079          } : Ext.emptyFn;
2080     };
2081     var createFailure = function(cb){
2082          return cb.failure ? function(xhr){
2083             cb.failure.call(cb.scope||window, {
2084                 responseText: xhr.responseText,
2085                 responseXML : xhr.responseXML,
2086                 argument: cb.argument
2087             });
2088          } : Ext.emptyFn;
2089     };
2090     return {
2091         request : function(method, uri, cb, data, options){
2092             var o = {
2093                 method: method,
2094                 parameters: data || '',
2095                 timeout: cb.timeout,
2096                 onSuccess: createSuccess(cb),
2097                 onFailure: createFailure(cb)
2098             };
2099             if(options){
2100                 var hs = options.headers;
2101                 if(hs){
2102                     o.requestHeaders = hs;
2103                 }
2104                 if(options.xmlData){
2105                     method = (method ? method : (options.method ? options.method : 'POST'));
2106                     if (!hs || !hs['Content-Type']){
2107                         o.contentType = 'text/xml';
2108                     }
2109                     o.postBody = options.xmlData;
2110                     delete o.parameters;
2111                 }
2112                 if(options.jsonData){
2113                     method = (method ? method : (options.method ? options.method : 'POST'));
2114                     if (!hs || !hs['Content-Type']){
2115                         o.contentType = 'application/json';
2116                     }
2117                     o.postBody = typeof options.jsonData == 'object' ? Ext.encode(options.jsonData) : options.jsonData;
2118                     delete o.parameters;
2119                 }
2120             }
2121             new Ajax.Request(uri, o);
2122         },
2123
2124         formRequest : function(form, uri, cb, data, isUpload, sslUri){
2125             new Ajax.Request(uri, {
2126                 method: Ext.getDom(form).method ||'POST',
2127                 parameters: Form.serialize(form)+(data?'&'+data:''),
2128                 timeout: cb.timeout,
2129                 onSuccess: createSuccess(cb),
2130                 onFailure: createFailure(cb)
2131             });
2132         },
2133
2134         isCallInProgress : function(trans){
2135             return false;
2136         },
2137
2138         abort : function(trans){
2139             return false;
2140         },
2141         
2142         serializeForm : function(form){
2143             return Form.serialize(form.dom||form);
2144         }
2145     };
2146 }();
2147
2148
2149 Ext.lib.Anim = function(){
2150     
2151     var easings = {
2152         easeOut: function(pos) {
2153             return 1-Math.pow(1-pos,2);
2154         },
2155         easeIn: function(pos) {
2156             return 1-Math.pow(1-pos,2);
2157         }
2158     };
2159     var createAnim = function(cb, scope){
2160         return {
2161             stop : function(skipToLast){
2162                 this.effect.cancel();
2163             },
2164
2165             isAnimated : function(){
2166                 return this.effect.state == 'running';
2167             },
2168
2169             proxyCallback : function(){
2170                 Ext.callback(cb, scope);
2171             }
2172         };
2173     };
2174     return {
2175         scroll : function(el, args, duration, easing, cb, scope){
2176             // not supported so scroll immediately?
2177             var anim = createAnim(cb, scope);
2178             el = Ext.getDom(el);
2179             if(typeof args.scroll.to[0] == 'number'){
2180                 el.scrollLeft = args.scroll.to[0];
2181             }
2182             if(typeof args.scroll.to[1] == 'number'){
2183                 el.scrollTop = args.scroll.to[1];
2184             }
2185             anim.proxyCallback();
2186             return anim;
2187         },
2188
2189         motion : function(el, args, duration, easing, cb, scope){
2190             return this.run(el, args, duration, easing, cb, scope);
2191         },
2192
2193         color : function(el, args, duration, easing, cb, scope){
2194             return this.run(el, args, duration, easing, cb, scope);
2195         },
2196
2197         run : function(el, args, duration, easing, cb, scope, type){
2198             var o = {};
2199             for(var k in args){
2200                 switch(k){   // scriptaculous doesn't support, so convert these
2201                     case 'points':
2202                         var by, pts, e = Ext.fly(el, '_animrun');
2203                         e.position();
2204                         if(by = args.points.by){
2205                             var xy = e.getXY();
2206                             pts = e.translatePoints([xy[0]+by[0], xy[1]+by[1]]);
2207                         }else{
2208                             pts = e.translatePoints(args.points.to);
2209                         }
2210                         o.left = pts.left+'px';
2211                         o.top = pts.top+'px';
2212                     break;
2213                     case 'width':
2214                         o.width = args.width.to+'px';
2215                     break;
2216                     case 'height':
2217                         o.height = args.height.to+'px';
2218                     break;
2219                     case 'opacity':
2220                         o.opacity = String(args.opacity.to);
2221                     break;
2222                     default:
2223                         o[k] = String(args[k].to);
2224                     break;
2225                 }
2226             }
2227             var anim = createAnim(cb, scope);
2228             anim.effect = new Effect.Morph(Ext.id(el), {
2229                 duration: duration,
2230                 afterFinish: anim.proxyCallback,
2231                 transition: easings[easing] || Effect.Transitions.linear,
2232                 style: o
2233             });
2234             return anim;
2235         }
2236     };
2237 }();
2238
2239
2240 // all lib flyweight calls use their own flyweight to prevent collisions with developer flyweights
2241 function fly(el){
2242     if(!libFlyweight){
2243         libFlyweight = new Ext.Element.Flyweight();
2244     }
2245     libFlyweight.dom = el;
2246     return libFlyweight;
2247 }
2248     
2249 Ext.lib.Region = function(t, r, b, l) {
2250     this.top = t;
2251     this[1] = t;
2252     this.right = r;
2253     this.bottom = b;
2254     this.left = l;
2255     this[0] = l;
2256 };
2257
2258 Ext.lib.Region.prototype = {
2259     contains : function(region) {
2260         return ( region.left   >= this.left   &&
2261                  region.right  <= this.right  &&
2262                  region.top    >= this.top    &&
2263                  region.bottom <= this.bottom    );
2264
2265     },
2266
2267     getArea : function() {
2268         return ( (this.bottom - this.top) * (this.right - this.left) );
2269     },
2270
2271     intersect : function(region) {
2272         var t = Math.max( this.top,    region.top    );
2273         var r = Math.min( this.right,  region.right  );
2274         var b = Math.min( this.bottom, region.bottom );
2275         var l = Math.max( this.left,   region.left   );
2276
2277         if (b >= t && r >= l) {
2278             return new Ext.lib.Region(t, r, b, l);
2279         } else {
2280             return null;
2281         }
2282     },
2283     union : function(region) {
2284         var t = Math.min( this.top,    region.top    );
2285         var r = Math.max( this.right,  region.right  );
2286         var b = Math.max( this.bottom, region.bottom );
2287         var l = Math.min( this.left,   region.left   );
2288
2289         return new Ext.lib.Region(t, r, b, l);
2290     },
2291
2292     constrainTo : function(r) {
2293             this.top = this.top.constrain(r.top, r.bottom);
2294             this.bottom = this.bottom.constrain(r.top, r.bottom);
2295             this.left = this.left.constrain(r.left, r.right);
2296             this.right = this.right.constrain(r.left, r.right);
2297             return this;
2298     },
2299
2300     adjust : function(t, l, b, r){
2301         this.top += t;
2302         this.left += l;
2303         this.right += r;
2304         this.bottom += b;
2305         return this;
2306     }
2307 };
2308
2309 Ext.lib.Region.getRegion = function(el) {
2310     var p = Ext.lib.Dom.getXY(el);
2311
2312     var t = p[1];
2313     var r = p[0] + el.offsetWidth;
2314     var b = p[1] + el.offsetHeight;
2315     var l = p[0];
2316
2317     return new Ext.lib.Region(t, r, b, l);
2318 };
2319
2320 Ext.lib.Point = function(x, y) {
2321    if (Ext.isArray(x)) {
2322       y = x[1];
2323       x = x[0];
2324    }
2325     this.x = this.right = this.left = this[0] = x;
2326     this.y = this.top = this.bottom = this[1] = y;
2327 };
2328
2329 Ext.lib.Point.prototype = new Ext.lib.Region();
2330
2331
2332 // prevent IE leaks
2333 if(Ext.isIE) {
2334     function fnCleanUp() {
2335         var p = Function.prototype;
2336         delete p.createSequence;
2337         delete p.defer;
2338         delete p.createDelegate;
2339         delete p.createCallback;
2340         delete p.createInterceptor;
2341
2342         window.detachEvent("onunload", fnCleanUp);
2343     }
2344     window.attachEvent("onunload", fnCleanUp);
2345 }
2346 })();