PageRenderTime 57ms CodeModel.GetById 24ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/ext-4.1.0_b3/src/core/src/Ext-more.js

https://bitbucket.org/srogerf/javascript
JavaScript | 1190 lines | 489 code | 122 blank | 579 comment | 168 complexity | ccae3db3a298e56b4cf71c7520614537 MD5 | raw file
   1/**
   2 * @class Ext
   3 *
   4 * The Ext namespace (global object) encapsulates all classes, singletons, and
   5 * utility methods provided by Sencha's libraries.
   6 *
   7 * Most user interface Components are at a lower level of nesting in the namespace,
   8 * but many common utility functions are provided as direct properties of the Ext namespace.
   9 *
  10 * Also many frequently used methods from other classes are provided as shortcuts
  11 * within the Ext namespace. For example {@link Ext#getCmp Ext.getCmp} aliases
  12 * {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
  13 *
  14 * Many applications are initiated with {@link Ext#onReady Ext.onReady} which is
  15 * called once the DOM is ready. This ensures all scripts have been loaded,
  16 * preventing dependency issues. For example:
  17 *
  18 *     Ext.onReady(function(){
  19 *         new Ext.Component({
  20 *             renderTo: document.body,
  21 *             html: 'DOM ready!'
  22 *         });
  23 *     });
  24 *
  25 * For more information about how to use the Ext classes, see:
  26 *
  27 * - <a href="http://www.sencha.com/learn/">The Learning Center</a>
  28 * - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
  29 * - <a href="http://www.sencha.com/forum/">The forums</a>
  30 *
  31 * @singleton
  32 */
  33Ext.apply(Ext, {
  34    userAgent: navigator.userAgent.toLowerCase(),
  35    cache: {},
  36    idSeed: 1000,
  37    windowId: 'ext-window',
  38    documentId: 'ext-document',
  39
  40    /**
  41     * True when the document is fully initialized and ready for action
  42     */
  43    isReady: false,
  44
  45    /**
  46     * True to automatically uncache orphaned Ext.Elements periodically
  47     */
  48    enableGarbageCollector: true,
  49
  50    /**
  51     * True to automatically purge event listeners during garbageCollection.
  52     */
  53    enableListenerCollection: true,
  54    
  55    /**
  56     * Generates unique ids. If the element already has an id, it is unchanged
  57     * @param {HTMLElement/Ext.Element} [el] The element to generate an id for
  58     * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
  59     * @return {String} The generated Id.
  60     */
  61    id: function(el, prefix) {
  62        var me = this,
  63            sandboxPrefix = '';
  64        el = Ext.getDom(el, true) || {};
  65        if (el === document) {
  66            el.id = me.documentId;
  67        }
  68        else if (el === window) {
  69            el.id = me.windowId;
  70        }
  71        if (!el.id) {
  72            if (me.isSandboxed) {
  73                sandboxPrefix = Ext.sandboxName.toLowerCase() + '-';
  74            }
  75            el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
  76        }
  77        return el.id;
  78    },
  79
  80    /**
  81     * Returns the current document body as an {@link Ext.Element}.
  82     * @return Ext.Element The document body
  83     */
  84    getBody: function() {
  85        var body;
  86        return function() {
  87            return body || (body = Ext.get(document.body));
  88        };
  89    }(),
  90
  91    /**
  92     * Returns the current document head as an {@link Ext.Element}.
  93     * @return Ext.Element The document head
  94     * @method
  95     */
  96    getHead: function() {
  97        var head;
  98        return function() {
  99            return head || (head = Ext.get(document.getElementsByTagName("head")[0]));
 100        };
 101    }(),
 102
 103    /**
 104     * Returns the current HTML document object as an {@link Ext.Element}.
 105     * @return Ext.Element The document
 106     */
 107    getDoc: function() {
 108        var doc;
 109        return function() {
 110            return doc || (doc = Ext.get(document));
 111        };
 112    }(),
 113
 114    /**
 115     * This is shorthand reference to {@link Ext.ComponentManager#get}.
 116     * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
 117     *
 118     * @param {String} id The component {@link Ext.Component#id id}
 119     * @return Ext.Component The Component, `undefined` if not found, or `null` if a
 120     * Class was found.
 121    */
 122    getCmp: function(id) {
 123        return Ext.ComponentManager.get(id);
 124    },
 125
 126    /**
 127     * Returns the current orientation of the mobile device
 128     * @return {String} Either 'portrait' or 'landscape'
 129     */
 130    getOrientation: function() {
 131        return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
 132    },
 133
 134    /**
 135     * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
 136     * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
 137     * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
 138     * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
 139     * passed into this function in a single call as separate arguments.
 140     *
 141     * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} args
 142     * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
 143     */
 144    destroy: function() {
 145        var ln = arguments.length,
 146        i, arg;
 147
 148        for (i = 0; i < ln; i++) {
 149            arg = arguments[i];
 150            if (arg) {
 151                if (Ext.isArray(arg)) {
 152                    this.destroy.apply(this, arg);
 153                }
 154                else if (Ext.isFunction(arg.destroy)) {
 155                    arg.destroy();
 156                }
 157                else if (arg.dom) {
 158                    arg.remove();
 159                }
 160            }
 161        }
 162    },
 163
 164    /**
 165     * Execute a callback function in a particular scope. If no function is passed the call is ignored.
 166     *
 167     * For example, these lines are equivalent:
 168     *
 169     *     Ext.callback(myFunc, this, [arg1, arg2]);
 170     *     Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
 171     *
 172     * @param {Function} callback The callback to execute
 173     * @param {Object} [scope] The scope to execute in
 174     * @param {Array} [args] The arguments to pass to the function
 175     * @param {Number} [delay] Pass a number to delay the call by a number of milliseconds.
 176     */
 177    callback: function(callback, scope, args, delay){
 178        if(Ext.isFunction(callback)){
 179            args = args || [];
 180            scope = scope || window;
 181            if (delay) {
 182                Ext.defer(callback, delay, scope, args);
 183            } else {
 184                callback.apply(scope, args);
 185            }
 186        }
 187    },
 188
 189    /**
 190     * Alias for {@link Ext.String#htmlEncode}.
 191     * @inheritdoc Ext.String#htmlEncode
 192     */
 193    htmlEncode : function(value) {
 194        return Ext.String.htmlEncode(value);
 195    },
 196
 197    /**
 198     * Alias for {@link Ext.String#htmlDecode}.
 199     * @inheritdoc Ext.String#htmlDecode
 200     */
 201    htmlDecode : function(value) {
 202         return Ext.String.htmlDecode(value);
 203    },
 204
 205    /**
 206     * Alias for {@link Ext.String#urlAppend}.
 207     * @inheritdoc Ext.String#urlAppend
 208     */
 209    urlAppend : function(url, s) {
 210        return Ext.String.urlAppend(url, s);
 211    }
 212});
 213
 214
 215Ext.ns = Ext.namespace;
 216
 217// for old browsers
 218window.undefined = window.undefined;
 219
 220/**
 221 * @class Ext
 222 */
 223(function(){
 224/*
 225FF 3.6      - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17
 226FF 4.0.1    - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
 227FF 5.0      - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
 228
 229IE6         - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
 230IE7         - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
 231IE8         - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
 232IE9         - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
 233
 234Chrome 11   - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
 235
 236Safari 5    - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
 237
 238Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
 239*/
 240    var check = function(regex){
 241            return regex.test(Ext.userAgent);
 242        },
 243        isStrict = document.compatMode == "CSS1Compat",
 244        version = function (is, regex) {
 245            var m;
 246            return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
 247        },
 248        docMode = document.documentMode,
 249        isOpera = check(/opera/),
 250        isOpera10_5 = isOpera && check(/version\/10\.5/),
 251        isChrome = check(/\bchrome\b/),
 252        isWebKit = check(/webkit/),
 253        isSafari = !isChrome && check(/safari/),
 254        isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
 255        isSafari3 = isSafari && check(/version\/3/),
 256        isSafari4 = isSafari && check(/version\/4/),
 257        isSafari5 = isSafari && check(/version\/5/),
 258        isIE = !isOpera && check(/msie/),
 259        isIE7 = isIE && ((check(/msie 7/) && docMode != 8 && docMode != 9) || docMode == 7),
 260        isIE8 = isIE && ((check(/msie 8/) && docMode != 7 && docMode != 9) || docMode == 8),
 261        isIE9 = isIE && ((check(/msie 9/) && docMode != 7 && docMode != 8) || docMode == 9),
 262        isIE6 = isIE && check(/msie 6/),
 263        isGecko = !isWebKit && check(/gecko/),
 264        isGecko3 = isGecko && check(/rv:1\.9/),
 265        isGecko4 = isGecko && check(/rv:2\.0/),
 266        isGecko5 = isGecko && check(/rv:5\./),
 267        isGecko10 = isGecko && check(/rv:10\./),
 268        isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
 269        isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
 270        isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
 271        isWindows = check(/windows|win32/),
 272        isMac = check(/macintosh|mac os x/),
 273        isLinux = check(/linux/),
 274        scrollbarSize = null,
 275        chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
 276        firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
 277        ieVersion = version(isIE, /msie (\d+\.\d+)/),
 278        operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
 279        safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
 280        webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
 281        isSecure = /^https/i.test(window.location.protocol);
 282
 283    // remove css image flicker
 284    try {
 285        document.execCommand("BackgroundImageCache", false, true);
 286    } catch(e) {}
 287
 288
 289    //<debug>
 290    var primitiveRe = /string|number|boolean/;
 291    function dumpObject (object) {
 292        var member, type, value, name,
 293            members = [];
 294
 295        // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
 296        // ...and the data could be prettier!
 297        for (name in object) {
 298            if (object.hasOwnProperty(name)) {
 299                value = object[name];
 300
 301                type = typeof value;
 302                if (type == "function") {
 303                    continue;
 304                }
 305
 306                if (type == 'undefined') {
 307                    member = type;
 308                } else if (value === null || primitiveRe.test(type) || Ext.isDate(value)) {
 309                    member = Ext.encode(value);
 310                } else if (Ext.isArray(value)) {
 311                    member = '[ ]';
 312                } else if (Ext.isObject(value)) {
 313                    member = '{ }';
 314                } else {
 315                    member = type;
 316                }
 317                members.push(Ext.encode(name) + ': ' + member);
 318            }
 319        }
 320
 321        if (members.length) {
 322            return ' \nData: {\n  ' + members.join(',\n  ') + '\n}';
 323        }
 324        return '';
 325    }
 326
 327    function log (message) {
 328        var options, dump,
 329            con = Ext.global.console,
 330            level = 'log',
 331            indent = log.indent || 0,
 332            stack;
 333
 334        log.indent = indent;
 335
 336        if (typeof message != 'string') {
 337            options = message;
 338            message = options.msg || '';
 339            level = options.level || level;
 340            dump = options.dump;
 341            stack = options.stack;
 342
 343            if (options.indent) {
 344                ++log.indent;
 345            } else if (options.outdent) {
 346                log.indent = indent = Math.max(indent - 1, 0);
 347            }
 348
 349            if (dump && !(con && con.dir)) {
 350                message += dumpObject(dump);
 351                dump = null;
 352            }
 353        }
 354
 355        if (arguments.length > 1) {
 356            message += Array.prototype.slice.call(arguments, 1).join('');
 357        }
 358
 359        message = indent ? Ext.String.repeat(' ', log.indentSize * indent) + message : message;
 360        // w/o console, all messages are equal, so munge the level into the message:
 361        if (level != 'log') {
 362            message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
 363        }
 364
 365        // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
 366        // an early test may fail either direction if Firebug is toggled.
 367        //
 368        if (con) { // if (Firebug-like console)
 369            if (con[level]) {
 370                con[level](message);
 371            } else {
 372                con.log(message);
 373            }
 374
 375            if (dump) {
 376                con.dir(dump);
 377            }
 378
 379            if (stack && con.trace) {
 380                // Firebug's console.error() includes a trace already...
 381                if (!con.firebug || level != 'error') {
 382                    con.trace();
 383                }
 384            }
 385        } else {
 386            if (Ext.isOpera) {
 387                opera.postError(message);
 388            } else {
 389                var out = log.out,
 390                    max = log.max;
 391
 392                if (out.length >= max) {
 393                    // this formula allows out.max to change (via debugger), where the
 394                    // more obvious "max/4" would not quite be the same
 395                    Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
 396                }
 397
 398                out.push(message);
 399            }
 400        }
 401
 402        // Mostly informational, but the Ext.Error notifier uses them:
 403        ++log.count;
 404        ++log.counters[level];
 405    }
 406
 407    function logx (level, args) {
 408        if (typeof args[0] == 'string') {
 409            args.unshift({});
 410        }
 411        args[0].level = level;
 412        log.apply(this, args);
 413    }
 414
 415    log.error = function () {
 416        logx('error', Array.prototype.slice.call(arguments));
 417    }
 418    log.info = function () {
 419        logx('info', Array.prototype.slice.call(arguments));
 420    }
 421    log.warn = function () {
 422        logx('warn', Array.prototype.slice.call(arguments));
 423    }
 424
 425    log.count = 0;
 426    log.counters = { error: 0, warn: 0, info: 0, log: 0 };
 427    log.indentSize = 2;
 428    log.out = [];
 429    log.max = 750;
 430    log.show = function () {
 431        window.open('','extlog').document.write([
 432            '<html><head><script type="text/javascript">',
 433                'var lastCount = 0;',
 434                'function update () {',
 435                    'var ext = window.opener.Ext,',
 436                        'extlog = ext && ext.log;',
 437                    'if (extlog && extlog.out && lastCount != extlog.count) {',
 438                        'lastCount = extlog.count;',
 439                        'var s = "<tt>" + extlog.out.join("~~~").replace(/[&]/g, "&amp;").replace(/[<]/g, "&lt;").replace(/[ ]/g, "&nbsp;").replace(/\\~\\~\\~/g, "<br>") + "</tt>";',
 440                        'document.body.innerHTML = s;',
 441                    '}',
 442                    'setTimeout(update, 1000);',
 443                '}',
 444                'setTimeout(update, 1000);',
 445            '</script></head><body></body></html>'].join(''));
 446    };
 447    //</debug>
 448
 449    var nullLog = function () {};
 450    nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn;
 451
 452    Ext.setVersion('extjs', '4.1.0');
 453    Ext.apply(Ext, {
 454        /**
 455         * @property {String} SSL_SECURE_URL
 456         * URL to a blank file used by Ext when in secure mode for iframe src and onReady src
 457         * to prevent the IE insecure content warning (`'about:blank'`, except for IE
 458         * in secure mode, which is `'javascript:""'`).
 459         */
 460        SSL_SECURE_URL : isSecure && isIE ? 'javascript:\'\'' : 'about:blank',
 461
 462        /**
 463         * @property {Boolean} enableFx
 464         * True if the {@link Ext.fx.Anim} Class is available.
 465         */
 466
 467        /**
 468         * @property {Boolean} scopeResetCSS
 469         * True to scope the reset CSS to be just applied to Ext components. Note that this
 470         * wraps root containers with an additional element. Also remember that when you turn
 471         * on this option, you have to use ext-all-scoped (unless you use the bootstrap.js to
 472         * load your javascript, in which case it will be handled for you).
 473         */
 474        scopeResetCSS : Ext.buildSettings.scopeResetCSS,
 475        
 476        /**
 477         * @property {String} resetCls
 478         * The css class used to wrap Ext components when the {@link #scopeResetCSS} option
 479         * is used.
 480         */
 481        resetCls: Ext.buildSettings.baseCSSPrefix + 'reset',
 482
 483        /**
 484         * @property {Boolean} enableNestedListenerRemoval
 485         * **Experimental.** True to cascade listener removal to child elements when an element
 486         * is removed. Currently not optimized for performance.
 487         */
 488        enableNestedListenerRemoval : false,
 489
 490        /**
 491         * @property {Boolean} USE_NATIVE_JSON
 492         * Indicates whether to use native browser parsing for JSON methods.
 493         * This option is ignored if the browser does not support native JSON methods.
 494         *
 495         * **Note:** Native JSON methods will not work with objects that have functions.
 496         * Also, property names must be quoted, otherwise the data will not parse.
 497         */
 498        USE_NATIVE_JSON : false,
 499
 500        /**
 501         * Returns the dom node for the passed String (id), dom node, or Ext.Element.
 502         * Optional 'strict' flag is needed for IE since it can return 'name' and
 503         * 'id' elements by using getElementById.
 504         *
 505         * Here are some examples:
 506         *
 507         *     // gets dom node based on id
 508         *     var elDom = Ext.getDom('elId');
 509         *     // gets dom node based on the dom node
 510         *     var elDom1 = Ext.getDom(elDom);
 511         *
 512         *     // If we don&#39;t know if we are working with an
 513         *     // Ext.Element or a dom node use Ext.getDom
 514         *     function(el){
 515         *         var dom = Ext.getDom(el);
 516         *         // do something with the dom node
 517         *     }
 518         *
 519         * **Note:** the dom node to be found actually needs to exist (be rendered, etc)
 520         * when this method is called to be successful.
 521         *
 522         * @param {String/HTMLElement/Ext.Element} el
 523         * @return HTMLElement
 524         */
 525        getDom : function(el, strict) {
 526            if (!el || !document) {
 527                return null;
 528            }
 529            if (el.dom) {
 530                return el.dom;
 531            } else {
 532                if (typeof el == 'string') {
 533                    var e = Ext.getElementById(el);
 534                    // IE returns elements with the 'name' and 'id' attribute.
 535                    // we do a strict check to return the element with only the id attribute
 536                    if (e && isIE && strict) {
 537                        if (el == e.getAttribute('id')) {
 538                            return e;
 539                        } else {
 540                            return null;
 541                        }
 542                    }
 543                    return e;
 544                } else {
 545                    return el;
 546                }
 547            }
 548        },
 549
 550        /**
 551         * Removes a DOM node from the document.
 552         *
 553         * Removes this element from the document, removes all DOM event listeners, and
 554         * deletes the cache reference. All DOM event listeners are removed from this element.
 555         * If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
 556         * `true`, then DOM event listeners are also removed from all child nodes.
 557         * The body node will be ignored if passed in.
 558         *
 559         * @param {HTMLElement} node The node to remove
 560         * @method
 561         */
 562        removeNode : isIE6 || isIE7 ? function() {
 563            var d;
 564            return function(n){
 565                if(n && n.tagName != 'BODY'){
 566                    (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
 567                    d = d || document.createElement('div');
 568                    d.appendChild(n);
 569                    d.innerHTML = '';
 570                    delete Ext.cache[n.id];
 571                }
 572            };
 573        }() : function(n) {
 574            if (n && n.parentNode && n.tagName != 'BODY') {
 575                (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
 576                n.parentNode.removeChild(n);
 577                delete Ext.cache[n.id];
 578            }
 579        },
 580
 581        isStrict: isStrict,
 582
 583        isIEQuirks: isIE && !isStrict,
 584
 585        /**
 586         * True if the detected browser is Opera.
 587         * @type Boolean
 588         */
 589        isOpera : isOpera,
 590
 591        /**
 592         * True if the detected browser is Opera 10.5x.
 593         * @type Boolean
 594         */
 595        isOpera10_5 : isOpera10_5,
 596
 597        /**
 598         * True if the detected browser uses WebKit.
 599         * @type Boolean
 600         */
 601        isWebKit : isWebKit,
 602
 603        /**
 604         * True if the detected browser is Chrome.
 605         * @type Boolean
 606         */
 607        isChrome : isChrome,
 608
 609        /**
 610         * True if the detected browser is Safari.
 611         * @type Boolean
 612         */
 613        isSafari : isSafari,
 614
 615        /**
 616         * True if the detected browser is Safari 3.x.
 617         * @type Boolean
 618         */
 619        isSafari3 : isSafari3,
 620
 621        /**
 622         * True if the detected browser is Safari 4.x.
 623         * @type Boolean
 624         */
 625        isSafari4 : isSafari4,
 626
 627        /**
 628         * True if the detected browser is Safari 5.x.
 629         * @type Boolean
 630         */
 631        isSafari5 : isSafari5,
 632
 633        /**
 634         * True if the detected browser is Safari 2.x.
 635         * @type Boolean
 636         */
 637        isSafari2 : isSafari2,
 638
 639        /**
 640         * True if the detected browser is Internet Explorer.
 641         * @type Boolean
 642         */
 643        isIE : isIE,
 644
 645        /**
 646         * True if the detected browser is Internet Explorer 6.x.
 647         * @type Boolean
 648         */
 649        isIE6 : isIE6,
 650
 651        /**
 652         * True if the detected browser is Internet Explorer 7.x.
 653         * @type Boolean
 654         */
 655        isIE7 : isIE7,
 656
 657        /**
 658         * True if the detected browser is Internet Explorer 8.x.
 659         * @type Boolean
 660         */
 661        isIE8 : isIE8,
 662
 663        /**
 664         * True if the detected browser is Internet Explorer 9.x.
 665         * @type Boolean
 666         */
 667        isIE9 : isIE9,
 668
 669        /**
 670         * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
 671         * @type Boolean
 672         */
 673        isGecko : isGecko,
 674
 675        /**
 676         * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
 677         * @type Boolean
 678         */
 679        isGecko3 : isGecko3,
 680
 681        /**
 682         * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
 683         * @type Boolean
 684         */
 685        isGecko4 : isGecko4,
 686
 687        /**
 688         * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
 689         * @type Boolean
 690         */
 691        isGecko5 : isGecko5,
 692
 693        /**
 694         * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
 695         * @type Boolean
 696         */
 697        isGecko10 : isGecko10,
 698
 699        /**
 700         * True if the detected browser uses FireFox 3.0
 701         * @type Boolean
 702         */
 703        isFF3_0 : isFF3_0,
 704
 705        /**
 706         * True if the detected browser uses FireFox 3.5
 707         * @type Boolean
 708         */
 709        isFF3_5 : isFF3_5,
 710
 711        /**
 712         * True if the detected browser uses FireFox 3.6
 713         * @type Boolean
 714         */
 715        isFF3_6 : isFF3_6,
 716
 717        /**
 718         * True if the detected browser uses FireFox 4
 719         * @type Boolean
 720         */
 721        isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
 722
 723        /**
 724         * True if the detected browser uses FireFox 5
 725         * @type Boolean
 726         */
 727        isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
 728
 729        /**
 730         * True if the detected browser uses FireFox 10
 731         * @type Boolean
 732         */
 733        isFF10 : 10 <= firefoxVersion && firefoxVersion < 11,
 734
 735        /**
 736         * True if the detected platform is Linux.
 737         * @type Boolean
 738         */
 739        isLinux : isLinux,
 740
 741        /**
 742         * True if the detected platform is Windows.
 743         * @type Boolean
 744         */
 745        isWindows : isWindows,
 746
 747        /**
 748         * True if the detected platform is Mac OS.
 749         * @type Boolean
 750         */
 751        isMac : isMac,
 752
 753        /**
 754         * The current version of Chrome (0 if the browser is not Chrome).
 755         * @type Number
 756         */
 757        chromeVersion: chromeVersion,
 758
 759        /**
 760         * The current version of Firefox (0 if the browser is not Firefox).
 761         * @type Number
 762         */
 763        firefoxVersion: firefoxVersion,
 764
 765        /**
 766         * The current version of IE (0 if the browser is not IE). This does not account
 767         * for the documentMode of the current page, which is factored into {@link #isIE7},
 768         * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
 769         *
 770         *     Ext.isIE8 == (Ext.ieVersion == 8)
 771         *
 772         * @type Number
 773         */
 774        ieVersion: ieVersion,
 775
 776        /**
 777         * The current version of Opera (0 if the browser is not Opera).
 778         * @type Number
 779         */
 780        operaVersion: operaVersion,
 781
 782        /**
 783         * The current version of Safari (0 if the browser is not Safari).
 784         * @type Number
 785         */
 786        safariVersion: safariVersion,
 787
 788        /**
 789         * The current version of WebKit (0 if the browser does not use WebKit).
 790         * @type Number
 791         */
 792        webKitVersion: webKitVersion,
 793
 794        /**
 795         * True if the page is running over SSL
 796         * @type Boolean
 797         */
 798        isSecure: isSecure,
 799        
 800        /**
 801         * URL to a 1x1 transparent gif image used by Ext to create inline icons with
 802         * CSS background images. In older versions of IE, this defaults to
 803         * "http://sencha.com/s.gif" and you should change this to a URL on your server.
 804         * For other browsers it uses an inline data URL.
 805         * @type String
 806         */
 807        BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
 808
 809        /**
 810         * Utility method for returning a default value if the passed value is empty.
 811         *
 812         * The value is deemed to be empty if it is:
 813         *
 814         * - null
 815         * - undefined
 816         * - an empty array
 817         * - a zero length string (Unless the `allowBlank` parameter is `true`)
 818         *
 819         * @param {Object} value The value to test
 820         * @param {Object} defaultValue The value to return if the original value is empty
 821         * @param {Boolean} [allowBlank=false] true to allow zero length strings to qualify as non-empty.
 822         * @return {Object} value, if non-empty, else defaultValue
 823         * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
 824         */
 825        value : function(v, defaultValue, allowBlank){
 826            return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
 827        },
 828
 829        /**
 830         * Escapes the passed string for use in a regular expression.
 831         * @param {String} str
 832         * @return {String}
 833         * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
 834         */
 835        escapeRe : function(s) {
 836            return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
 837        },
 838
 839        /**
 840         * Applies event listeners to elements by selectors when the document is ready.
 841         * The event name is specified with an `@` suffix.
 842         *
 843         *     Ext.addBehaviors({
 844         *         // add a listener for click on all anchors in element with id foo
 845         *         '#foo a@click' : function(e, t){
 846         *             // do something
 847         *         },
 848         *      
 849         *         // add the same listener to multiple selectors (separated by comma BEFORE the @)
 850         *         '#foo a, #bar span.some-class@mouseover' : function(){
 851         *             // do something
 852         *         }
 853         *     });
 854         *
 855         * @param {Object} obj The list of behaviors to apply
 856         */
 857        addBehaviors : function(o){
 858            if(!Ext.isReady){
 859                Ext.onReady(function(){
 860                    Ext.addBehaviors(o);
 861                });
 862            } else {
 863                var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
 864                    parts,
 865                    b,
 866                    s;
 867                for (b in o) {
 868                    if ((parts = b.split('@'))[1]) { // for Object prototype breakers
 869                        s = parts[0];
 870                        if(!cache[s]){
 871                            cache[s] = Ext.select(s);
 872                        }
 873                        cache[s].on(parts[1], o[b]);
 874                    }
 875                }
 876                cache = null;
 877            }
 878        },
 879
 880        /**
 881         * Returns the size of the browser scrollbars. This can differ depending on
 882         * operating system settings, such as the theme or font size.
 883         * @param {Boolean} [force] true to force a recalculation of the value.
 884         * @return {Object} An object containing scrollbar sizes.
 885         * @return.width {Number} The width of the vertical scrollbar.
 886         * @return.height {Number} The height of the horizontal scrollbar.
 887         */
 888        getScrollbarSize: function (force) {
 889            if (!Ext.isReady) {
 890                return {};
 891            }
 892
 893            if (force || !scrollbarSize) {
 894                var db = document.body,
 895                    div = document.createElement('div');
 896
 897                div.style.width = div.style.height = '100px';
 898                div.style.overflow = 'scroll';
 899                div.style.position = 'absolute';
 900
 901                db.appendChild(div); // now we can measure the div...
 902
 903                // at least in iE9 the div is not 100px - the scrollbar size is removed!
 904                scrollbarSize = {
 905                    width: div.offsetWidth - div.clientWidth,
 906                    height: div.offsetHeight - div.clientHeight
 907                };
 908
 909                db.removeChild(div);
 910            }
 911
 912            return scrollbarSize;
 913        },
 914
 915        /**
 916         * Utility method for getting the width of the browser's vertical scrollbar. This
 917         * can differ depending on operating system settings, such as the theme or font size.
 918         *
 919         * This method is deprected in favor of {@link #getScrollbarSize}.
 920         *
 921         * @param {Boolean} [force] true to force a recalculation of the value.
 922         * @return {Number} The width of a vertical scrollbar.
 923         * @deprecated
 924         */
 925        getScrollBarWidth: function(force){
 926            var size = Ext.getScrollbarSize(force);
 927            return size.width + 2; // legacy fudge factor
 928        },
 929
 930        /**
 931         * Copies a set of named properties fom the source object to the destination object.
 932         *
 933         * Example:
 934         *
 935         *     ImageComponent = Ext.extend(Ext.Component, {
 936         *         initComponent: function() {
 937         *             this.autoEl = { tag: 'img' };
 938         *             MyComponent.superclass.initComponent.apply(this, arguments);
 939         *             this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
 940         *         }
 941         *     });
 942         *
 943         * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
 944         *
 945         * @param {Object} dest The destination object.
 946         * @param {Object} source The source object.
 947         * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
 948         * of property names to copy.
 949         * @param {Boolean} [usePrototypeKeys] Defaults to false. Pass true to copy keys off of the
 950         * prototype as well as the instance.
 951         * @return {Object} The modified object.
 952         */
 953        copyTo : function(dest, source, names, usePrototypeKeys){
 954            if(typeof names == 'string'){
 955                names = names.split(/[,;\s]/);
 956            }
 957
 958            var n,
 959                nLen = names.length,
 960                name;
 961
 962            for(n = 0; n < nLen; n++) {
 963                name = names[n];
 964
 965                if(usePrototypeKeys || source.hasOwnProperty(name)){
 966                    dest[name] = source[name];
 967                }
 968            }
 969
 970            return dest;
 971        },
 972
 973        /**
 974         * Attempts to destroy and then remove a set of named properties of the passed object.
 975         * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
 976         * @param {String...} args One or more names of the properties to destroy and remove from the object.
 977         */
 978        destroyMembers : function(o){
 979            for (var i = 1, a = arguments, len = a.length; i < len; i++) {
 980                Ext.destroy(o[a[i]]);
 981                delete o[a[i]];
 982            }
 983        },
 984
 985        /**
 986         * Logs a message. If a console is present it will be used. On Opera, the method
 987         * "opera.postError" is called. In other cases, the message is logged to an array
 988         * "Ext.log.out". An attached debugger can watch this array and view the log. The
 989         * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
 990         * The `Ext.log.out` array can also be written to a popup window by entering the
 991         * following in the URL bar (a "bookmarklet"):
 992         *
 993         *    javascript:void(Ext.log.show());
 994         *
 995         * If additional parameters are passed, they are joined and appended to the message.
 996         * A technique for tracing entry and exit of a function is this:
 997         *
 998         *      function foo () {
 999         *          Ext.log({ indent: 1 }, '>> foo');
1000         *
1001         *          // log statements in here or methods called from here will be indented
1002         *          // by one step
1003         *
1004         *          Ext.log({ outdent: 1 }, '<< foo');
1005         *      }
1006         *
1007         * This method does nothing in a release build.
1008         *
1009         * @param {String/Object} message The message to log or an options object with any
1010         * of the following properties:
1011         *
1012         *  - `msg`: The message to log (required).
1013         *  - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
1014         *  - `dump`: An object to dump to the log as part of the message.
1015         *  - `stack`: True to include a stack trace in the log.
1016         *  - `indent`: Cause subsequent log statements to be indented one step.
1017         *  - `outdent`: Cause this and following statements to be one step less indented.
1018         *
1019         * @method
1020         */
1021        log :
1022            //<debug>
1023            log ||
1024            //</debug>
1025            nullLog,
1026
1027        /**
1028         * Partitions the set into two sets: a true set and a false set.
1029         *
1030         * Example 1:
1031         *
1032         *     Ext.partition([true, false, true, true, false]);
1033         *     // returns [[true, true, true], [false, false]]
1034         *
1035         * Example 2:
1036         *
1037         *     Ext.partition(
1038         *         Ext.query("p"),
1039         *         function(val){
1040         *             return val.className == "class1"
1041         *         }
1042         *     );
1043         *     // true are those paragraph elements with a className of "class1",
1044         *     // false set are those that do not have that className.
1045         *
1046         * @param {Array/NodeList} arr The array to partition
1047         * @param {Function} truth (optional) a function to determine truth.
1048         * If this is omitted the element itself must be able to be evaluated for its truthfulness.
1049         * @return {Array} [array of truish values, array of falsy values]
1050         * @deprecated 4.0.0 Will be removed in the next major version
1051         */
1052        partition : function(arr, truth){
1053            var ret = [[],[]],
1054            	a, v,
1055                aLen = arr.length;
1056
1057            for (a = 0; a < aLen; a++) {
1058                v = arr[a];
1059                ret[ (truth && truth(v, a, arr)) || (!truth && v) ? 0 : 1].push(v);
1060            }
1061
1062            return ret;
1063        },
1064
1065        /**
1066         * Invokes a method on each item in an Array.
1067         *
1068         * Example:
1069         *
1070         *     Ext.invoke(Ext.query("p"), "getAttribute", "id");
1071         *     // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
1072         *
1073         * @param {Array/NodeList} arr The Array of items to invoke the method on.
1074         * @param {String} methodName The method name to invoke.
1075         * @param {Object...} args Arguments to send into the method invocation.
1076         * @return {Array} The results of invoking the method on each item in the array.
1077         * @deprecated 4.0.0 Will be removed in the next major version
1078         */
1079        invoke : function(arr, methodName){
1080            var ret  = [],
1081                args = Array.prototype.slice.call(arguments, 2),
1082                a, v,
1083                aLen = arr.length;
1084
1085            for (a = 0; a < aLen; a++) {
1086                v = arr[a];
1087
1088                if (v && typeof v[methodName] == 'function') {
1089                    ret.push(v[methodName].apply(v, args));
1090                } else {
1091                    ret.push(undefined);
1092                }
1093            }
1094
1095            return ret;
1096        },
1097
1098        /**
1099         * Zips N sets together.
1100         *
1101         * Example 1:
1102         *
1103         *     Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
1104         *
1105         * Example 2:
1106         *
1107         *     Ext.zip(
1108         *         [ "+", "-", "+"],
1109         *         [  12,  10,  22],
1110         *         [  43,  15,  96],
1111         *         function(a, b, c){
1112         *             return "$" + a + "" + b + "." + c
1113         *         }
1114         *     ); // ["$+12.43", "$-10.15", "$+22.96"]
1115         *
1116         * @param {Array/NodeList...} arr This argument may be repeated. Array(s)
1117         * to contribute values.
1118         * @param {Function} zipper (optional) The last item in the argument list.
1119         * This will drive how the items are zipped together.
1120         * @return {Array} The zipped set.
1121         * @deprecated 4.0.0 Will be removed in the next major version
1122         */
1123        zip : function(){
1124            var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
1125                arrs = parts[0],
1126                fn = parts[1][0],
1127                len = Ext.max(Ext.pluck(arrs, "length")),
1128                ret = [];
1129
1130            for (var i = 0; i < len; i++) {
1131                ret[i] = [];
1132                if(fn){
1133                    ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
1134                }else{
1135                    for (var j = 0, aLen = arrs.length; j < aLen; j++){
1136                        ret[i].push( arrs[j][i] );
1137                    }
1138                }
1139            }
1140            return ret;
1141        },
1142
1143        /**
1144         * Turns an array into a sentence, joined by a specified connector - e.g.:
1145         * 
1146         *     Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
1147         *     Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
1148         * 
1149         * @param {String[]} items The array to create a sentence from
1150         * @param {String} connector The string to use to connect the last two words.
1151         * Usually 'and' or 'or' - defaults to 'and'.
1152         * @return {String} The sentence string
1153         * @deprecated 4.0.0 Will be removed in the next major version
1154         */
1155        toSentence: function(items, connector) {
1156            var length = items.length;
1157
1158            if (length <= 1) {
1159                return items[0];
1160            } else {
1161                var head = items.slice(0, length - 1),
1162                    tail = items[length - 1];
1163
1164                return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
1165            }
1166        },
1167
1168        /**
1169         * @property {Boolean} useShims
1170         * By default, Ext intelligently decides whether floating elements should be shimmed.
1171         * If you are using flash, you may want to set this to true.
1172         */
1173        useShims: isIE6
1174    });
1175})();
1176
1177/**
1178 * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
1179 *
1180 * See Ext.app.Application for details.
1181 *
1182 * @param {Object} config
1183 */
1184Ext.application = function(config) {
1185    Ext.require('Ext.app.Application');
1186
1187    Ext.onReady(function() {
1188        new Ext.app.Application(config);
1189    });
1190};