/** * @class Ext * * The Ext namespace (global object) encapsulates all classes, singletons, and * utility methods provided by Sencha's libraries. * * Most user interface Components are at a lower level of nesting in the namespace, * but many common utility functions are provided as direct properties of the Ext namespace. * * Also many frequently used methods from other classes are provided as shortcuts * within the Ext namespace. For example {@link Ext#getCmp Ext.getCmp} aliases * {@link Ext.ComponentManager#get Ext.ComponentManager.get}. * * Many applications are initiated with {@link Ext#onReady Ext.onReady} which is * called once the DOM is ready. This ensures all scripts have been loaded, * preventing dependency issues. For example: * * Ext.onReady(function(){ * new Ext.Component({ * renderTo: document.body, * html: 'DOM ready!' * }); * }); * * For more information about how to use the Ext classes, see: * * - The Learning Center * - The FAQ * - The forums * * @singleton */ Ext.apply(Ext, { userAgent: navigator.userAgent.toLowerCase(), cache: {}, idSeed: 1000, windowId: 'ext-window', documentId: 'ext-document', /** * True when the document is fully initialized and ready for action */ isReady: false, /** * True to automatically uncache orphaned Ext.Elements periodically */ enableGarbageCollector: true, /** * True to automatically purge event listeners during garbageCollection. */ enableListenerCollection: true, addCacheEntry: function(id, el, dom) { dom = dom || el.dom; // if (!dom) { // Without the DOM node we can't GC the entry Ext.Error.raise('Cannot add an entry to the element cache without the DOM node'); } // var key = id || (el && el.id) || dom.id, entry = Ext.cache[key] || (Ext.cache[key] = { data: {}, events: {}, dom: dom, // Skip garbage collection for special elements (window, document, iframes) skipGarbageCollection: !!(dom.getElementById || dom.navigator) }); if (el) { el.$cache = entry; // Inject the back link from the cache in case the cache entry // had already been created by Ext.fly. Ext.fly creates a cache entry with no el link. entry.el = el; } return entry; }, /** * Generates unique ids. If the element already has an id, it is unchanged * @param {HTMLElement/Ext.Element} [el] 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 = me.documentId; } else if (el === window) { el.id = me.windowId; } if (!el.id) { if (me.isSandboxed) { sandboxPrefix = Ext.sandboxName.toLowerCase() + '-'; } el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed); } return el.id; }, escapeId: (function(){ var validIdRe = /^[a-zA-Z_][a-zA-Z0-9_\-]*$/i, escapeRx = /([\W]{1})/g, leadingNumRx = /^(\d)/g, escapeFn = function(match, capture){ return "\\" + capture; }, numEscapeFn = function(match, capture){ return '\\00' + capture.charCodeAt(0).toString(16) + ' '; }; return function(id) { return validIdRe.test(id) ? id // replace the number portion last to keep the trailing ' ' // from being escaped : id.replace(escapeRx, escapeFn) .replace(leadingNumRx, numEscapeFn); }; }()), /** * Returns the current document body as an {@link Ext.Element}. * @return Ext.Element The document body */ getBody: (function() { var body; return function() { return body || (body = Ext.get(document.body)); }; }()), /** * Returns the current document head as an {@link Ext.Element}. * @return Ext.Element The document head * @method */ getHead: (function() { var head; return function() { return head || (head = Ext.get(document.getElementsByTagName("head")[0])); }; }()), /** * Returns the current HTML document object as an {@link Ext.Element}. * @return Ext.Element The document */ getDoc: (function() { var doc; return function() { return doc || (doc = Ext.get(document)); }; }()), /** * This is shorthand reference to {@link Ext.ComponentManager#get}. * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id} * * @param {String} id The component {@link Ext.Component#id id} * @return Ext.Component The Component, `undefined` if not found, or `null` if a * Class was found. */ getCmp: function(id) { return Ext.ComponentManager.get(id); }, /** * Returns the current orientation of the mobile device * @return {String} Either 'portrait' or 'landscape' */ getOrientation: function() { return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape'; }, /** * 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.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 {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} args * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy */ destroy: function() { var ln = arguments.length, i, arg; for (i = 0; i < ln; i++) { arg = arguments[i]; if (arg) { if (Ext.isArray(arg)) { this.destroy.apply(this, arg); } else if (Ext.isFunction(arg.destroy)) { arg.destroy(); } else if (arg.dom) { arg.remove(); } } } }, /** * 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] The scope to execute in * @param {Array} [args] The arguments to pass to the function * @param {Number} [delay] Pass a number to delay the call by a number of milliseconds. */ callback: function(callback, scope, args, delay){ if(Ext.isFunction(callback)){ args = args || []; scope = scope || window; if (delay) { Ext.defer(callback, delay, scope, args); } else { callback.apply(scope, args); } } }, /** * Alias for {@link Ext.String#htmlEncode}. * @inheritdoc Ext.String#htmlEncode */ htmlEncode : function(value) { return Ext.String.htmlEncode(value); }, /** * Alias for {@link Ext.String#htmlDecode}. * @inheritdoc Ext.String#htmlDecode */ htmlDecode : function(value) { return Ext.String.htmlDecode(value); }, /** * Alias for {@link Ext.String#urlAppend}. * @inheritdoc Ext.String#urlAppend */ urlAppend : function(url, s) { return Ext.String.urlAppend(url, s); } }); Ext.ns = Ext.namespace; // for old browsers window.undefined = window.undefined; /** * @class Ext */ (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/), isChrome = check(/\bchrome\b/), isWebKit = check(/webkit/), isSafari = !isChrome && check(/safari/), isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2 isSafari3 = isSafari && check(/version\/3/), isSafari4 = isSafari && check(/version\/4/), isSafari5_0 = isSafari && check(/version\/5\.0/), isSafari5 = isSafari && check(/version\/5/), isIE = !isOpera && check(/msie/), isIE7 = isIE && ((check(/msie 7/) && docMode != 8 && docMode != 9) || docMode == 7), isIE8 = isIE && ((check(/msie 8/) && docMode != 7 && docMode != 9) || docMode == 8), isIE9 = isIE && ((check(/msie 9/) && docMode != 7 && docMode != 8) || docMode == 9), isIE6 = isIE && check(/msie 6/), isGecko = !isWebKit && check(/gecko/), isGecko3 = isGecko && check(/rv:1\.9/), isGecko4 = isGecko && check(/rv:2\.0/), isGecko5 = isGecko && check(/rv:5\./), isGecko10 = isGecko && check(/rv:10\./), 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/), 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), nullLog; // remove css image flicker try { document.execCommand("BackgroundImageCache", false, true); } catch(e) {} // var primitiveRe = /string|number|boolean/; function dumpObject (object) { var member, type, value, name, members = []; // Cannot use Ext.encode since it can recurse endlessly (if we're lucky) // ...and the data could be prettier! for (name in object) { if (object.hasOwnProperty(name)) { value = object[name]; type = typeof value; if (type == "function") { continue; } if (type == 'undefined') { member = type; } else if (value === null || primitiveRe.test(type) || Ext.isDate(value)) { member = Ext.encode(value); } else if (Ext.isArray(value)) { member = '[ ]'; } else if (Ext.isObject(value)) { member = '{ }'; } else { member = type; } 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, out, max; log.indent = indent; if (typeof message != 'string') { 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(' ', log.indentSize * 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 { 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]; } function logx (level, args) { if (typeof args[0] == 'string') { args.unshift({}); } args[0].level = level; log.apply(this, args); } log.error = function () { logx('error', Array.prototype.slice.call(arguments)); }; log.info = function () { logx('info', Array.prototype.slice.call(arguments)); }; log.warn = function () { logx('warn', Array.prototype.slice.call(arguments)); }; log.count = 0; log.counters = { error: 0, warn: 0, info: 0, log: 0 }; log.indentSize = 2; log.out = []; log.max = 750; log.show = function () { window.open('','extlog').document.write([ ''].join('')); }; // nullLog = function () {}; nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn; Ext.setVersion('extjs', '4.1.0'); Ext.apply(Ext, { /** * @property {String} SSL_SECURE_URL * 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 (`'about:blank'`, except for IE * in secure mode, which is `'javascript:""'`). */ SSL_SECURE_URL : isSecure && isIE ? 'javascript:\'\'' : 'about:blank', /** * @property {Boolean} enableFx * True if the {@link Ext.fx.Anim} Class is available. */ /** * @property {Boolean} scopeResetCSS * True to scope the reset CSS to be just applied to Ext components. Note that this * wraps root containers with an additional element. Also remember that when you turn * on this option, you have to use ext-all-scoped (unless you use the bootstrap.js to * load your javascript, in which case it will be handled for you). */ scopeResetCSS : Ext.buildSettings.scopeResetCSS, /** * @property {String} resetCls * The css class used to wrap Ext components when the {@link #scopeResetCSS} option * is used. */ resetCls: Ext.buildSettings.baseCSSPrefix + 'reset', /** * @property {Boolean} enableNestedListenerRemoval * **Experimental.** True to cascade listener removal to child elements when an element * is removed. Currently not optimized for performance. */ enableNestedListenerRemoval : false, /** * @property {Boolean} USE_NATIVE_JSON * Indicates whether to use native browser parsing for JSON methods. * This option is ignored if the browser does not support native JSON methods. * * **Note:** Native JSON methods will not work with objects that have functions. * Also, property names must be quoted, otherwise the data will not parse. */ USE_NATIVE_JSON : false, /** * Returns 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: * * // gets dom node based on id * var elDom = Ext.getDom('elId'); * // gets dom node based on the dom node * var elDom1 = Ext.getDom(elDom); * * // If we don't know if we are working with an * // Ext.Element or a dom node use Ext.getDom * function(el){ * var dom = Ext.getDom(el); * // do something with the dom node * } * * **Note:** the dom node to be found actually needs to exist (be rendered, etc) * when this method is called to be successful. * * @param {String/HTMLElement/Ext.Element} el * @return HTMLElement */ getDom : function(el, strict) { if (!el || !document) { return null; } if (el.dom) { return el.dom; } else { if (typeof el == 'string') { var e = Ext.getElementById(el); // IE returns elements with the 'name' and 'id' attribute. // we do a strict check to return the element with only the id attribute if (e && isIE && strict) { if (el == e.getAttribute('id')) { return e; } else { return null; } } return e; } else { return el; } } }, /** * Removes a DOM node from the document. * * Removes this element from the document, removes all DOM event listeners, and * deletes the cache reference. All DOM event listeners are removed from this element. * If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is * `true`, then DOM event listeners are also removed from all child nodes. * The body node will be ignored if passed in. * * @param {HTMLElement} node The node to remove * @method */ removeNode : isIE6 || isIE7 || isIE8 ? (function() { var d; return function(n){ if(n && n.tagName.toUpperCase() != 'BODY'){ (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n); var cache = Ext.cache, id = n.id; if (cache[id]) { delete cache[id].dom; delete cache[id]; } // removing an iframe this way can cause severe leaks // fixes leak issue with htmleditor in themes example if (n.tagName.toUpperCase() != 'IFRAME') { if (isIE8 && n.parentNode) { n.parentNode.removeChild(n); } d = d || document.createElement('div'); d.appendChild(n); d.innerHTML = ''; } } }; }()) : function(n) { if (n && n.parentNode && n.tagName.toUpperCase() != 'BODY') { (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n); var cache = Ext.cache, id = n.id; if (cache[id]) { delete cache[id].dom; delete cache[id]; } n.parentNode.removeChild(n); } }, isStrict: isStrict, isIEQuirks: isIE && !isStrict, /** * True if the detected browser is Opera. * @type Boolean */ isOpera : isOpera, /** * True if the detected browser is Opera 10.5x. * @type Boolean */ isOpera10_5 : isOpera10_5, /** * True if the detected browser uses WebKit. * @type Boolean */ isWebKit : isWebKit, /** * True if the detected browser is Chrome. * @type Boolean */ isChrome : isChrome, /** * True if the detected browser is Safari. * @type Boolean */ isSafari : isSafari, /** * True if the detected browser is Safari 3.x. * @type Boolean */ isSafari3 : isSafari3, /** * True if the detected browser is Safari 4.x. * @type Boolean */ isSafari4 : isSafari4, /** * True if the detected browser is Safari 5.x. * @type Boolean */ isSafari5 : isSafari5, /** * True if the detected browser is Safari 5.0.x. * @type Boolean */ isSafari5_0 : isSafari5_0, /** * True if the detected browser is Safari 2.x. * @type Boolean */ isSafari2 : isSafari2, /** * True if the detected browser is Internet Explorer. * @type Boolean */ isIE : isIE, /** * True if the detected browser is Internet Explorer 6.x. * @type Boolean */ isIE6 : isIE6, /** * True if the detected browser is Internet Explorer 7.x. * @type Boolean */ isIE7 : isIE7, /** * True if the detected browser is Internet Explorer 8.x. * @type Boolean */ isIE8 : isIE8, /** * True if the detected browser is Internet Explorer 9.x. * @type Boolean */ isIE9 : isIE9, /** * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox). * @type Boolean */ isGecko : isGecko, /** * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x). * @type Boolean */ isGecko3 : isGecko3, /** * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x). * @type Boolean */ isGecko4 : isGecko4, /** * 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 a Gecko 5.0+ layout engine (e.g. Firefox 5.x). * @type Boolean */ isGecko10 : isGecko10, /** * 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 browser uses FireFox 10 * @type Boolean */ isFF10 : 10 <= firefoxVersion && firefoxVersion < 11, /** * True if the detected platform is Linux. * @type Boolean */ isLinux : isLinux, /** * True if the detected platform is Windows. * @type Boolean */ isWindows : isWindows, /** * True if the detected platform is Mac OS. * @type Boolean */ 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 */ 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) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', /** * Utility method for returning a default value if the passed value is empty. * * The value is deemed to be empty if it is: * * - null * - undefined * - an empty array * - a zero length string (Unless the `allowBlank` parameter is `true`) * * @param {Object} value The value to test * @param {Object} defaultValue The value to return if the original value is empty * @param {Boolean} [allowBlank=false] true to allow zero length strings to qualify as non-empty. * @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; }, /** * Escapes the passed string for use in a regular expression. * @param {String} str * @return {String} * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead */ escapeRe : function(s) { return s.replace(/([-.*+?\^${}()|\[\]\/\\])/g, "\\$1"); }, /** * Applies event listeners to elements by selectors when the document is ready. * The event name is specified with an `@` suffix. * * Ext.addBehaviors({ * // add a listener for click on all anchors in element with id foo * '#foo a@click' : function(e, t){ * // do something * }, * * // add the same listener to multiple selectors (separated by comma BEFORE the @) * '#foo a, #bar span.some-class@mouseover' : function(){ * // do something * } * }); * * @param {Object} obj The list of behaviors to apply */ addBehaviors : function(o){ if(!Ext.isReady){ Ext.onReady(function(){ Ext.addBehaviors(o); }); } else { var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times parts, b, s; for (b in o) { if ((parts = b.split('@'))[1]) { // for Object prototype breakers s = parts[0]; if(!cache[s]){ cache[s] = Ext.select(s); } cache[s].on(parts[1], o[b]); } } cache = null; } }, /** * 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] true to force a recalculation of the value. * @return {Object} An object containing scrollbar sizes. * @return.width {Number} The width of the vertical scrollbar. * @return.height {Number} The height of the horizontal scrollbar. */ getScrollbarSize: function (force) { if (!Ext.isReady) { return {}; } if (force || !scrollbarSize) { var db = document.body, div = document.createElement('div'); div.style.width = div.style.height = '100px'; div.style.overflow = 'scroll'; div.style.position = 'absolute'; db.appendChild(div); // now we can measure the div... // at least in iE9 the div is not 100px - the scrollbar size is removed! scrollbarSize = { width: div.offsetWidth - div.clientWidth, height: div.offsetHeight - div.clientHeight }; db.removeChild(div); } 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] 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. * * 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 {String/String[]} names Either an Array of property names, or a comma-delimited list * of property names to copy. * @param {Boolean} [usePrototypeKeys] 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]/); } var n, nLen = names.length, name; for(n = 0; n < nLen; n++) { name = names[n]; if(usePrototypeKeys || source.hasOwnProperty(name)){ dest[name] = source[name]; } } return dest; }, /** * 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 {String...} args One or more names of the properties to destroy and remove from the object. */ 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. * * @method */ log : // log || // nullLog, /** * Partitions the set into two sets: a true set and a false set. * * Example 1: * * Ext.partition([true, false, true, true, false]); * // returns [[true, true, true], [false, false]] * * Example 2: * * Ext.partition( * Ext.query("p"), * function(val){ * return val.className == "class1" * } * ); * // true are those paragraph elements with a className of "class1", * // false set are those that do not have that className. * * @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} [array of truish values, array of falsy values] * @deprecated 4.0.0 Will be removed in the next major version */ partition : function(arr, truth){ var ret = [[],[]], a, v, aLen = arr.length; for (a = 0; a < aLen; a++) { v = arr[a]; ret[ (truth && truth(v, a, arr)) || (!truth && v) ? 0 : 1].push(v); } return ret; }, /** * Invokes a method on each item in an Array. * * Example: * * Ext.invoke(Ext.query("p"), "getAttribute", "id"); * // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")] * * @param {Array/NodeList} arr The Array of items to invoke the method on. * @param {String} methodName The method name to invoke. * @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 */ invoke : function(arr, methodName){ var ret = [], args = Array.prototype.slice.call(arguments, 2), a, v, aLen = arr.length; for (a = 0; a < aLen; a++) { v = arr[a]; if (v && typeof v[methodName] == 'function') { ret.push(v[methodName].apply(v, args)); } else { ret.push(undefined); } } return ret; }, /** * Zips N sets together. * * Example 1: * * Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]] * * Example 2: * * Ext.zip( * [ "+", "-", "+"], * [ 12, 10, 22], * [ 43, 15, 96], * function(a, b, c){ * return "$" + a + "" + b + "." + c * } * ); // ["$+12.43", "$-10.15", "$+22.96"] * * @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 */ zip : function(){ var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }), arrs = parts[0], fn = parts[1][0], len = Ext.max(Ext.pluck(arrs, "length")), ret = [], i, j, aLen; for (i = 0; i < len; i++) { ret[i] = []; if(fn){ ret[i] = fn.apply(fn, Ext.pluck(arrs, i)); }else{ for (j = 0, aLen = arrs.length; j < aLen; j++){ ret[i].push( arrs[j][i] ); } } } return ret; }, /** * 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 {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 */ toSentence: function(items, connector) { var length = items.length, head, tail; if (length <= 1) { return items[0]; } else { head = items.slice(0, length - 1); tail = items[length - 1]; return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail); } }, /** * @property {Boolean} useShims * By default, Ext intelligently decides whether floating elements should be shimmed. * If you are using flash, you may want to set this to true. */ useShims: isIE6 }); }()); /** * 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) { Ext.require('Ext.app.Application'); Ext.onReady(function() { new Ext.app.Application(config); }); };