3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
17 * Modified version of Douglas Crockford's JSON.js that doesn't
18 * mess with the Object prototype
19 * http://www.json.org/js.html
22 Ext.JSON = new(function() {
23 var useHasOwn = !! {}.hasOwnProperty,
24 isNative = function() {
28 if (useNative === null) {
29 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
36 return n < 10 ? "0" + n : n;
38 doDecode = function(json) {
39 return eval("(" + json + ')');
41 doEncode = function(o) {
42 if (!Ext.isDefined(o) || o === null) {
44 } else if (Ext.isArray(o)) {
45 return encodeArray(o);
46 } else if (Ext.isDate(o)) {
47 return Ext.JSON.encodeDate(o);
48 } else if (Ext.isString(o)) {
49 return encodeString(o);
50 } else if (typeof o == "number") {
51 //don't use isNumber here, since finite checks happen inside isNumber
52 return isFinite(o) ? String(o) : "null";
53 } else if (Ext.isBoolean(o)) {
55 } else if (Ext.isObject(o)) {
56 return encodeObject(o);
57 } else if (typeof o === "function") {
70 '\x0b': '\\u000b' //ie doesn't handle \v
72 charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
73 encodeString = function(s) {
74 return '"' + s.replace(charToReplace, function(a) {
76 return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
79 encodeArray = function(o) {
81 // Note empty string in case there are no serializable members.
84 for (i = 0; i < len; i += 1) {
85 a.push(doEncode(o[i]), ',');
87 // Overwrite trailing comma (or empty string)
88 a[a.length - 1] = ']';
91 encodeObject = function(o) {
93 // Note empty string in case there are no serializable members.
96 if (!useHasOwn || o.hasOwnProperty(i)) {
97 a.push(doEncode(i), ":", doEncode(o[i]), ',');
100 // Overwrite trailing comma (or empty string)
101 a[a.length - 1] = '}';
106 * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
107 * <b>The returned value includes enclosing double quotation marks.</b></p>
108 * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
109 * <p>To override this:</p><pre><code>
110 Ext.JSON.encodeDate = function(d) {
111 return Ext.Date.format(d, '"Y-m-d"');
114 * @param {Date} d The Date to encode
115 * @return {String} The string literal to use in a JSON string.
117 this.encodeDate = function(o) {
118 return '"' + o.getFullYear() + "-"
119 + pad(o.getMonth() + 1) + "-"
120 + pad(o.getDate()) + "T"
121 + pad(o.getHours()) + ":"
122 + pad(o.getMinutes()) + ":"
123 + pad(o.getSeconds()) + '"';
127 * Encodes an Object, Array or other value
128 * @param {Object} o The variable to encode
129 * @return {String} The JSON string
131 this.encode = function() {
135 // setup encoding function on first access
136 ec = isNative() ? JSON.stringify : doEncode;
144 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
145 * @param {String} json The JSON string
146 * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
147 * @return {Object} The resulting object
149 this.decode = function() {
151 return function(json, safe) {
153 // setup decoding function on first access
154 dc = isNative() ? JSON.parse : doDecode;
163 sourceClass: "Ext.JSON",
164 sourceMethod: "decode",
165 msg: "You're trying to decode an invalid JSON String: " + json
173 * Shorthand for {@link Ext.JSON#encode}
176 * @alias Ext.JSON#encode
178 Ext.encode = Ext.JSON.encode;
180 * Shorthand for {@link Ext.JSON#decode}
183 * @alias Ext.JSON#decode
185 Ext.decode = Ext.JSON.decode;
191 The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
192 Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
193 as direct properties of the Ext namespace.
195 Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
196 For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
198 Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
199 This ensures all scripts have been loaded, preventing dependency issues. For example
201 Ext.onReady(function(){
203 renderTo: document.body,
208 For more information about how to use the Ext classes, see
210 - <a href="http://www.sencha.com/learn/">The Learning Center</a>
211 - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
212 - <a href="http://www.sencha.com/forum/">The forums</a>
218 userAgent: navigator.userAgent.toLowerCase(),
221 windowId: 'ext-window',
222 documentId: 'ext-document',
225 * True when the document is fully initialized and ready for action
231 * True to automatically uncache orphaned Ext.Elements periodically
234 enableGarbageCollector: true,
237 * True to automatically purge event listeners during garbageCollection.
240 enableListenerCollection: true,
243 * Generates unique ids. If the element already has an id, it is unchanged
244 * @param {HTMLElement/Ext.Element} el (optional) The element to generate an id for
245 * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
246 * @return {String} The generated Id.
248 id: function(el, prefix) {
251 el = Ext.getDom(el, true) || {};
252 if (el === document) {
253 el.id = me.documentId;
255 else if (el === window) {
259 if (me.isSandboxed) {
260 if (!me.uniqueGlobalNamespace) {
261 me.getUniqueGlobalNamespace();
263 sandboxPrefix = me.uniqueGlobalNamespace + '-';
265 el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
271 * Returns the current document body as an {@link Ext.Element}.
272 * @return Ext.Element The document body
274 getBody: function() {
275 return Ext.get(document.body || false);
279 * Returns the current document head as an {@link Ext.Element}.
280 * @return Ext.Element The document head
283 getHead: function() {
287 if (head == undefined) {
288 head = Ext.get(document.getElementsByTagName("head")[0]);
296 * Returns the current HTML document object as an {@link Ext.Element}.
297 * @return Ext.Element The document
300 return Ext.get(document);
304 * This is shorthand reference to {@link Ext.ComponentManager#get}.
305 * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
306 * @param {String} id The component {@link Ext.Component#id id}
307 * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
310 getCmp: function(id) {
311 return Ext.ComponentManager.get(id);
315 * Returns the current orientation of the mobile device
316 * @return {String} Either 'portrait' or 'landscape'
318 getOrientation: function() {
319 return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
323 * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
324 * DOM (if applicable) and calling their destroy functions (if available). This method is primarily
325 * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
326 * {@link Ext.util.Observable} can be passed in. Any number of elements and/or components can be
327 * passed into this function in a single call as separate arguments.
328 * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} arg1
329 * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
331 destroy: function() {
332 var ln = arguments.length,
335 for (i = 0; i < ln; i++) {
338 if (Ext.isArray(arg)) {
339 this.destroy.apply(this, arg);
341 else if (Ext.isFunction(arg.destroy)) {
352 * Execute a callback function in a particular scope. If no function is passed the call is ignored.
354 * For example, these lines are equivalent:
356 * Ext.callback(myFunc, this, [arg1, arg2]);
357 * Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
359 * @param {Function} callback The callback to execute
360 * @param {Object} scope (optional) The scope to execute in
361 * @param {Array} args (optional) The arguments to pass to the function
362 * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
364 callback: function(callback, scope, args, delay){
365 if(Ext.isFunction(callback)){
367 scope = scope || window;
369 Ext.defer(callback, delay, scope, args);
371 callback.apply(scope, args);
377 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
378 * @param {String} value The string to encode
379 * @return {String} The encoded text
381 htmlEncode : function(value) {
382 return Ext.String.htmlEncode(value);
386 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
387 * @param {String} value The string to decode
388 * @return {String} The decoded text
390 htmlDecode : function(value) {
391 return Ext.String.htmlDecode(value);
395 * Appends content to the query string of a URL, handling logic for whether to place
396 * a question mark or ampersand.
397 * @param {String} url The URL to append to.
398 * @param {String} s The content to append to the URL.
399 * @return (String) The resulting URL
401 urlAppend : function(url, s) {
402 if (!Ext.isEmpty(s)) {
403 return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
410 Ext.ns = Ext.namespace;
413 window.undefined = window.undefined;
417 * Ext core utilities and functions.
422 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
423 FF 4.0.1 - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
424 FF 5.0 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
426 IE6 - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
427 IE7 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
428 IE8 - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
429 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)
431 Chrome 11 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
433 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
435 Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
437 var check = function(regex){
438 return regex.test(Ext.userAgent);
440 isStrict = document.compatMode == "CSS1Compat",
441 version = function (is, regex) {
443 return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
445 docMode = document.documentMode,
446 isOpera = check(/opera/),
447 isOpera10_5 = isOpera && check(/version\/10\.5/),
448 isChrome = check(/\bchrome\b/),
449 isWebKit = check(/webkit/),
450 isSafari = !isChrome && check(/safari/),
451 isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
452 isSafari3 = isSafari && check(/version\/3/),
453 isSafari4 = isSafari && check(/version\/4/),
454 isSafari5 = isSafari && check(/version\/5/),
455 isIE = !isOpera && check(/msie/),
456 isIE7 = isIE && (check(/msie 7/) || docMode == 7),
457 isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
458 isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
459 isIE6 = isIE && check(/msie 6/),
460 isGecko = !isWebKit && check(/gecko/),
461 isGecko3 = isGecko && check(/rv:1\.9/),
462 isGecko4 = isGecko && check(/rv:2\.0/),
463 isGecko5 = isGecko && check(/rv:5\./),
464 isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
465 isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
466 isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
467 isWindows = check(/windows|win32/),
468 isMac = check(/macintosh|mac os x/),
469 isLinux = check(/linux/),
470 scrollbarSize = null,
471 chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
472 firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
473 ieVersion = version(isIE, /msie (\d+\.\d+)/),
474 operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
475 safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
476 webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
477 isSecure = /^https/i.test(window.location.protocol);
479 // remove css image flicker
481 document.execCommand("BackgroundImageCache", false, true);
485 function dumpObject (object) {
486 var member, members = [];
488 // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
489 // ...and the data could be prettier!
490 Ext.Object.each(object, function (name, value) {
491 if (typeof(value) === "function") {
495 if (!Ext.isDefined(value) || value === null ||
497 Ext.isString(value) || (typeof(value) == "number") ||
498 Ext.isBoolean(value)) {
499 member = Ext.encode(value);
500 } else if (Ext.isArray(value)) {
502 } else if (Ext.isObject(value)) {
505 member = 'undefined';
507 members.push(Ext.encode(name) + ': ' + member);
510 if (members.length) {
511 return ' \nData: {\n ' + members.join(',\n ') + '\n}';
516 function log (message) {
518 con = Ext.global.console,
520 indent = log.indent || 0,
525 if (!Ext.isString(message)) {
527 message = options.msg || '';
528 level = options.level || level;
530 stack = options.stack;
532 if (options.indent) {
534 } else if (options.outdent) {
535 log.indent = indent = Math.max(indent - 1, 0);
538 if (dump && !(con && con.dir)) {
539 message += dumpObject(dump);
544 if (arguments.length > 1) {
545 message += Array.prototype.slice.call(arguments, 1).join('');
548 message = indent ? Ext.String.repeat(' ', indent) + message : message;
549 // w/o console, all messages are equal, so munge the level into the message:
550 if (level != 'log') {
551 message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
554 // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
555 // an early test may fail either direction if Firebug is toggled.
557 if (con) { // if (Firebug-like console)
568 if (stack && con.trace) {
569 // Firebug's console.error() includes a trace already...
570 if (!con.firebug || level != 'error') {
576 opera.postError(message);
581 if (out.length >= max) {
582 // this formula allows out.max to change (via debugger), where the
583 // more obvious "max/4" would not quite be the same
584 Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
591 // Mostly informational, but the Ext.Error notifier uses them:
593 ++log.counters[level];
597 log.counters = { error: 0, warn: 0, info: 0, log: 0 };
600 log.show = function () {
601 window.open('','extlog').document.write([
602 '<html><head><script type="text/javascript">',
603 'var lastCount = 0;',
604 'function update () {',
605 'var ext = window.opener.Ext,',
606 'extlog = ext && ext.log;',
607 'if (extlog && extlog.out && lastCount != extlog.count) {',
608 'lastCount = extlog.count;',
609 'var s = "<tt>" + extlog.out.join("<br>").replace(/[ ]/g, " ") + "</tt>";',
610 'document.body.innerHTML = s;',
612 'setTimeout(update, 1000);',
614 'setTimeout(update, 1000);',
615 '</script></head><body></body></html>'].join(''));
619 Ext.setVersion('extjs', '4.0.7');
622 * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
623 * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
626 SSL_SECURE_URL : isSecure && isIE ? 'javascript:""' : 'about:blank',
629 * True if the {@link Ext.fx.Anim} Class is available
635 * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
636 * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
637 * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
640 scopeResetCSS : Ext.buildSettings.scopeResetCSS,
643 * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
644 * Currently not optimized for performance.
647 enableNestedListenerRemoval : false,
650 * Indicates whether to use native browser parsing for JSON methods.
651 * This option is ignored if the browser does not support native JSON methods.
652 * <b>Note: Native JSON methods will not work with objects that have functions.
653 * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
656 USE_NATIVE_JSON : false,
659 * Return the dom node for the passed String (id), dom node, or Ext.Element.
660 * Optional 'strict' flag is needed for IE since it can return 'name' and
661 * 'id' elements by using getElementById.
662 * Here are some examples:
664 // gets dom node based on id
665 var elDom = Ext.getDom('elId');
666 // gets dom node based on the dom node
667 var elDom1 = Ext.getDom(elDom);
669 // If we don't know if we are working with an
670 // Ext.Element or a dom node use Ext.getDom
672 var dom = Ext.getDom(el);
673 // do something with the dom node
676 * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
677 * when this method is called to be successful.
678 * @param {String/HTMLElement/Ext.Element} el
679 * @return HTMLElement
681 getDom : function(el, strict) {
682 if (!el || !document) {
688 if (typeof el == 'string') {
689 var e = document.getElementById(el);
690 // IE returns elements with the 'name' and 'id' attribute.
691 // we do a strict check to return the element with only the id attribute
692 if (e && isIE && strict) {
693 if (el == e.getAttribute('id')) {
707 * Removes a DOM node from the document.
708 * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
709 * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
710 * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
711 * will be ignored if passed in.</p>
712 * @param {HTMLElement} node The node to remove
715 removeNode : isIE6 || isIE7 ? function() {
718 if(n && n.tagName != 'BODY'){
719 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
720 d = d || document.createElement('div');
723 delete Ext.cache[n.id];
727 if (n && n.parentNode && n.tagName != 'BODY') {
728 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
729 n.parentNode.removeChild(n);
730 delete Ext.cache[n.id];
736 isIEQuirks: isIE && !isStrict,
739 * True if the detected browser is Opera.
745 * True if the detected browser is Opera 10.5x.
748 isOpera10_5 : isOpera10_5,
751 * True if the detected browser uses WebKit.
757 * True if the detected browser is Chrome.
763 * True if the detected browser is Safari.
769 * True if the detected browser is Safari 3.x.
772 isSafari3 : isSafari3,
775 * True if the detected browser is Safari 4.x.
778 isSafari4 : isSafari4,
781 * True if the detected browser is Safari 5.x.
784 isSafari5 : isSafari5,
787 * True if the detected browser is Safari 2.x.
790 isSafari2 : isSafari2,
793 * True if the detected browser is Internet Explorer.
799 * True if the detected browser is Internet Explorer 6.x.
805 * True if the detected browser is Internet Explorer 7.x.
811 * True if the detected browser is Internet Explorer 8.x.
817 * True if the detected browser is Internet Explorer 9.x.
823 * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
829 * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
835 * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
841 * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
847 * True if the detected browser uses FireFox 3.0
853 * True if the detected browser uses FireFox 3.5
859 * True if the detected browser uses FireFox 3.6
865 * True if the detected browser uses FireFox 4
868 isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
871 * True if the detected browser uses FireFox 5
874 isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
877 * True if the detected platform is Linux.
883 * True if the detected platform is Windows.
886 isWindows : isWindows,
889 * True if the detected platform is Mac OS.
895 * The current version of Chrome (0 if the browser is not Chrome).
898 chromeVersion: chromeVersion,
901 * The current version of Firefox (0 if the browser is not Firefox).
904 firefoxVersion: firefoxVersion,
907 * The current version of IE (0 if the browser is not IE). This does not account
908 * for the documentMode of the current page, which is factored into {@link #isIE7},
909 * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
911 * Ext.isIE8 == (Ext.ieVersion == 8)
916 ieVersion: ieVersion,
919 * The current version of Opera (0 if the browser is not Opera).
922 operaVersion: operaVersion,
925 * The current version of Safari (0 if the browser is not Safari).
928 safariVersion: safariVersion,
931 * The current version of WebKit (0 if the browser does not use WebKit).
934 webKitVersion: webKitVersion,
937 * True if the page is running over SSL
943 * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
944 * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
945 * For other browsers it uses an inline data URL.
948 BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
951 * <p>Utility method for returning a default value if the passed value is empty.</p>
952 * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
955 * <li>an empty array</li>
956 * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
958 * @param {Object} value The value to test
959 * @param {Object} defaultValue The value to return if the original value is empty
960 * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
961 * @return {Object} value, if non-empty, else defaultValue
962 * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
964 value : function(v, defaultValue, allowBlank){
965 return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
969 * Escapes the passed string for use in a regular expression
970 * @param {String} str
972 * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
974 escapeRe : function(s) {
975 return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
979 * Applies event listeners to elements by selectors when the document is ready.
980 * The event name is specified with an <tt>@</tt> suffix.
983 // add a listener for click on all anchors in element with id foo
984 '#foo a@click' : function(e, t){
988 // add the same listener to multiple selectors (separated by comma BEFORE the @)
989 '#foo a, #bar span.some-class@mouseover' : function(){
994 * @param {Object} obj The list of behaviors to apply
996 addBehaviors : function(o){
998 Ext.onReady(function(){
1002 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
1007 if ((parts = b.split('@'))[1]) { // for Object prototype breakers
1010 cache[s] = Ext.select(s);
1012 cache[s].on(parts[1], o[b]);
1020 * Returns the size of the browser scrollbars. This can differ depending on
1021 * operating system settings, such as the theme or font size.
1022 * @param {Boolean} force (optional) true to force a recalculation of the value.
1023 * @return {Object} An object containing the width of a vertical scrollbar and the
1024 * height of a horizontal scrollbar.
1026 getScrollbarSize: function (force) {
1031 if(force === true || scrollbarSize === null){
1033 // When IE9 positions an element offscreen via offsets, the offsetWidth is
1034 // inaccurately reported. For IE9 only, we render on screen before removing.
1035 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets',
1036 // Append our div, do our calculation and then remove it
1037 div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
1038 child = div.child('div', true),
1039 w1 = child.offsetWidth;
1041 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
1043 var w2 = child.offsetWidth, width = w1 - w2;
1046 // We assume width == height for now. TODO: is this always true?
1047 scrollbarSize = { width: width, height: width };
1050 return scrollbarSize;
1054 * Utility method for getting the width of the browser's vertical scrollbar. This
1055 * can differ depending on operating system settings, such as the theme or font size.
1057 * This method is deprected in favor of {@link #getScrollbarSize}.
1059 * @param {Boolean} force (optional) true to force a recalculation of the value.
1060 * @return {Number} The width of a vertical scrollbar.
1063 getScrollBarWidth: function(force){
1064 var size = Ext.getScrollbarSize(force);
1065 return size.width + 2; // legacy fudge factor
1069 * Copies a set of named properties fom the source object to the destination object.
1073 * ImageComponent = Ext.extend(Ext.Component, {
1074 * initComponent: function() {
1075 * this.autoEl = { tag: 'img' };
1076 * MyComponent.superclass.initComponent.apply(this, arguments);
1077 * this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
1081 * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
1083 * @param {Object} dest The destination object.
1084 * @param {Object} source The source object.
1085 * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
1086 * of property names to copy.
1087 * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
1088 * @return {Object} The modified object.
1090 copyTo : function(dest, source, names, usePrototypeKeys){
1091 if(typeof names == 'string'){
1092 names = names.split(/[,;\s]/);
1094 Ext.each(names, function(name){
1095 if(usePrototypeKeys || source.hasOwnProperty(name)){
1096 dest[name] = source[name];
1103 * Attempts to destroy and then remove a set of named properties of the passed object.
1104 * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
1105 * @param {String...} args One or more names of the properties to destroy and remove from the object.
1107 destroyMembers : function(o){
1108 for (var i = 1, a = arguments, len = a.length; i < len; i++) {
1109 Ext.destroy(o[a[i]]);
1115 * Logs a message. If a console is present it will be used. On Opera, the method
1116 * "opera.postError" is called. In other cases, the message is logged to an array
1117 * "Ext.log.out". An attached debugger can watch this array and view the log. The
1118 * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
1119 * The `Ext.log.out` array can also be written to a popup window by entering the
1120 * following in the URL bar (a "bookmarklet"):
1122 * javascript:void(Ext.log.show());
1124 * If additional parameters are passed, they are joined and appended to the message.
1125 * A technique for tracing entry and exit of a function is this:
1128 * Ext.log({ indent: 1 }, '>> foo');
1130 * // log statements in here or methods called from here will be indented
1133 * Ext.log({ outdent: 1 }, '<< foo');
1136 * This method does nothing in a release build.
1138 * @param {String/Object} message The message to log or an options object with any
1139 * of the following properties:
1141 * - `msg`: The message to log (required).
1142 * - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
1143 * - `dump`: An object to dump to the log as part of the message.
1144 * - `stack`: True to include a stack trace in the log.
1145 * - `indent`: Cause subsequent log statements to be indented one step.
1146 * - `outdent`: Cause this and following statements to be one step less indented.
1156 * Partitions the set into two sets: a true set and a false set.
1161 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
1167 return val.className == "class1"
1170 // true are those paragraph elements with a className of "class1",
1171 // false set are those that do not have that className.
1173 * @param {Array/NodeList} arr The array to partition
1174 * @param {Function} truth (optional) a function to determine truth. If this is omitted the element
1175 * itself must be able to be evaluated for its truthfulness.
1176 * @return {Array} [array of truish values, array of falsy values]
1177 * @deprecated 4.0.0 Will be removed in the next major version
1179 partition : function(arr, truth){
1181 Ext.each(arr, function(v, i, a) {
1182 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
1188 * Invokes a method on each item in an Array.
1191 Ext.invoke(Ext.query("p"), "getAttribute", "id");
1192 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
1194 * @param {Array/NodeList} arr The Array of items to invoke the method on.
1195 * @param {String} methodName The method name to invoke.
1196 * @param {Object...} args Arguments to send into the method invocation.
1197 * @return {Array} The results of invoking the method on each item in the array.
1198 * @deprecated 4.0.0 Will be removed in the next major version
1200 invoke : function(arr, methodName){
1202 args = Array.prototype.slice.call(arguments, 2);
1203 Ext.each(arr, function(v,i) {
1204 if (v && typeof v[methodName] == 'function') {
1205 ret.push(v[methodName].apply(v, args));
1207 ret.push(undefined);
1214 * <p>Zips N sets together.</p>
1217 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
1224 return "$" + a + "" + b + "." + c
1226 ); // ["$+12.43", "$-10.15", "$+22.96"]
1228 * @param {Array/NodeList...} arr This argument may be repeated. Array(s) to contribute values.
1229 * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
1230 * @return {Array} The zipped set.
1231 * @deprecated 4.0.0 Will be removed in the next major version
1234 var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
1237 len = Ext.max(Ext.pluck(arrs, "length")),
1240 for (var i = 0; i < len; i++) {
1243 ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
1245 for (var j = 0, aLen = arrs.length; j < aLen; j++){
1246 ret[i].push( arrs[j][i] );
1254 * Turns an array into a sentence, joined by a specified connector - e.g.:
1255 * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
1256 * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
1257 * @param {String[]} items The array to create a sentence from
1258 * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
1259 * @return {String} The sentence string
1260 * @deprecated 4.0.0 Will be removed in the next major version
1262 toSentence: function(items, connector) {
1263 var length = items.length;
1268 var head = items.slice(0, length - 1),
1269 tail = items[length - 1];
1271 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
1276 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
1277 * you may want to set this to true.
1285 * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
1287 * See Ext.app.Application for details.
1289 * @param {Object} config
1291 Ext.application = function(config) {
1292 Ext.require('Ext.app.Application');
1294 Ext.onReady(function() {
1295 Ext.create('Ext.app.Application', config);
1300 * @class Ext.util.Format
1302 This class is a centralized place for formatting functions. It includes
1303 functions to format various different types of data, such as text, dates and numeric values.
1306 This class contains several options for localization. These can be set once the library has loaded,
1307 all calls to the functions from that point will use the locale settings that were specified.
1314 This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
1316 __Using with renderers__
1317 There are two helper functions that return a new function that can be used in conjunction with
1322 renderer: Ext.util.Format.dateRenderer('Y-m-d')
1325 renderer: Ext.util.Format.numberRenderer('0.000')
1328 Functions that only take a single argument can also be passed directly:
1331 renderer: Ext.util.Format.usMoney
1333 dataIndex: 'productCode',
1334 renderer: Ext.util.Format.uppercase
1337 __Using with XTemplates__
1338 XTemplates can also directly use Ext.util.Format functions:
1341 'Date: {startDate:date("Y-m-d")}',
1342 'Cost: {cost:usMoney}'
1351 Ext.util.Format = {};
1352 var UtilFormat = Ext.util.Format,
1353 stripTagsRE = /<\/?[^>]+>/gi,
1354 stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
1357 // A RegExp to remove from a number format string, all characters except digits and '.'
1358 formatCleanRe = /[^\d\.]/g,
1360 // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
1361 // Created on first use. The local decimal separator character must be initialized for this to be created.
1364 Ext.apply(UtilFormat, {
1366 * @property {String} thousandSeparator
1367 * <p>The character that the {@link #number} function uses as a thousand separator.</p>
1368 * <p>This may be overridden in a locale file.</p>
1370 thousandSeparator: ',',
1373 * @property {String} decimalSeparator
1374 * <p>The character that the {@link #number} function uses as a decimal point.</p>
1375 * <p>This may be overridden in a locale file.</p>
1377 decimalSeparator: '.',
1380 * @property {Number} currencyPrecision
1381 * <p>The number of decimal places that the {@link #currency} function displays.</p>
1382 * <p>This may be overridden in a locale file.</p>
1384 currencyPrecision: 2,
1387 * @property {String} currencySign
1388 * <p>The currency sign that the {@link #currency} function displays.</p>
1389 * <p>This may be overridden in a locale file.</p>
1394 * @property {Boolean} currencyAtEnd
1395 * <p>This may be set to <code>true</code> to make the {@link #currency} function
1396 * append the currency sign to the formatted value.</p>
1397 * <p>This may be overridden in a locale file.</p>
1399 currencyAtEnd: false,
1402 * Checks a reference and converts it to empty string if it is undefined
1403 * @param {Object} value Reference to check
1404 * @return {Object} Empty string if converted, otherwise the original value
1406 undef : function(value) {
1407 return value !== undefined ? value : "";
1411 * Checks a reference and converts it to the default value if it's empty
1412 * @param {Object} value Reference to check
1413 * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
1416 defaultValue : function(value, defaultValue) {
1417 return value !== undefined && value !== '' ? value : defaultValue;
1421 * Returns a substring from within an original string
1422 * @param {String} value The original text
1423 * @param {Number} start The start index of the substring
1424 * @param {Number} length The length of the substring
1425 * @return {String} The substring
1427 substr : function(value, start, length) {
1428 return String(value).substr(start, length);
1432 * Converts a string to all lower case letters
1433 * @param {String} value The text to convert
1434 * @return {String} The converted text
1436 lowercase : function(value) {
1437 return String(value).toLowerCase();
1441 * Converts a string to all upper case letters
1442 * @param {String} value The text to convert
1443 * @return {String} The converted text
1445 uppercase : function(value) {
1446 return String(value).toUpperCase();
1450 * Format a number as US currency
1451 * @param {Number/String} value The numeric value to format
1452 * @return {String} The formatted currency string
1454 usMoney : function(v) {
1455 return UtilFormat.currency(v, '$', 2);
1459 * Format a number as a currency
1460 * @param {Number/String} value The numeric value to format
1461 * @param {String} sign The currency sign to use (defaults to {@link #currencySign})
1462 * @param {Number} decimals The number of decimals to use for the currency (defaults to {@link #currencyPrecision})
1463 * @param {Boolean} end True if the currency sign should be at the end of the string (defaults to {@link #currencyAtEnd})
1464 * @return {String} The formatted currency string
1466 currency: function(v, currencySign, decimals, end) {
1467 var negativeSign = '',
1475 decimals = decimals || UtilFormat.currencyPrecision;
1476 format += format + (decimals > 0 ? '.' : '');
1477 for (; i < decimals; i++) {
1480 v = UtilFormat.number(v, format);
1481 if ((end || UtilFormat.currencyAtEnd) === true) {
1482 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
1484 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
1489 * Formats the passed date using the specified format pattern.
1490 * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date by the Javascript
1491 * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method.
1492 * @param {String} format (Optional) Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
1493 * @return {String} The formatted date string.
1495 date: function(v, format) {
1499 if (!Ext.isDate(v)) {
1500 v = new Date(Date.parse(v));
1502 return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
1506 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
1507 * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
1508 * @return {Function} The date formatting function
1510 dateRenderer : function(format) {
1511 return function(v) {
1512 return UtilFormat.date(v, format);
1517 * Strips all HTML tags
1518 * @param {Object} value The text from which to strip tags
1519 * @return {String} The stripped text
1521 stripTags : function(v) {
1522 return !v ? v : String(v).replace(stripTagsRE, "");
1526 * Strips all script tags
1527 * @param {Object} value The text from which to strip script tags
1528 * @return {String} The stripped text
1530 stripScripts : function(v) {
1531 return !v ? v : String(v).replace(stripScriptsRe, "");
1535 * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
1536 * @param {Number/String} size The numeric value to format
1537 * @return {String} The formatted file size
1539 fileSize : function(size) {
1541 return size + " bytes";
1542 } else if (size < 1048576) {
1543 return (Math.round(((size*10) / 1024))/10) + " KB";
1545 return (Math.round(((size*10) / 1048576))/10) + " MB";
1550 * It does simple math for use in a template, for example:<pre><code>
1551 * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
1553 * @return {Function} A function that operates on the passed value.
1559 return function(v, a){
1561 fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
1568 * Rounds the passed number to the required decimal precision.
1569 * @param {Number/String} value The numeric value to round.
1570 * @param {Number} precision The number of decimal places to which to round the first parameter's value.
1571 * @return {Number} The rounded value.
1573 round : function(value, precision) {
1574 var result = Number(value);
1575 if (typeof precision == 'number') {
1576 precision = Math.pow(10, precision);
1577 result = Math.round(value * precision) / precision;
1583 * <p>Formats the passed number according to the passed format string.</p>
1584 * <p>The number of digits after the decimal separator character specifies the number of
1585 * decimal places in the resulting string. The <u>local-specific</u> decimal character is used in the result.</p>
1586 * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
1587 * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
1588 * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
1589 * <p><b>New to Ext JS 4</b></p>
1590 * <p>Locale-specific characters are always used in the formatted output when inserting
1591 * thousand and decimal separators.</p>
1592 * <p>The format string must specify separator characters according to US/UK conventions ("," as the
1593 * thousand separator, and "." as the decimal separator)</p>
1594 * <p>To allow specification of format strings according to local conventions for separator characters, add
1595 * the string <code>/i</code> to the end of the format string.</p>
1596 * <div style="margin-left:40px">examples (123456.789):
1597 * <div style="margin-left:10px">
1598 * 0 - (123456) show only digits, no precision<br>
1599 * 0.00 - (123456.78) show only digits, 2 precision<br>
1600 * 0.0000 - (123456.7890) show only digits, 4 precision<br>
1601 * 0,000 - (123,456) show comma and digits, no precision<br>
1602 * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
1603 * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
1604 * To allow specification of the formatting string using UK/US grouping characters (,) and decimal (.) for international numbers, add /i to the end.
1605 * For example: 0.000,00/i
1607 * @param {Number} v The number to format.
1608 * @param {String} format The way you would like to format this text.
1609 * @return {String} The formatted number.
1611 number: function(v, formatString) {
1612 if (!formatString) {
1615 v = Ext.Number.from(v, NaN);
1619 var comma = UtilFormat.thousandSeparator,
1620 dec = UtilFormat.decimalSeparator,
1628 // The "/i" suffix allows caller to use a locale-specific formatting string.
1629 // Clean the format string by removing all but numerals and the decimal separator.
1630 // Then split the format string into pre and post decimal segments according to *what* the
1631 // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
1632 if (formatString.substr(formatString.length - 2) == '/i') {
1633 if (!I18NFormatCleanRe) {
1634 I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
1636 formatString = formatString.substr(0, formatString.length - 2);
1638 hasComma = formatString.indexOf(comma) != -1;
1639 psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
1641 hasComma = formatString.indexOf(',') != -1;
1642 psplit = formatString.replace(formatCleanRe, '').split('.');
1645 if (1 < psplit.length) {
1646 v = v.toFixed(psplit[1].length);
1647 } else if(2 < psplit.length) {
1650 sourceClass: "Ext.util.Format",
1651 sourceMethod: "number",
1653 formatString: formatString,
1654 msg: "Invalid number format, should have no more than 1 decimal"
1661 var fnum = v.toString();
1663 psplit = fnum.split('.');
1666 var cnum = psplit[0],
1669 m = Math.floor(j / 3),
1670 n = cnum.length % 3 || 3,
1673 for (i = 0; i < j; i += n) {
1678 parr[parr.length] = cnum.substr(i, n);
1681 fnum = parr.join(comma);
1683 fnum += dec + psplit[1];
1687 fnum = psplit[0] + dec + psplit[1];
1693 * Edge case. If we have a very small negative number it will get rounded to 0,
1694 * however the initial check at the top will still report as negative. Replace
1695 * everything but 1-9 and check if the string is empty to determine a 0 value.
1697 neg = fnum.replace(/[^1-9]/g, '') !== '';
1700 return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
1704 * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
1705 * @param {String} format Any valid number format string for {@link #number}
1706 * @return {Function} The number formatting function
1708 numberRenderer : function(format) {
1709 return function(v) {
1710 return UtilFormat.number(v, format);
1715 * Selectively do a plural form of a word based on a numeric value. For example, in a template,
1716 * {commentCount:plural("Comment")} would result in "1 Comment" if commentCount was 1 or would be "x Comments"
1717 * if the value is 0 or greater than 1.
1718 * @param {Number} value The value to compare against
1719 * @param {String} singular The singular form of the word
1720 * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
1722 plural : function(v, s, p) {
1723 return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
1727 * Converts newline characters to the HTML tag <br/>
1728 * @param {String} The string value to format.
1729 * @return {String} The string with embedded <br/> tags in place of newlines.
1731 nl2br : function(v) {
1732 return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
1736 * Alias for {@link Ext.String#capitalize}.
1738 * @alias Ext.String#capitalize
1740 capitalize: Ext.String.capitalize,
1743 * Alias for {@link Ext.String#ellipsis}.
1745 * @alias Ext.String#ellipsis
1747 ellipsis: Ext.String.ellipsis,
1750 * Alias for {@link Ext.String#format}.
1752 * @alias Ext.String#format
1754 format: Ext.String.format,
1757 * Alias for {@link Ext.String#htmlDecode}.
1759 * @alias Ext.String#htmlDecode
1761 htmlDecode: Ext.String.htmlDecode,
1764 * Alias for {@link Ext.String#htmlEncode}.
1766 * @alias Ext.String#htmlEncode
1768 htmlEncode: Ext.String.htmlEncode,
1771 * Alias for {@link Ext.String#leftPad}.
1773 * @alias Ext.String#leftPad
1775 leftPad: Ext.String.leftPad,
1778 * Alias for {@link Ext.String#trim}.
1780 * @alias Ext.String#trim
1782 trim : Ext.String.trim,
1785 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
1786 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
1787 * @param {Number/String} v The encoded margins
1788 * @return {Object} An object with margin sizes for top, right, bottom and left
1790 parseBox : function(box) {
1791 if (Ext.isNumber(box)) {
1792 box = box.toString();
1794 var parts = box.split(' '),
1798 parts[1] = parts[2] = parts[3] = parts[0];
1801 parts[2] = parts[0];
1802 parts[3] = parts[1];
1805 parts[3] = parts[1];
1809 top :parseInt(parts[0], 10) || 0,
1810 right :parseInt(parts[1], 10) || 0,
1811 bottom:parseInt(parts[2], 10) || 0,
1812 left :parseInt(parts[3], 10) || 0
1817 * Escapes the passed string for use in a regular expression
1818 * @param {String} str
1821 escapeRegex : function(s) {
1822 return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
1828 * @class Ext.util.TaskRunner
1829 * Provides the ability to execute one or more arbitrary tasks in a multithreaded
1830 * manner. Generally, you can use the singleton {@link Ext.TaskManager} instead, but
1831 * if needed, you can create separate instances of TaskRunner. Any number of
1832 * separate tasks can be started at any time and will run independently of each
1833 * other. Example usage:
1835 // Start a simple clock task that updates a div once per second
1836 var updateClock = function(){
1837 Ext.fly('clock').update(new Date().format('g:i:s A'));
1841 interval: 1000 //1 second
1843 var runner = new Ext.util.TaskRunner();
1846 // equivalent using TaskManager
1847 Ext.TaskManager.start({
1853 * <p>See the {@link #start} method for details about how to configure a task object.</p>
1854 * Also see {@link Ext.util.DelayedTask}.
1857 * @param {Number} [interval=10] The minimum precision in milliseconds supported by this TaskRunner instance
1861 Ext.util.TaskRunner = function(interval) {
1862 interval = interval || 10;
1869 stopThread = function() {
1876 startThread = function() {
1879 id = setInterval(runTasks, interval);
1884 removeTask = function(t) {
1885 removeQueue.push(t);
1887 t.onStop.apply(t.scope || t);
1892 runTasks = function() {
1893 var rqLen = removeQueue.length,
1894 now = new Date().getTime(),
1898 for (i = 0; i < rqLen; i++) {
1899 Ext.Array.remove(tasks, removeQueue[i]);
1902 if (tasks.length < 1) {
1912 for (; i < len; ++i) {
1914 itime = now - t.taskRunTime;
1915 if (t.interval <= itime) {
1916 rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
1917 t.taskRunTime = now;
1918 if (rt === false || t.taskRunCount === t.repeat) {
1923 if (t.duration && t.duration <= (now - t.taskStartTime)) {
1930 * Starts a new task.
1932 * @param {Object} task <p>A config object that supports the following properties:<ul>
1933 * <li><code>run</code> : Function<div class="sub-desc"><p>The function to execute each time the task is invoked. The
1934 * function will be called at each interval and passed the <code>args</code> argument if specified, and the
1935 * current invocation count if not.</p>
1936 * <p>If a particular scope (<code>this</code> reference) is required, be sure to specify it using the <code>scope</code> argument.</p>
1937 * <p>Return <code>false</code> from this function to terminate the task.</p></div></li>
1938 * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
1939 * should be invoked.</div></li>
1940 * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
1941 * specified by <code>run</code>. If not specified, the current invocation count is passed.</div></li>
1942 * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
1943 * <code>run</code> function. Defaults to the task config object.</div></li>
1944 * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to invoke
1945 * the task before stopping automatically (defaults to indefinite).</div></li>
1946 * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to invoke the task before
1947 * stopping automatically (defaults to indefinite).</div></li>
1949 * <p>Before each invocation, Ext injects the property <code>taskRunCount</code> into the task object so
1950 * that calculations based on the repeat count can be performed.</p>
1951 * @return {Object} The task
1953 this.start = function(task) {
1955 task.taskStartTime = new Date().getTime();
1956 task.taskRunTime = 0;
1957 task.taskRunCount = 0;
1963 * Stops an existing running task.
1965 * @param {Object} task The task to stop
1966 * @return {Object} The task
1968 this.stop = function(task) {
1974 * Stops all tasks that are currently running.
1977 this.stopAll = function() {
1979 for (var i = 0, len = tasks.length; i < len; i++) {
1980 if (tasks[i].onStop) {
1990 * @class Ext.TaskManager
1991 * @extends Ext.util.TaskRunner
1992 * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks. See
1993 * {@link Ext.util.TaskRunner} for supported methods and task config properties.
1995 // Start a simple clock task that updates a div once per second
1998 Ext.fly('clock').update(new Date().format('g:i:s A'));
2000 interval: 1000 //1 second
2002 Ext.TaskManager.start(task);
2004 * <p>See the {@link #start} method for details about how to configure a task object.</p>
2007 Ext.TaskManager = Ext.create('Ext.util.TaskRunner');
2011 * Determines information about the current platform the application is running on.
2016 init : function(navigator) {
2017 var platforms = this.platforms,
2018 ln = platforms.length,
2021 navigator = navigator || window.navigator;
2023 for (i = 0; i < ln; i++) {
2024 platform = platforms[i];
2025 this[platform.identity] = platform.regex.test(navigator[platform.property]);
2029 * @property Desktop True if the browser is running on a desktop machine
2032 this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
2034 * @property Tablet True if the browser is running on a tablet (iPad)
2036 this.Tablet = this.iPad;
2038 * @property Phone True if the browser is running on a phone.
2041 this.Phone = !this.Desktop && !this.Tablet;
2043 * @property iOS True if the browser is running on iOS
2046 this.iOS = this.iPhone || this.iPad || this.iPod;
2049 * @property Standalone Detects when application has been saved to homescreen.
2052 this.Standalone = !!window.navigator.standalone;
2056 * @property iPhone True when the browser is running on a iPhone
2060 property: 'platform',
2066 * @property iPod True when the browser is running on a iPod
2070 property: 'platform',
2076 * @property iPad True when the browser is running on a iPad
2080 property: 'userAgent',
2086 * @property Blackberry True when the browser is running on a Blackberry
2090 property: 'userAgent',
2091 regex: /Blackberry/i,
2092 identity: 'Blackberry'
2096 * @property Android True when the browser is running on an Android device
2100 property: 'userAgent',
2106 * @property Mac True when the browser is running on a Mac
2110 property: 'platform',
2116 * @property Windows True when the browser is running on Windows
2120 property: 'platform',
2126 * @property Linux True when the browser is running on Linux
2130 property: 'platform',
2139 * @class Ext.supports
2141 * Determines information about features are supported in the current environment
2148 div = doc.createElement('div'),
2154 '<div style="height:30px;width:50px;">',
2155 '<div style="height:20px;width:20px;"></div>',
2157 '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
2158 '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
2160 '<div style="float:left; background-color:transparent;"></div>'
2163 doc.body.appendChild(div);
2165 for (i = 0; i < ln; i++) {
2167 this[test.identity] = test.fn.call(this, doc, div);
2170 doc.body.removeChild(div);
2174 * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
2177 CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow),
2180 * @property ClassList True if document environment supports the HTML5 classList API.
2183 ClassList: !!document.documentElement.classList,
2186 * @property OrientationChange True if the device supports orientation change
2189 OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
2192 * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
2195 DeviceMotion: ('ondevicemotion' in window),
2198 * @property Touch True if the device supports touch
2201 // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
2202 // and Safari 4.0 (they all have 'ontouchstart' in the window object).
2203 Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
2207 * @property Transitions True if the device supports CSS3 Transitions
2211 identity: 'Transitions',
2212 fn: function(doc, div) {
2220 TE = 'TransitionEnd',
2221 transitionEndName = [
2223 'transitionend', //Moz bucks the prefixing convention
2232 for (; i < ln; i++) {
2233 if (div.getStyle(prefix[i] + "TransitionProperty")) {
2234 Ext.supports.CSS3Prefix = prefix[i];
2235 Ext.supports.CSS3TransitionEnd = transitionEndName[i];
2245 * @property RightMargin True if the device supports right margin.
2246 * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
2250 identity: 'RightMargin',
2251 fn: function(doc, div) {
2252 var view = doc.defaultView;
2253 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
2258 * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
2259 * selection when their display style is changed. Essentially, if a text input
2260 * has focus and its display style is changed, the I-beam disappears.
2262 * This bug is encountered due to the work around in place for the {@link #RightMargin}
2263 * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
2264 * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
2265 * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
2268 identity: 'DisplayChangeInputSelectionBug',
2270 var webKitVersion = Ext.webKitVersion;
2271 // WebKit but older than Safari 5 or Chrome 6:
2272 return 0 < webKitVersion && webKitVersion < 533;
2277 * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
2278 * selection when their display style is changed. Essentially, if a text area has
2279 * focus and its display style is changed, the I-beam disappears.
2281 * This bug is encountered due to the work around in place for the {@link #RightMargin}
2282 * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
2283 * be fixed in Chrome 11.
2286 identity: 'DisplayChangeTextAreaSelectionBug',
2288 var webKitVersion = Ext.webKitVersion;
2293 (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
2294 AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
2296 (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
2297 AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
2302 (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
2303 AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
2306 return 0 < webKitVersion && webKitVersion < 534.24;
2311 * @property TransparentColor True if the device supports transparent color
2315 identity: 'TransparentColor',
2316 fn: function(doc, div, view) {
2317 view = doc.defaultView;
2318 return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
2323 * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
2327 identity: 'ComputedStyle',
2328 fn: function(doc, div, view) {
2329 view = doc.defaultView;
2330 return view && view.getComputedStyle;
2335 * @property SVG True if the device supports SVG
2341 return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
2346 * @property Canvas True if the device supports Canvas
2352 return !!doc.createElement('canvas').getContext;
2357 * @property VML True if the device supports VML
2363 var d = doc.createElement("div");
2364 d.innerHTML = "<!--[if vml]><br><br><![endif]-->";
2365 return (d.childNodes.length == 2);
2370 * @property Float True if the device supports CSS float
2375 fn: function(doc, div) {
2376 return !!div.lastChild.style.cssFloat;
2381 * @property AudioTag True if the device supports the HTML5 audio tag
2385 identity: 'AudioTag',
2387 return !!doc.createElement('audio').canPlayType;
2392 * @property History True if the device supports HTML5 history
2396 identity: 'History',
2398 return !!(window.history && history.pushState);
2403 * @property CSS3DTransform True if the device supports CSS3DTransform
2407 identity: 'CSS3DTransform',
2409 return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
2414 * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
2418 identity: 'CSS3LinearGradient',
2419 fn: function(doc, div) {
2420 var property = 'background-image:',
2421 webkit = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
2422 w3c = 'linear-gradient(left top, black, white)',
2423 moz = '-moz-' + w3c,
2424 options = [property + webkit, property + w3c, property + moz];
2426 div.style.cssText = options.join(';');
2428 return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
2433 * @property CSS3BorderRadius True if the device supports CSS3 border radius
2437 identity: 'CSS3BorderRadius',
2438 fn: function(doc, div) {
2439 var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
2442 for (i = 0; i < domPrefixes.length; i++) {
2443 if (document.body.style[domPrefixes[i]] !== undefined) {
2452 * @property GeoLocation True if the device supports GeoLocation
2456 identity: 'GeoLocation',
2458 return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
2462 * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
2466 identity: 'MouseEnterLeave',
2467 fn: function(doc, div){
2468 return ('onmouseenter' in div && 'onmouseleave' in div);
2472 * @property MouseWheel True if the browser supports the mousewheel event
2476 identity: 'MouseWheel',
2477 fn: function(doc, div) {
2478 return ('onmousewheel' in div);
2482 * @property Opacity True if the browser supports normal css opacity
2486 identity: 'Opacity',
2487 fn: function(doc, div){
2488 // Not a strict equal comparison in case opacity can be converted to a number.
2489 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
2492 div.firstChild.style.cssText = 'opacity:0.73';
2493 return div.firstChild.style.opacity == '0.73';
2497 * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
2501 identity: 'Placeholder',
2503 return 'placeholder' in doc.createElement('input');
2508 * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight,
2509 * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
2513 identity: 'Direct2DBug',
2515 return Ext.isString(document.body.style.msTransformOrigin);
2519 * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
2523 identity: 'BoundingClientRect',
2524 fn: function(doc, div) {
2525 return Ext.isFunction(div.getBoundingClientRect);
2529 identity: 'IncludePaddingInWidthCalculation',
2530 fn: function(doc, div){
2531 var el = Ext.get(div.childNodes[1].firstChild);
2532 return el.getWidth() == 210;
2536 identity: 'IncludePaddingInHeightCalculation',
2537 fn: function(doc, div){
2538 var el = Ext.get(div.childNodes[1].firstChild);
2539 return el.getHeight() == 210;
2544 * @property ArraySort True if the Array sort native method isn't bugged.
2548 identity: 'ArraySort',
2550 var a = [1,2,3,4,5].sort(function(){ return 0; });
2551 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
2555 * @property Range True if browser support document.createRange native method.
2561 return !!document.createRange;
2565 * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
2569 identity: 'CreateContextualFragment',
2571 var range = Ext.supports.Range ? document.createRange() : false;
2573 return range && !!range.createContextualFragment;
2578 * @property WindowOnError True if browser supports window.onerror.
2582 identity: 'WindowOnError',
2584 // sadly, we cannot feature detect this...
2585 return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+