Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / core / src / Ext-more.js
1 /**
2  * @class Ext
3
4  The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
5  Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
6  as direct properties of the Ext namespace.
7
8  Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
9  For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
10
11  Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
12  This ensures all scripts have been loaded, preventing dependency issues. For example
13
14      Ext.onReady(function(){
15          new Ext.Component({
16              renderTo: document.body,
17              html: 'DOM ready!'
18          });
19      });
20
21 For more information about how to use the Ext classes, see
22
23 * <a href="http://www.sencha.com/learn/">The Learning Center</a>
24 * <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
25 * <a href="http://www.sencha.com/forum/">The forums</a>
26
27  * @singleton
28  * @markdown
29  */
30 Ext.apply(Ext, {
31     userAgent: navigator.userAgent.toLowerCase(),
32     cache: {},
33     idSeed: 1000,
34     BLANK_IMAGE_URL : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
35     isStrict: document.compatMode == "CSS1Compat",
36     windowId: 'ext-window',
37     documentId: 'ext-document',
38
39     /**
40      * True when the document is fully initialized and ready for action
41      * @type Boolean
42      */
43     isReady: false,
44
45     /**
46      * True to automatically uncache orphaned Ext.core.Elements periodically (defaults to true)
47      * @type Boolean
48      */
49     enableGarbageCollector: true,
50
51     /**
52      * True to automatically purge event listeners during garbageCollection (defaults to true).
53      * @type Boolean
54      */
55     enableListenerCollection: true,
56
57     /**
58      * Generates unique ids. If the element already has an id, it is unchanged
59      * @param {Mixed} el (optional) The element to generate an id for
60      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
61      * @return {String} The generated Id.
62      */
63     id: function(el, prefix) {
64         el = Ext.getDom(el, true) || {};
65         if (el === document) {
66             el.id = this.documentId;
67         }
68         else if (el === window) {
69             el.id = this.windowId;
70         }
71         if (!el.id) {
72             el.id = (prefix || "ext-gen") + (++Ext.idSeed);
73         }
74         return el.id;
75     },
76
77     /**
78      * Returns the current document body as an {@link Ext.core.Element}.
79      * @return Ext.core.Element The document body
80      */
81     getBody: function() {
82         return Ext.get(document.body || false);
83     },
84
85     /**
86      * Returns the current document head as an {@link Ext.core.Element}.
87      * @return Ext.core.Element The document head
88      */
89     getHead: function() {
90         var head;
91
92         return function() {
93             if (head == undefined) {
94                 head = Ext.get(document.getElementsByTagName("head")[0]);
95             }
96
97             return head;
98         };
99     }(),
100
101     /**
102      * Returns the current HTML document object as an {@link Ext.core.Element}.
103      * @return Ext.core.Element The document
104      */
105     getDoc: function() {
106         return Ext.get(document);
107     },
108
109     /**
110      * This is shorthand reference to {@link Ext.ComponentManager#get}.
111      * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
112      * @param {String} id The component {@link Ext.Component#id id}
113      * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
114      * Class was found.
115     */
116     getCmp: function(id) {
117         return Ext.ComponentManager.get(id);
118     },
119
120     /**
121      * Returns the current orientation of the mobile device
122      * @return {String} Either 'portrait' or 'landscape'
123      */
124     getOrientation: function() {
125         return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
126     },
127
128     /**
129      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
130      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
131      * intended for arguments of type {@link Ext.core.Element} and {@link Ext.Component}, but any subclass of
132      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
133      * passed into this function in a single call as separate arguments.
134      * @param {Mixed} arg1 An {@link Ext.core.Element}, {@link Ext.Component}, or an Array of either of these to destroy
135      * @param {Mixed} arg2 (optional)
136      * @param {Mixed} etc... (optional)
137      */
138     destroy: function() {
139         var ln = arguments.length,
140         i, arg;
141
142         for (i = 0; i < ln; i++) {
143             arg = arguments[i];
144             if (arg) {
145                 if (Ext.isArray(arg)) {
146                     this.destroy.apply(this, arg);
147                 }
148                 else if (Ext.isFunction(arg.destroy)) {
149                     arg.destroy();
150                 }
151                 else if (arg.dom) {
152                     arg.remove();
153                 }
154             }
155         }
156     },
157
158     /**
159      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
160      * @param {Function} callback The callback to execute
161      * @param {Object} scope (optional) The scope to execute in
162      * @param {Array} args (optional) The arguments to pass to the function
163      * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
164      */
165     callback: function(callback, scope, args, delay){
166         if(Ext.isFunction(callback)){
167             args = args || [];
168             scope = scope || window;
169             if (delay) {
170                 Ext.defer(callback, delay, scope, args);
171             } else {
172                 callback.apply(scope, args);
173             }
174         }
175     },
176
177     /**
178      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
179      * @param {String} value The string to encode
180      * @return {String} The encoded text
181      */
182     htmlEncode : function(value) {
183         return Ext.String.htmlEncode(value);
184     },
185
186     /**
187      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
188      * @param {String} value The string to decode
189      * @return {String} The decoded text
190      */
191     htmlDecode : function(value) {
192          return Ext.String.htmlDecode(value);
193     },
194
195     /**
196      * Appends content to the query string of a URL, handling logic for whether to place
197      * a question mark or ampersand.
198      * @param {String} url The URL to append to.
199      * @param {String} s The content to append to the URL.
200      * @return (String) The resulting URL
201      */
202     urlAppend : function(url, s) {
203         if (!Ext.isEmpty(s)) {
204             return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
205         }
206         return url;
207     }
208 });
209
210
211 Ext.ns = Ext.namespace;
212
213 // for old browsers
214 window.undefined = window.undefined;
215 /**
216  * @class Ext
217  * Ext core utilities and functions.
218  * @singleton
219  */
220 (function(){
221     var check = function(regex){
222             return regex.test(Ext.userAgent);
223         },
224         docMode = document.documentMode,
225         isOpera = check(/opera/),
226         isOpera10_5 = isOpera && check(/version\/10\.5/),
227         isChrome = check(/\bchrome\b/),
228         isWebKit = check(/webkit/),
229         isSafari = !isChrome && check(/safari/),
230         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
231         isSafari3 = isSafari && check(/version\/3/),
232         isSafari4 = isSafari && check(/version\/4/),
233         isIE = !isOpera && check(/msie/),
234         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
235         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
236         isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
237         isIE6 = isIE && check(/msie 6/),
238         isGecko = !isWebKit && check(/gecko/),
239         isGecko3 = isGecko && check(/rv:1\.9/),
240         isGecko4 = isGecko && check(/rv:2\.0/),
241         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
242         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
243         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
244         isWindows = check(/windows|win32/),
245         isMac = check(/macintosh|mac os x/),
246         isLinux = check(/linux/),
247         scrollWidth = null;
248
249     // remove css image flicker
250     try {
251         document.execCommand("BackgroundImageCache", false, true);
252     } catch(e) {}
253
254     Ext.setVersion('extjs', '4.0.0');
255     Ext.apply(Ext, {
256         /**
257          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
258          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
259          * @type String
260          */
261         SSL_SECURE_URL : Ext.isSecure && isIE ? 'javascript:""' : 'about:blank',
262
263         /**
264          * True if the {@link Ext.fx.Anim} Class is available
265          * @type Boolean
266          * @property enableFx
267          */
268
269         /**
270          * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
271          * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
272          * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
273          * @type Boolean
274          */
275         scopeResetCSS : Ext.buildSettings.scopeResetCSS,
276
277         /**
278          * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
279          * Currently not optimized for performance.
280          * @type Boolean
281          */
282         enableNestedListenerRemoval : false,
283
284         /**
285          * Indicates whether to use native browser parsing for JSON methods.
286          * This option is ignored if the browser does not support native JSON methods.
287          * <b>Note: Native JSON methods will not work with objects that have functions.
288          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
289          * @type Boolean
290          */
291         USE_NATIVE_JSON : false,
292
293         /**
294          * Return the dom node for the passed String (id), dom node, or Ext.core.Element.
295          * Optional 'strict' flag is needed for IE since it can return 'name' and
296          * 'id' elements by using getElementById.
297          * Here are some examples:
298          * <pre><code>
299 // gets dom node based on id
300 var elDom = Ext.getDom('elId');
301 // gets dom node based on the dom node
302 var elDom1 = Ext.getDom(elDom);
303
304 // If we don&#39;t know if we are working with an
305 // Ext.core.Element or a dom node use Ext.getDom
306 function(el){
307     var dom = Ext.getDom(el);
308     // do something with the dom node
309 }
310          * </code></pre>
311          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
312          * when this method is called to be successful.
313          * @param {Mixed} el
314          * @return HTMLElement
315          */
316         getDom : function(el, strict) {
317             if (!el || !document) {
318                 return null;
319             }
320             if (el.dom) {
321                 return el.dom;
322             } else {
323                 if (typeof el == 'string') {
324                     var e = document.getElementById(el);
325                     // IE returns elements with the 'name' and 'id' attribute.
326                     // we do a strict check to return the element with only the id attribute
327                     if (e && isIE && strict) {
328                         if (el == e.getAttribute('id')) {
329                             return e;
330                         } else {
331                             return null;
332                         }
333                     }
334                     return e;
335                 } else {
336                     return el;
337                 }
338             }
339         },
340
341         /**
342          * Removes a DOM node from the document.
343          * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
344          * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
345          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
346          * will be ignored if passed in.</p>
347          * @param {HTMLElement} node The node to remove
348          */
349         removeNode : isIE6 || isIE7 ? function() {
350             var d;
351             return function(n){
352                 if(n && n.tagName != 'BODY'){
353                     (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
354                     d = d || document.createElement('div');
355                     d.appendChild(n);
356                     d.innerHTML = '';
357                     delete Ext.cache[n.id];
358                 }
359             };
360         }() : function(n) {
361             if (n && n.parentNode && n.tagName != 'BODY') {
362                 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
363                 n.parentNode.removeChild(n);
364                 delete Ext.cache[n.id];
365             }
366         },
367
368         /**
369          * True if the detected browser is Opera.
370          * @type Boolean
371          */
372         isOpera : isOpera,
373
374         /**
375          * True if the detected browser is Opera 10.5x.
376          * @type Boolean
377          */
378         isOpera10_5 : isOpera10_5,
379
380         /**
381          * True if the detected browser uses WebKit.
382          * @type Boolean
383          */
384         isWebKit : isWebKit,
385
386         /**
387          * True if the detected browser is Chrome.
388          * @type Boolean
389          */
390         isChrome : isChrome,
391
392         /**
393          * True if the detected browser is Safari.
394          * @type Boolean
395          */
396         isSafari : isSafari,
397
398         /**
399          * True if the detected browser is Safari 3.x.
400          * @type Boolean
401          */
402         isSafari3 : isSafari3,
403
404         /**
405          * True if the detected browser is Safari 4.x.
406          * @type Boolean
407          */
408         isSafari4 : isSafari4,
409
410         /**
411          * True if the detected browser is Safari 2.x.
412          * @type Boolean
413          */
414         isSafari2 : isSafari2,
415
416         /**
417          * True if the detected browser is Internet Explorer.
418          * @type Boolean
419          */
420         isIE : isIE,
421
422         /**
423          * True if the detected browser is Internet Explorer 6.x.
424          * @type Boolean
425          */
426         isIE6 : isIE6,
427
428         /**
429          * True if the detected browser is Internet Explorer 7.x.
430          * @type Boolean
431          */
432         isIE7 : isIE7,
433
434         /**
435          * True if the detected browser is Internet Explorer 8.x.
436          * @type Boolean
437          */
438         isIE8 : isIE8,
439
440         /**
441          * True if the detected browser is Internet Explorer 9.x.
442          * @type Boolean
443          */
444         isIE9 : isIE9,
445
446         /**
447          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
448          * @type Boolean
449          */
450         isGecko : isGecko,
451
452         /**
453          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
454          * @type Boolean
455          */
456         isGecko3 : isGecko3,
457
458         /**
459          * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
460          * @type Boolean
461          */
462         isGecko4 : isGecko4,
463
464         /**
465          * True if the detected browser uses FireFox 3.0
466          * @type Boolean
467          */
468
469         isFF3_0 : isFF3_0,
470         /**
471          * True if the detected browser uses FireFox 3.5
472          * @type Boolean
473          */
474
475         isFF3_5 : isFF3_5,
476         /**
477          * True if the detected browser uses FireFox 3.6
478          * @type Boolean
479          */
480         isFF3_6 : isFF3_6,
481
482         /**
483          * True if the detected platform is Linux.
484          * @type Boolean
485          */
486         isLinux : isLinux,
487
488         /**
489          * True if the detected platform is Windows.
490          * @type Boolean
491          */
492         isWindows : isWindows,
493
494         /**
495          * True if the detected platform is Mac OS.
496          * @type Boolean
497          */
498         isMac : isMac,
499
500         /**
501          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
502          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
503          * For other browsers it uses an inline data URL.
504          * @type String
505          */
506         BLANK_IMAGE_URL : (isIE6 || isIE7) ? 'http:/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
507
508         /**
509          * <p>Utility method for returning a default value if the passed value is empty.</p>
510          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
511          * <li>null</li>
512          * <li>undefined</li>
513          * <li>an empty array</li>
514          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
515          * </ul></div>
516          * @param {Mixed} value The value to test
517          * @param {Mixed} defaultValue The value to return if the original value is empty
518          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
519          * @return {Mixed} value, if non-empty, else defaultValue
520          * @deprecated 4.0.0 Use {Ext#valueFrom} instead
521          */
522         value : function(v, defaultValue, allowBlank){
523             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
524         },
525
526         /**
527          * Escapes the passed string for use in a regular expression
528          * @param {String} str
529          * @return {String}
530          * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
531          */
532         escapeRe : function(s) {
533             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
534         },
535
536         /**
537          * Applies event listeners to elements by selectors when the document is ready.
538          * The event name is specified with an <tt>&#64;</tt> suffix.
539          * <pre><code>
540 Ext.addBehaviors({
541     // add a listener for click on all anchors in element with id foo
542     '#foo a&#64;click' : function(e, t){
543         // do something
544     },
545
546     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
547     '#foo a, #bar span.some-class&#64;mouseover' : function(){
548         // do something
549     }
550 });
551          * </code></pre>
552          * @param {Object} obj The list of behaviors to apply
553          */
554         addBehaviors : function(o){
555             if(!Ext.isReady){
556                 Ext.onReady(function(){
557                     Ext.addBehaviors(o);
558                 });
559             } else {
560                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
561                     parts,
562                     b,
563                     s;
564                 for (b in o) {
565                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
566                         s = parts[0];
567                         if(!cache[s]){
568                             cache[s] = Ext.select(s);
569                         }
570                         cache[s].on(parts[1], o[b]);
571                     }
572                 }
573                 cache = null;
574             }
575         },
576
577         /**
578          * Utility method for getting the width of the browser scrollbar. This can differ depending on
579          * operating system settings, such as the theme or font size.
580          * @param {Boolean} force (optional) true to force a recalculation of the value.
581          * @return {Number} The width of the scrollbar.
582          */
583         getScrollBarWidth: function(force){
584             if(!Ext.isReady){
585                 return 0;
586             }
587
588             if(force === true || scrollWidth === null){
589                 // BrowserBug: IE9
590                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
591                 // inaccurately reported. For IE9 only, we render on screen before removing.
592                 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets';
593                     // Append our div, do our calculation and then remove it
594                 var div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
595                     child = div.child('div', true);
596                 var w1 = child.offsetWidth;
597                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
598                 var w2 = child.offsetWidth;
599                 div.remove();
600                 // Need to add 2 to ensure we leave enough space
601                 scrollWidth = w1 - w2 + 2;
602             }
603             return scrollWidth;
604         },
605
606         /**
607          * Copies a set of named properties fom the source object to the destination object.
608          * <p>example:<pre><code>
609 ImageComponent = Ext.extend(Ext.Component, {
610     initComponent: function() {
611         this.autoEl = { tag: 'img' };
612         MyComponent.superclass.initComponent.apply(this, arguments);
613         this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
614     }
615 });
616          * </code></pre>
617          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
618          * @param {Object} dest The destination object.
619          * @param {Object} source The source object.
620          * @param {Array/String} names Either an Array of property names, or a comma-delimited list
621          * of property names to copy.
622          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
623          * @return {Object} The modified object.
624         */
625         copyTo : function(dest, source, names, usePrototypeKeys){
626             if(typeof names == 'string'){
627                 names = names.split(/[,;\s]/);
628             }
629             Ext.each(names, function(name){
630                 if(usePrototypeKeys || source.hasOwnProperty(name)){
631                     dest[name] = source[name];
632                 }
633             }, this);
634             return dest;
635         },
636
637         /**
638          * Attempts to destroy and then remove a set of named properties of the passed object.
639          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
640          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
641          * @param {Mixed} etc... More property names to destroy and remove.
642          */
643         destroyMembers : function(o, arg1, arg2, etc){
644             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
645                 Ext.destroy(o[a[i]]);
646                 delete o[a[i]];
647             }
648         },
649
650         /**
651          * Partitions the set into two sets: a true set and a false set.
652          * Example:
653          * Example2:
654          * <pre><code>
655 // Example 1:
656 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
657
658 // Example 2:
659 Ext.partition(
660     Ext.query("p"),
661     function(val){
662         return val.className == "class1"
663     }
664 );
665 // true are those paragraph elements with a className of "class1",
666 // false set are those that do not have that className.
667          * </code></pre>
668          * @param {Array|NodeList} arr The array to partition
669          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
670          *                   itself must be able to be evaluated for its truthfulness.
671          * @return {Array} [true<Array>,false<Array>]
672          * @deprecated 4.0.0 Will be removed in the next major version
673          */
674         partition : function(arr, truth){
675             var ret = [[],[]];
676             Ext.each(arr, function(v, i, a) {
677                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
678             });
679             return ret;
680         },
681
682         /**
683          * Invokes a method on each item in an Array.
684          * <pre><code>
685 // Example:
686 Ext.invoke(Ext.query("p"), "getAttribute", "id");
687 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
688          * </code></pre>
689          * @param {Array|NodeList} arr The Array of items to invoke the method on.
690          * @param {String} methodName The method name to invoke.
691          * @param {...*} args Arguments to send into the method invocation.
692          * @return {Array} The results of invoking the method on each item in the array.
693          * @deprecated 4.0.0 Will be removed in the next major version
694          */
695         invoke : function(arr, methodName){
696             var ret = [],
697                 args = Array.prototype.slice.call(arguments, 2);
698             Ext.each(arr, function(v,i) {
699                 if (v && typeof v[methodName] == 'function') {
700                     ret.push(v[methodName].apply(v, args));
701                 } else {
702                     ret.push(undefined);
703                 }
704             });
705             return ret;
706         },
707
708         /**
709          * <p>Zips N sets together.</p>
710          * <pre><code>
711 // Example 1:
712 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
713 // Example 2:
714 Ext.zip(
715     [ "+", "-", "+"],
716     [  12,  10,  22],
717     [  43,  15,  96],
718     function(a, b, c){
719         return "$" + a + "" + b + "." + c
720     }
721 ); // ["$+12.43", "$-10.15", "$+22.96"]
722          * </code></pre>
723          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
724          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
725          * @return {Array} The zipped set.
726          * @deprecated 4.0.0 Will be removed in the next major version
727          */
728         zip : function(){
729             var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
730                 arrs = parts[0],
731                 fn = parts[1][0],
732                 len = Ext.max(Ext.pluck(arrs, "length")),
733                 ret = [];
734
735             for (var i = 0; i < len; i++) {
736                 ret[i] = [];
737                 if(fn){
738                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
739                 }else{
740                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
741                         ret[i].push( arrs[j][i] );
742                     }
743                 }
744             }
745             return ret;
746         },
747
748         /**
749          * Turns an array into a sentence, joined by a specified connector - e.g.:
750          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
751          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
752          * @param {Array} items The array to create a sentence from
753          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
754          * @return {String} The sentence string
755          * @deprecated 4.0.0 Will be removed in the next major version
756          */
757         toSentence: function(items, connector) {
758             var length = items.length;
759
760             if (length <= 1) {
761                 return items[0];
762             } else {
763                 var head = items.slice(0, length - 1),
764                     tail = items[length - 1];
765
766                 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
767             }
768         },
769
770         /**
771          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
772          * you may want to set this to true.
773          * @type Boolean
774          */
775         useShims: isIE6
776     });
777 })();
778
779 /**
780  * TBD
781  * @type Function
782  * @param {Object} config
783  */
784 Ext.application = function(config) {
785     Ext.require('Ext.app.Application');
786
787     Ext.onReady(function() {
788         Ext.create('Ext.app.Application', config);
789     });
790 };