Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / pkgs / extras.js
index eea5b97..f4c99d7 100644 (file)
@@ -1,12 +1,20 @@
 /*
-Ext JS - JavaScript Library
-Copyright (c) 2006-2011, Sencha Inc.
-All rights reserved.
-licensing@sencha.com
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
 */
 /**
  * @class Ext.JSON
- * Modified version of Douglas Crockford"s json.js that doesn"t
+ * Modified version of Douglas Crockford's JSON.js that doesn't
  * mess with the Object prototype
  * http://www.json.org/js.html
  * @singleton
@@ -99,15 +107,15 @@ Ext.JSON = new(function() {
      * <b>The returned value includes enclosing double quotation marks.</b></p>
      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
      * <p>To override this:</p><pre><code>
-     Ext.JSON.encodeDate = function(d) {
-     return d.format('"Y-m-d"');
-     };
+Ext.JSON.encodeDate = function(d) {
+    return Ext.Date.format(d, '"Y-m-d"');
+};
      </code></pre>
      * @param {Date} d The Date to encode
      * @return {String} The string literal to use in a JSON string.
      */
     this.encodeDate = function(o) {
-        return '"' + o.getFullYear() + "-" 
+        return '"' + o.getFullYear() + "-"
         + pad(o.getMonth() + 1) + "-"
         + pad(o.getDate()) + "T"
         + pad(o.getHours()) + ":"
@@ -117,7 +125,7 @@ Ext.JSON = new(function() {
 
     /**
      * Encodes an Object, Array or other value
-     * @param {Mixed} o The variable to encode
+     * @param {Object} o The variable to encode
      * @return {String} The JSON string
      */
     this.encode = function() {
@@ -154,7 +162,7 @@ Ext.JSON = new(function() {
                 Ext.Error.raise({
                     sourceClass: "Ext.JSON",
                     sourceMethod: "decode",
-                    msg: "You're trying to decode and invalid JSON String: " + json
+                    msg: "You're trying to decode an invalid JSON String: " + json
                 });
             }
         };
@@ -163,19 +171,16 @@ Ext.JSON = new(function() {
 })();
 /**
  * Shorthand for {@link Ext.JSON#encode}
- * @param {Mixed} o The variable to encode
- * @return {String} The JSON string
  * @member Ext
  * @method encode
+ * @alias Ext.JSON#encode
  */
 Ext.encode = Ext.JSON.encode;
 /**
  * Shorthand for {@link Ext.JSON#decode}
- * @param {String} json The JSON string
- * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
- * @return {Object} The resulting object
  * @member Ext
  * @method decode
+ * @alias Ext.JSON#decode
  */
 Ext.decode = Ext.JSON.decode;
 
@@ -202,9 +207,9 @@ Ext.decode = Ext.JSON.decode;
 
 For more information about how to use the Ext classes, see
 
-* <a href="http://www.sencha.com/learn/">The Learning Center</a>
-* <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
-* <a href="http://www.sencha.com/forum/">The forums</a>
+- <a href="http://www.sencha.com/learn/">The Learning Center</a>
+- <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
+- <a href="http://www.sencha.com/forum/">The forums</a>
 
  * @singleton
  * @markdown
@@ -213,8 +218,6 @@ Ext.apply(Ext, {
     userAgent: navigator.userAgent.toLowerCase(),
     cache: {},
     idSeed: 1000,
-    BLANK_IMAGE_URL : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
-    isStrict: document.compatMode == "CSS1Compat",
     windowId: 'ext-window',
     documentId: 'ext-document',
 
@@ -225,48 +228,57 @@ Ext.apply(Ext, {
     isReady: false,
 
     /**
-     * True to automatically uncache orphaned Ext.core.Elements periodically (defaults to true)
+     * True to automatically uncache orphaned Ext.Elements periodically
      * @type Boolean
      */
     enableGarbageCollector: true,
 
     /**
-     * True to automatically purge event listeners during garbageCollection (defaults to true).
+     * True to automatically purge event listeners during garbageCollection.
      * @type Boolean
      */
     enableListenerCollection: true,
 
     /**
      * Generates unique ids. If the element already has an id, it is unchanged
-     * @param {Mixed} el (optional) The element to generate an id for
+     * @param {HTMLElement/Ext.Element} el (optional) The element to generate an id for
      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
      * @return {String} The generated Id.
      */
     id: function(el, prefix) {
+        var me = this,
+            sandboxPrefix = '';
         el = Ext.getDom(el, true) || {};
         if (el === document) {
-            el.id = this.documentId;
+            el.id = me.documentId;
         }
         else if (el === window) {
-            el.id = this.windowId;
+            el.id = me.windowId;
         }
         if (!el.id) {
-            el.id = (prefix || "ext-gen") + (++Ext.idSeed);
+            if (me.isSandboxed) {
+                if (!me.uniqueGlobalNamespace) {
+                    me.getUniqueGlobalNamespace();
+                }
+                sandboxPrefix = me.uniqueGlobalNamespace + '-';
+            }
+            el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
         }
         return el.id;
     },
 
     /**
-     * Returns the current document body as an {@link Ext.core.Element}.
-     * @return Ext.core.Element The document body
+     * Returns the current document body as an {@link Ext.Element}.
+     * @return Ext.Element The document body
      */
     getBody: function() {
         return Ext.get(document.body || false);
     },
 
     /**
-     * Returns the current document head as an {@link Ext.core.Element}.
-     * @return Ext.core.Element The document head
+     * Returns the current document head as an {@link Ext.Element}.
+     * @return Ext.Element The document head
+     * @method
      */
     getHead: function() {
         var head;
@@ -281,8 +293,8 @@ Ext.apply(Ext, {
     }(),
 
     /**
-     * Returns the current HTML document object as an {@link Ext.core.Element}.
-     * @return Ext.core.Element The document
+     * Returns the current HTML document object as an {@link Ext.Element}.
+     * @return Ext.Element The document
      */
     getDoc: function() {
         return Ext.get(document);
@@ -310,12 +322,11 @@ Ext.apply(Ext, {
     /**
      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
-     * intended for arguments of type {@link Ext.core.Element} and {@link Ext.Component}, but any subclass of
+     * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
      * passed into this function in a single call as separate arguments.
-     * @param {Mixed} arg1 An {@link Ext.core.Element}, {@link Ext.Component}, or an Array of either of these to destroy
-     * @param {Mixed} arg2 (optional)
-     * @param {Mixed} etc... (optional)
+     * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} arg1
+     * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
      */
     destroy: function() {
         var ln = arguments.length,
@@ -339,6 +350,12 @@ Ext.apply(Ext, {
 
     /**
      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
+     *
+     * For example, these lines are equivalent:
+     *
+     *     Ext.callback(myFunc, this, [arg1, arg2]);
+     *     Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
+     *
      * @param {Function} callback The callback to execute
      * @param {Object} scope (optional) The scope to execute in
      * @param {Array} args (optional) The arguments to pass to the function
@@ -394,15 +411,37 @@ Ext.ns = Ext.namespace;
 
 // for old browsers
 window.undefined = window.undefined;
+
 /**
  * @class Ext
  * Ext core utilities and functions.
  * @singleton
  */
 (function(){
+/*
+FF 3.6      - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17
+FF 4.0.1    - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
+FF 5.0      - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
+
+IE6         - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
+IE7         - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
+IE8         - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
+IE9         - 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)
+
+Chrome 11   - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
+
+Safari 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
+
+Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
+*/
     var check = function(regex){
             return regex.test(Ext.userAgent);
         },
+        isStrict = document.compatMode == "CSS1Compat",
+        version = function (is, regex) {
+            var m;
+            return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
+        },
         docMode = document.documentMode,
         isOpera = check(/opera/),
         isOpera10_5 = isOpera && check(/version\/10\.5/),
@@ -412,6 +451,7 @@ window.undefined = window.undefined;
         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
         isSafari3 = isSafari && check(/version\/3/),
         isSafari4 = isSafari && check(/version\/4/),
+        isSafari5 = isSafari && check(/version\/5/),
         isIE = !isOpera && check(/msie/),
         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
@@ -420,27 +460,170 @@ window.undefined = window.undefined;
         isGecko = !isWebKit && check(/gecko/),
         isGecko3 = isGecko && check(/rv:1\.9/),
         isGecko4 = isGecko && check(/rv:2\.0/),
+        isGecko5 = isGecko && check(/rv:5\./),
         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
         isWindows = check(/windows|win32/),
         isMac = check(/macintosh|mac os x/),
         isLinux = check(/linux/),
-        scrollWidth = null;
+        scrollbarSize = null,
+        chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
+        firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
+        ieVersion = version(isIE, /msie (\d+\.\d+)/),
+        operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
+        safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
+        webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
+        isSecure = /^https/i.test(window.location.protocol);
 
     // remove css image flicker
     try {
         document.execCommand("BackgroundImageCache", false, true);
     } catch(e) {}
 
-    Ext.setVersion('extjs', '4.0.0');
+    //<debug>
+    function dumpObject (object) {
+        var member, members = [];
+
+        // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
+        // ...and the data could be prettier!
+        Ext.Object.each(object, function (name, value) {
+            if (typeof(value) === "function") {
+                return;
+            }
+
+            if (!Ext.isDefined(value) || value === null ||
+                    Ext.isDate(value) ||
+                    Ext.isString(value) || (typeof(value) == "number") ||
+                    Ext.isBoolean(value)) {
+                member = Ext.encode(value);
+            } else if (Ext.isArray(value)) {
+                member = '[ ]';
+            } else if (Ext.isObject(value)) {
+                member = '{ }';
+            } else {
+                member = 'undefined';
+            }
+            members.push(Ext.encode(name) + ': ' + member);
+        });
+
+        if (members.length) {
+            return ' \nData: {\n  ' + members.join(',\n  ') + '\n}';
+        }
+        return '';
+    }
+
+    function log (message) {
+        var options, dump,
+            con = Ext.global.console,
+            level = 'log',
+            indent = log.indent || 0,
+            stack;
+
+        log.indent = indent;
+
+        if (!Ext.isString(message)) {
+            options = message;
+            message = options.msg || '';
+            level = options.level || level;
+            dump = options.dump;
+            stack = options.stack;
+
+            if (options.indent) {
+                ++log.indent;
+            } else if (options.outdent) {
+                log.indent = indent = Math.max(indent - 1, 0);
+            }
+
+            if (dump && !(con && con.dir)) {
+                message += dumpObject(dump);
+                dump = null;
+            }
+        }
+
+        if (arguments.length > 1) {
+            message += Array.prototype.slice.call(arguments, 1).join('');
+        }
+
+        message = indent ? Ext.String.repeat('   ', indent) + message : message;
+        // w/o console, all messages are equal, so munge the level into the message:
+        if (level != 'log') {
+            message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
+        }
+
+        // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
+        // an early test may fail either direction if Firebug is toggled.
+        //
+        if (con) { // if (Firebug-like console)
+            if (con[level]) {
+                con[level](message);
+            } else {
+                con.log(message);
+            }
+
+            if (dump) {
+                con.dir(dump);
+            }
+
+            if (stack && con.trace) {
+                // Firebug's console.error() includes a trace already...
+                if (!con.firebug || level != 'error') {
+                    con.trace();
+                }
+            }
+        } else {
+            if (Ext.isOpera) {
+                opera.postError(message);
+            } else {
+                var out = log.out,
+                    max = log.max;
+
+                if (out.length >= max) {
+                    // this formula allows out.max to change (via debugger), where the
+                    // more obvious "max/4" would not quite be the same
+                    Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
+                }
+
+                out.push(message);
+            }
+        }
+
+        // Mostly informational, but the Ext.Error notifier uses them:
+        ++log.count;
+        ++log.counters[level];
+    }
+
+    log.count = 0;
+    log.counters = { error: 0, warn: 0, info: 0, log: 0 };
+    log.out = [];
+    log.max = 250;
+    log.show = function () {
+        window.open('','extlog').document.write([
+            '<html><head><script type="text/javascript">',
+                'var lastCount = 0;',
+                'function update () {',
+                    'var ext = window.opener.Ext,',
+                        'extlog = ext && ext.log;',
+                    'if (extlog && extlog.out && lastCount != extlog.count) {',
+                        'lastCount = extlog.count;',
+                        'var s = "<tt>" + extlog.out.join("<br>").replace(/[ ]/g, "&nbsp;") + "</tt>";',
+                        'document.body.innerHTML = s;',
+                    '}',
+                    'setTimeout(update, 1000);',
+                '}',
+                'setTimeout(update, 1000);',
+            '</script></head><body></body></html>'].join(''));
+    };
+    //</debug>
+
+    Ext.setVersion('extjs', '4.0.7');
     Ext.apply(Ext, {
         /**
          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
          * @type String
          */
-        SSL_SECURE_URL : Ext.isSecure && isIE ? 'javascript:""' : 'about:blank',
+        SSL_SECURE_URL : isSecure && isIE ? 'javascript:""' : 'about:blank',
 
         /**
          * True if the {@link Ext.fx.Anim} Class is available
@@ -473,7 +656,7 @@ window.undefined = window.undefined;
         USE_NATIVE_JSON : false,
 
         /**
-         * Return the dom node for the passed String (id), dom node, or Ext.core.Element.
+         * Return the dom node for the passed String (id), dom node, or Ext.Element.
          * Optional 'strict' flag is needed for IE since it can return 'name' and
          * 'id' elements by using getElementById.
          * Here are some examples:
@@ -484,7 +667,7 @@ var elDom = Ext.getDom('elId');
 var elDom1 = Ext.getDom(elDom);
 
 // If we don&#39;t know if we are working with an
-// Ext.core.Element or a dom node use Ext.getDom
+// Ext.Element or a dom node use Ext.getDom
 function(el){
     var dom = Ext.getDom(el);
     // do something with the dom node
@@ -492,7 +675,7 @@ function(el){
          * </code></pre>
          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
          * when this method is called to be successful.
-         * @param {Mixed} el
+         * @param {String/HTMLElement/Ext.Element} el
          * @return HTMLElement
          */
         getDom : function(el, strict) {
@@ -527,6 +710,7 @@ function(el){
          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
          * will be ignored if passed in.</p>
          * @param {HTMLElement} node The node to remove
+         * @method
          */
         removeNode : isIE6 || isIE7 ? function() {
             var d;
@@ -547,6 +731,10 @@ function(el){
             }
         },
 
+        isStrict: isStrict,
+
+        isIEQuirks: isIE && !isStrict,
+
         /**
          * True if the detected browser is Opera.
          * @type Boolean
@@ -589,6 +777,12 @@ function(el){
          */
         isSafari4 : isSafari4,
 
+        /**
+         * True if the detected browser is Safari 5.x.
+         * @type Boolean
+         */
+        isSafari5 : isSafari5,
+
         /**
          * True if the detected browser is Safari 2.x.
          * @type Boolean
@@ -644,23 +838,41 @@ function(el){
         isGecko4 : isGecko4,
 
         /**
-         * True if the detected browser uses FireFox 3.0
+         * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
          * @type Boolean
          */
+        isGecko5 : isGecko5,
 
+        /**
+         * True if the detected browser uses FireFox 3.0
+         * @type Boolean
+         */
         isFF3_0 : isFF3_0,
+
         /**
          * True if the detected browser uses FireFox 3.5
          * @type Boolean
          */
-
         isFF3_5 : isFF3_5,
+
         /**
          * True if the detected browser uses FireFox 3.6
          * @type Boolean
          */
         isFF3_6 : isFF3_6,
 
+        /**
+         * True if the detected browser uses FireFox 4
+         * @type Boolean
+         */
+        isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
+
+        /**
+         * True if the detected browser uses FireFox 5
+         * @type Boolean
+         */
+        isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
+
         /**
          * True if the detected platform is Linux.
          * @type Boolean
@@ -679,13 +891,61 @@ function(el){
          */
         isMac : isMac,
 
+        /**
+         * The current version of Chrome (0 if the browser is not Chrome).
+         * @type Number
+         */
+        chromeVersion: chromeVersion,
+
+        /**
+         * The current version of Firefox (0 if the browser is not Firefox).
+         * @type Number
+         */
+        firefoxVersion: firefoxVersion,
+
+        /**
+         * The current version of IE (0 if the browser is not IE). This does not account
+         * for the documentMode of the current page, which is factored into {@link #isIE7},
+         * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
+         *
+         *      Ext.isIE8 == (Ext.ieVersion == 8)
+         *
+         * @type Number
+         * @markdown
+         */
+        ieVersion: ieVersion,
+
+        /**
+         * The current version of Opera (0 if the browser is not Opera).
+         * @type Number
+         */
+        operaVersion: operaVersion,
+
+        /**
+         * The current version of Safari (0 if the browser is not Safari).
+         * @type Number
+         */
+        safariVersion: safariVersion,
+
+        /**
+         * The current version of WebKit (0 if the browser does not use WebKit).
+         * @type Number
+         */
+        webKitVersion: webKitVersion,
+
+        /**
+         * True if the page is running over SSL
+         * @type Boolean
+         */
+        isSecure: isSecure,
+
         /**
          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
          * For other browsers it uses an inline data URL.
          * @type String
          */
-        BLANK_IMAGE_URL : (isIE6 || isIE7) ? 'http:/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
+        BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
 
         /**
          * <p>Utility method for returning a default value if the passed value is empty.</p>
@@ -695,11 +955,11 @@ function(el){
          * <li>an empty array</li>
          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
          * </ul></div>
-         * @param {Mixed} value The value to test
-         * @param {Mixed} defaultValue The value to return if the original value is empty
+         * @param {Object} value The value to test
+         * @param {Object} defaultValue The value to return if the original value is empty
          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
-         * @return {Mixed} value, if non-empty, else defaultValue
-         * @deprecated 4.0.0 Use {Ext#valueFrom} instead
+         * @return {Object} value, if non-empty, else defaultValue
+         * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
          */
         value : function(v, defaultValue, allowBlank){
             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
@@ -757,53 +1017,76 @@ Ext.addBehaviors({
         },
 
         /**
-         * Utility method for getting the width of the browser scrollbar. This can differ depending on
+         * Returns the size of the browser scrollbars. This can differ depending on
          * operating system settings, such as the theme or font size.
          * @param {Boolean} force (optional) true to force a recalculation of the value.
-         * @return {Number} The width of the scrollbar.
+         * @return {Object} An object containing the width of a vertical scrollbar and the
+         * height of a horizontal scrollbar.
          */
-        getScrollBarWidth: function(force){
+        getScrollbarSize: function (force) {
             if(!Ext.isReady){
                 return 0;
             }
 
-            if(force === true || scrollWidth === null){
+            if(force === true || scrollbarSize === null){
                 // BrowserBug: IE9
                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
                 // inaccurately reported. For IE9 only, we render on screen before removing.
-                var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets';
+                var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets',
                     // Append our div, do our calculation and then remove it
-                var div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
-                    child = div.child('div', true);
-                var w1 = child.offsetWidth;
+                    div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
+                    child = div.child('div', true),
+                    w1 = child.offsetWidth;
+
                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
-                var w2 = child.offsetWidth;
+
+                var w2 = child.offsetWidth, width = w1 - w2;
                 div.remove();
-                // Need to add 2 to ensure we leave enough space
-                scrollWidth = w1 - w2 + 2;
+
+                // We assume width == height for now. TODO: is this always true?
+                scrollbarSize = { width: width, height: width };
             }
-            return scrollWidth;
+
+            return scrollbarSize;
+        },
+
+        /**
+         * Utility method for getting the width of the browser's vertical scrollbar. This
+         * can differ depending on operating system settings, such as the theme or font size.
+         *
+         * This method is deprected in favor of {@link #getScrollbarSize}.
+         *
+         * @param {Boolean} force (optional) true to force a recalculation of the value.
+         * @return {Number} The width of a vertical scrollbar.
+         * @deprecated
+         */
+        getScrollBarWidth: function(force){
+            var size = Ext.getScrollbarSize(force);
+            return size.width + 2; // legacy fudge factor
         },
 
         /**
          * Copies a set of named properties fom the source object to the destination object.
-         * <p>example:<pre><code>
-ImageComponent = Ext.extend(Ext.Component, {
-    initComponent: function() {
-        this.autoEl = { tag: 'img' };
-        MyComponent.superclass.initComponent.apply(this, arguments);
-        this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
-    }
-});
-         * </code></pre>
+         *
+         * Example:
+         *
+         *     ImageComponent = Ext.extend(Ext.Component, {
+         *         initComponent: function() {
+         *             this.autoEl = { tag: 'img' };
+         *             MyComponent.superclass.initComponent.apply(this, arguments);
+         *             this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
+         *         }
+         *     });
+         *
          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
+         *
          * @param {Object} dest The destination object.
          * @param {Object} source The source object.
-         * @param {Array/String} names Either an Array of property names, or a comma-delimited list
+         * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
          * of property names to copy.
          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
          * @return {Object} The modified object.
-        */
+         */
         copyTo : function(dest, source, names, usePrototypeKeys){
             if(typeof names == 'string'){
                 names = names.split(/[,;\s]/);
@@ -819,16 +1102,56 @@ ImageComponent = Ext.extend(Ext.Component, {
         /**
          * Attempts to destroy and then remove a set of named properties of the passed object.
          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
-         * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
-         * @param {Mixed} etc... More property names to destroy and remove.
+         * @param {String...} args One or more names of the properties to destroy and remove from the object.
          */
-        destroyMembers : function(o, arg1, arg2, etc){
+        destroyMembers : function(o){
             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
                 Ext.destroy(o[a[i]]);
                 delete o[a[i]];
             }
         },
 
+        /**
+         * Logs a message. If a console is present it will be used. On Opera, the method
+         * "opera.postError" is called. In other cases, the message is logged to an array
+         * "Ext.log.out". An attached debugger can watch this array and view the log. The
+         * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
+         * The `Ext.log.out` array can also be written to a popup window by entering the
+         * following in the URL bar (a "bookmarklet"):
+         *
+         *    javascript:void(Ext.log.show());
+         *
+         * If additional parameters are passed, they are joined and appended to the message.
+         * A technique for tracing entry and exit of a function is this:
+         *
+         *      function foo () {
+         *          Ext.log({ indent: 1 }, '>> foo');
+         *
+         *          // log statements in here or methods called from here will be indented
+         *          // by one step
+         *
+         *          Ext.log({ outdent: 1 }, '<< foo');
+         *      }
+         *
+         * This method does nothing in a release build.
+         *
+         * @param {String/Object} message The message to log or an options object with any
+         * of the following properties:
+         *
+         *  - `msg`: The message to log (required).
+         *  - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
+         *  - `dump`: An object to dump to the log as part of the message.
+         *  - `stack`: True to include a stack trace in the log.
+         *  - `indent`: Cause subsequent log statements to be indented one step.
+         *  - `outdent`: Cause this and following statements to be one step less indented.
+         * @markdown
+         */
+        log :
+            //<debug>
+            log ||
+            //</debug>
+            Ext.emptyFn,
+
         /**
          * Partitions the set into two sets: a true set and a false set.
          * Example:
@@ -847,10 +1170,10 @@ Ext.partition(
 // true are those paragraph elements with a className of "class1",
 // false set are those that do not have that className.
          * </code></pre>
-         * @param {Array|NodeList} arr The array to partition
+         * @param {Array/NodeList} arr The array to partition
          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
-         *                   itself must be able to be evaluated for its truthfulness.
-         * @return {Array} [true<Array>,false<Array>]
+         * itself must be able to be evaluated for its truthfulness.
+         * @return {Array} [array of truish values, array of falsy values]
          * @deprecated 4.0.0 Will be removed in the next major version
          */
         partition : function(arr, truth){
@@ -868,9 +1191,9 @@ Ext.partition(
 Ext.invoke(Ext.query("p"), "getAttribute", "id");
 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
          * </code></pre>
-         * @param {Array|NodeList} arr The Array of items to invoke the method on.
+         * @param {Array/NodeList} arr The Array of items to invoke the method on.
          * @param {String} methodName The method name to invoke.
-         * @param {...*} args Arguments to send into the method invocation.
+         * @param {Object...} args Arguments to send into the method invocation.
          * @return {Array} The results of invoking the method on each item in the array.
          * @deprecated 4.0.0 Will be removed in the next major version
          */
@@ -902,7 +1225,7 @@ Ext.zip(
     }
 ); // ["$+12.43", "$-10.15", "$+22.96"]
          * </code></pre>
-         * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
+         * @param {Array/NodeList...} arr This argument may be repeated. Array(s) to contribute values.
          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
          * @return {Array} The zipped set.
          * @deprecated 4.0.0 Will be removed in the next major version
@@ -931,7 +1254,7 @@ Ext.zip(
          * Turns an array into a sentence, joined by a specified connector - e.g.:
          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
-         * @param {Array} items The array to create a sentence from
+         * @param {String[]} items The array to create a sentence from
          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
          * @return {String} The sentence string
          * @deprecated 4.0.0 Will be removed in the next major version
@@ -959,8 +1282,10 @@ Ext.zip(
 })();
 
 /**
- * TBD
- * @type Function
+ * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
+ *
+ * See Ext.app.Application for details.
+ *
  * @param {Object} config
  */
 Ext.application = function(config) {
@@ -974,7 +1299,7 @@ Ext.application = function(config) {
 /**
  * @class Ext.util.Format
 
-This class is a centralized place for formatting functions inside the library. It includes
+This class is a centralized place for formatting functions. It includes
 functions to format various different types of data, such as text, dates and numeric values.
 
 __Localization__
@@ -986,10 +1311,10 @@ Options include:
 - currenyPrecision
 - currencySign
 - currencyAtEnd
-This class also uses the default date format defined here: {@link Ext.date#defaultFormat}.
+This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
 
 __Using with renderers__
-There are two helper functions that return a new function that can be used in conjunction with 
+There are two helper functions that return a new function that can be used in conjunction with
 grid renderers:
 
     columns: [{
@@ -999,7 +1324,7 @@ grid renderers:
         dataIndex: 'time',
         renderer: Ext.util.Format.numberRenderer('0.000')
     }]
-    
+
 Functions that only take a single argument can also be passed directly:
     columns: [{
         dataIndex: 'cost',
@@ -1008,7 +1333,7 @@ Functions that only take a single argument can also be passed directly:
         dataIndex: 'productCode',
         renderer: Ext.util.Format.uppercase
     }]
-    
+
 __Using with XTemplates__
 XTemplates can also directly use Ext.util.Format functions:
 
@@ -1038,50 +1363,45 @@ XTemplates can also directly use Ext.util.Format functions:
 
     Ext.apply(UtilFormat, {
         /**
-         * @type String
-         * @property thousandSeparator
+         * @property {String} thousandSeparator
          * <p>The character that the {@link #number} function uses as a thousand separator.</p>
-         * <p>This defaults to <code>,</code>, but may be overridden in a locale file.</p>
+         * <p>This may be overridden in a locale file.</p>
          */
         thousandSeparator: ',',
 
         /**
-         * @type String
-         * @property decimalSeparator
+         * @property {String} decimalSeparator
          * <p>The character that the {@link #number} function uses as a decimal point.</p>
-         * <p>This defaults to <code>.</code>, but may be overridden in a locale file.</p>
+         * <p>This may be overridden in a locale file.</p>
          */
         decimalSeparator: '.',
 
         /**
-         * @type Number
-         * @property currencyPrecision
+         * @property {Number} currencyPrecision
          * <p>The number of decimal places that the {@link #currency} function displays.</p>
-         * <p>This defaults to <code>2</code>, but may be overridden in a locale file.</p>
+         * <p>This may be overridden in a locale file.</p>
          */
         currencyPrecision: 2,
 
         /**
-         * @type String
-         * @property currencySign
+         * @property {String} currencySign
          * <p>The currency sign that the {@link #currency} function displays.</p>
-         * <p>This defaults to <code>$</code>, but may be overridden in a locale file.</p>
+         * <p>This may be overridden in a locale file.</p>
          */
         currencySign: '$',
 
         /**
-         * @type Boolean
-         * @property currencyAtEnd
+         * @property {Boolean} currencyAtEnd
          * <p>This may be set to <code>true</code> to make the {@link #currency} function
          * append the currency sign to the formatted value.</p>
-         * <p>This defaults to <code>false</code>, but may be overridden in a locale file.</p>
+         * <p>This may be overridden in a locale file.</p>
          */
         currencyAtEnd: false,
 
         /**
          * Checks a reference and converts it to empty string if it is undefined
-         * @param {Mixed} value Reference to check
-         * @return {Mixed} Empty string if converted, otherwise the original value
+         * @param {Object} value Reference to check
+         * @return {Object} Empty string if converted, otherwise the original value
          */
         undef : function(value) {
             return value !== undefined ? value : "";
@@ -1089,7 +1409,7 @@ XTemplates can also directly use Ext.util.Format functions:
 
         /**
          * Checks a reference and converts it to the default value if it's empty
-         * @param {Mixed} value Reference to check
+         * @param {Object} value Reference to check
          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
          * @return {String}
          */
@@ -1157,7 +1477,7 @@ XTemplates can also directly use Ext.util.Format functions:
             for (; i < decimals; i++) {
                 format += '0';
             }
-            v = UtilFormat.number(v, format); 
+            v = UtilFormat.number(v, format);
             if ((end || UtilFormat.currencyAtEnd) === true) {
                 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
             } else {
@@ -1195,7 +1515,7 @@ XTemplates can also directly use Ext.util.Format functions:
 
         /**
          * Strips all HTML tags
-         * @param {Mixed} value The text from which to strip tags
+         * @param {Object} value The text from which to strip tags
          * @return {String} The stripped text
          */
         stripTags : function(v) {
@@ -1204,7 +1524,7 @@ XTemplates can also directly use Ext.util.Format functions:
 
         /**
          * Strips all script tags
-         * @param {Mixed} value The text from which to strip script tags
+         * @param {Object} value The text from which to strip script tags
          * @return {String} The stripped text
          */
         stripScripts : function(v) {
@@ -1231,6 +1551,7 @@ XTemplates can also directly use Ext.util.Format functions:
          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
          * </code></pre>
          * @return {Function} A function that operates on the passed value.
+         * @method
          */
         math : function(){
             var fns = {};
@@ -1265,7 +1586,7 @@ XTemplates can also directly use Ext.util.Format functions:
          * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
          * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
          * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
-         * <p><b>New to Ext4</b></p>
+         * <p><b>New to Ext JS 4</b></p>
          * <p>Locale-specific characters are always used in the formatted output when inserting
          * thousand and decimal separators.</p>
          * <p>The format string must specify separator characters according to US/UK conventions ("," as the
@@ -1287,8 +1608,7 @@ XTemplates can also directly use Ext.util.Format functions:
          * @param {String} format The way you would like to format this text.
          * @return {String} The formatted number.
          */
-        number:
-            function(v, formatString) {
+        number: function(v, formatString) {
             if (!formatString) {
                 return v;
             }
@@ -1368,6 +1688,15 @@ XTemplates can also directly use Ext.util.Format functions:
                 }
             }
 
+            if (neg) {
+                /*
+                 * Edge case. If we have a very small negative number it will get rounded to 0,
+                 * however the initial check at the top will still report as negative. Replace
+                 * everything but 1-9 and check if the string is empty to determine a 0 value.
+                 */
+                neg = fnum.replace(/[^1-9]/g, '') !== '';
+            }
+
             return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
         },
 
@@ -1404,47 +1733,58 @@ XTemplates can also directly use Ext.util.Format functions:
         },
 
         /**
-         * Capitalize the given string. See {@link Ext.String#capitalize}.
+         * Alias for {@link Ext.String#capitalize}.
+         * @method
+         * @alias Ext.String#capitalize
          */
         capitalize: Ext.String.capitalize,
 
         /**
-         * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
-         * See {@link Ext.String#ellipsis}.
+         * Alias for {@link Ext.String#ellipsis}.
+         * @method
+         * @alias Ext.String#ellipsis
          */
         ellipsis: Ext.String.ellipsis,
 
         /**
-         * Formats to a string. See {@link Ext.String#format}
+         * Alias for {@link Ext.String#format}.
+         * @method
+         * @alias Ext.String#format
          */
         format: Ext.String.format,
 
         /**
-         * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
-         * See {@link Ext.string#htmlDecode}.
+         * Alias for {@link Ext.String#htmlDecode}.
+         * @method
+         * @alias Ext.String#htmlDecode
          */
         htmlDecode: Ext.String.htmlDecode,
 
         /**
-         * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
-         * See {@link Ext.String#htmlEncode}.
+         * Alias for {@link Ext.String#htmlEncode}.
+         * @method
+         * @alias Ext.String#htmlEncode
          */
         htmlEncode: Ext.String.htmlEncode,
 
         /**
-         * Adds left padding to a string. See {@link Ext.String#leftPad}
+         * Alias for {@link Ext.String#leftPad}.
+         * @method
+         * @alias Ext.String#leftPad
          */
         leftPad: Ext.String.leftPad,
 
         /**
-         * Trims any whitespace from either side of a string. See {@link Ext.String#trim}.
+         * Alias for {@link Ext.String#trim}.
+         * @method
+         * @alias Ext.String#trim
          */
         trim : Ext.String.trim,
 
         /**
          * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
          * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
-         * @param {Number|String} v The encoded margins
+         * @param {Number/String} v The encoded margins
          * @return {Object} An object with margin sizes for top, right, bottom and left
          */
         parseBox : function(box) {
@@ -1514,8 +1854,7 @@ Ext.TaskManager.start({
  * Also see {@link Ext.util.DelayedTask}. 
  * 
  * @constructor
- * @param {Number} interval (optional) The minimum precision in milliseconds supported by this TaskRunner instance
- * (defaults to 10)
+ * @param {Number} [interval=10] The minimum precision in milliseconds supported by this TaskRunner instance
  */
 Ext.ns('Ext.util');
 
@@ -1909,12 +2248,65 @@ Ext.supports = {
          */
         {
             identity: 'RightMargin',
-            fn: function(doc, div, view) {
-                view = doc.defaultView;
+            fn: function(doc, div) {
+                var view = doc.defaultView;
                 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
             }
         },
-        
+
+        /**
+         * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
+         * selection when their display style is changed. Essentially, if a text input
+         * has focus and its display style is changed, the I-beam disappears.
+         * 
+         * This bug is encountered due to the work around in place for the {@link #RightMargin}
+         * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
+         * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
+         * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
+         */
+        {
+            identity: 'DisplayChangeInputSelectionBug',
+            fn: function() {
+                var webKitVersion = Ext.webKitVersion;
+                // WebKit but older than Safari 5 or Chrome 6:
+                return 0 < webKitVersion && webKitVersion < 533;
+            }
+        },
+
+        /**
+         * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
+         * selection when their display style is changed. Essentially, if a text area has
+         * focus and its display style is changed, the I-beam disappears.
+         *
+         * This bug is encountered due to the work around in place for the {@link #RightMargin}
+         * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
+         * be fixed in Chrome 11.
+         */
+        {
+            identity: 'DisplayChangeTextAreaSelectionBug',
+            fn: function() {
+                var webKitVersion = Ext.webKitVersion;
+
+                /*
+                Has bug w/textarea:
+
+                (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
+                            AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
+                            Safari/534.16
+                (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
+                            AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
+                            Safari/533.21.1
+
+                No bug:
+
+                (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
+                            AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
+                            Safari/534.24
+                */
+                return 0 < webKitVersion && webKitVersion < 534.24;
+            }
+        },
+
         /**
          * @property TransparentColor True if the device supports transparent color
          * @type {Boolean}
@@ -2180,8 +2572,19 @@ Ext.supports = {
                 
                 return range && !!range.createContextualFragment;
             }
+        },
+
+        /**
+         * @property WindowOnError True if browser supports window.onerror.
+         * @type {Boolean}
+         */
+        {
+            identity: 'WindowOnError',
+            fn: function () {
+                // sadly, we cannot feature detect this...
+                return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
+            }
         }
-        
     ]
 };