Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / src / core / core / Ext.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