Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / core / core / Ext.js
1 /*!
2  * Ext JS Library 3.0.3
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.1'\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         ua = navigator.userAgent.toLowerCase(),\r
50         check = function(r){\r
51             return r.test(ua);\r
52         },\r
53         DOC = document,\r
54         isStrict = DOC.compatMode == "CSS1Compat",\r
55         isOpera = check(/opera/),\r
56         isChrome = check(/chrome/),\r
57         isWebKit = check(/webkit/),\r
58         isSafari = !isChrome && check(/safari/),\r
59         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2\r
60         isSafari3 = isSafari && check(/version\/3/),\r
61         isSafari4 = isSafari && check(/version\/4/),\r
62         isIE = !isOpera && check(/msie/),\r
63         isIE7 = isIE && check(/msie 7/),\r
64         isIE8 = isIE && check(/msie 8/),\r
65         isIE6 = isIE && !isIE7 && !isIE8,\r
66         isGecko = !isWebKit && check(/gecko/),\r
67         isGecko2 = isGecko && check(/rv:1\.8/),\r
68         isGecko3 = isGecko && check(/rv:1\.9/),\r
69         isBorderBox = isIE && !isStrict,\r
70         isWindows = check(/windows|win32/),\r
71         isMac = check(/macintosh|mac os x/),\r
72         isAir = check(/adobeair/),\r
73         isLinux = check(/linux/),\r
74         isSecure = /^https/i.test(window.location.protocol);\r
75 \r
76     // remove css image flicker\r
77     if(isIE6){\r
78         try{\r
79             DOC.execCommand("BackgroundImageCache", false, true);\r
80         }catch(e){}\r
81     }\r
82 \r
83     Ext.apply(Ext, {\r
84         /**\r
85          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent\r
86          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).\r
87          * @type String\r
88          */\r
89         SSL_SECURE_URL : isSecure && isIE ? 'javascript:""' : 'about:blank', \r
90         /**\r
91          * True if the browser is in strict (standards-compliant) mode, as opposed to quirks mode\r
92          * @type Boolean\r
93          */\r
94         isStrict : isStrict,\r
95         /**\r
96          * True if the page is running over SSL\r
97          * @type Boolean\r
98          */\r
99         isSecure : isSecure,\r
100         /**\r
101          * True when the document is fully initialized and ready for action\r
102          * @type Boolean\r
103          */\r
104         isReady : false,\r
105 \r
106         /**\r
107          * True if the {@link Ext.Fx} Class is available\r
108          * @type Boolean\r
109          * @property enableFx\r
110          */\r
111 \r
112         /**\r
113          * True to automatically uncache orphaned Ext.Elements periodically (defaults to true)\r
114          * @type Boolean\r
115          */\r
116         enableGarbageCollector : true,\r
117 \r
118         /**\r
119          * True to automatically purge event listeners after uncaching an element (defaults to false).\r
120          * Note: this only happens if {@link #enableGarbageCollector} is true.\r
121          * @type Boolean\r
122          */\r
123         enableListenerCollection : false,\r
124 \r
125         /**\r
126          * Indicates whether to use native browser parsing for JSON methods.\r
127          * This option is ignored if the browser does not support native JSON methods.\r
128          * <b>Note: Native JSON methods will not work with objects that have functions.\r
129          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)\r
130          * @type Boolean\r
131          */\r
132         USE_NATIVE_JSON : false,\r
133 \r
134         /**\r
135          * Copies all the properties of config to obj if they don't already exist.\r
136          * @param {Object} obj The receiver of the properties\r
137          * @param {Object} config The source of the properties\r
138          * @return {Object} returns obj\r
139          */\r
140         applyIf : function(o, c){\r
141             if(o){\r
142                 for(var p in c){\r
143                     if(!Ext.isDefined(o[p])){\r
144                         o[p] = c[p];\r
145                     }\r
146                 }\r
147             }\r
148             return o;\r
149         },\r
150 \r
151         /**\r
152          * Generates unique ids. If the element already has an id, it is unchanged\r
153          * @param {Mixed} el (optional) The element to generate an id for\r
154          * @param {String} prefix (optional) Id prefix (defaults "ext-gen")\r
155          * @return {String} The generated Id.\r
156          */\r
157         id : function(el, prefix){\r
158             return (el = Ext.getDom(el) || {}).id = el.id || (prefix || "ext-gen") + (++idSeed);\r
159         },\r
160 \r
161         /**\r
162          * <p>Extends one class to create a subclass and optionally overrides members with the passed literal. This method\r
163          * also adds the function "override()" to the subclass that can be used to override members of the class.</p>\r
164          * For example, to create a subclass of Ext GridPanel:\r
165          * <pre><code>\r
166 MyGridPanel = Ext.extend(Ext.grid.GridPanel, {\r
167     constructor: function(config) {\r
168 \r
169 //      Create configuration for this Grid.\r
170         var store = new Ext.data.Store({...});\r
171         var colModel = new Ext.grid.ColumnModel({...});\r
172 \r
173 //      Create a new config object containing our computed properties\r
174 //      *plus* whatever was in the config parameter.\r
175         config = Ext.apply({\r
176             store: store,\r
177             colModel: colModel\r
178         }, config);\r
179 \r
180         MyGridPanel.superclass.constructor.call(this, config);\r
181 \r
182 //      Your postprocessing here\r
183     },\r
184 \r
185     yourMethod: function() {\r
186         // etc.\r
187     }\r
188 });\r
189 </code></pre>\r
190          *\r
191          * <p>This function also supports a 3-argument call in which the subclass's constructor is\r
192          * passed as an argument. In this form, the parameters are as follows:</p>\r
193          * <div class="mdetail-params"><ul>\r
194          * <li><code>subclass</code> : Function <div class="sub-desc">The subclass constructor.</div></li>\r
195          * <li><code>superclass</code> : Function <div class="sub-desc">The constructor of class being extended</div></li>\r
196          * <li><code>overrides</code> : Object <div class="sub-desc">A literal with members which are copied into the subclass's\r
197          * prototype, and are therefore shared among all instances of the new class.</div></li>\r
198          * </ul></div>\r
199          *\r
200          * @param {Function} subclass The constructor of class being extended.\r
201          * @param {Object} overrides <p>A literal with members which are copied into the subclass's\r
202          * prototype, and are therefore shared between all instances of the new class.</p>\r
203          * <p>This may contain a special member named <tt><b>constructor</b></tt>. This is used\r
204          * to define the constructor of the new class, and is returned. If this property is\r
205          * <i>not</i> specified, a constructor is generated and returned which just calls the\r
206          * superclass's constructor passing on its parameters.</p>\r
207          * <p><b>It is essential that you call the superclass constructor in any provided constructor. See example code.</b></p>\r
208          * @return {Function} The subclass constructor.\r
209          */\r
210         extend : function(){\r
211             // inline overrides\r
212             var io = function(o){\r
213                 for(var m in o){\r
214                     this[m] = o[m];\r
215                 }\r
216             };\r
217             var oc = Object.prototype.constructor;\r
218 \r
219             return function(sb, sp, overrides){\r
220                 if(Ext.isObject(sp)){\r
221                     overrides = sp;\r
222                     sp = sb;\r
223                     sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};\r
224                 }\r
225                 var F = function(){},\r
226                     sbp,\r
227                     spp = sp.prototype;\r
228 \r
229                 F.prototype = spp;\r
230                 sbp = sb.prototype = new F();\r
231                 sbp.constructor=sb;\r
232                 sb.superclass=spp;\r
233                 if(spp.constructor == oc){\r
234                     spp.constructor=sp;\r
235                 }\r
236                 sb.override = function(o){\r
237                     Ext.override(sb, o);\r
238                 };\r
239                 sbp.superclass = sbp.supr = (function(){\r
240                     return spp;\r
241                 });\r
242                 sbp.override = io;\r
243                 Ext.override(sb, overrides);\r
244                 sb.extend = function(o){return Ext.extend(sb, o);};\r
245                 return sb;\r
246             };\r
247         }(),\r
248 \r
249         /**\r
250          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.\r
251          * Usage:<pre><code>\r
252 Ext.override(MyClass, {\r
253     newMethod1: function(){\r
254         // etc.\r
255     },\r
256     newMethod2: function(foo){\r
257         // etc.\r
258     }\r
259 });\r
260 </code></pre>\r
261          * @param {Object} origclass The class to override\r
262          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal\r
263          * containing one or more methods.\r
264          * @method override\r
265          */\r
266         override : function(origclass, overrides){\r
267             if(overrides){\r
268                 var p = origclass.prototype;\r
269                 Ext.apply(p, overrides);\r
270                 if(Ext.isIE && overrides.toString != origclass.toString){\r
271                     p.toString = overrides.toString;\r
272                 }\r
273             }\r
274         },\r
275 \r
276         /**\r
277          * Creates namespaces to be used for scoping variables and classes so that they are not global.\r
278          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:\r
279          * <pre><code>\r
280 Ext.namespace('Company', 'Company.data');\r
281 Ext.namespace('Company.data'); // equivalent and preferable to above syntax\r
282 Company.Widget = function() { ... }\r
283 Company.data.CustomStore = function(config) { ... }\r
284 </code></pre>\r
285          * @param {String} namespace1\r
286          * @param {String} namespace2\r
287          * @param {String} etc\r
288          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)\r
289          * @method namespace\r
290          */\r
291         namespace : function(){\r
292             var o, d;\r
293             Ext.each(arguments, function(v) {\r
294                 d = v.split(".");\r
295                 o = window[d[0]] = window[d[0]] || {};\r
296                 Ext.each(d.slice(1), function(v2){\r
297                     o = o[v2] = o[v2] || {};\r
298                 });\r
299             });\r
300             return o;\r
301         },\r
302 \r
303         /**\r
304          * 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
305          * @param {Object} o\r
306          * @param {String} pre (optional) A prefix to add to the url encoded string\r
307          * @return {String}\r
308          */\r
309         urlEncode : function(o, pre){\r
310             var empty,\r
311                 buf = [],\r
312                 e = encodeURIComponent;\r
313 \r
314             Ext.iterate(o, function(key, item){\r
315                 empty = Ext.isEmpty(item);\r
316                 Ext.each(empty ? key : item, function(val){\r
317                     buf.push('&', e(key), '=', (!Ext.isEmpty(val) && (val != key || !empty)) ? (Ext.isDate(val) ? Ext.encode(val).replace(/"/g, '') : e(val)) : '');\r
318                 });\r
319             });\r
320             if(!pre){\r
321                 buf.shift();\r
322                 pre = '';\r
323             }\r
324             return pre + buf.join('');\r
325         },\r
326 \r
327         /**\r
328          * Takes an encoded URL and and converts it to an object. Example: <pre><code>\r
329 Ext.urlDecode("foo=1&bar=2"); // returns {foo: "1", bar: "2"}\r
330 Ext.urlDecode("foo=1&bar=2&bar=3&bar=4", false); // returns {foo: "1", bar: ["2", "3", "4"]}\r
331 </code></pre>\r
332          * @param {String} string\r
333          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).\r
334          * @return {Object} A literal with members\r
335          */\r
336         urlDecode : function(string, overwrite){\r
337             if(Ext.isEmpty(string)){\r
338                 return {};\r
339             }\r
340             var obj = {},\r
341                 pairs = string.split('&'),\r
342                 d = decodeURIComponent,\r
343                 name,\r
344                 value;\r
345             Ext.each(pairs, function(pair) {\r
346                 pair = pair.split('=');\r
347                 name = d(pair[0]);\r
348                 value = d(pair[1]);\r
349                 obj[name] = overwrite || !obj[name] ? value :\r
350                             [].concat(obj[name]).concat(value);\r
351             });\r
352             return obj;\r
353         },\r
354 \r
355         /**\r
356          * Appends content to the query string of a URL, handling logic for whether to place\r
357          * a question mark or ampersand.\r
358          * @param {String} url The URL to append to.\r
359          * @param {String} s The content to append to the URL.\r
360          * @return (String) The resulting URL\r
361          */\r
362         urlAppend : function(url, s){\r
363             if(!Ext.isEmpty(s)){\r
364                 return url + (url.indexOf('?') === -1 ? '?' : '&') + s;\r
365             }\r
366             return url;\r
367         },\r
368 \r
369         /**\r
370          * Converts any iterable (numeric indices and a length property) into a true array\r
371          * Don't use this on strings. IE doesn't support "abc"[0] which this implementation depends on.\r
372          * For strings, use this instead: "abc".match(/./g) => [a,b,c];\r
373          * @param {Iterable} the iterable object to be turned into a true Array.\r
374          * @return (Array) array\r
375          */\r
376         toArray : function(){\r
377             return isIE ?\r
378                 function(a, i, j, res){\r
379                     res = [];\r
380                     Ext.each(a, function(v) {\r
381                         res.push(v);\r
382                     });\r
383                     return res.slice(i || 0, j || res.length);\r
384                 } :\r
385                 function(a, i, j){\r
386                     return Array.prototype.slice.call(a, i || 0, j || a.length);\r
387                 }\r
388         }(),\r
389 \r
390         isIterable : function(v){\r
391             //check for array or arguments\r
392             if(Ext.isArray(v) || v.callee){\r
393                 return true;\r
394             }\r
395             //check for node list type\r
396             if(/NodeList|HTMLCollection/.test(toString.call(v))){\r
397                 return true;\r
398             }\r
399             //NodeList has an item and length property\r
400             //IXMLDOMNodeList has nextNode method, needs to be checked first.\r
401             return ((v.nextNode || v.item) && Ext.isNumber(v.length));\r
402         },\r
403 \r
404         /**\r
405          * Iterates an array calling the supplied function.\r
406          * @param {Array/NodeList/Mixed} array The array to be iterated. If this\r
407          * argument is not really an array, the supplied function is called once.\r
408          * @param {Function} fn The function to be called with each item. If the\r
409          * supplied function returns false, iteration stops and this method returns\r
410          * the current <code>index</code>. This function is called with\r
411          * the following arguments:\r
412          * <div class="mdetail-params"><ul>\r
413          * <li><code>item</code> : <i>Mixed</i>\r
414          * <div class="sub-desc">The item at the current <code>index</code>\r
415          * in the passed <code>array</code></div></li>\r
416          * <li><code>index</code> : <i>Number</i>\r
417          * <div class="sub-desc">The current index within the array</div></li>\r
418          * <li><code>allItems</code> : <i>Array</i>\r
419          * <div class="sub-desc">The <code>array</code> passed as the first\r
420          * argument to <code>Ext.each</code>.</div></li>\r
421          * </ul></div>\r
422          * @param {Object} scope The scope (<code>this</code> reference) in which the specified function is executed.\r
423          * Defaults to the <code>item</code> at the current <code>index</code>\r
424          * within the passed <code>array</code>.\r
425          * @return See description for the fn parameter.\r
426          */\r
427         each : function(array, fn, scope){\r
428             if(Ext.isEmpty(array, true)){\r
429                 return;\r
430             }\r
431             if(!Ext.isIterable(array) || Ext.isPrimitive(array)){\r
432                 array = [array];\r
433             }\r
434             for(var i = 0, len = array.length; i < len; i++){\r
435                 if(fn.call(scope || array[i], array[i], i, array) === false){\r
436                     return i;\r
437                 };\r
438             }\r
439         },\r
440 \r
441         /**\r
442          * Iterates either the elements in an array, or each of the properties in an object.\r
443          * <b>Note</b>: If you are only iterating arrays, it is better to call {@link #each}.\r
444          * @param {Object/Array} object The object or array to be iterated\r
445          * @param {Function} fn The function to be called for each iteration.\r
446          * The iteration will stop if the supplied function returns false, or\r
447          * all array elements / object properties have been covered. The signature\r
448          * varies depending on the type of object being interated:\r
449          * <div class="mdetail-params"><ul>\r
450          * <li>Arrays : <tt>(Object item, Number index, Array allItems)</tt>\r
451          * <div class="sub-desc">\r
452          * When iterating an array, the supplied function is called with each item.</div></li>\r
453          * <li>Objects : <tt>(String key, Object value)</tt>\r
454          * <div class="sub-desc">\r
455          * When iterating an object, the supplied function is called with each key-value pair in\r
456          * the object.</div></li>\r
457          * </ul></div>\r
458          * @param {Object} scope The scope (<code>this</code> reference) in which the specified function is executed. Defaults to\r
459          * the <code>object</code> being iterated.\r
460          */\r
461         iterate : function(obj, fn, scope){\r
462             if(Ext.isEmpty(obj)){\r
463                 return;\r
464             }\r
465             if(Ext.isIterable(obj)){\r
466                 Ext.each(obj, fn, scope);\r
467                 return;\r
468             }else if(Ext.isObject(obj)){\r
469                 for(var prop in obj){\r
470                     if(obj.hasOwnProperty(prop)){\r
471                         if(fn.call(scope || obj, prop, obj[prop]) === false){\r
472                             return;\r
473                         };\r
474                     }\r
475                 }\r
476             }\r
477         },\r
478 \r
479         /**\r
480          * Return the dom node for the passed String (id), dom node, or Ext.Element.\r
481          * Here are some examples:\r
482          * <pre><code>\r
483 // gets dom node based on id\r
484 var elDom = Ext.getDom('elId');\r
485 // gets dom node based on the dom node\r
486 var elDom1 = Ext.getDom(elDom);\r
487 \r
488 // If we don&#39;t know if we are working with an\r
489 // Ext.Element or a dom node use Ext.getDom\r
490 function(el){\r
491     var dom = Ext.getDom(el);\r
492     // do something with the dom node\r
493 }\r
494          * </code></pre>\r
495          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)\r
496          * when this method is called to be successful.\r
497          * @param {Mixed} el\r
498          * @return HTMLElement\r
499          */\r
500         getDom : function(el){\r
501             if(!el || !DOC){\r
502                 return null;\r
503             }\r
504             return el.dom ? el.dom : (Ext.isString(el) ? DOC.getElementById(el) : el);\r
505         },\r
506 \r
507         /**\r
508          * Returns the current document body as an {@link Ext.Element}.\r
509          * @return Ext.Element The document body\r
510          */\r
511         getBody : function(){\r
512             return Ext.get(DOC.body || DOC.documentElement);\r
513         },\r
514 \r
515         /**\r
516          * Removes a DOM node from the document.  The body node will be ignored if passed in.\r
517          * @param {HTMLElement} node The node to remove\r
518          */\r
519         removeNode : isIE ? function(){\r
520             var d;\r
521             return function(n){\r
522                 if(n && n.tagName != 'BODY'){\r
523                     d = d || DOC.createElement('div');\r
524                     d.appendChild(n);\r
525                     d.innerHTML = '';\r
526                 }\r
527             }\r
528         }() : function(n){\r
529             if(n && n.parentNode && n.tagName != 'BODY'){\r
530                 n.parentNode.removeChild(n);\r
531             }\r
532         },\r
533 \r
534         /**\r
535          * <p>Returns true if the passed value is empty.</p>\r
536          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>\r
537          * <li>null</li>\r
538          * <li>undefined</li>\r
539          * <li>an empty array</li>\r
540          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>\r
541          * </ul></div>\r
542          * @param {Mixed} value The value to test\r
543          * @param {Boolean} allowBlank (optional) true to allow empty strings (defaults to false)\r
544          * @return {Boolean}\r
545          */\r
546         isEmpty : function(v, allowBlank){\r
547             return v === null || v === undefined || ((Ext.isArray(v) && !v.length)) || (!allowBlank ? v === '' : false);\r
548         },\r
549 \r
550         /**\r
551          * Returns true if the passed value is a JavaScript array, otherwise false.\r
552          * @param {Mixed} value The value to test\r
553          * @return {Boolean}\r
554          */\r
555         isArray : function(v){\r
556             return toString.apply(v) === '[object Array]';\r
557         },\r
558 \r
559         /**\r
560          * Returns true if the passed object is a JavaScript date object, otherwise false.\r
561          * @param {Object} object The object to test\r
562          * @return {Boolean}\r
563          */\r
564         isDate : function(v){\r
565             return toString.apply(v) === '[object Date]';\r
566         },\r
567 \r
568         /**\r
569          * Returns true if the passed value is a JavaScript Object, otherwise false.\r
570          * @param {Mixed} value The value to test\r
571          * @return {Boolean}\r
572          */\r
573         isObject : function(v){\r
574             return v && typeof v == "object";\r
575         },\r
576 \r
577         /**\r
578          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.\r
579          * @param {Mixed} value The value to test\r
580          * @return {Boolean}\r
581          */\r
582         isPrimitive : function(v){\r
583             return Ext.isString(v) || Ext.isNumber(v) || Ext.isBoolean(v);\r
584         },\r
585 \r
586         /**\r
587          * Returns true if the passed value is a JavaScript Function, otherwise false.\r
588          * @param {Mixed} value The value to test\r
589          * @return {Boolean}\r
590          */\r
591         isFunction : function(v){\r
592             return toString.apply(v) === '[object Function]';\r
593         },\r
594 \r
595         /**\r
596          * Returns true if the passed value is a number. Returns false for non-finite numbers.\r
597          * @param {Mixed} value The value to test\r
598          * @return {Boolean}\r
599          */\r
600         isNumber : function(v){\r
601             return typeof v === 'number' && isFinite(v);\r
602         },\r
603 \r
604         /**\r
605          * Returns true if the passed value is a string.\r
606          * @param {Mixed} value The value to test\r
607          * @return {Boolean}\r
608          */\r
609         isString : function(v){\r
610             return typeof v === 'string';\r
611         },\r
612 \r
613         /**\r
614          * Returns true if the passed value is a boolean.\r
615          * @param {Mixed} value The value to test\r
616          * @return {Boolean}\r
617          */\r
618         isBoolean : function(v){\r
619             return typeof v === 'boolean';\r
620         },\r
621 \r
622         /**\r
623          * Returns true if the passed value is not undefined.\r
624          * @param {Mixed} value The value to test\r
625          * @return {Boolean}\r
626          */\r
627         isDefined : function(v){\r
628             return typeof v !== 'undefined';\r
629         },\r
630 \r
631         /**\r
632          * True if the detected browser is Opera.\r
633          * @type Boolean\r
634          */\r
635         isOpera : isOpera,\r
636         /**\r
637          * True if the detected browser uses WebKit.\r
638          * @type Boolean\r
639          */\r
640         isWebKit : isWebKit,\r
641         /**\r
642          * True if the detected browser is Chrome.\r
643          * @type Boolean\r
644          */\r
645         isChrome : isChrome,\r
646         /**\r
647          * True if the detected browser is Safari.\r
648          * @type Boolean\r
649          */\r
650         isSafari : isSafari,\r
651         /**\r
652          * True if the detected browser is Safari 3.x.\r
653          * @type Boolean\r
654          */\r
655         isSafari3 : isSafari3,\r
656         /**\r
657          * True if the detected browser is Safari 4.x.\r
658          * @type Boolean\r
659          */\r
660         isSafari4 : isSafari4,\r
661         /**\r
662          * True if the detected browser is Safari 2.x.\r
663          * @type Boolean\r
664          */\r
665         isSafari2 : isSafari2,\r
666         /**\r
667          * True if the detected browser is Internet Explorer.\r
668          * @type Boolean\r
669          */\r
670         isIE : isIE,\r
671         /**\r
672          * True if the detected browser is Internet Explorer 6.x.\r
673          * @type Boolean\r
674          */\r
675         isIE6 : isIE6,\r
676         /**\r
677          * True if the detected browser is Internet Explorer 7.x.\r
678          * @type Boolean\r
679          */\r
680         isIE7 : isIE7,\r
681         /**\r
682          * True if the detected browser is Internet Explorer 8.x.\r
683          * @type Boolean\r
684          */\r
685         isIE8 : isIE8,\r
686         /**\r
687          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).\r
688          * @type Boolean\r
689          */\r
690         isGecko : isGecko,\r
691         /**\r
692          * True if the detected browser uses a pre-Gecko 1.9 layout engine (e.g. Firefox 2.x).\r
693          * @type Boolean\r
694          */\r
695         isGecko2 : isGecko2,\r
696         /**\r
697          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).\r
698          * @type Boolean\r
699          */\r
700         isGecko3 : isGecko3,\r
701         /**\r
702          * True if the detected browser is Internet Explorer running in non-strict mode.\r
703          * @type Boolean\r
704          */\r
705         isBorderBox : isBorderBox,\r
706         /**\r
707          * True if the detected platform is Linux.\r
708          * @type Boolean\r
709          */\r
710         isLinux : isLinux,\r
711         /**\r
712          * True if the detected platform is Windows.\r
713          * @type Boolean\r
714          */\r
715         isWindows : isWindows,\r
716         /**\r
717          * True if the detected platform is Mac OS.\r
718          * @type Boolean\r
719          */\r
720         isMac : isMac,\r
721         /**\r
722          * True if the detected platform is Adobe Air.\r
723          * @type Boolean\r
724          */\r
725         isAir : isAir\r
726     });\r
727 \r
728     /**\r
729      * Creates namespaces to be used for scoping variables and classes so that they are not global.\r
730      * Specifying the last node of a namespace implicitly creates all other nodes. Usage:\r
731      * <pre><code>\r
732 Ext.namespace('Company', 'Company.data');\r
733 Ext.namespace('Company.data'); // equivalent and preferable to above syntax\r
734 Company.Widget = function() { ... }\r
735 Company.data.CustomStore = function(config) { ... }\r
736 </code></pre>\r
737      * @param {String} namespace1\r
738      * @param {String} namespace2\r
739      * @param {String} etc\r
740      * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)\r
741      * @method ns\r
742      */\r
743     Ext.ns = Ext.namespace;\r
744 })();\r
745 \r
746 Ext.ns("Ext", "Ext.util", "Ext.lib", "Ext.data");\r
747 \r
748 \r
749 /**\r
750  * @class Function\r
751  * These functions are available on every Function object (any JavaScript function).\r
752  */\r
753 Ext.apply(Function.prototype, {\r
754      /**\r
755      * Creates an interceptor function. The passed function is called before the original one. If it returns false,\r
756      * the original one is not called. The resulting function returns the results of the original function.\r
757      * The passed function is called with the parameters of the original function. Example usage:\r
758      * <pre><code>\r
759 var sayHi = function(name){\r
760     alert('Hi, ' + name);\r
761 }\r
762 \r
763 sayHi('Fred'); // alerts "Hi, Fred"\r
764 \r
765 // create a new function that validates input without\r
766 // directly modifying the original function:\r
767 var sayHiToFriend = sayHi.createInterceptor(function(name){\r
768     return name == 'Brian';\r
769 });\r
770 \r
771 sayHiToFriend('Fred');  // no alert\r
772 sayHiToFriend('Brian'); // alerts "Hi, Brian"\r
773 </code></pre>\r
774      * @param {Function} fcn The function to call before the original\r
775      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the passed function is executed.\r
776      * <b>If omitted, defaults to the scope in which the original function is called or the browser window.</b>\r
777      * @return {Function} The new function\r
778      */\r
779     createInterceptor : function(fcn, scope){\r
780         var method = this;\r
781         return !Ext.isFunction(fcn) ?\r
782                 this :\r
783                 function() {\r
784                     var me = this,\r
785                         args = arguments;\r
786                     fcn.target = me;\r
787                     fcn.method = method;\r
788                     return (fcn.apply(scope || me || window, args) !== false) ?\r
789                             method.apply(me || window, args) :\r
790                             null;\r
791                 };\r
792     },\r
793 \r
794      /**\r
795      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...\r
796      * Call directly on any function. Example: <code>myFunction.createCallback(arg1, arg2)</code>\r
797      * Will create a function that is bound to those 2 args. <b>If a specific scope is required in the\r
798      * callback, use {@link #createDelegate} instead.</b> The function returned by createCallback always\r
799      * executes in the window scope.\r
800      * <p>This method is required when you want to pass arguments to a callback function.  If no arguments\r
801      * are needed, you can simply pass a reference to the function as a callback (e.g., callback: myFn).\r
802      * However, if you tried to pass a function with arguments (e.g., callback: myFn(arg1, arg2)) the function\r
803      * would simply execute immediately when the code is parsed. Example usage:\r
804      * <pre><code>\r
805 var sayHi = function(name){\r
806     alert('Hi, ' + name);\r
807 }\r
808 \r
809 // clicking the button alerts "Hi, Fred"\r
810 new Ext.Button({\r
811     text: 'Say Hi',\r
812     renderTo: Ext.getBody(),\r
813     handler: sayHi.createCallback('Fred')\r
814 });\r
815 </code></pre>\r
816      * @return {Function} The new function\r
817     */\r
818     createCallback : function(/*args...*/){\r
819         // make args available, in function below\r
820         var args = arguments,\r
821             method = this;\r
822         return function() {\r
823             return method.apply(window, args);\r
824         };\r
825     },\r
826 \r
827     /**\r
828      * Creates a delegate (callback) that sets the scope to obj.\r
829      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this, [arg1, arg2])</code>\r
830      * Will create a function that is automatically scoped to obj so that the <tt>this</tt> variable inside the\r
831      * callback points to obj. Example usage:\r
832      * <pre><code>\r
833 var sayHi = function(name){\r
834     // Note this use of "this.text" here.  This function expects to\r
835     // execute within a scope that contains a text property.  In this\r
836     // example, the "this" variable is pointing to the btn object that\r
837     // was passed in createDelegate below.\r
838     alert('Hi, ' + name + '. You clicked the "' + this.text + '" button.');\r
839 }\r
840 \r
841 var btn = new Ext.Button({\r
842     text: 'Say Hi',\r
843     renderTo: Ext.getBody()\r
844 });\r
845 \r
846 // This callback will execute in the scope of the\r
847 // button instance. Clicking the button alerts\r
848 // "Hi, Fred. You clicked the "Say Hi" button."\r
849 btn.on('click', sayHi.createDelegate(btn, ['Fred']));\r
850 </code></pre>\r
851      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.\r
852      * <b>If omitted, defaults to the browser window.</b>\r
853      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)\r
854      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,\r
855      * if a number the args are inserted at the specified position\r
856      * @return {Function} The new function\r
857      */\r
858     createDelegate : function(obj, args, appendArgs){\r
859         var method = this;\r
860         return function() {\r
861             var callArgs = args || arguments;\r
862             if (appendArgs === true){\r
863                 callArgs = Array.prototype.slice.call(arguments, 0);\r
864                 callArgs = callArgs.concat(args);\r
865             }else if (Ext.isNumber(appendArgs)){\r
866                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first\r
867                 var applyArgs = [appendArgs, 0].concat(args); // create method call params\r
868                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in\r
869             }\r
870             return method.apply(obj || window, callArgs);\r
871         };\r
872     },\r
873 \r
874     /**\r
875      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:\r
876      * <pre><code>\r
877 var sayHi = function(name){\r
878     alert('Hi, ' + name);\r
879 }\r
880 \r
881 // executes immediately:\r
882 sayHi('Fred');\r
883 \r
884 // executes after 2 seconds:\r
885 sayHi.defer(2000, this, ['Fred']);\r
886 \r
887 // this syntax is sometimes useful for deferring\r
888 // execution of an anonymous function:\r
889 (function(){\r
890     alert('Anonymous');\r
891 }).defer(100);\r
892 </code></pre>\r
893      * @param {Number} millis The number of milliseconds for the setTimeout call (if less than or equal to 0 the function is executed immediately)\r
894      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.\r
895      * <b>If omitted, defaults to the browser window.</b>\r
896      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)\r
897      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,\r
898      * if a number the args are inserted at the specified position\r
899      * @return {Number} The timeout id that can be used with clearTimeout\r
900      */\r
901     defer : function(millis, obj, args, appendArgs){\r
902         var fn = this.createDelegate(obj, args, appendArgs);\r
903         if(millis > 0){\r
904             return setTimeout(fn, millis);\r
905         }\r
906         fn();\r
907         return 0;\r
908     }\r
909 });\r
910 \r
911 /**\r
912  * @class String\r
913  * These functions are available on every String object.\r
914  */\r
915 Ext.applyIf(String, {\r
916     /**\r
917      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each\r
918      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:\r
919      * <pre><code>\r
920 var cls = 'my-class', text = 'Some text';\r
921 var s = String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);\r
922 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'\r
923      * </code></pre>\r
924      * @param {String} string The tokenized string to be formatted\r
925      * @param {String} value1 The value to replace token {0}\r
926      * @param {String} value2 Etc...\r
927      * @return {String} The formatted string\r
928      * @static\r
929      */\r
930     format : function(format){\r
931         var args = Ext.toArray(arguments, 1);\r
932         return format.replace(/\{(\d+)\}/g, function(m, i){\r
933             return args[i];\r
934         });\r
935     }\r
936 });\r
937 \r
938 /**\r
939  * @class Array\r
940  */\r
941 Ext.applyIf(Array.prototype, {\r
942     /**\r
943      * Checks whether or not the specified object exists in the array.\r
944      * @param {Object} o The object to check for\r
945      * @param {Number} from (Optional) The index at which to begin the search\r
946      * @return {Number} The index of o in the array (or -1 if it is not found)\r
947      */\r
948     indexOf : function(o, from){\r
949         var len = this.length;\r
950         from = from || 0;\r
951         from += (from < 0) ? len : 0;\r
952         for (; from < len; ++from){\r
953             if(this[from] === o){\r
954                 return from;\r
955             }\r
956         }\r
957         return -1;\r
958     },\r
959 \r
960     /**\r
961      * Removes the specified object from the array.  If the object is not found nothing happens.\r
962      * @param {Object} o The object to remove\r
963      * @return {Array} this array\r
964      */\r
965     remove : function(o){\r
966         var index = this.indexOf(o);\r
967         if(index != -1){\r
968             this.splice(index, 1);\r
969         }\r
970         return this;\r
971     }\r
972 });\r