ext-foundation-debug.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:532k
源码类别:

JavaScript

开发平台:

JavaScript

  1.     * Adds elements to this composite.
  2.     * @param {String/Array} els A string CSS selector, an array of elements or an element
  3.     * @return {CompositeElement} this
  4.     */
  5.     /**
  6.      * Returns the Element object at the specified index
  7.      * @param {Number} index
  8.      * @return {Ext.Element}
  9.      */
  10.     /**
  11.      * Iterates each <code>element</code> in this <code>composite</code>
  12.      * calling the supplied function using {@link Ext#each}.
  13.      * @param {Function} fn The function to be called with each
  14.      * <code>element</code>. If the supplied function returns <tt>false</tt>,
  15.      * iteration stops. This function is called with the following arguments:
  16.      * <div class="mdetail-params"><ul>
  17.      * <li><code>element</code> : <i>Ext.Element</i><div class="sub-desc">The element at the current <code>index</code>
  18.      * in the <code>composite</code></div></li>
  19.      * <li><code>composite</code> : <i>Object</i> <div class="sub-desc">This composite.</div></li>
  20.      * <li><code>index</code> : <i>Number</i> <div class="sub-desc">The current index within the <code>composite</code> </div></li>
  21.      * </ul></div>
  22.      * @param {Object} scope (optional) The scope (<code><this</code> reference) in which the specified function is executed.
  23.      * Defaults to the <code>element</code> at the current <code>index</code>
  24.      * within the composite.
  25.      * @return {CompositeElement} this
  26.      */
  27. });
  28. /**
  29.  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
  30.  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
  31.  * {@link Ext.CompositeElementLite CompositeElementLite} object.
  32.  * @param {String/Array} selector The CSS selector or an array of elements
  33.  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
  34.  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
  35.  * @return {CompositeElementLite/CompositeElement}
  36.  * @member Ext.Element
  37.  * @method select
  38.  */
  39. Ext.Element.select = function(selector, unique, root){
  40.     var els;
  41.     if(typeof selector == "string"){
  42.         els = Ext.Element.selectorFunction(selector, root);
  43.     }else if(selector.length !== undefined){
  44.         els = selector;
  45.     }else{
  46.         throw "Invalid selector";
  47.     }
  48.     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
  49. };
  50. /**
  51.  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
  52.  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
  53.  * {@link Ext.CompositeElementLite CompositeElementLite} object.
  54.  * @param {String/Array} selector The CSS selector or an array of elements
  55.  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
  56.  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
  57.  * @return {CompositeElementLite/CompositeElement}
  58.  * @member Ext.Element
  59.  * @method select
  60.  */
  61. Ext.select = Ext.Element.select;(function(){
  62.     var BEFOREREQUEST = "beforerequest",
  63.         REQUESTCOMPLETE = "requestcomplete",
  64.         REQUESTEXCEPTION = "requestexception",
  65.         UNDEFINED = undefined,
  66.         LOAD = 'load',
  67.         POST = 'POST',
  68.         GET = 'GET',
  69.         WINDOW = window;
  70.     
  71.     /**
  72.      * @class Ext.data.Connection
  73.      * @extends Ext.util.Observable
  74.      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
  75.      * either to a configured URL, or to a URL specified at request time.</p>
  76.      * <p>Requests made by this class are asynchronous, and will return immediately. No data from
  77.      * the server will be available to the statement immediately following the {@link #request} call.
  78.      * To process returned data, use a
  79.      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
  80.      * in the request options object,
  81.      * or an {@link #requestcomplete event listener}.</p>
  82.      * <p><h3>File Uploads</h3><a href="#request-option-isUpload" ext:member="request-option-isUpload" ext:cls="Ext.data.Connection">File uploads</a> are not performed using normal "Ajax" techniques, that
  83.      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
  84.      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
  85.      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
  86.      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
  87.      * but removed after the return data has been gathered.</p>
  88.      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
  89.      * server is using JSON to send the return object, then the
  90.      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
  91.      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
  92.      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
  93.      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
  94.      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
  95.      * is created containing a <tt>responseText</tt> property in order to conform to the
  96.      * requirements of event handlers and callbacks.</p>
  97.      * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
  98.      * and some server technologies (notably JEE) may require some custom processing in order to
  99.      * retrieve parameter names and parameter values from the packet content.</p>
  100.      * @constructor
  101.      * @param {Object} config a configuration object.
  102.      */
  103.     Ext.data.Connection = function(config){    
  104.         Ext.apply(this, config);
  105.         this.addEvents(
  106.             /**
  107.              * @event beforerequest
  108.              * Fires before a network request is made to retrieve a data object.
  109.              * @param {Connection} conn This Connection object.
  110.              * @param {Object} options The options config object passed to the {@link #request} method.
  111.              */
  112.             BEFOREREQUEST,
  113.             /**
  114.              * @event requestcomplete
  115.              * Fires if the request was successfully completed.
  116.              * @param {Connection} conn This Connection object.
  117.              * @param {Object} response The XHR object containing the response data.
  118.              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
  119.              * for details.
  120.              * @param {Object} options The options config object passed to the {@link #request} method.
  121.              */
  122.             REQUESTCOMPLETE,
  123.             /**
  124.              * @event requestexception
  125.              * Fires if an error HTTP status was returned from the server.
  126.              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
  127.              * for details of HTTP status codes.
  128.              * @param {Connection} conn This Connection object.
  129.              * @param {Object} response The XHR object containing the response data.
  130.              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
  131.              * for details.
  132.              * @param {Object} options The options config object passed to the {@link #request} method.
  133.              */
  134.             REQUESTEXCEPTION
  135.         );
  136.         Ext.data.Connection.superclass.constructor.call(this);
  137.     };
  138.     Ext.extend(Ext.data.Connection, Ext.util.Observable, {
  139.         /**
  140.          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
  141.          * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
  142.          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
  143.          */
  144.         /**
  145.          * @cfg {Object} extraParams (Optional) An object containing properties which are used as
  146.          * extra parameters to each request made by this object. (defaults to undefined)
  147.          */
  148.         /**
  149.          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
  150.          *  to each request made by this object. (defaults to undefined)
  151.          */
  152.         /**
  153.          * @cfg {String} method (Optional) The default HTTP method to be used for requests.
  154.          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
  155.          * otherwise, GET will be used.)
  156.          */
  157.         /**
  158.          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
  159.          */
  160.         timeout : 30000,
  161.         /**
  162.          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
  163.          * @type Boolean
  164.          */
  165.         autoAbort:false,
  166.     
  167.         /**
  168.          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
  169.          * @type Boolean
  170.          */
  171.         disableCaching: true,
  172.         
  173.         /**
  174.          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
  175.          * through a cache buster. Defaults to '_dc'
  176.          * @type String
  177.          */
  178.         disableCachingParam: '_dc',
  179.         
  180.         /**
  181.          * <p>Sends an HTTP request to a remote server.</p>
  182.          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
  183.          * return before the response has been received. Process any returned data
  184.          * in a callback function.</p>
  185.          * <pre><code>
  186. Ext.Ajax.request({
  187.    url: 'ajax_demo/sample.json',
  188.    success: function(response, opts) {
  189.       var obj = Ext.decode(response.responseText);
  190.       console.dir(obj);
  191.    },
  192.    failure: function(response, opts) {
  193.       console.log('server-side failure with status code ' + response.status);
  194.    }
  195. });
  196.          * </code></pre>
  197.          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
  198.          * @param {Object} options An object which may contain the following properties:<ul>
  199.          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
  200.          * which to send the request, or a function to call which returns a URL string. The scope of the
  201.          * function is specified by the <tt>scope</tt> option. Defaults to the configured
  202.          * <tt>{@link #url}</tt>.</div></li>
  203.          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
  204.          * An object containing properties which are used as parameters to the
  205.          * request, a url encoded string or a function to call to get either. The scope of the function
  206.          * is specified by the <tt>scope</tt> option.</div></li>
  207.          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
  208.          * for the request. Defaults to the configured method, or if no method was configured,
  209.          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
  210.          * the method name is case-sensitive and should be all caps.</div></li>
  211.          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
  212.          * function to be called upon receipt of the HTTP response. The callback is
  213.          * called regardless of success or failure and is passed the following
  214.          * parameters:<ul>
  215.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  216.          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
  217.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data. 
  218.          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about 
  219.          * accessing elements of the response.</div></li>
  220.          * </ul></div></li>
  221.          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
  222.          * to be called upon success of the request. The callback is passed the following
  223.          * parameters:<ul>
  224.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
  225.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  226.          * </ul></div></li>
  227.          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
  228.          * to be called upon failure of the request. The callback is passed the
  229.          * following parameters:<ul>
  230.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
  231.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  232.          * </ul></div></li>
  233.          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
  234.          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
  235.          * specified as functions from which to draw values, then this also serves as the scope for those function calls.
  236.          * Defaults to the browser window.</div></li>
  237.          * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
  238.          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
  239.          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
  240.          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used 
  241.          * with the <tt>form</tt> option</b>.
  242.          * <p>True if the form object is a file upload (will be set automatically if the form was
  243.          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
  244.          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
  245.          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
  246.          * DOM <tt>&lt;form></tt> element temporarily modified to have its
  247.          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
  248.          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
  249.          * but removed after the return data has been gathered.</p>
  250.          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
  251.          * server is using JSON to send the return object, then the
  252.          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
  253.          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
  254.          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
  255.          * is created containing a <tt>responseText</tt> property in order to conform to the
  256.          * requirements of event handlers and callbacks.</p>
  257.          * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
  258.          * and some server technologies (notably JEE) may require some custom processing in order to
  259.          * retrieve parameter names and parameter values from the packet content.</p>
  260.          * </div></li>
  261.          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
  262.          * headers to set for the request.</div></li>
  263.          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
  264.          * to use for the post. Note: This will be used instead of params for the post
  265.          * data. Any params will be appended to the URL.</div></li>
  266.          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
  267.          * data to use as the post. Note: This will be used instead of params for the post
  268.          * data. Any params will be appended to the URL.</div></li>
  269.          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
  270.          * to add a unique cache-buster param to GET requests.</div></li>
  271.          * </ul></p>
  272.          * <p>The options object may also contain any other property which might be needed to perform
  273.          * postprocessing in a callback because it is passed to callback functions.</p>
  274.          * @return {Number} transactionId The id of the server transaction. This may be used
  275.          * to cancel the request.
  276.          */
  277.         request : function(o){
  278.             var me = this;
  279.             if(me.fireEvent(BEFOREREQUEST, me, o)){
  280.                 if (o.el) {
  281.                     if(!Ext.isEmpty(o.indicatorText)){
  282.                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
  283.                     }
  284.                     if(me.indicatorText) {
  285.                         Ext.getDom(o.el).innerHTML = me.indicatorText;                        
  286.                     }
  287.                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
  288.                         Ext.getDom(o.el).innerHTML = response.responseText;
  289.                     });
  290.                 }
  291.                 
  292.                 var p = o.params,
  293.                     url = o.url || me.url,                
  294.                     method,
  295.                     cb = {success: me.handleResponse,
  296.                           failure: me.handleFailure,
  297.                           scope: me,
  298.                           argument: {options: o},
  299.                           timeout : o.timeout || me.timeout
  300.                     },
  301.                     form,                    
  302.                     serForm;                    
  303.                   
  304.                      
  305.                 if (Ext.isFunction(p)) {
  306.                     p = p.call(o.scope||WINDOW, o);
  307.                 }
  308.                                                            
  309.                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);    
  310.                 
  311.                 if (Ext.isFunction(url)) {
  312.                     url = url.call(o.scope || WINDOW, o);
  313.                 }
  314.     
  315.                 if((form = Ext.getDom(o.form))){
  316.                     url = url || form.action;
  317.                      if(o.isUpload || /multipart/form-data/i.test(form.getAttribute("enctype"))) { 
  318.                          return me.doFormUpload.call(me, o, p, url);
  319.                      }
  320.                     serForm = Ext.lib.Ajax.serializeForm(form);                    
  321.                     p = p ? (p + '&' + serForm) : serForm;
  322.                 }
  323.                 
  324.                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
  325.                 
  326.                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
  327.                     var dcp = o.disableCachingParam || me.disableCachingParam;
  328.                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
  329.                 }
  330.                 
  331.                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
  332.                 
  333.                 if(o.autoAbort === true || me.autoAbort) {
  334.                     me.abort();
  335.                 }
  336.                  
  337.                 if((method == GET || o.xmlData || o.jsonData) && p){
  338.                     url = Ext.urlAppend(url, p);  
  339.                     p = '';
  340.                 }
  341.                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
  342.             }else{                
  343.                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
  344.             }
  345.         },
  346.     
  347.         /**
  348.          * Determine whether this object has a request outstanding.
  349.          * @param {Number} transactionId (Optional) defaults to the last transaction
  350.          * @return {Boolean} True if there is an outstanding request.
  351.          */
  352.         isLoading : function(transId){
  353.             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;            
  354.         },
  355.     
  356.         /**
  357.          * Aborts any outstanding request.
  358.          * @param {Number} transactionId (Optional) defaults to the last transaction
  359.          */
  360.         abort : function(transId){
  361.             if(transId || this.isLoading()){
  362.                 Ext.lib.Ajax.abort(transId || this.transId);
  363.             }
  364.         },
  365.         // private
  366.         handleResponse : function(response){
  367.             this.transId = false;
  368.             var options = response.argument.options;
  369.             response.argument = options ? options.argument : null;
  370.             this.fireEvent(REQUESTCOMPLETE, this, response, options);
  371.             if(options.success){
  372.                 options.success.call(options.scope, response, options);
  373.             }
  374.             if(options.callback){
  375.                 options.callback.call(options.scope, options, true, response);
  376.             }
  377.         },
  378.         // private
  379.         handleFailure : function(response, e){
  380.             this.transId = false;
  381.             var options = response.argument.options;
  382.             response.argument = options ? options.argument : null;
  383.             this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
  384.             if(options.failure){
  385.                 options.failure.call(options.scope, response, options);
  386.             }
  387.             if(options.callback){
  388.                 options.callback.call(options.scope, options, false, response);
  389.             }
  390.         },
  391.         // private
  392.         doFormUpload : function(o, ps, url){
  393.             var id = Ext.id(),
  394.                 doc = document,
  395.                 frame = doc.createElement('iframe'),
  396.                 form = Ext.getDom(o.form),
  397.                 hiddens = [],
  398.                 hd,
  399.                 encoding = 'multipart/form-data',
  400.                 buf = {
  401.                     target: form.target,
  402.                     method: form.method,
  403.                     encoding: form.encoding,
  404.                     enctype: form.enctype,
  405.                     action: form.action
  406.                 };
  407.             Ext.fly(frame).set({
  408.                 id: id,
  409.                 name: id,
  410.                 cls: 'x-hidden',
  411.                 src: Ext.SSL_SECURE_URL // for IE
  412.             });
  413.             doc.body.appendChild(frame);
  414.             // This is required so that IE doesn't pop the response up in a new window.
  415.             if(Ext.isIE){
  416.                document.frames[id].name = id;
  417.             }
  418.             Ext.fly(form).set({
  419.                 target: id,
  420.                 method: POST,
  421.                 enctype: encoding,
  422.                 encoding: encoding,
  423.                 action: url || buf.action
  424.             });
  425.             // add dynamic params
  426.             Ext.iterate(Ext.urlDecode(ps, false), function(k, v){
  427.                 hd = doc.createElement('input');
  428.                 Ext.fly(hd).set({
  429.                     type: 'hidden',
  430.                     value: v,
  431.                     name: k
  432.                 });
  433.                 form.appendChild(hd);
  434.                 hiddens.push(hd);
  435.             });
  436.             function cb(){
  437.                 var me = this,
  438.                     // bogus response object
  439.                     r = {responseText : '',
  440.                          responseXML : null,
  441.                          argument : o.argument},
  442.                     doc,
  443.                     firstChild;
  444.                 try{
  445.                     doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
  446.                     if(doc){
  447.                         if(doc.body){
  448.                             if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
  449.                                 r.responseText = firstChild.value;
  450.                             }else{
  451.                                 r.responseText = doc.body.innerHTML;
  452.                             }
  453.                         }
  454.                         //in IE the document may still have a body even if returns XML.
  455.                         r.responseXML = doc.XMLDocument || doc;
  456.                     }
  457.                 }
  458.                 catch(e) {}
  459.                 Ext.EventManager.removeListener(frame, LOAD, cb, me);
  460.                 me.fireEvent(REQUESTCOMPLETE, me, r, o);
  461.                 function runCallback(fn, scope, args){
  462.                     if(Ext.isFunction(fn)){
  463.                         fn.apply(scope, args);
  464.                     }
  465.                 }
  466.                 runCallback(o.success, o.scope, [r, o]);
  467.                 runCallback(o.callback, o.scope, [o, true, r]);
  468.                 if(!me.debugUploads){
  469.                     setTimeout(function(){Ext.removeNode(frame);}, 100);
  470.                 }
  471.             }
  472.             Ext.EventManager.on(frame, LOAD, cb, this);
  473.             form.submit();
  474.             Ext.fly(form).set(buf);
  475.             Ext.each(hiddens, function(h) {
  476.                 Ext.removeNode(h);
  477.             });
  478.         }
  479.     });
  480. })();
  481. /**
  482.  * @class Ext.Ajax
  483.  * @extends Ext.data.Connection
  484.  * <p>The global Ajax request class that provides a simple way to make Ajax requests
  485.  * with maximum flexibility.</p>
  486.  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
  487.  * and override them at the request function level only if necessary.</p>
  488.  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
  489.  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
  490.  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
  491.  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
  492.  * </ul></div>
  493.  * <pre><code>
  494. // Default headers to pass in every request
  495. Ext.Ajax.defaultHeaders = {
  496.     'Powered-By': 'Ext'
  497. };
  498.  * </code></pre> 
  499.  * </p>
  500.  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
  501.  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
  502.  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
  503.  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
  504.  * </ul></div>
  505.  * <pre><code>
  506. // Example: show a spinner during all Ajax requests
  507. Ext.Ajax.on('beforerequest', this.showSpinner, this);
  508. Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
  509. Ext.Ajax.on('requestexception', this.hideSpinner, this);
  510.  * </code></pre> 
  511.  * </p>
  512.  * <p>An example request:</p>
  513.  * <pre><code>
  514. // Basic request
  515. Ext.Ajax.{@link Ext.data.Connection#request request}({
  516.    url: 'foo.php',
  517.    success: someFn,
  518.    failure: otherFn,
  519.    headers: {
  520.        'my-header': 'foo'
  521.    },
  522.    params: { foo: 'bar' }
  523. });
  524. // Simple ajax form submission
  525. Ext.Ajax.{@link Ext.data.Connection#request request}({
  526.     form: 'some-form',
  527.     params: 'foo=bar'
  528. });
  529.  * </code></pre> 
  530.  * </p>
  531.  * @singleton
  532.  */
  533. Ext.Ajax = new Ext.data.Connection({
  534.     /**
  535.      * @cfg {String} url @hide
  536.      */
  537.     /**
  538.      * @cfg {Object} extraParams @hide
  539.      */
  540.     /**
  541.      * @cfg {Object} defaultHeaders @hide
  542.      */
  543.     /**
  544.      * @cfg {String} method (Optional) @hide
  545.      */
  546.     /**
  547.      * @cfg {Number} timeout (Optional) @hide
  548.      */
  549.     /**
  550.      * @cfg {Boolean} autoAbort (Optional) @hide
  551.      */
  552.     /**
  553.      * @cfg {Boolean} disableCaching (Optional) @hide
  554.      */
  555.     /**
  556.      * @property  disableCaching
  557.      * True to add a unique cache-buster param to GET requests. (defaults to true)
  558.      * @type Boolean
  559.      */
  560.     /**
  561.      * @property  url
  562.      * The default URL to be used for requests to the server. (defaults to undefined)
  563.      * If the server receives all requests through one URL, setting this once is easier than
  564.      * entering it on every request.
  565.      * @type String
  566.      */
  567.     /**
  568.      * @property  extraParams
  569.      * An object containing properties which are used as extra parameters to each request made
  570.      * by this object (defaults to undefined). Session information and other data that you need
  571.      * to pass with each request are commonly put here.
  572.      * @type Object
  573.      */
  574.     /**
  575.      * @property  defaultHeaders
  576.      * An object containing request headers which are added to each request made by this object
  577.      * (defaults to undefined).
  578.      * @type Object
  579.      */
  580.     /**
  581.      * @property  method
  582.      * The default HTTP method to be used for requests. Note that this is case-sensitive and
  583.      * should be all caps (defaults to undefined; if not set but params are present will use
  584.      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
  585.      * @type String
  586.      */
  587.     /**
  588.      * @property  timeout
  589.      * The timeout in milliseconds to be used for requests. (defaults to 30000)
  590.      * @type Number
  591.      */
  592.     /**
  593.      * @property  autoAbort
  594.      * Whether a new request should abort any pending requests. (defaults to false)
  595.      * @type Boolean
  596.      */
  597.     autoAbort : false,
  598.     /**
  599.      * Serialize the passed form into a url encoded string
  600.      * @param {String/HTMLElement} form
  601.      * @return {String}
  602.      */
  603.     serializeForm : function(form){
  604.         return Ext.lib.Ajax.serializeForm(form);
  605.     }
  606. });
  607. /**  * @class Ext.Updater  * @extends Ext.util.Observable  * Provides AJAX-style update capabilities for Element objects.  Updater can be used to {@link #update}  * an {@link Ext.Element} once, or you can use {@link #startAutoRefresh} to set up an auto-updating  * {@link Ext.Element Element} on a specific interval.<br><br>  * Usage:<br>  * <pre><code>  * var el = Ext.get("foo"); // Get Ext.Element object  * var mgr = el.getUpdater();  * mgr.update({         url: "http://myserver.com/index.php",         params: {             param1: "foo",             param2: "bar"         }  * });  * ...  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");  * <br>  * // or directly (returns the same Updater instance)  * var mgr = new Ext.Updater("myElementId");  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");  * mgr.on("update", myFcnNeedsToKnow);  * <br>  * // short handed call directly from the element object  * Ext.get("foo").load({         url: "bar.php",         scripts: true,         params: "param1=foo&amp;param2=bar",         text: "Loading Foo..."  * });  * </code></pre>  * @constructor  * Create new Updater directly.  * @param {Mixed} el The element to update  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already  * has an Updater and if it does it returns the same instance. This will skip that check (useful for extending this class).  */ Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable,  function() { var BEFOREUPDATE = "beforeupdate", UPDATE = "update", FAILURE = "failure"; // private     function processSuccess(response){          var me = this;         me.transaction = null;         if (response.argument.form && response.argument.reset) {             try { // put in try/catch since some older FF releases had problems with this                 response.argument.form.reset();             } catch(e){}         }         if (me.loadScripts) {             me.renderer.render(me.el, response, me,                updateComplete.createDelegate(me, [response]));         } else {             me.renderer.render(me.el, response, me);             updateComplete.call(me, response);         }     }          // private     function updateComplete(response, type, success){         this.fireEvent(type || UPDATE, this.el, response);         if(Ext.isFunction(response.argument.callback)){             response.argument.callback.call(response.argument.scope, this.el, Ext.isEmpty(success) ? true : false, response, response.argument.options);         }     }     // private     function processFailure(response){                      updateComplete.call(this, response, FAILURE, !!(this.transaction = null));     }      return {     constructor: function(el, forceNew){     var me = this;         el = Ext.get(el);         if(!forceNew && el.updateManager){             return el.updateManager;         }         /**          * The Element object          * @type Ext.Element          */         me.el = el;         /**          * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.          * @type String          */         me.defaultUrl = null;         me.addEvents(             /**              * @event beforeupdate              * Fired before an update is made, return false from your handler and the update is cancelled.              * @param {Ext.Element} el              * @param {String/Object/Function} url              * @param {String/Object} params              */             BEFOREUPDATE,             /**              * @event update              * Fired after successful update is made.              * @param {Ext.Element} el              * @param {Object} oResponseObject The response Object              */             UPDATE,             /**              * @event failure              * Fired on update failure.              * @param {Ext.Element} el              * @param {Object} oResponseObject The response Object              */             FAILURE         );         Ext.apply(me, Ext.Updater.defaults);         /**          * Blank page URL to use with SSL file uploads (defaults to {@link Ext.Updater.defaults#sslBlankUrl}).          * @property sslBlankUrl          * @type String          */         /**          * Whether to append unique parameter on get request to disable caching (defaults to {@link Ext.Updater.defaults#disableCaching}).          * @property disableCaching          * @type Boolean          */         /**          * Text for loading indicator (defaults to {@link Ext.Updater.defaults#indicatorText}).          * @property indicatorText          * @type String          */         /**          * Whether to show indicatorText when loading (defaults to {@link Ext.Updater.defaults#showLoadIndicator}).          * @property showLoadIndicator          * @type String          */         /**          * Timeout for requests or form posts in seconds (defaults to {@link Ext.Updater.defaults#timeout}).          * @property timeout          * @type Number          */         /**          * True to process scripts in the output (defaults to {@link Ext.Updater.defaults#loadScripts}).          * @property loadScripts          * @type Boolean          */         /**          * Transaction object of the current executing transaction, or null if there is no active transaction.          */         me.transaction = null;         /**          * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments          * @type Function          */         me.refreshDelegate = me.refresh.createDelegate(me);         /**          * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments          * @type Function          */         me.updateDelegate = me.update.createDelegate(me);         /**          * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments          * @type Function          */         me.formUpdateDelegate = (me.formUpdate || function(){}).createDelegate(me);          /**  * The renderer for this Updater (defaults to {@link Ext.Updater.BasicRenderer}).  */         me.renderer = me.renderer || me.getDefaultRenderer();                  Ext.Updater.superclass.constructor.call(me);     },          /**      * Sets the content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.      * @param {Object} renderer The object implementing the render() method      */     setRenderer : function(renderer){         this.renderer = renderer;     },              /**      * Returns the current content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.      * @return {Object}      */     getRenderer : function(){        return this.renderer;     },     /**      * This is an overrideable method which returns a reference to a default      * renderer class if none is specified when creating the Ext.Updater.      * Defaults to {@link Ext.Updater.BasicRenderer}      */     getDefaultRenderer: function() {         return new Ext.Updater.BasicRenderer();     },                      /**      * Sets the default URL used for updates.      * @param {String/Function} defaultUrl The url or a function to call to get the url      */     setDefaultUrl : function(defaultUrl){         this.defaultUrl = defaultUrl;     },              /**      * Get the Element this Updater is bound to      * @return {Ext.Element} The element      */     getEl : function(){         return this.el;     }, /**      * Performs an <b>asynchronous</b> request, updating this element with the response.      * If params are specified it uses POST, otherwise it uses GET.<br><br>      * <b>Note:</b> Due to the asynchronous nature of remote server requests, the Element      * will not have been fully updated when the function returns. To post-process the returned      * data, use the callback option, or an <b><code>update</code></b> event handler.      * @param {Object} options A config object containing any of the following options:<ul>      * <li>url : <b>String/Function</b><p class="sub-desc">The URL to request or a function which      * <i>returns</i> the URL (defaults to the value of {@link Ext.Ajax#url} if not specified).</p></li>      * <li>method : <b>String</b><p class="sub-desc">The HTTP method to      * use. Defaults to POST if the <code>params</code> argument is present, otherwise GET.</p></li>      * <li>params : <b>String/Object/Function</b><p class="sub-desc">The      * parameters to pass to the server (defaults to none). These may be specified as a url-encoded      * string, or as an object containing properties which represent parameters,      * or as a function, which returns such an object.</p></li>      * <li>scripts : <b>Boolean</b><p class="sub-desc">If <code>true</code>      * any &lt;script&gt; tags embedded in the response text will be extracted      * and executed (defaults to {@link Ext.Updater.defaults#loadScripts}). If this option is specified,      * the callback will be called <i>after</i> the execution of the scripts.</p></li>      * <li>callback : <b>Function</b><p class="sub-desc">A function to      * be called when the response from the server arrives. The following      * parameters are passed:<ul>      * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>      * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>      * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li>      * <li><b>options</b> : Object<p class="sub-desc">The config object passed to the update call.</p></li></ul>      * </p></li>      * <li>scope : <b>Object</b><p class="sub-desc">The scope in which      * to execute the callback (The callback's <code>this</code> reference.) If the      * <code>params</code> argument is a function, this scope is used for that function also.</p></li>      * <li>discardUrl : <b>Boolean</b><p class="sub-desc">By default, the URL of this request becomes      * the default URL for this Updater object, and will be subsequently used in {@link #refresh}      * calls.  To bypass this behavior, pass <code>discardUrl:true</code> (defaults to false).</p></li>      * <li>timeout : <b>Number</b><p class="sub-desc">The number of seconds to wait for a response before      * timing out (defaults to {@link Ext.Updater.defaults#timeout}).</p></li>      * <li>text : <b>String</b><p class="sub-desc">The text to use as the innerHTML of the      * {@link Ext.Updater.defaults#indicatorText} div (defaults to 'Loading...').  To replace the entire div, not      * just the text, override {@link Ext.Updater.defaults#indicatorText} directly.</p></li>      * <li>nocache : <b>Boolean</b><p class="sub-desc">Only needed for GET      * requests, this option causes an extra, auto-generated parameter to be appended to the request      * to defeat caching (defaults to {@link Ext.Updater.defaults#disableCaching}).</p></li></ul>      * <p>      * For example: <pre><code> um.update({     url: "your-url.php",     params: {param1: "foo", param2: "bar"}, // or a URL encoded string     callback: yourFunction,     scope: yourObject, //(optional scope)     discardUrl: true,     nocache: true,     text: "Loading...",     timeout: 60,     scripts: false // Save time by avoiding RegExp execution. }); </code></pre>      */     update : function(url, params, callback, discardUrl){     var me = this,      cfg,       callerScope;              if(me.fireEvent(BEFOREUPDATE, me.el, url, params) !== false){                          if(Ext.isObject(url)){ // must be config object                 cfg = url;                 url = cfg.url;                 params = params || cfg.params;                 callback = callback || cfg.callback;                 discardUrl = discardUrl || cfg.discardUrl;                 callerScope = cfg.scope;                                  if(!Ext.isEmpty(cfg.nocache)){me.disableCaching = cfg.nocache;};                 if(!Ext.isEmpty(cfg.text)){me.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};                 if(!Ext.isEmpty(cfg.scripts)){me.loadScripts = cfg.scripts;};                 if(!Ext.isEmpty(cfg.timeout)){me.timeout = cfg.timeout;};             }             me.showLoading();             if(!discardUrl){                 me.defaultUrl = url;             }             if(Ext.isFunction(url)){                 url = url.call(me);             }             var o = Ext.apply({}, {                 url : url,                 params: (Ext.isFunction(params) && callerScope) ? params.createDelegate(callerScope) : params,                 success: processSuccess,                 failure: processFailure,                 scope: me,                 callback: undefined,                 timeout: (me.timeout*1000),                 disableCaching: me.disableCaching,                 argument: {                     "options": cfg,                     "url": url,                     "form": null,                     "callback": callback,                     "scope": callerScope || window,                     "params": params                 }             }, cfg);             me.transaction = Ext.Ajax.request(o);         }     },      /**      * <p>Performs an asynchronous form post, updating this element with the response. If the form has the attribute      * enctype="<a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>", it assumes it's a file upload.      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.</p>      * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>      * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the      * DOM <code>&lt;form></code> element temporarily modified to have its      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer      * to a dynamically generated, hidden <code>&lt;iframe></code> which is inserted into the document      * but removed after the return data has been gathered.</p>      * <p>Be aware that file upload packets, sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>      * and some server technologies (notably JEE) may require some custom processing in order to      * retrieve parameter names and parameter values from the packet content.</p>      * @param {String/HTMLElement} form The form Id or form element      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.      * @param {Boolean} reset (optional) Whether to try to reset the form after the update      * @param {Function} callback (optional) Callback when transaction is complete. The following      * parameters are passed:<ul>      * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>      * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>      * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li></ul>      */     formUpdate : function(form, url, reset, callback){     var me = this;         if(me.fireEvent(BEFOREUPDATE, me.el, form, url) !== false){             if(Ext.isFunction(url)){                 url = url.call(me);             }             form = Ext.getDom(form)             me.transaction = Ext.Ajax.request({                 form: form,                 url:url,                 success: processSuccess,                 failure: processFailure,                 scope: me,                 timeout: (me.timeout*1000),                 argument: {                     "url": url,                     "form": form,                     "callback": callback,                     "reset": reset                 }             });             me.showLoading.defer(1, me);         }     },                      /**      * Set this element to auto refresh.  Can be canceled by calling {@link #stopAutoRefresh}.      * @param {Number} interval How often to update (in seconds).      * @param {String/Object/Function} url (optional) The url for this request, a config object in the same format      * supported by {@link #load}, or a function to call to get the url (defaults to the last used url).  Note that while      * the url used in a load call can be reused by this method, other load config options will not be reused and must be      * sepcified as part of a config object passed as this paramter if needed.      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string      * "&param1=1&param2=2" or as an object {param1: 1, param2: 2}      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval      */     startAutoRefresh : function(interval, url, params, callback, refreshNow){     var me = this;         if(refreshNow){             me.update(url || me.defaultUrl, params, callback, true);         }         if(me.autoRefreshProcId){             clearInterval(me.autoRefreshProcId);         }         me.autoRefreshProcId = setInterval(me.update.createDelegate(me, [url || me.defaultUrl, params, callback, true]), interval * 1000);     },     /**      * Stop auto refresh on this element.      */     stopAutoRefresh : function(){         if(this.autoRefreshProcId){             clearInterval(this.autoRefreshProcId);             delete this.autoRefreshProcId;         }     },     /**      * Returns true if the Updater is currently set to auto refresh its content (see {@link #startAutoRefresh}), otherwise false.      */     isAutoRefreshing : function(){        return !!this.autoRefreshProcId;     },     /**      * Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This      * method may be overridden to perform a custom action while this Updater is actively updating its contents.      */     showLoading : function(){         if(this.showLoadIndicator){              this.el.dom.innerHTML = this.indicatorText;         }     },     /**      * Aborts the currently executing transaction, if any.      */     abort : function(){         if(this.transaction){             Ext.Ajax.abort(this.transaction);         }     },     /**      * Returns true if an update is in progress, otherwise false.      * @return {Boolean}      */     isUpdating : function(){              return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false;             },          /**      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)      */     refresh : function(callback){         if(this.defaultUrl){          this.update(this.defaultUrl, null, callback, true);      }     }     } }()); /**  * @class Ext.Updater.defaults  * The defaults collection enables customizing the default properties of Updater  */ Ext.Updater.defaults = {    /**      * Timeout for requests or form posts in seconds (defaults to 30 seconds).      * @type Number      */     timeout : 30,         /**      * True to append a unique parameter to GET requests to disable caching (defaults to false).      * @type Boolean      */     disableCaching : false,     /**      * Whether or not to show {@link #indicatorText} during loading (defaults to true).      * @type Boolean      */     showLoadIndicator : true,     /**      * Text for loading indicator (defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').      * @type String      */     indicatorText : '<div class="loading-indicator">Loading...</div>',      /**      * True to process scripts by default (defaults to false).      * @type Boolean      */     loadScripts : false,     /**     * Blank page URL to use with SSL file uploads (defaults to {@link Ext#SSL_SECURE_URL} if set, or "javascript:false").     * @type String     */     sslBlankUrl : Ext.SSL_SECURE_URL       }; /**  * Static convenience method. <b>This method is deprecated in favor of el.load({url:'foo.php', ...})</b>.  * Usage:  * <pre><code>Ext.Updater.updateElement("my-div", "stuff.php");</code></pre>  * @param {Mixed} el The element to update  * @param {String} url The url  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs  * @param {Object} options (optional) A config object with any of the Updater properties you want to set - for  * example: {disableCaching:true, indicatorText: "Loading data..."}  * @static  * @deprecated  * @member Ext.Updater  */ Ext.Updater.updateElement = function(el, url, params, options){     var um = Ext.get(el).getUpdater();     Ext.apply(um, options);     um.update(url, params, options ? options.callback : null); }; /**  * @class Ext.Updater.BasicRenderer  * <p>This class is a base class implementing a simple render method which updates an element using results from an Ajax request.</p>  * <p>The BasicRenderer updates the element's innerHTML with the responseText. To perform a custom render (i.e. XML or JSON processing),  * create an object with a conforming {@link #render} method and pass it to setRenderer on the Updater.</p>  */ Ext.Updater.BasicRenderer = function(){}; Ext.Updater.BasicRenderer.prototype = {     /**      * This method is called when an Ajax response is received, and an Element needs updating.      * @param {Ext.Element} el The element being rendered      * @param {Object} xhr The XMLHttpRequest object      * @param {Updater} updateManager The calling update manager      * @param {Function} callback A callback that will need to be called if loadScripts is true on the Updater      */      render : function(el, response, updateManager, callback){               el.update(response.responseText, updateManager.loadScripts, callback);     } };/**  * @class Date  *  * The date parsing and formatting syntax contains a subset of  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are  * supported will provide results equivalent to their PHP versions.  *  * The following is a list of all currently supported formats:  * <pre> Format  Description                                                               Example returned values ------  -----------------------------------------------------------------------   -----------------------   d     Day of the month, 2 digits with leading zeros                             01 to 31   D     A short textual representation of the day of the week                     Mon to Sun   j     Day of the month without leading zeros                                    1 to 31   l     A full textual representation of the day of the week                      Sunday to Saturday   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53   F     A full textual representation of a month, such as January or March        January to December   m     Numeric representation of a month, with leading zeros                     01 to 12   M     A short textual representation of a month                                 Jan to Dec   n     Numeric representation of a month, without leading zeros                  1 to 12   t     Number of days in the given month                                         28 to 31   L     Whether it's a leap year                                                  1 if it is a leap year, 0 otherwise.   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004         belongs to the previous or next year, that year is used instead)   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003   y     A two digit representation of a year                                      Examples: 99 or 03   a     Lowercase Ante meridiem and Post meridiem                                 am or pm   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM   g     12-hour format of an hour without leading zeros                           1 to 12   G     24-hour format of an hour without leading zeros                           0 to 23   h     12-hour format of an hour with leading zeros                              01 to 12   H     24-hour format of an hour with leading zeros                              00 to 23   i     Minutes, with leading zeros                                               00 to 59   s     Seconds, with leading zeros                                               00 to 59   u     Decimal fraction of a second                                              Examples:         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or                                                                                   100 (i.e. 0.100s) or                                                                                   999 (i.e. 0.999s) or                                                                                   999876543210 (i.e. 0.999876543210s)   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400   c     ISO 8601 date         Notes:                                                                    Examples:         1) If unspecified, the month / day defaults to the current month / day,   1991 or            the time defaults to midnight, while the timezone defaults to the      1992-10 or            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or            are optional.                                                          1995-07-18T17:21:28-02:00 or         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or         date-time granularity which are supported, or see                         2000-02-13T21:25:33         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463   M$    Microsoft AJAX serialized dates                                           /Date(1238606590509)/ (i.e. UTC milliseconds since epoch) or                                                                                   /Date(1238606590509+0800)/ </pre>  *  * Example usage (note that you must escape format specifiers with '\' to render them as character literals):  * <pre><code> // Sample date: // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)' var dt = new Date('1/10/2007 03:05:01 PM GMT-0600'); document.write(dt.format('Y-m-d'));                           // 2007-01-10 document.write(dt.format('F j, Y, g:i a'));                   // January 10, 2007, 3:05 pm document.write(dt.format('l, \t\he jS \of F Y h:i:s A'));  // Wednesday, the 10th of January 2007 03:05:01 PM </code></pre>  *  * Here are some standard date/time patterns that you might find helpful.  They  * are not part of the source of Date.js, but to use them you can simply copy this  * block of code into any script that is included after Date.js and they will also become  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.  * <pre><code> Date.patterns = {     ISO8601Long:"Y-m-d H:i:s",     ISO8601Short:"Y-m-d",     ShortDate: "n/j/Y",     LongDate: "l, F d, Y",     FullDateTime: "l, F d, Y g:i:s A",     MonthDay: "F d",     ShortTime: "g:i A",     LongTime: "g:i:s A",     SortableDateTime: "Y-m-d\TH:i:s",     UniversalSortableDateTime: "Y-m-d H:i:sO",     YearMonth: "F, Y" }; </code></pre>  *  * Example usage:  * <pre><code> var dt = new Date(); document.write(dt.format(Date.patterns.ShortDate)); </code></pre>  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>  */ /*  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)  * They generate precompiled functions from format patterns instead of parsing and  * processing each pattern every time a date is formatted. These functions are available  * on every Date object.  */ (function() { /**  * Global flag which determines if strict date parsing should be used.  * Strict date parsing will not roll-over invalid dates, which is the  * default behaviour of javascript Date objects.  * (see {@link #parseDate} for more information)  * Defaults to <tt>false</tt>.  * @static  * @type Boolean */ Date.useStrict = false; // create private copy of Ext's String.format() method // - to remove unnecessary dependency // - to resolve namespace conflict with M$-Ajax's implementation function xf(format) {     var args = Array.prototype.slice.call(arguments, 1);     return format.replace(/{(d+)}/g, function(m, i) {         return args[i];     }); } // private Date.formatCodeToRegex = function(character, currentGroup) {     // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below)     var p = Date.parseCodes[character];     if (p) {       p = typeof p == 'function'? p() : p;       Date.parseCodes[character] = p; // reassign function result to prevent repeated execution     }     return p? Ext.applyIf({       c: p.c? xf(p.c, currentGroup || "{0}") : p.c     }, p) : {         g:0,         c:null,         s:Ext.escapeRe(character) // treat unrecognised characters as literals     } } // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often var $f = Date.formatCodeToRegex; Ext.apply(Date, {     /**      * <p>An object hash in which each property is a date parsing function. The property name is the      * format string which that function parses.</p>      * <p>This object is automatically populated with date parsing functions as      * date formats are requested for Ext standard formatting strings.</p>      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on      * may be used as a format string to {@link #parseDate}.<p>      * <p>Example:</p><pre><code> Date.parseFunctions['x-date-format'] = myDateParser; </code></pre>      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing      * (i.e. prevent javascript Date "rollover") (The default must be false).      * Invalid date strings should return null when parsed.</div></li>      * </ul></div></p>      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding      * formatting function must be placed into the {@link #formatFunctions} property.      * @property parseFunctions      * @static      * @type Object      */     parseFunctions: {         "M$": function(input, strict) {             // note: the timezone offset is ignored since the M$ Ajax server sends             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)             var re = new RegExp('\/Date\(([-+])?(\d+)(?:[+-]\d{4})?\)\/');             var r = (input || '').match(re);             return r? new Date(((r[1] || '') + r[2]) * 1) : null;         }     },     parseRegexes: [],     /**      * <p>An object hash in which each property is a date formatting function. The property name is the      * format string which corresponds to the produced formatted date string.</p>      * <p>This object is automatically populated with date formatting functions as      * date formats are requested for Ext standard formatting strings.</p>      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on      * may be used as a format string to {@link #format}. Example:</p><pre><code> Date.formatFunctions['x-date-format'] = myDateFormatter; </code></pre>      * <p>A formatting function should return a string repesentation of the passed Date object:<div class="mdetail-params"><ul>      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>      * </ul></div></p>      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding      * parsing function must be placed into the {@link #parseFunctions} property.      * @property formatFunctions      * @static      * @type Object      */     formatFunctions: {         "M$": function() {             // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF))             return '\/Date(' + this.getTime() + ')\/';         }     },     y2kYear : 50,     /**      * Date interval constant      * @static      * @type String      */     MILLI : "ms",     /**      * Date interval constant      * @static      * @type String      */     SECOND : "s",     /**      * Date interval constant      * @static      * @type String      */     MINUTE : "mi",     /** Date interval constant      * @static      * @type String      */     HOUR : "h",     /**      * Date interval constant      * @static      * @type String      */     DAY : "d",     /**      * Date interval constant      * @static      * @type String      */     MONTH : "mo",     /**      * Date interval constant      * @static      * @type String      */     YEAR : "y",     /**      * <p>An object hash containing default date values used during date parsing.</p>      * <p>The following properties are available:<div class="mdetail-params"><ul>      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>      * </ul></div></p>      * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p>      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.      * It is the responsiblity of the developer to account for this.</b></p>      * Example Usage:      * <pre><code> // set default day value to the first day of the month Date.defaults.d = 1; // parse a February date string containing only year and month values. // setting the default day value to 1 prevents weird date rollover issues // when attempting to parse the following date string on, for example, March 31st 2009. Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009 </code></pre>      * @property defaults      * @static      * @type Object      */     defaults: {},     /**      * An array of textual day names.      * Override these values for international dates.      * Example:      * <pre><code> Date.dayNames = [     'SundayInYourLang',     'MondayInYourLang',     ... ]; </code></pre>      * @type Array      * @static      */     dayNames : [         "Sunday",         "Monday",         "Tuesday",         "Wednesday",         "Thursday",         "Friday",         "Saturday"     ],     /**      * An array of textual month names.      * Override these values for international dates.      * Example:      * <pre><code> Date.monthNames = [     'JanInYourLang',     'FebInYourLang',     ... ]; </code></pre>      * @type Array      * @static      */     monthNames : [         "January",         "February",         "March",         "April",         "May",         "June",         "July",         "August",         "September",         "October",         "November",         "December"     ],     /**      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).      * Override these values for international dates.      * Example:      * <pre><code> Date.monthNumbers = {     'ShortJanNameInYourLang':0,     'ShortFebNameInYourLang':1,     ... }; </code></pre>      * @type Object      * @static      */     monthNumbers : {         Jan:0,         Feb:1,         Mar:2,         Apr:3,         May:4,         Jun:5,         Jul:6,         Aug:7,         Sep:8,         Oct:9,         Nov:10,         Dec:11     },     /**      * Get the short month name for the given month number.      * Override this function for international dates.      * @param {Number} month A zero-based javascript month number.      * @return {String} The short month name.      * @static      */     getShortMonthName : function(month) {         return Date.monthNames[month].substring(0, 3);     },     /**      * Get the short day name for the given day number.      * Override this function for international dates.      * @param {Number} day A zero-based javascript day number.      * @return {String} The short day name.      * @static      */     getShortDayName : function(day) {         return Date.dayNames[day].substring(0, 3);     },     /**      * Get the zero-based javascript month number for the given short/full month name.      * Override this function for international dates.      * @param {String} name The short/full month name.      * @return {Number} The zero-based javascript month number.      * @static      */     getMonthNumber : function(name) {         // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)         return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];     },     /**      * The base format-code to formatting-function hashmap used by the {@link #format} method.      * Formatting functions are strings (or functions which return strings) which      * will return the appropriate value when evaluated in the context of the Date object      * from which the {@link #format} method is called.      * Add to / override these mappings for custom date formatting.      * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found.      * Example:      * <pre><code> Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')"; (new Date()).format("X"); // returns the current day of the month </code></pre>      * @type Object      * @static      */     formatCodes : {         d: "String.leftPad(this.getDate(), 2, '0')",         D: "Date.getShortDayName(this.getDay())", // get localised short day name         j: "this.getDate()",         l: "Date.dayNames[this.getDay()]",         N: "(this.getDay() ? this.getDay() : 7)",         S: "this.getSuffix()",         w: "this.getDay()",         z: "this.getDayOfYear()",         W: "String.leftPad(this.getWeekOfYear(), 2, '0')",         F: "Date.monthNames[this.getMonth()]",         m: "String.leftPad(this.getMonth() + 1, 2, '0')",         M: "Date.getShortMonthName(this.getMonth())", // get localised short month name         n: "(this.getMonth() + 1)",         t: "this.getDaysInMonth()",         L: "(this.isLeapYear() ? 1 : 0)",         o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))",         Y: "this.getFullYear()",         y: "('' + this.getFullYear()).substring(2, 4)",         a: "(this.getHours() < 12 ? 'am' : 'pm')",         A: "(this.getHours() < 12 ? 'AM' : 'PM')",         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",         G: "this.getHours()",         h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",         H: "String.leftPad(this.getHours(), 2, '0')",         i: "String.leftPad(this.getMinutes(), 2, '0')",         s: "String.leftPad(this.getSeconds(), 2, '0')",         u: "String.leftPad(this.getMilliseconds(), 3, '0')",         O: "this.getGMTOffset()",         P: "this.getGMTOffset(true)",         T: "this.getTimezone()",         Z: "(this.getTimezoneOffset() * -60)",         c: function() { // ISO-8601 -- GMT format             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {                 var e = c.charAt(i);                 code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal             }             return code.join(" + ");         },         /*         c: function() { // ISO-8601 -- UTC format             return [               "this.getUTCFullYear()", "'-'",               "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",               "String.leftPad(this.getUTCDate(), 2, '0')",               "'T'",               "String.leftPad(this.getUTCHours(), 2, '0')", "':'",               "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'",               "String.leftPad(this.getUTCSeconds(), 2, '0')",               "'Z'"             ].join(" + ");         },         */         U: "Math.round(this.getTime() / 1000)"     },     /**      * Checks if the passed Date parameters will cause a javascript Date "rollover".      * @param {Number} year 4-digit year      * @param {Number} month 1-based month-of-year      * @param {Number} day Day of month      * @param {Number} hour (optional) Hour      * @param {Number} minute (optional) Minute      * @param {Number} second (optional) Second      * @param {Number} millisecond (optional) Millisecond      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.      * @static      */     isValid : function(y, m, d, h, i, s, ms) {         // setup defaults         h = h || 0;         i = i || 0;         s = s || 0;         ms = ms || 0;         var dt = new Date(y, m - 1, d, h, i, s, ms);         return y == dt.getFullYear() &&             m == dt.getMonth() + 1 &&             d == dt.getDate() &&             h == dt.getHours() &&             i == dt.getMinutes() &&             s == dt.getSeconds() &&             ms == dt.getMilliseconds();     },     /**      * Parses the passed string using the specified date format.      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.      * Keep in mind that the input date string must precisely match the specified format string      * in order for the parse operation to be successful (failed parse operations return a null value).      * <p>Example:</p><pre><code> //dt = Fri May 25 2007 (current date) var dt = new Date(); //dt = Thu May 25 2006 (today&#39;s month/day in 2006) dt = Date.parseDate("2006", "Y"); //dt = Sun Jan 15 2006 (all date parts specified) dt = Date.parseDate("2006-01-15", "Y-m-d"); //dt = Sun Jan 15 2006 15:20:01 dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A"); // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null </code></pre>      * @param {String} input The raw date string.      * @param {String} format The expected date string format.      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")                         (defaults to false). Invalid date strings will return null when parsed.      * @return {Date} The parsed Date.      * @static      */     parseDate : function(input, format, strict) {         var p = Date.parseFunctions;         if (p[format] == null) {             Date.createParser(format);         }         return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict);     },     // private     getFormatCode : function(character) {         var f = Date.formatCodes[character];         if (f) {           f = typeof f == 'function'? f() : f;           Date.formatCodes[character] = f; // reassign function result to prevent repeated execution         }         // note: unknown characters are treated as literals         return f || ("'" + String.escape(character) + "'");     },     // private     createFormat : function(format) {         var code = [],             special = false,             ch = '';         for (var i = 0; i < format.length; ++i) {             ch = format.charAt(i);             if (!special && ch == "\") {                 special = true;             } else if (special) {                 special = false;                 code.push("'" + String.escape(ch) + "'");             } else {                 code.push(Date.getFormatCode(ch))             }         }         Date.formatFunctions[format] = new Function("return " + code.join('+'));     },     // private     createParser : function() {         var code = [             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",                 "def = Date.defaults,",                 "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings             "if(results){",                 "{1}",                 "if(u != null){", // i.e. unix time is defined                     "v = new Date(u * 1000);", // give top priority to UNIX time                 "}else{",                     // create Date object representing midnight of the current day;                     // this will provide us with our date defaults                     // (note: clearTime() handles Daylight Saving Time automatically)                     "dt = (new Date()).clearTime();",                     // date calculations (note: these calculations create a dependency on Ext.num())                     "y = y >= 0? y : Ext.num(def.y, dt.getFullYear());",                     "m = m >= 0? m : Ext.num(def.m - 1, dt.getMonth());",                     "d = d >= 0? d : Ext.num(def.d, dt.getDate());",                     // time calculations (note: these calculations create a dependency on Ext.num())                     "h  = h || Ext.num(def.h, dt.getHours());",                     "i  = i || Ext.num(def.i, dt.getMinutes());",                     "s  = s || Ext.num(def.s, dt.getSeconds());",                     "ms = ms || Ext.num(def.ms, dt.getMilliseconds());",                     "if(z >= 0 && y >= 0){",                         // both the year and zero-based day of year are defined and >= 0.                         // these 2 values alone provide sufficient info to create a full date object                         // create Date object representing January 1st for the given year                         "v = new Date(y, 0, 1, h, i, s, ms);",                         // then add day of year, checking for Date "rollover" if necessary                         "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);",                     "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"                         "v = null;", // invalid date, so return null                     "}else{",                         // plain old Date object                         "v = new Date(y, m, d, h, i, s, ms);",                     "}",                 "}",             "}",             "if(v){",                 // favour UTC offset over GMT offset                 "if(zz != null){",                     // reset to UTC, then add offset                     "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",                 "}else if(o){",                     // reset to GMT, then add offset                     "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",                 "}",             "}",             "return v;"         ].join('n');         return function(format) {             var regexNum = Date.parseRegexes.length,                 currentGroup = 1,                 calc = [],                 regex = [],                 special = false,                 ch = "";             for (var i = 0; i < format.length; ++i) {                 ch = format.charAt(i);                 if (!special && ch == "\") {                     special = true;                 } else if (special) {                     special = false;                     regex.push(String.escape(ch));                 } else {                     var obj = $f(ch, currentGroup);                     currentGroup += obj.g;                     regex.push(obj.s);                     if (obj.g && obj.c) {                         calc.push(obj.c);                     }                 }             }             Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", "i");             Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join('')));         }     }(),     // private     parseCodes : {         /*          * Notes:          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'          */         d: {             g:1,             c:"d = parseInt(results[{0}], 10);n",             s:"(\d{2})" // day of month with leading zeroes (01 - 31)         },         j: {             g:1,             c:"d = parseInt(results[{0}], 10);n",             s:"(\d{1,2})" // day of month without leading zeroes (1 - 31)         },         D: function() {             for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names             return {                 g:0,                 c:null,                 s:"(?:" + a.join("|") +")"             }         },         l: function() {             return {                 g:0,                 c:null,                 s:"(?:" + Date.dayNames.join("|") + ")"             }         },         N: {             g:0,             c:null,             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))         },         S: {             g:0,             c:null,             s:"(?:st|nd|rd|th)"         },         w: {             g:0,             c:null,             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))         },         z: {             g:1,             c:"z = parseInt(results[{0}], 10);n",             s:"(\d{1,3})" // day of the year (0 - 364 (365 in leap years))         },         W: {             g:0,             c:null,             s:"(?:\d{2})" // ISO-8601 week number (with leading zero)         },         F: function() {             return {                 g:1,                 c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);n", // get localised month number                 s:"(" + Date.monthNames.join("|") + ")"             }         },         M: function() {             for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names             return Ext.applyIf({                 s:"(" + a.join("|") + ")"             }, $f("F"));         },         m: {             g:1,             c:"m = parseInt(results[{0}], 10) - 1;n",             s:"(\d{2})" // month number with leading zeros (01 - 12)         },         n: {             g:1,             c:"m = parseInt(results[{0}], 10) - 1;n",             s:"(\d{1,2})" // month number without leading zeros (1 - 12)         },         t: {             g:0,             c:null,             s:"(?:\d{2})" // no. of days in the month (28 - 31)         },         L: {             g:0,             c:null,             s:"(?:1|0)"         },         o: function() {             return $f("Y");         },         Y: {             g:1,             c:"y = parseInt(results[{0}], 10);n",             s:"(\d{4})" // 4-digit year         },         y: {             g:1,             c:"var ty = parseInt(results[{0}], 10);n"                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;n", // 2-digit year             s:"(\d{1,2})"         },         a: {             g:1,             c:"if (results[{0}] == 'am') {n"                 + "if (!h || h == 12) { h = 0; }n"                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",             s:"(am|pm)"         },         A: {             g:1,             c:"if (results[{0}] == 'AM') {n"                 + "if (!h || h == 12) { h = 0; }n"                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",             s:"(AM|PM)"         },         g: function() {             return $f("G");         },         G: {             g:1,             c:"h = parseInt(results[{0}], 10);n",             s:"(\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)         },         h: function() {             return $f("H");         },         H: {             g:1,             c:"h = parseInt(results[{0}], 10);n",             s:"(\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)         },         i: {             g:1,             c:"i = parseInt(results[{0}], 10);n",             s:"(\d{2})" // minutes with leading zeros (00 - 59)         },         s: {             g:1,             c:"s = parseInt(results[{0}], 10);n",             s:"(\d{2})" // seconds with leading zeros (00 - 59)         },         u: {             g:1,             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);n",             s:"(\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)         },         O: {             g:1,             c:[                 "o = results[{0}];",                 "var sn = o.substring(0,1),", // get + / - sign                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)                     "mn = o.substring(3,5) % 60;", // get minutes                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;n" // -12hrs <= GMT offset <= 14hrs             ].join("n"),             s: "([+-]\d{4})" // GMT offset in hrs and mins         },         P: {             g:1,             c:[                 "o = results[{0}];",                 "var sn = o.substring(0,1),", // get + / - sign                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)                     "mn = o.substring(4,6) % 60;", // get minutes                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;n" // -12hrs <= GMT offset <= 14hrs             ].join("n"),             s: "([+-]\d{2}:\d{2})" // GMT offset in hrs and mins (with colon separator)         },         T: {             g:0,             c:null,             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars         },         Z: {             g:1,             c:"zz = results[{0}] * 1;n" // -43200 <= UTC offset <= 50400                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;n",             s:"([+-]?\d{1,5})" // leading '+' sign is optional for UTC offset         },         c: function() {             var calc = [],                 arr = [                     $f("Y", 1), // year                     $f("m", 2), // month                     $f("d", 3), // day                     $f("h", 4), // hour                     $f("i", 5), // minute                     $f("s", 6), // second                     {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)                     {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified                         "if(results[8]) {", // timezone specified                             "if(results[8] == 'Z'){",                                 "zz = 0;", // UTC                             "}else if (results[8].indexOf(':') > -1){",                                 $f("P", 8).c, // timezone offset with colon separator                             "}else{",                                 $f("O", 8).c, // timezone offset without colon separator                             "}",                         "}"                     ].join('n')}                 ];             for (var i = 0, l = arr.length; i < l; ++i) {                 calc.push(arr[i].c);             }             return {                 g:1,                 c:calc.join(""),                 s:[                     arr[0].s, // year (required)                     "(?:", "-", arr[1].s, // month (optional)                         "(?:", "-", arr[2].s, // day (optional)                             "(?:",                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space                                 arr[3].s, ":", arr[4].s,  // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space                                 "(?::", arr[5].s, ")?", // seconds (optional)                                 "(?:(?:\.|,)(\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)                                 "(Z|(?:[-+]\d{2}(?::)?\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)                             ")?",                         ")?",                     ")?"                 ].join("")             }         },         U: {             g:1,             c:"u = parseInt(results[{0}], 10);n",             s:"(-?\d+)" // leading minus sign indicates seconds before UNIX epoch         }     } }); }()); Ext.apply(Date.prototype, {     // private     dateFormat : function(format) {         if (Date.formatFunctions[format] == null) {             Date.createFormat(format);         }         return Date.formatFunctions[format].call(this);     },     /**      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').      *      * Note: The date string returned by the javascript Date object's toString() method varies      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation      * from the GMT offset portion of the date string.      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).      */     getTimezone : function() {         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:         //         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot         // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev         //         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.         // step 1: (?:((.*)) -- find timezone in parentheses         // step 2: ([A-Z]{1,4})(?:[-+][0-9]{4})?(?: -?d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string         // step 3: remove all non uppercase characters found in step 1 and 2         return this.toString().replace(/^.* (?:((.*))|([A-Z]{1,4})(?:[-+][0-9]{4})?(?: -?d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");     },     /**      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').      */     getGMTOffset : function(colon) {         return (this.getTimezoneOffset() > 0 ? "-" : "+")             + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0")             + (colon ? ":" : "")             + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");     },     /**      * Get the numeric day number of the year, adjusted for leap year.      * @return {Number} 0 to 364 (365 in leap years).      */     getDayOfYear: function() {         var num = 0,             d = this.clone(),             m = this.getMonth(),             i;         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {             num += d.getDaysInMonth();         }         return num + this.getDate() - 1;     },     /**      * Get the numeric ISO-8601 week number of the year.      * (equivalent to the format specifier 'W', but without a leading zero).      * @return {Number} 1 to 53      */     getWeekOfYear : function() {         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm         var ms1d = 864e5, // milliseconds in a day             ms7d = 7 * ms1d; // milliseconds in a week         return function() { // return a closure so constants get calculated only once             var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number                 Wyr = new Date(AWN * ms7d).getUTCFullYear();             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;         }     }(),     /**      * Checks if the current date falls within a leap year.      * @return {Boolean} True if the current date falls within a leap year, false otherwise.      */     isLeapYear : function() {         var year = this.getFullYear();         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));     },     /**      * Get the first day of the current month, adjusted for leap year.  The returned value      * is the numeric day index within the week (0-6) which can be used in conjunction with      * the {@link #monthNames} array to retrieve the textual day name.      * Example:      * <pre><code> var dt = new Date('1/10/2007'); document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday' </code></pre>      * @return {Number} The day number (0-6).      */     getFirstDayOfMonth : function() {         var day = (this.getDay() - (this.getDate() - 1)) % 7;         return (day < 0) ? (day + 7) : day;     },     /**      * Get the last day of the current month, adjusted for leap year.  The returned value      * is the numeric day index within the week (0-6) which can be used in conjunction with      * the {@link #monthNames} array to retrieve the textual day name.      * Example:      * <pre><code> var dt = new Date('1/10/2007'); document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday' </code></pre>      * @return {Number} The day number (0-6).      */     getLastDayOfMonth : function() {         return this.getLastDateOfMonth().getDay();     },     /**      * Get the date of the first day of the month in which this date resides.      * @return {Date}      */     getFirstDateOfMonth : function() {         return new Date(this.getFullYear(), this.getMonth(), 1);     },     /**      * Get the date of the last day of the month in which this date resides.      * @return {Date}      */     getLastDateOfMonth : function() {         return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());     },     /**      * Get the number of days in the current month, adjusted for leap year.      * @return {Number} The number of days in the month.      */     getDaysInMonth: function() {         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];         return function() { // return a closure for efficiency             var m = this.getMonth();             return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m];         }     }(),     /**      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').      * @return {String} 'st, 'nd', 'rd' or 'th'.      */     getSuffix : function() {         switch (this.getDate()) {             case 1:             case 21:             case 31:                 return "st";             case 2:             case 22:                 return "nd";             case 3:             case 23:                 return "rd";             default:                 return "th";         }     },     /**      * Creates and returns a new Date instance with the exact same date value as the called instance.      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original      * variable will also be changed.  When the intention is to create a new variable that will not      * modify the original instance, you should create a clone.      *      * Example of correctly cloning a date:      * <pre><code> //wrong way: var orig = new Date('10/1/2006'); var copy = orig; copy.setDate(5); document.write(orig);  //returns 'Thu Oct 05 2006'! //correct way: var orig = new Date('10/1/2006'); var copy = orig.clone(); copy.setDate(5); document.write(orig);  //returns 'Thu Oct 01 2006' </code></pre>      * @return {Date} The new Date instance.      */     clone : function() {         return new Date(this.getTime());     },     /**      * Checks if the current date is affected by Daylight Saving Time (DST).      * @return {Boolean} True if the current date is affected by DST.      */     isDST : function() {         // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172         // courtesy of @geoffrey.mcgill         return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset();     },     /**      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,      * automatically adjusting for Daylight Saving Time (DST) where applicable.      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).      * @return {Date} this or the clone.      */     clearTime : function(clone) {         if (clone) {             return this.clone().clearTime();         }         // get current date before clearing time         var d = this.getDate();         // clear time         this.setHours(0);         this.setMinutes(0);         this.setSeconds(0);         this.setMilliseconds(0);         if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule             // increment hour until cloned date == current date             for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));             this.setDate(d);             this.setHours(c.getHours());         }         return this;     },     /**      * Provides a convenient method for performing basic date arithmetic. This method      * does not modify the Date instance being called - it creates and returns      * a new Date instance containing the resulting date value.      *      * Examples:      * <pre><code> // Basic usage: var dt = new Date('10/29/2006').add(Date.DAY, 5); document.write(dt); //returns 'Fri Nov 03 2006 00:00:00' // Negative values will be subtracted: var dt2 = new Date('10/1/2006').add(Date.DAY, -5); document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00' // You can even chain several calls together in one line: var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30); document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00' </code></pre>      *      * @param {String} interval A valid date interval enum value.      * @param {Number} value The amount to add to the current date.      * @return {Date} The new Date instance.      */     add : function(interval, value) {         var d = this.clone();         if (!interval || value === 0) return d;         switch(interval.toLowerCase()) {             case Date.MILLI:                 d.setMilliseconds(this.getMilliseconds() + value);                 break;             case Date.SECOND:                 d.setSeconds(this.getSeconds() + value);                 break;             case Date.MINUTE:                 d.setMinutes(this.getMinutes() + value);                 break;             case Date.HOUR:                 d.setHours(this.getHours() + value);                 break;             case Date.DAY:                 d.setDate(this.getDate() + value);                 break;             case Date.MONTH:                 var day = this.getDate();                 if (day > 28) {                     day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());                 }                 d.setDate(day);                 d.setMonth(this.getMonth() + value);                 break;             case Date.YEAR:                 d.setFullYear(this.getFullYear() + value);                 break;         }         return d;     },     /**      * Checks if this date falls on or between the given start and end dates.      * @param {Date} start Start date      * @param {Date} end End date      * @return {Boolean} true if this date falls on or between the given start and end dates.      */     between : function(start, end) {         var t = this.getTime();         return start.getTime() <= t && t <= end.getTime();     } }); /**  * Formats a date given the supplied format string.  * @param {String} format The format string.  * @return {String} The formatted date.  * @method format  */ Date.prototype.format = Date.prototype.dateFormat; // private if (Ext.isSafari && (navigator.userAgent.match(/WebKit/(d+)/)[1] || NaN) < 420) {     Ext.apply(Date.prototype, {         _xMonth : Date.prototype.setMonth,         _xDate  : Date.prototype.setDate,         // Bug in Safari 1.3, 2.0 (WebKit build < 420)         // Date.setMonth does not work consistently if iMonth is not 0-11         setMonth : function(num) {             if (num <= -1) {                 var n = Math.ceil(-num),                     back_year = Math.ceil(n / 12),                     month = (n % 12) ? 12 - n % 12 : 0;                 this.setFullYear(this.getFullYear() - back_year);                 return this._xMonth(month);             } else {                 return this._xMonth(num);             }         },         // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420)         // The parameter for Date.setDate() is converted to a signed byte integer in Safari         // http://brianary.blogspot.com/2006/03/safari-date-bug.html         setDate : function(d) {             // use setTime() to workaround setDate() bug             // subtract current day of month in milliseconds, then add desired day of month in milliseconds             return this.setTime(this.getTime() - (this.getDate() - d) * 864e5);         }     }); } /* Some basic Date tests... (requires Firebug) Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier // standard tests console.group('Standard Date.parseDate() Tests');     console.log('Date.parseDate("2009-01-05T11:38:56", "c")               = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting     console.log('Date.parseDate("2009-02-04T12:37:55.001000", "c")        = %o', Date.parseDate("2009-02-04T12:37:55.001000", "c")); // assumes browser's timezone setting     console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c")       = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC     console.log('Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")   = %o', Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")); // GMT-0530     console.log('Date.parseDate("2009-05-01T15:34:52,9876000+08:00", "c") = %o', Date.parseDate("2009-05-01T15:34:52,987600+08:00", "c")); // GMT+08:00 console.groupEnd(); // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime // -- accepts ALL 6 levels of date-time granularity console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)');     console.log('Date.parseDate("1997", "c")                              = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997)     console.log('Date.parseDate("1997-07", "c")                           = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07)     console.log('Date.parseDate("1997-07-16", "c")                        = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16)     console.log('Date.parseDate("1997-07-16T19:20+01:00", "c")            = %o', Date.parseDate("1997-07-16T19:20+01:00", "c")); // YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00)     console.log('Date.parseDate("1997-07-16T19:20:30+01:00", "c")         = %o', Date.parseDate("1997-07-16T19:20:30+01:00", "c")); // YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:30+01:00)     console.log('Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")      = %o', Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")); // YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)     console.log('Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")      = %o', Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")); // YYYY-MM-DD hh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)     console.log('Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)= %o', Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)); // strict date parsing with invalid month value console.groupEnd(); //*//**  * @class Ext.util.MixedCollection  * @extends Ext.util.Observable  * A Collection class that maintains both numeric indexes and keys and exposes events.  * @constructor  * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}  * function should add function references to the collection. Defaults to  * <tt>false</tt>.  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection  * and return the key value for that item.  This is used when available to look up the key on items that  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is  * equivalent to providing an implementation for the {@link #getKey} method.  */ Ext.util.MixedCollection = function(allowFunctions, keyFn){     this.items = [];     this.map = {};     this.keys = [];     this.length = 0;     this.addEvents(         /**          * @event clear          * Fires when the collection is cleared.          */         'clear',         /**          * @event add          * Fires when an item is added to the collection.          * @param {Number} index The index at which the item was added.          * @param {Object} o The item added.          * @param {String} key The key associated with the added item.          */         'add',         /**          * @event replace          * Fires when an item is replaced in the collection.          * @param {String} key he key associated with the new added.          * @param {Object} old The item being replaced.          * @param {Object} new The new item.          */         'replace',         /**          * @event remove          * Fires when an item is removed from the collection.          * @param {Object} o The item being removed.          * @param {String} key (optional) The key associated with the removed item.          */         'remove',         'sort'     );     this.allowFunctions = allowFunctions === true;     if(keyFn){         this.getKey = keyFn;     }     Ext.util.MixedCollection.superclass.constructor.call(this); }; Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {     /**      * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}      * function should add function references to the collection. Defaults to      * <tt>false</tt>.      */     allowFunctions : false,     /**      * Adds an item to the collection. Fires the {@link #add} event when complete.      * @param {String} key <p>The key to associate with the item, or the new item.</p>      * <p>If a {@link #getKey} implementation was specified for this MixedCollection,      * or if the key of the stored items is in a property called <tt><b>id</b></tt>,      * the MixedCollection will be able to <i>derive</i> the key for the new item.      * In this case just pass the new item in this parameter.</p>      * @param {Object} o The item to add.      * @return {Object} The item added.      */     add : function(key, o){         if(arguments.length == 1){             o = arguments[0];             key = this.getKey(o);         }         if(typeof key != 'undefined' && key !== null){             var old = this.map[key];             if(typeof old != 'undefined'){                 return this.replace(key, o);             }             this.map[key] = o;         }         this.length++;         this.items.push(o);         this.keys.push(key);         this.fireEvent('add', this.length-1, o, key);         return o;     },     /**       * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation       * simply returns <b><code>item.id</code></b> but you can provide your own implementation       * to return a different value as in the following examples:<pre><code> // normal way var mc = new Ext.util.MixedCollection(); mc.add(someEl.dom.id, someEl); mc.add(otherEl.dom.id, otherEl); //and so on // using getKey var mc = new Ext.util.MixedCollection(); mc.getKey = function(el){    return el.dom.id; }; mc.add(someEl); mc.add(otherEl); // or via the constructor var mc = new Ext.util.MixedCollection(false, function(el){    return el.dom.id; }); mc.add(someEl); mc.add(otherEl);      * </code></pre>      * @param {Object} item The item for which to find the key.      * @return {Object} The key for the passed item.      */     getKey : function(o){          return o.id;     },     /**      * Replaces an item in the collection. Fires the {@link #replace} event when complete.      * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>      * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key      * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection      * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item      * with one having the same key value, then just pass the replacement item in this parameter.</p>      * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate      * with that key.      * @return {Object}  The new item.      */     replace : function(key, o){         if(arguments.length == 1){             o = arguments[0];             key = this.getKey(o);         }         var old = this.map[key];         if(typeof key == 'undefined' || key === null || typeof old == 'undefined'){              return this.add(key, o);         }         var index = this.indexOfKey(key);         this.items[index] = o;         this.map[key] = o;         this.fireEvent('replace', key, old, o);         return o;     },     /**      * Adds all elements of an Array or an Object to the collection.      * @param {Object/Array} objs An Object containing properties which will be added      * to the collection, or an Array of values, each of which are added to the collection.      * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>      * has been set to <tt>true</tt>.      */     addAll : function(objs){         if(arguments.length > 1 || Ext.isArray(objs)){             var args = arguments.length > 1 ? arguments : objs;             for(var i = 0, len = args.length; i < len; i++){                 this.add(args[i]);             }         }else{             for(var key in objs){                 if(this.allowFunctions || typeof objs[key] != 'function'){                     this.add(key, objs[key]);                 }             }         }     },     /**      * Executes the specified function once for every item in the collection, passing the following arguments:      * <div class="mdetail-params"><ul>      * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>      * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>      * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>      * </ul></div>      * The function should return a boolean value. Returning false from the function will stop the iteration.      * @param {Function} fn The function to execute for each item.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.      */     each : function(fn, scope){         var items = [].concat(this.items); // each safe for removal         for(var i = 0, len = items.length; i < len; i++){             if(fn.call(scope || items[i], items[i], i, len) === false){                 break;             }         }     },     /**      * Executes the specified function once for every key in the collection, passing each      * key, and its associated item as the first two parameters.      * @param {Function} fn The function to execute for each item.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.      */     eachKey : function(fn, scope){         for(var i = 0, len = this.keys.length; i < len; i++){             fn.call(scope || window, this.keys[i], this.items[i], i, len);         }     },     /**      * Returns the first item in the collection which elicits a true return value from the      * passed selection function.      * @param {Function} fn The selection function to execute for each item.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.      * @return {Object} The first item in the collection which returned true from the selection function.      */     find : function(fn, scope){         for(var i = 0, len = this.items.length; i < len; i++){             if(fn.call(scope || window, this.items[i], this.keys[i])){                 return this.items[i];             }         }         return null;     },     /**      * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.      * @param {Number} index The index to insert the item at.      * @param {String} key The key to associate with the new item, or the item itself.      * @param {Object} o (optional) If the second parameter was a key, the new item.      * @return {Object} The item inserted.      */     insert : function(index, key, o){         if(arguments.length == 2){             o = arguments[1];             key = this.getKey(o);         }         if(this.containsKey(key)){             this.suspendEvents();             this.removeKey(key);             this.resumeEvents();         }         if(index >= this.length){             return this.add(key, o);         }         this.length++;         this.items.splice(index, 0, o);         if(typeof key != 'undefined' && key !== null){             this.map[key] = o;         }         this.keys.splice(index, 0, key);         this.fireEvent('add', index, o, key);         return o;     },     /**      * Remove an item from the collection.      * @param {Object} o The item to remove.      * @return {Object} The item removed or false if no item was removed.      */     remove : function(o){         return this.removeAt(this.indexOf(o));     },     /**      * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.      * @param {Number} index The index within the collection of the item to remove.      * @return {Object} The item removed or false if no item was removed.      */     removeAt : function(index){         if(index < this.length && index >= 0){             this.length--;             var o = this.items[index];             this.items.splice(index, 1);             var key = this.keys[index];             if(typeof key != 'undefined'){                 delete this.map[key];             }             this.keys.splice(index, 1);             this.fireEvent('remove', o, key);             return o;         }         return false;     },     /**      * Removed an item associated with the passed key fom the collection.      * @param {String} key The key of the item to remove.      * @return {Object} The item removed or false if no item was removed.      */     removeKey : function(key){         return this.removeAt(this.indexOfKey(key));     },     /**      * Returns the number of items in the collection.      * @return {Number} the number of items in the collection.      */     getCount : function(){         return this.length;     },     /**      * Returns index within the collection of the passed Object.      * @param {Object} o The item to find the index of.      * @return {Number} index of the item. Returns -1 if not found.      */     indexOf : function(o){         return this.items.indexOf(o);     },     /**      * Returns index within the collection of the passed key.      * @param {String} key The key to find the index of.      * @return {Number} index of the key.      */     indexOfKey : function(key){         return this.keys.indexOf(key);     },     /**      * Returns the item associated with the passed key OR index.      * Key has priority over index.  This is the equivalent      * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.      * @param {String/Number} key The key or index of the item.      * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.      * If an item was found, but is a Class, returns <tt>null</tt>.      */     item : function(key){         var mk = this.map[key],             item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;         return !Ext.isFunction(item) || this.allowFunctions ? item : null; // for prototype!     },     /**      * Returns the item at the specified index.      * @param {Number} index The index of the item.      * @return {Object} The item at the specified index.      */     itemAt : function(index){         return this.items[index];     },     /**      * Returns the item associated with the passed key.      * @param {String/Number} key The key of the item.      * @return {Object} The item associated with the passed key.      */     key : function(key){         return this.map[key];     },     /**      * Returns true if the collection contains the passed Object as an item.      * @param {Object} o  The Object to look for in the collection.      * @return {Boolean} True if the collection contains the Object as an item.      */     contains : function(o){         return this.indexOf(o) != -1;     },     /**      * Returns true if the collection contains the passed Object as a key.      * @param {String} key The key to look for in the collection.      * @return {Boolean} True if the collection contains the Object as a key.      */     containsKey : function(key){         return typeof this.map[key] != 'undefined';     },     /**      * Removes all items from the collection.  Fires the {@link #clear} event when complete.      */     clear : function(){         this.length = 0;         this.items = [];         this.keys = [];         this.map = {};         this.fireEvent('clear');     },     /**      * Returns the first item in the collection.      * @return {Object} the first item in the collection..      */     first : function(){         return this.items[0];     },     /**      * Returns the last item in the collection.      * @return {Object} the last item in the collection..      */     last : function(){         return this.items[this.length-1];     },     /**      * @private      * @param {String} property Property to sort by ('key', 'value', or 'index')      * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.      * @param {Function} fn (optional) Comparison function that defines the sort order.      * Defaults to sorting by numeric value.      */     _sort : function(property, dir, fn){         var i,             len,             dsc = String(dir).toUpperCase() == 'DESC' ? -1 : 1,             c = [], k = this.keys, items = this.items;         fn = fn || function(a, b){             return a-b;         };         for(i = 0, len = items.length; i < len; i++){             c[c.length] = {key: k[i], value: items[i], index: i};         }         c.sort(function(a, b){             var v = fn(a[property], b[property]) * dsc;             if(v === 0){                 v = (a.index < b.index ? -1 : 1);             }             return v;         });         for(i = 0, len = c.length; i < len; i++){             items[i] = c[i].value;             k[i] = c[i].key;         }         this.fireEvent('sort', this);     },     /**      * Sorts this collection by <b>item</b> value with the passed comparison function.      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.      * @param {Function} fn (optional) Comparison function that defines the sort order.      * Defaults to sorting by numeric value.      */     sort : function(dir, fn){         this._sort('value', dir, fn);     },     /**      * Sorts this collection by <b>key</b>s.      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.      * @param {Function} fn (optional) Comparison function that defines the sort order.      * Defaults to sorting by case insensitive string.      */     keySort : function(dir, fn){         this._sort('key', dir, fn || function(a, b){             var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);         });     },     /**      * Returns a range of items in this collection      * @param {Number} startIndex (optional) The starting index. Defaults to 0.      * @param {Number} endIndex (optional) The ending index. Defaults to the last item.      * @return {Array} An array of items      */     getRange : function(start, end){         var items = this.items;         if(items.length < 1){             return [];         }         start = start || 0;         end = Math.min(typeof end == 'undefined' ? this.length-1 : end, this.length-1);         var i, r = [];         if(start <= end){             for(i = start; i <= end; i++) {                 r[r.length] = items[i];             }         }else{             for(i = start; i >= end; i--) {                 r[r.length] = items[i];             }         }         return r;     },     /**      * Filter the <i>objects</i> in this collection by a specific property.      * Returns a new collection that has been filtered.      * @param {String} property A property on your objects      * @param {String/RegExp} value Either string that the property values      * should start with or a RegExp to test against the property      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).      * @return {MixedCollection} The new filtered collection      */     filter : function(property, value, anyMatch, caseSensitive){         if(Ext.isEmpty(value, false)){             return this.clone();         }         value = this.createValueMatcher(value, anyMatch, caseSensitive);         return this.filterBy(function(o){             return o && value.test(o[property]);         });     },     /**      * Filter by a function. Returns a <i>new</i> collection that has been filtered.      * The passed function will be called with each object in the collection.      * If the function returns true, the value is included otherwise it is filtered.      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.      * @return {MixedCollection} The new filtered collection      */     filterBy : function(fn, scope){         var r = new Ext.util.MixedCollection();         r.getKey = this.getKey;         var k = this.keys, it = this.items;         for(var i = 0, len = it.length; i < len; i++){             if(fn.call(scope||this, it[i], k[i])){                 r.add(k[i], it[i]);             }         }         return r;     },     /**      * Finds the index of the first matching object in this collection by a specific property/value.      * @param {String} property The name of a property on your objects.      * @param {String/RegExp} value A string that the property values      * should start with or a RegExp to test against the property.      * @param {Number} start (optional) The index to start searching at (defaults to 0).      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.      * @return {Number} The matched index or -1      */     findIndex : function(property, value, start, anyMatch, caseSensitive){         if(Ext.isEmpty(value, false)){             return -1;         }         value = this.createValueMatcher(value, anyMatch, caseSensitive);         return this.findIndexBy(function(o){             return o && value.test(o[property]);         }, null, start);     },     /**      * Find the index of the first matching object in this collection by a function.      * If the function returns <i>true</i> it is considered a match.      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.      * @param {Number} start (optional) The index to start searching at (defaults to 0).      * @return {Number} The matched index or -1      */     findIndexBy : function(fn, scope, start){         var k = this.keys, it = this.items;         for(var i = (start||0), len = it.length; i < len; i++){             if(fn.call(scope||this, it[i], k[i])){                 return i;             }         }         return -1;     },     // private     createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {         if (!value.exec) { // not a regex             var er = Ext.escapeRe;             value = String(value);             if (anyMatch === true) {                 value = er(value);             } else {                 value = '^' + er(value);                 if (exactMatch === true) {                     value += '$';                 }             }             value = new RegExp(value, caseSensitive ? '' : 'i');          }          return value;     },     /**      * Creates a shallow copy of this collection      * @return {MixedCollection}      */     clone : function(){         var r = new Ext.util.MixedCollection();         var k = this.keys, it = this.items;         for(var i = 0, len = it.length; i < len; i++){             r.add(k[i], it[i]);         }         r.getKey = this.getKey;         return r;     } }); /**  * This method calls {@link #item item()}.  * Returns the item associated with the passed key OR index. Key has priority  * over index.  This is the equivalent of calling {@link #key} first, then if  * nothing matched calling {@link #itemAt}.  * @param {String/Number} key The key or index of the item.  * @return {Object} If the item is found, returns the item.  If the item was  * not found, returns <tt>undefined</tt>. If an item was found, but is a Class,  * returns <tt>null</tt>.  */ Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item;/**  * @class Ext.util.JSON  * Modified version of Douglas Crockford"s json.js that doesn"t  * mess with the Object prototype  * http://www.json.org/js.html  * @singleton  */ Ext.util.JSON = new (function(){     var useHasOwn = !!{}.hasOwnProperty,         isNative = function() {             var useNative = null;             return function() {                 if (useNative === null) {                     useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';                 }                          return useNative;             };         }(),         pad = function(n) {             return n < 10 ? "0" + n : n;         },         doDecode = function(json){             return eval("(" + json + ')');             },         doEncode = function(o){             if(!Ext.isDefined(o) || o === null){                 return "null";             }else if(Ext.isArray(o)){                 return encodeArray(o);             }else if(Ext.isDate(o)){                 return Ext.util.JSON.encodeDate(o);             }else if(Ext.isString(o)){                 return encodeString(o);             }else if(typeof o == "number"){                 //don't use isNumber here, since finite checks happen inside isNumber                 return isFinite(o) ? String(o) : "null";             }else if(Ext.isBoolean(o)){                 return String(o);             }else {                 var a = ["{"], b, i, v;                 for (i in o) {                     // don't encode DOM objects                     if(!o.getElementsByTagName){                         if(!useHasOwn || o.hasOwnProperty(i)) {                             v = o[i];                             switch (typeof v) {                             case "undefined":                             case "function":                             case "unknown":                                 break;                             default:                                 if(b){                                     a.push(',');                                 }                                 a.push(doEncode(i), ":",                                         v === null ? "null" : doEncode(v));                                 b = true;                             }                         }                     }                 }                 a.push("}");                 return a.join("");             }             },         m = {             "b": '\b',             "t": '\t',             "n": '\n',             "f": '\f',             "r": '\r',             '"' : '\"',             "\": '\\'         },         encodeString = function(s){             if (/["\x00-x1f]/.test(s)) {                 return '"' + s.replace(/([x00-x1f\"])/g, function(a, b) {                     var c = m[b];                     if(c){                         return c;                     }                     c = b.charCodeAt();                     return "\u00" +                         Math.floor(c / 16).toString(16) +                         (c % 16).toString(16);                 }) + '"';             }             return '"' + s + '"';         },         encodeArray = function(o){             var a = ["["], b, i, l = o.length, v;                 for (i = 0; i < l; i += 1) {                     v = o[i];                     switch (typeof v) {                         case "undefined":                         case "function":                         case "unknown":                             break;                         default:                             if (b) {                                 a.push(',');                             }                             a.push(v === null ? "null" : Ext.util.JSON.encode(v));                             b = true;                     }                 }                 a.push("]");                 return a.join("");         };     this.encodeDate = function(o){         return '"' + o.getFullYear() + "-" +                 pad(o.getMonth() + 1) + "-" +                 pad(o.getDate()) + "T" +                 pad(o.getHours()) + ":" +                 pad(o.getMinutes()) + ":" +                 pad(o.getSeconds()) + '"';     };     /**      * Encodes an Object, Array or other value      * @param {Mixed} o The variable to encode      * @return {String} The JSON string      */     this.encode = function() {         var ec;         return function(o) {             if (!ec) {                 // setup encoding function on first access                 ec = isNative() ? JSON.stringify : doEncode;             }             return ec(o);         };     }();     /**      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.      * @param {String} json The JSON string      * @return {Object} The resulting object      */     this.decode = function() {         var dc;         return function(json) {             if (!dc) {                 // setup decoding function on first access                 dc = isNative() ? JSON.parse : doDecode;             }             return dc(json);         };     }(); })(); /**  * Shorthand for {@link Ext.util.JSON#encode}  * @param {Mixed} o The variable to encode  * @return {String} The JSON string  * @member Ext  * @method encode  */ Ext.encode = Ext.util.JSON.encode; /**  * Shorthand for {@link Ext.util.JSON#decode}  * @param {String} json The JSON string  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.  * @return {Object} The resulting object  * @member Ext  * @method decode  */ Ext.decode = Ext.util.JSON.decode; /**
  608.  * @class Ext.util.Format
  609.  * Reusable data formatting functions
  610.  * @singleton
  611.  */
  612. Ext.util.Format = function(){
  613.     var trimRe = /^s+|s+$/g,
  614.         stripTagsRE = /</?[^>]+>/gi,
  615.         stripScriptsRe = /(?:<script.*?>)((n|r|.)*?)(?:</script>)/ig,
  616.         nl2brRe = /r?n/g;
  617.         
  618.     return {
  619.         /**
  620.          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
  621.          * @param {String} value The string to truncate
  622.          * @param {Number} length The maximum length to allow before truncating
  623.          * @param {Boolean} word True to try to find a common work break
  624.          * @return {String} The converted text
  625.          */
  626.         ellipsis : function(value, len, word){
  627.             if(value && value.length > len){
  628.                 if(word){
  629.                     var vs = value.substr(0, len - 2),
  630.                         index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
  631.                     if(index == -1 || index < (len - 15)){
  632.                         return value.substr(0, len - 3) + "...";
  633.                     }else{
  634.                         return vs.substr(0, index) + "...";
  635.                     }
  636.                 } else{
  637.                     return value.substr(0, len - 3) + "...";
  638.                 }
  639.             }
  640.             return value;
  641.         },
  642.         /**
  643.          * Checks a reference and converts it to empty string if it is undefined
  644.          * @param {Mixed} value Reference to check
  645.          * @return {Mixed} Empty string if converted, otherwise the original value
  646.          */
  647.         undef : function(value){
  648.             return value !== undefined ? value : "";
  649.         },
  650.         /**
  651.          * Checks a reference and converts it to the default value if it's empty
  652.          * @param {Mixed} value Reference to check
  653.          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
  654.          * @return {String}
  655.          */
  656.         defaultValue : function(value, defaultValue){
  657.             return value !== undefined && value !== '' ? value : defaultValue;
  658.         },
  659.         /**
  660.          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
  661.          * @param {String} value The string to encode
  662.          * @return {String} The encoded text
  663.          */
  664.         htmlEncode : function(value){
  665.             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
  666.         },
  667.         /**
  668.          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
  669.          * @param {String} value The string to decode
  670.          * @return {String} The decoded text
  671.          */
  672.         htmlDecode : function(value){
  673.             return !value ? value : String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");
  674.         },
  675.         /**
  676.          * Trims any whitespace from either side of a string
  677.          * @param {String} value The text to trim
  678.          * @return {String} The trimmed text
  679.          */
  680.         trim : function(value){
  681.             return String(value).replace(trimRe, "");
  682.         },
  683.         /**
  684.          * Returns a substring from within an original string
  685.          * @param {String} value The original text
  686.          * @param {Number} start The start index of the substring
  687.          * @param {Number} length The length of the substring
  688.          * @return {String} The substring
  689.          */
  690.         substr : function(value, start, length){
  691.             return String(value).substr(start, length);
  692.         },
  693.         /**
  694.          * Converts a string to all lower case letters
  695.          * @param {String} value The text to convert
  696.          * @return {String} The converted text
  697.          */
  698.         lowercase : function(value){
  699.             return String(value).toLowerCase();
  700.         },
  701.         /**
  702.          * Converts a string to all upper case letters
  703.          * @param {String} value The text to convert
  704.          * @return {String} The converted text
  705.          */
  706.         uppercase : function(value){
  707.             return String(value).toUpperCase();
  708.         },
  709.         /**
  710.          * Converts the first character only of a string to upper case
  711.          * @param {String} value The text to convert
  712.          * @return {String} The converted text
  713.          */
  714.         capitalize : function(value){
  715.             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
  716.         },
  717.         // private
  718.         call : function(value, fn){
  719.             if(arguments.length > 2){
  720.                 var args = Array.prototype.slice.call(arguments, 2);
  721.                 args.unshift(value);
  722.                 return eval(fn).apply(window, args);
  723.             }else{
  724.                 return eval(fn).call(window, value);
  725.             }
  726.         },
  727.         /**
  728.          * Format a number as US currency
  729.          * @param {Number/String} value The numeric value to format
  730.          * @return {String} The formatted currency string
  731.          */
  732.         usMoney : function(v){
  733.             v = (Math.round((v-0)*100))/100;
  734.             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
  735.             v = String(v);
  736.             var ps = v.split('.'),
  737.                 whole = ps[0],
  738.                 sub = ps[1] ? '.'+ ps[1] : '.00',
  739.                 r = /(d+)(d{3})/;
  740.             while (r.test(whole)) {
  741.                 whole = whole.replace(r, '$1' + ',' + '$2');
  742.             }
  743.             v = whole + sub;
  744.             if(v.charAt(0) == '-'){
  745.                 return '-$' + v.substr(1);
  746.             }
  747.             return "$" +  v;
  748.         },
  749.         /**
  750.          * Parse a value into a formatted date using the specified format pattern.
  751.          * @param {String/Date} value The value to format (Strings must conform to the format expected by the javascript Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method)
  752.          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
  753.          * @return {String} The formatted date string
  754.          */
  755.         date : function(v, format){
  756.             if(!v){
  757.                 return "";
  758.             }
  759.             if(!Ext.isDate(v)){
  760.                 v = new Date(Date.parse(v));
  761.             }
  762.             return v.dateFormat(format || "m/d/Y");
  763.         },
  764.         /**
  765.          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
  766.          * @param {String} format Any valid date format string
  767.          * @return {Function} The date formatting function
  768.          */
  769.         dateRenderer : function(format){
  770.             return function(v){
  771.                 return Ext.util.Format.date(v, format);
  772.             };
  773.         },
  774.         
  775.         /**
  776.          * Strips all HTML tags
  777.          * @param {Mixed} value The text from which to strip tags
  778.          * @return {String} The stripped text
  779.          */
  780.         stripTags : function(v){
  781.             return !v ? v : String(v).replace(stripTagsRE, "");
  782.         },
  783.         /**
  784.          * Strips all script tags
  785.          * @param {Mixed} value The text from which to strip script tags
  786.          * @return {String} The stripped text
  787.          */
  788.         stripScripts : function(v){
  789.             return !v ? v : String(v).replace(stripScriptsRe, "");
  790.         },
  791.         /**
  792.          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
  793.          * @param {Number/String} size The numeric value to format
  794.          * @return {String} The formatted file size
  795.          */
  796.         fileSize : function(size){
  797.             if(size < 1024) {
  798.                 return size + " bytes";
  799.             } else if(size < 1048576) {
  800.                 return (Math.round(((size*10) / 1024))/10) + " KB";
  801.             } else {
  802.                 return (Math.round(((size*10) / 1048576))/10) + " MB";
  803.             }
  804.         },
  805.         /**
  806.          * It does simple math for use in a template, for example:<pre><code>
  807.          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
  808.          * </code></pre>
  809.          * @return {Function} A function that operates on the passed value.
  810.          */
  811.         math : function(){
  812.             var fns = {};
  813.             return function(v, a){
  814.                 if(!fns[a]){
  815.                     fns[a] = new Function('v', 'return v ' + a + ';');
  816.                 }
  817.                 return fns[a](v);
  818.             }
  819.         }(),
  820.         /**
  821.          * Rounds the passed number to the required decimal precision.
  822.          * @param {Number/String} value The numeric value to round.
  823.          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
  824.          * @return {Number} The rounded value.
  825.          */
  826.         round : function(value, precision) {
  827.             var result = Number(value);
  828.             if (typeof precision == 'number') {
  829.                 precision = Math.pow(10, precision);
  830.                 result = Math.round(value * precision) / precision;
  831.             }
  832.             return result;
  833.         },
  834.         /**
  835.          * Formats the number according to the format string.
  836.          * <div style="margin-left:40px">examples (123456.789):
  837.          * <div style="margin-left:10px">
  838.          * 0 - (123456) show only digits, no precision<br>
  839.          * 0.00 - (123456.78) show only digits, 2 precision<br>
  840.          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
  841.          * 0,000 - (123,456) show comma and digits, no precision<br>
  842.          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
  843.          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
  844.          * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.
  845.          * For example: 0.000,00/i
  846.          * </div></div>
  847.          * @param {Number} v The number to format.
  848.          * @param {String} format The way you would like to format this text.
  849.          * @return {String} The formatted number.
  850.          */
  851.         number: function(v, format) {
  852.             if(!format){
  853.         return v;
  854.     }
  855.     v = Ext.num(v, NaN);
  856.             if (isNaN(v)){
  857.                 return '';
  858.             }
  859.     var comma = ',',
  860.         dec = '.',
  861.         i18n = false,
  862.         neg = v < 0;
  863.     v = Math.abs(v);
  864.     if(format.substr(format.length - 2) == '/i'){
  865.         format = format.substr(0, format.length - 2);
  866.         i18n = true;
  867.         comma = '.';
  868.         dec = ',';
  869.     }
  870.     var hasComma = format.indexOf(comma) != -1, 
  871.         psplit = (i18n ? format.replace(/[^d,]/g, '') : format.replace(/[^d.]/g, '')).split(dec);
  872.     if(1 < psplit.length){
  873.         v = v.toFixed(psplit[1].length);
  874.     }else if(2 < psplit.length){
  875.         throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
  876.     }else{
  877.         v = v.toFixed(0);
  878.     }
  879.     var fnum = v.toString();
  880.     if(hasComma){
  881.         psplit = fnum.split('.');
  882.         var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;
  883.         for(var i = 0; i < j; i += n){
  884.             if(i != 0){
  885.                 n = 3;
  886.             }
  887.             parr[parr.length] = cnum.substr(i, n);
  888.             m -= 1;
  889.         }
  890.         fnum = parr.join(comma);
  891.         if(psplit[1]){
  892.             fnum += dec + psplit[1];
  893.         }
  894.     }
  895.     return (neg ? '-' : '') + format.replace(/[d,?.?]+/, fnum);
  896.         },
  897.         /**
  898.          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
  899.          * @param {String} format Any valid number format string for {@link #number}
  900.          * @return {Function} The number formatting function
  901.          */
  902.         numberRenderer : function(format){
  903.             return function(v){
  904.                 return Ext.util.Format.number(v, format);
  905.             };
  906.         },
  907.         /**
  908.          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
  909.          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
  910.          * if the value is 0 or greater than 1.
  911.          * @param {Number} value The value to compare against
  912.          * @param {String} singular The singular form of the word
  913.          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
  914.          */
  915.         plural : function(v, s, p){
  916.             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
  917.         },
  918.         
  919.         /**
  920.          * Converts newline characters to the HTML tag &lt;br/>
  921.          * @param {String} The string value to format.
  922.          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
  923.          */
  924.         nl2br : function(v){
  925.             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
  926.         }
  927.     }
  928. }();
  929. /**  * @class Ext.XTemplate  * @extends Ext.Template  * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>  * <li>Autofilling arrays using templates and sub-templates</li>  * <li>Conditional processing with basic comparison operators</li>  * <li>Basic math function support</li>  * <li>Execute arbitrary inline code with special built-in template variables</li>  * <li>Custom member functions</li>  * <li>Many special tags and built-in operators that aren't defined as part of  * the API, but are supported in the templates that can be created</li>  * </ul></div></p>  * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>  * <li>{@link Ext.DataView}</li>  * <li>{@link Ext.ListView}</li>  * <li>{@link Ext.form.ComboBox}</li>  * <li>{@link Ext.grid.TemplateColumn}</li>  * <li>{@link Ext.grid.GroupingView}</li>  * <li>{@link Ext.menu.Item}</li>  * <li>{@link Ext.layout.MenuLayout}</li>  * <li>{@link Ext.ColorPalette}</li>  * </ul></div></p>  *   * <p>For example usage {@link #XTemplate see the constructor}.</p>    *     * @constructor  * The {@link Ext.Template#Template Ext.Template constructor} describes  * the acceptable parameters to pass to the constructor. The following  * examples demonstrate all of the supported features.</p>  *   * <div class="mdetail-params"><ul>  *   * <li><b><u>Sample Data</u></b>   * <div class="sub-desc">  * <p>This is the data object used for reference in each code example:</p>  * <pre><code> var data = {     name: 'Jack Slocum',     title: 'Lead Developer',     company: 'Ext JS, LLC',     email: 'jack@extjs.com',     address: '4 Red Bulls Drive',     city: 'Cleveland',     state: 'Ohio',     zip: '44102',     drinks: ['Red Bull', 'Coffee', 'Water'],     kids: [{         name: 'Sara Grace',         age:3     },{         name: 'Zachary',         age:2     },{         name: 'John James',         age:0     }] };  * </code></pre>  * </div>  * </li>  *   *   * <li><b><u>Auto filling of arrays</u></b>   * <div class="sub-desc">  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used  * to process the provided data object:  * <ul>  * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,  * repeating the template block inside the <tt>tpl</tt> tag for each item in the  * array.</li>  * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>  * <li>While processing an array, the special variable <tt>{#}</tt>  * will provide the current array index + 1 (starts at 1, not 0).</li>  * </ul>  * </p>  * <pre><code> &lt;tpl <b>for</b>=".">...&lt;/tpl>       // loop through array at root node &lt;tpl <b>for</b>="foo">...&lt;/tpl>     // loop through array at foo node &lt;tpl <b>for</b>="foo.bar">...&lt;/tpl> // loop through array at foo.bar node  * </code></pre>  * Using the sample data above:  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Kids: ',     '&lt;tpl <b>for</b>=".">',       // process the data.kids node         '&lt;p>{#}. {name}&lt;/p>',  // use current array index to autonumber     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object  * </code></pre>  * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged  * to access specified members of the provided data object to populate the template:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Title: {title}&lt;/p>',     '&lt;p>Company: {company}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl <b>for="kids"</b>>',     // interrogate the kids property within the data         '&lt;p>{name}&lt;/p>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data);  // pass the root node of the data object  * </code></pre>  * <p>Flat arrays that contain values (and not objects) can be auto-rendered  * using the special <b><tt>{.}</tt></b> variable inside a loop.  This variable  * will represent the value of the array at the current index:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>{name}&#39;s favorite beverages:&lt;/p>',     '&lt;tpl for="drinks">',        '&lt;div> - {.}&lt;/div>',     '&lt;/tpl>' ); tpl.overwrite(panel.body, data);  * </code></pre>  * <p>When processing a sub-template, for example while looping through a child array,  * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl for="kids">',         '&lt;tpl if="age > 1">',             '&lt;p>{name}&lt;/p>',             '&lt;p>Dad: {<b>parent</b>.name}&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data);  * </code></pre>  * </div>  * </li>  *   *   * <li><b><u>Conditional processing with basic comparison operators</u></b>   * <div class="sub-desc">  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used  * to provide conditional checks for deciding whether or not to render specific  * parts of the template. Notes:<div class="sub-desc"><ul>  * <li>Double quotes must be encoded if used within the conditional</li>  * <li>There is no <tt>else</tt> operator &mdash; if needed, two opposite  * <tt>if</tt> statements should be used.</li>  * </ul></div>  * <pre><code> &lt;tpl if="age &gt; 1 &amp;&amp; age &lt; 10">Child&lt;/tpl> &lt;tpl if="age >= 10 && age < 18">Teenager&lt;/tpl> &lt;tpl <b>if</b>="this.isGirl(name)">...&lt;/tpl> &lt;tpl <b>if</b>="id=='download'">...&lt;/tpl> &lt;tpl <b>if</b>="needsIcon">&lt;img src="{icon}" class="{iconCls}"/>&lt;/tpl> // no good: &lt;tpl if="name == "Jack"">Hello&lt;/tpl> // encode &#34; if it is part of the condition, e.g. &lt;tpl if="name == &#38;quot;Jack&#38;quot;">Hello&lt;/tpl>  * </code></pre>  * Using the sample data above:  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl for="kids">',         '&lt;tpl if="age > 1">',             '&lt;p>{name}&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data);  * </code></pre>  * </div>  * </li>  *   *   * <li><b><u>Basic math support</u></b>   * <div class="sub-desc">  * <p>The following basic math operators may be applied directly on numeric  * data values:</p><pre>  * + - * /  * </pre>  * For example:  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl for="kids">',         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded             '&lt;p>{#}: {name}&lt;/p>',  // <-- Auto-number each item             '&lt;p>In 5 Years: {age+5}&lt;/p>',  // <-- Basic math             '&lt;p>Dad: {parent.name}&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data); </code></pre>  * </div>  * </li>  *  *   * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b>   * <div class="sub-desc">  * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed  * in the scope of the template. There are some special variables available in that code:  * <ul>  * <li><b><tt>values</tt></b>: The values in the current scope. If you are using  * scope changing sub-templates, you can change what <tt>values</tt> is.</li>  * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>  * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the  * loop you are in (1-based).</li>  * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length  * of the array you are looping.</li>  * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li>  * </ul>  * This example demonstrates basic row striping using an inline code block and the  * <tt>xindex</tt> variable:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl for="kids">',        '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',         '{name}',         '&lt;/div>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data);  * </code></pre>  * </div>  * </li>  *   * <li><b><u>Template member functions</u></b>   * <div class="sub-desc">  * <p>One or more member functions can be specified in a configuration  * object passed into the XTemplate constructor for more complex processing:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Name: {name}&lt;/p>',     '&lt;p>Kids: ',     '&lt;tpl for="kids">',         '&lt;tpl if="this.isGirl(name)">',             '&lt;p>Girl: {name} - {age}&lt;/p>',         '&lt;/tpl>',         // use opposite if statement to simulate 'else' processing:         '&lt;tpl if="this.isGirl(name) == false">',             '&lt;p>Boy: {name} - {age}&lt;/p>',         '&lt;/tpl>',         '&lt;tpl if="this.isBaby(age)">',             '&lt;p>{name} is a baby!&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>',     {         // XTemplate configuration:         compiled: true,         disableFormats: true,         // member functions:         isGirl: function(name){             return name == 'Sara Grace';         },         isBaby: function(age){             return age < 1;         }     } ); tpl.overwrite(panel.body, data);  * </code></pre>  * </div>  * </li>  *   * </ul></div>  *   * @param {Mixed} config  */ Ext.XTemplate = function(){     Ext.XTemplate.superclass.constructor.apply(this, arguments);     var me = this,      s = me.html,      re = /<tplb[^>]*>((?:(?=([^<]+))2|<(?!tplb[^>]*>))*?)</tpl>/,      nameRe = /^<tplb[^>]*?for="(.*?)"/,      ifRe = /^<tplb[^>]*?if="(.*?)"/,      execRe = /^<tplb[^>]*?exec="(.*?)"/,      m,      id = 0,      tpls = [],      VALUES = 'values',      PARENT = 'parent',      XINDEX = 'xindex',      XCOUNT = 'xcount',      RETURN = 'return ',      WITHVALUES = 'with(values){ ';     s = ['<tpl>', s, '</tpl>'].join('');     while((m = s.match(re))){         var m2 = m[0].match(nameRe), m3 = m[0].match(ifRe),         m4 = m[0].match(execRe),         exp = null,         fn = null,         exec = null,         name = m2 && m2[1] ? m2[1] : '';        if (m3) {            exp = m3 && m3[1] ? m3[1] : null;            if(exp){                fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }');            }        }        if (m4) {            exp = m4 && m4[1] ? m4[1] : null;            if(exp){                exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }');            }        }        if(name){            switch(name){                case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break;                case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break;                default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }');            }        }        tpls.push({             id: id,             target: name,             exec: exec,             test: fn,             body: m[1]||''         });        s = s.replace(m[0], '{xtpl'+ id + '}');        ++id;     } Ext.each(tpls, function(t) {         me.compileTpl(t);     });     me.master = tpls[tpls.length-1];     me.tpls = tpls; }; Ext.extend(Ext.XTemplate, Ext.Template, {     // private     re : /{([w-.#]+)(?::([w.]*)(?:((.*?)?))?)?(s?[+-*\]s?[d.+-*\()]+)?}/g,     // private     codeRe : /{[((?:\]|.|n)*?)]}/g,     // private     applySubTemplate : function(id, values, parent, xindex, xcount){         var me = this,          len,          t = me.tpls[id],          vs,          buf = [];         if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) ||             (t.exec && t.exec.call(me, values, parent, xindex, xcount))) {             return '';         }         vs = t.target ? t.target.call(me, values, parent) : values;         len = vs.length;         parent = t.target ? values : parent;         if(t.target && Ext.isArray(vs)){         Ext.each(vs, function(v, i) {                 buf[buf.length] = t.compiled.call(me, v, parent, i+1, len);             });             return buf.join('');         }         return t.compiled.call(me, vs, parent, xindex, xcount);     },     // private     compileTpl : function(tpl){         var fm = Ext.util.Format,         useF = this.disableFormats !== true,             sep = Ext.isGecko ? "+" : ",",             body;         function fn(m, name, format, args, math){             if(name.substr(0, 4) == 'xtpl'){                 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'";             }             var v;             if(name === '.'){                 v = 'values';             }else if(name === '#'){                 v = 'xindex';             }else if(name.indexOf('.') != -1){                 v = name;             }else{                 v = "values['" + name + "']";             }             if(math){                 v = '(' + v + math + ')';             }             if (format && useF) {                 args = args ? ',' + args : "";                 if(format.substr(0, 5) != "this."){                     format = "fm." + format + '(';                 }else{                     format = 'this.call("'+ format.substr(5) + '", ';                     args = ", values";                 }             } else {                 args= ''; format = "("+v+" === undefined ? '' : ";             }             return "'"+ sep + format + v + args + ")"+sep+"'";         }         function codeFn(m, code){             // Single quotes get escaped when the template is compiled, however we want to undo this when running code.             return "'" + sep + '(' + code.replace(/\'/g, "'") + ')' + sep + "'";         }         // branched to use + in gecko and [].join() in others         if(Ext.isGecko){             body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" +                    tpl.body.replace(/(rn|n)/g, '\n').replace(/'/g, "\'").replace(this.re, fn).replace(this.codeRe, codeFn) +                     "';};";         }else{             body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"];             body.push(tpl.body.replace(/(rn|n)/g, '\n').replace(/'/g, "\'").replace(this.re, fn).replace(this.codeRe, codeFn));             body.push("'].join('');};");             body = body.join('');         }         eval(body);         return this;     },     /**      * Returns an HTML fragment of this template with the specified values applied.      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})      * @return {String} The HTML fragment      */     applyTemplate : function(values){         return this.master.compiled.call(this, values, {}, 1, 1);     },     /**      * Compile the template to a function for optimized performance.  Recommended if the template will be used frequently.      * @return {Function} The compiled function      */     compile : function(){return this;}     /**      * @property re      * @hide      */     /**      * @property disableFormats      * @hide      */     /**      * @method set      * @hide      */ }); /**  * Alias for {@link #applyTemplate}  * Returns an HTML fragment of this template with the specified values applied.  * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})  * @return {String} The HTML fragment  * @member Ext.XTemplate  * @method apply  */ Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate; /**  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.  * @param {String/HTMLElement} el A DOM element or its id  * @return {Ext.Template} The created template  * @static  */ Ext.XTemplate.from = function(el){     el = Ext.getDom(el);     return new Ext.XTemplate(el.value || el.innerHTML); };/**
  930.  * @class Ext.util.CSS
  931.  * Utility class for manipulating CSS rules
  932.  * @singleton
  933.  */
  934. Ext.util.CSS = function(){
  935. var rules = null;
  936.     var doc = document;
  937.     var camelRe = /(-[a-z])/gi;
  938.     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
  939.    return {
  940.    /**
  941.     * Creates a stylesheet from a text blob of rules.
  942.     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
  943.     * @param {String} cssText The text containing the css rules
  944.     * @param {String} id An id to add to the stylesheet for later removal
  945.     * @return {StyleSheet}
  946.     */
  947.    createStyleSheet : function(cssText, id){
  948.        var ss;
  949.        var head = doc.getElementsByTagName("head")[0];
  950.        var rules = doc.createElement("style");
  951.        rules.setAttribute("type", "text/css");
  952.        if(id){
  953.            rules.setAttribute("id", id);
  954.        }
  955.        if(Ext.isIE){
  956.            head.appendChild(rules);
  957.            ss = rules.styleSheet;
  958.            ss.cssText = cssText;
  959.        }else{
  960.            try{
  961.                 rules.appendChild(doc.createTextNode(cssText));
  962.            }catch(e){
  963.                rules.cssText = cssText;
  964.            }
  965.            head.appendChild(rules);
  966.            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
  967.        }
  968.        this.cacheStyleSheet(ss);
  969.        return ss;
  970.    },
  971.    /**
  972.     * Removes a style or link tag by id
  973.     * @param {String} id The id of the tag
  974.     */
  975.    removeStyleSheet : function(id){
  976.        var existing = doc.getElementById(id);
  977.        if(existing){
  978.            existing.parentNode.removeChild(existing);
  979.        }
  980.    },
  981.    /**
  982.     * Dynamically swaps an existing stylesheet reference for a new one
  983.     * @param {String} id The id of an existing link tag to remove
  984.     * @param {String} url The href of the new stylesheet to include
  985.     */
  986.    swapStyleSheet : function(id, url){
  987.        this.removeStyleSheet(id);
  988.        var ss = doc.createElement("link");
  989.        ss.setAttribute("rel", "stylesheet");
  990.        ss.setAttribute("type", "text/css");
  991.        ss.setAttribute("id", id);
  992.        ss.setAttribute("href", url);
  993.        doc.getElementsByTagName("head")[0].appendChild(ss);
  994.    },
  995.    
  996.    /**
  997.     * Refresh the rule cache if you have dynamically added stylesheets
  998.     * @return {Object} An object (hash) of rules indexed by selector
  999.     */
  1000.    refreshCache : function(){
  1001.        return this.getRules(true);
  1002.    },
  1003.    // private
  1004.    cacheStyleSheet : function(ss){
  1005.        if(!rules){
  1006.            rules = {};
  1007.        }
  1008.        try{// try catch for cross domain access issue
  1009.            var ssRules = ss.cssRules || ss.rules;
  1010.            for(var j = ssRules.length-1; j >= 0; --j){
  1011.                rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j];
  1012.            }
  1013.        }catch(e){}
  1014.    },
  1015.    
  1016.    /**
  1017.     * Gets all css rules for the document
  1018.     * @param {Boolean} refreshCache true to refresh the internal cache
  1019.     * @return {Object} An object (hash) of rules indexed by selector
  1020.     */
  1021.    getRules : function(refreshCache){
  1022.     if(rules === null || refreshCache){
  1023.     rules = {};
  1024.     var ds = doc.styleSheets;
  1025.     for(var i =0, len = ds.length; i < len; i++){
  1026.         try{
  1027.              this.cacheStyleSheet(ds[i]);
  1028.          }catch(e){} 
  1029.         }
  1030.     }
  1031.     return rules;
  1032.     },
  1033.    
  1034.     /**
  1035.     * Gets an an individual CSS rule by selector(s)
  1036.     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
  1037.     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
  1038.     * @return {CSSRule} The CSS rule or null if one is not found
  1039.     */
  1040.    getRule : function(selector, refreshCache){
  1041.     var rs = this.getRules(refreshCache);
  1042.     if(!Ext.isArray(selector)){
  1043.         return rs[selector.toLowerCase()];
  1044.     }
  1045.     for(var i = 0; i < selector.length; i++){
  1046. if(rs[selector[i]]){
  1047. return rs[selector[i].toLowerCase()];
  1048. }
  1049. }
  1050. return null;
  1051.     },
  1052.    
  1053.    
  1054.     /**
  1055.     * Updates a rule property
  1056.     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
  1057.     * @param {String} property The css property
  1058.     * @param {String} value The new value for the property
  1059.     * @return {Boolean} true If a rule was found and updated
  1060.     */
  1061.    updateRule : function(selector, property, value){
  1062.     if(!Ext.isArray(selector)){
  1063.     var rule = this.getRule(selector);
  1064.     if(rule){
  1065.     rule.style[property.replace(camelRe, camelFn)] = value;
  1066.     return true;
  1067.     }
  1068.     }else{
  1069.     for(var i = 0; i < selector.length; i++){
  1070.     if(this.updateRule(selector[i], property, value)){
  1071.     return true;
  1072.     }
  1073.     }
  1074.     }
  1075.     return false;
  1076.     }
  1077.    };
  1078. }();/**  @class Ext.util.ClickRepeater  @extends Ext.util.Observable  A wrapper class which can be applied to any element. Fires a "click" event while the  mouse is pressed. The interval between firings may be specified in the config but  defaults to 20 milliseconds.  Optionally, a CSS class may be applied to the element during the time it is pressed.  @cfg {Mixed} el The element to act as a button.  @cfg {Number} delay The initial delay before the repeating event begins firing.  Similar to an autorepeat key delay.  @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.  @cfg {String} pressClass A CSS class name to be applied to the element while pressed.  @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.            "interval" and "delay" are ignored.  @cfg {Boolean} preventDefault True to prevent the default click event  @cfg {Boolean} stopDefault True to stop the default click event  @history     2007-02-02 jvs Original code contributed by Nige "Animal" White     2007-02-02 jvs Renamed to ClickRepeater     2007-02-03 jvs Modifications for FF Mac and Safari  @constructor  @param {Mixed} el The element to listen on  @param {Object} config  */ Ext.util.ClickRepeater = function(el, config) {     this.el = Ext.get(el);     this.el.unselectable();     Ext.apply(this, config);     this.addEvents(     /**      * @event mousedown      * Fires when the mouse button is depressed.      * @param {Ext.util.ClickRepeater} this      */         "mousedown",     /**      * @event click      * Fires on a specified interval during the time the element is pressed.      * @param {Ext.util.ClickRepeater} this      */         "click",     /**      * @event mouseup      * Fires when the mouse key is released.      * @param {Ext.util.ClickRepeater} this      */         "mouseup"     );     if(!this.disabled){         this.disabled = true;         this.enable();     }     // allow inline handler     if(this.handler){         this.on("click", this.handler,  this.scope || this);     }     Ext.util.ClickRepeater.superclass.constructor.call(this); }; Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, {     interval : 20,     delay: 250,     preventDefault : true,     stopDefault : false,     timer : 0,     /**      * Enables the repeater and allows events to fire.      */     enable: function(){         if(this.disabled){             this.el.on('mousedown', this.handleMouseDown, this);             if(this.preventDefault || this.stopDefault){                 this.el.on('click', this.eventOptions, this);             }         }         this.disabled = false;     },          /**      * Disables the repeater and stops events from firing.      */     disable: function(/* private */ force){         if(force || !this.disabled){             clearTimeout(this.timer);             if(this.pressClass){                 this.el.removeClass(this.pressClass);             }             Ext.getDoc().un('mouseup', this.handleMouseUp, this);             this.el.removeAllListeners();         }         this.disabled = true;     },          /**      * Convenience function for setting disabled/enabled by boolean.      * @param {Boolean} disabled      */     setDisabled: function(disabled){         this[disabled ? 'disable' : 'enable']();         },          eventOptions: function(e){         if(this.preventDefault){             e.preventDefault();         }         if(this.stopDefault){             e.stopEvent();         }            },          // private     destroy : function() {         this.disable(true);         Ext.destroy(this.el);         this.purgeListeners();     },          // private     handleMouseDown : function(){         clearTimeout(this.timer);         this.el.blur();         if(this.pressClass){             this.el.addClass(this.pressClass);         }         this.mousedownTime = new Date();         Ext.getDoc().on("mouseup", this.handleMouseUp, this);         this.el.on("mouseout", this.handleMouseOut, this);         this.fireEvent("mousedown", this);         this.fireEvent("click", this); //      Do not honor delay or interval if acceleration wanted.         if (this.accelerate) {             this.delay = 400;     }         this.timer = this.click.defer(this.delay || this.interval, this);     },     // private     click : function(){         this.fireEvent("click", this);         this.timer = this.click.defer(this.accelerate ?             this.easeOutExpo(this.mousedownTime.getElapsed(),                 400,                 -390,                 12000) :             this.interval, this);     },     easeOutExpo : function (t, b, c, d) {         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;     },     // private     handleMouseOut : function(){         clearTimeout(this.timer);         if(this.pressClass){             this.el.removeClass(this.pressClass);         }         this.el.on("mouseover", this.handleMouseReturn, this);     },     // private     handleMouseReturn : function(){         this.el.un("mouseover", this.handleMouseReturn, this);         if(this.pressClass){             this.el.addClass(this.pressClass);         }         this.click();     },     // private     handleMouseUp : function(){         clearTimeout(this.timer);         this.el.un("mouseover", this.handleMouseReturn, this);         this.el.un("mouseout", this.handleMouseOut, this);         Ext.getDoc().un("mouseup", this.handleMouseUp, this);         this.el.removeClass(this.pressClass);         this.fireEvent("mouseup", this);     } });/**  * @class Ext.KeyNav  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind  * navigation keys to function calls that will get called when the keys are pressed, providing an easy  * way to implement custom navigation schemes for any UI component.</p>  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,  * pageUp, pageDown, del, home, end.  Usage:</p>  <pre><code> var nav = new Ext.KeyNav("my-element", {     "left" : function(e){         this.moveLeft(e.ctrlKey);     },     "right" : function(e){         this.moveRight(e.ctrlKey);     },     "enter" : function(e){         this.save();     },     scope : this }); </code></pre>  * @constructor  * @param {Mixed} el The element to bind to  * @param {Object} config The config  */ Ext.KeyNav = function(el, config){     this.el = Ext.get(el);     Ext.apply(this, config);     if(!this.disabled){         this.disabled = true;         this.enable();     } }; Ext.KeyNav.prototype = {     /**      * @cfg {Boolean} disabled      * True to disable this KeyNav instance (defaults to false)      */     disabled : false,     /**      * @cfg {String} defaultEventAction      * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are      * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and      * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')      */     defaultEventAction: "stopEvent",     /**      * @cfg {Boolean} forceKeyDown      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also      * handle keydown instead of keypress.      */     forceKeyDown : false,     // private     relay : function(e){         var k = e.getKey();         var h = this.keyToHandler[k];         if(h && this[h]){             if(this.doRelay(e, this[h], h) !== true){                 e[this.defaultEventAction]();             }         }     },     // private     doRelay : function(e, h, hname){         return h.call(this.scope || this, e);     },     // possible handlers     enter : false,     left : false,     right : false,     up : false,     down : false,     tab : false,     esc : false,     pageUp : false,     pageDown : false,     del : false,     home : false,     end : false,     // quick lookup hash     keyToHandler : {         37 : "left",         39 : "right",         38 : "up",         40 : "down",         33 : "pageUp",         34 : "pageDown",         46 : "del",         36 : "home",         35 : "end",         13 : "enter",         27 : "esc",         9  : "tab"     },          stopKeyUp: function(e) {         var k = e.getKey();         if (k >= 37 && k <= 40) {             // *** bugfix - safari 2.x fires 2 keyup events on cursor keys             // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2)             e.stopEvent();         }     },          /**      * Destroy this KeyNav (this is the same as calling disable).      */     destroy: function(){         this.disable();         }, /**  * Enable this KeyNav  */ enable: function() {         if (this.disabled) {             if (Ext.isSafari2) {                 // call stopKeyUp() on "keyup" event                 this.el.on('keyup', this.stopKeyUp, this);             }             this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);             this.disabled = false;         }     }, /**  * Disable this KeyNav  */ disable: function() {         if (!this.disabled) {             if (Ext.isSafari2) {                 // remove "keyup" event handler                 this.el.un('keyup', this.stopKeyUp, this);             }             this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);             this.disabled = true;         }     },          /**      * Convenience function for setting disabled/enabled by boolean.      * @param {Boolean} disabled      */     setDisabled : function(disabled){         this[disabled ? "disable" : "enable"]();     },          // private     isKeydown: function(){         return this.forceKeyDown || Ext.EventManager.useKeydown;     } }; /**
  1079.  * @class Ext.KeyMap
  1080.  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
  1081.  * The constructor accepts the same config object as defined by {@link #addBinding}.
  1082.  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
  1083.  * combination it will call the function with this signature (if the match is a multi-key
  1084.  * combination the callback will still be called only once): (String key, Ext.EventObject e)
  1085.  * A KeyMap can also handle a string representation of keys.<br />
  1086.  * Usage:
  1087.  <pre><code>
  1088. // map one key by key code
  1089. var map = new Ext.KeyMap("my-element", {
  1090.     key: 13, // or Ext.EventObject.ENTER
  1091.     fn: myHandler,
  1092.     scope: myObject
  1093. });
  1094. // map multiple keys to one action by string
  1095. var map = new Ext.KeyMap("my-element", {
  1096.     key: "arnt",
  1097.     fn: myHandler,
  1098.     scope: myObject
  1099. });
  1100. // map multiple keys to multiple actions by strings and array of codes
  1101. var map = new Ext.KeyMap("my-element", [
  1102.     {
  1103.         key: [10,13],
  1104.         fn: function(){ alert("Return was pressed"); }
  1105.     }, {
  1106.         key: "abc",
  1107.         fn: function(){ alert('a, b or c was pressed'); }
  1108.     }, {
  1109.         key: "t",
  1110.         ctrl:true,
  1111.         shift:true,
  1112.         fn: function(){ alert('Control + shift + tab was pressed.'); }
  1113.     }
  1114. ]);
  1115. </code></pre>
  1116.  * <b>Note: A KeyMap starts enabled</b>
  1117.  * @constructor
  1118.  * @param {Mixed} el The element to bind to
  1119.  * @param {Object} config The config (see {@link #addBinding})
  1120.  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
  1121.  */
  1122. Ext.KeyMap = function(el, config, eventName){
  1123.     this.el  = Ext.get(el);
  1124.     this.eventName = eventName || "keydown";
  1125.     this.bindings = [];
  1126.     if(config){
  1127.         this.addBinding(config);
  1128.     }
  1129.     this.enable();
  1130. };
  1131. Ext.KeyMap.prototype = {
  1132.     /**
  1133.      * True to stop the event from bubbling and prevent the default browser action if the
  1134.      * key was handled by the KeyMap (defaults to false)
  1135.      * @type Boolean
  1136.      */
  1137.     stopEvent : false,
  1138.     /**
  1139.      * Add a new binding to this KeyMap. The following config object properties are supported:
  1140.      * <pre>
  1141. Property    Type             Description
  1142. ----------  ---------------  ----------------------------------------------------------------------
  1143. key         String/Array     A single keycode or an array of keycodes to handle
  1144. shift       Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
  1145. ctrl        Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
  1146. alt         Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
  1147. handler     Function         The function to call when KeyMap finds the expected key combination
  1148. fn          Function         Alias of handler (for backwards-compatibility)
  1149. scope       Object           The scope of the callback function
  1150. stopEvent   Boolean          True to stop the event from bubbling and prevent the default browser action if the key was handled by the KeyMap (defaults to false)
  1151. </pre>
  1152.      *
  1153.      * Usage:
  1154.      * <pre><code>
  1155. // Create a KeyMap
  1156. var map = new Ext.KeyMap(document, {
  1157.     key: Ext.EventObject.ENTER,
  1158.     fn: handleKey,
  1159.     scope: this
  1160. });
  1161. //Add a new binding to the existing KeyMap later
  1162. map.addBinding({
  1163.     key: 'abc',
  1164.     shift: true,
  1165.     fn: handleKey,
  1166.     scope: this
  1167. });
  1168. </code></pre>
  1169.      * @param {Object/Array} config A single KeyMap config or an array of configs
  1170.      */
  1171. addBinding : function(config){
  1172.         if(Ext.isArray(config)){
  1173.             Ext.each(config, function(c){
  1174.                 this.addBinding(c);
  1175.             }, this);
  1176.             return;
  1177.         }
  1178.         var keyCode = config.key,
  1179.             fn = config.fn || config.handler,
  1180.             scope = config.scope;
  1181. if (config.stopEvent) {
  1182.     this.stopEvent = config.stopEvent;    
  1183. }
  1184.         if(typeof keyCode == "string"){
  1185.             var ks = [];
  1186.             var keyString = keyCode.toUpperCase();
  1187.             for(var j = 0, len = keyString.length; j < len; j++){
  1188.                 ks.push(keyString.charCodeAt(j));
  1189.             }
  1190.             keyCode = ks;
  1191.         }
  1192.         var keyArray = Ext.isArray(keyCode);
  1193.         
  1194.         var handler = function(e){
  1195.             if(this.checkModifiers(config, e)){
  1196.                 var k = e.getKey();
  1197.                 if(keyArray){
  1198.                     for(var i = 0, len = keyCode.length; i < len; i++){
  1199.                         if(keyCode[i] == k){
  1200.                           if(this.stopEvent){
  1201.                               e.stopEvent();
  1202.                           }
  1203.                           fn.call(scope || window, k, e);
  1204.                           return;
  1205.                         }
  1206.                     }
  1207.                 }else{
  1208.                     if(k == keyCode){
  1209.                         if(this.stopEvent){
  1210.                            e.stopEvent();
  1211.                         }
  1212.                         fn.call(scope || window, k, e);
  1213.                     }
  1214.                 }
  1215.             }
  1216.         };
  1217.         this.bindings.push(handler);
  1218. },
  1219.     
  1220.     // private
  1221.     checkModifiers: function(config, e){
  1222.         var val, key, keys = ['shift', 'ctrl', 'alt'];
  1223.         for (var i = 0, len = keys.length; i < len; ++i){
  1224.             key = keys[i];
  1225.             val = config[key];
  1226.             if(!(val === undefined || (val === e[key + 'Key']))){
  1227.                 return false;
  1228.             }
  1229.         }
  1230.         return true;
  1231.     },
  1232.     /**
  1233.      * Shorthand for adding a single key listener
  1234.      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
  1235.      * following options:
  1236.      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
  1237.      * @param {Function} fn The function to call
  1238.      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
  1239.      */
  1240.     on : function(key, fn, scope){
  1241.         var keyCode, shift, ctrl, alt;
  1242.         if(typeof key == "object" && !Ext.isArray(key)){
  1243.             keyCode = key.key;
  1244.             shift = key.shift;
  1245.             ctrl = key.ctrl;
  1246.             alt = key.alt;
  1247.         }else{
  1248.             keyCode = key;
  1249.         }
  1250.         this.addBinding({
  1251.             key: keyCode,
  1252.             shift: shift,
  1253.             ctrl: ctrl,
  1254.             alt: alt,
  1255.             fn: fn,
  1256.             scope: scope
  1257.         });
  1258.     },
  1259.     // private
  1260.     handleKeyDown : function(e){
  1261.     if(this.enabled){ //just in case
  1262.          var b = this.bindings;
  1263.          for(var i = 0, len = b.length; i < len; i++){
  1264.              b[i].call(this, e);
  1265.          }
  1266.     }
  1267. },
  1268. /**
  1269.  * Returns true if this KeyMap is enabled
  1270.  * @return {Boolean}
  1271.  */
  1272. isEnabled : function(){
  1273.     return this.enabled;
  1274. },
  1275. /**
  1276.  * Enables this KeyMap
  1277.  */
  1278. enable: function(){
  1279. if(!this.enabled){
  1280.     this.el.on(this.eventName, this.handleKeyDown, this);
  1281.     this.enabled = true;
  1282. }
  1283. },
  1284. /**
  1285.  * Disable this KeyMap
  1286.  */
  1287. disable: function(){
  1288. if(this.enabled){
  1289.     this.el.removeListener(this.eventName, this.handleKeyDown, this);
  1290.     this.enabled = false;
  1291. }
  1292. },
  1293.     
  1294.     /**
  1295.      * Convenience function for setting disabled/enabled by boolean.
  1296.      * @param {Boolean} disabled
  1297.      */
  1298.     setDisabled : function(disabled){
  1299.         this[disabled ? "disable" : "enable"]();
  1300.     }
  1301. };/**  * @class Ext.util.TextMetrics  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and  * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and  * should not contain any HTML, otherwise it may not be measured correctly.  * @singleton  */ Ext.util.TextMetrics = function(){     var shared;     return {         /**          * Measures the size of the specified text          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles          * that can affect the size of the rendered text          * @param {String} text The text to measure          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width          * in order to accurately measure the text height          * @return {Object} An object containing the text's size {width: (width), height: (height)}          */         measure : function(el, text, fixedWidth){             if(!shared){                 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);             }             shared.bind(el);             shared.setFixedWidth(fixedWidth || 'auto');             return shared.getSize(text);         },         /**          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces          * the overhead of multiple calls to initialize the style properties on each measurement.          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width          * in order to accurately measure the text height          * @return {Ext.util.TextMetrics.Instance} instance The new instance          */         createInstance : function(el, fixedWidth){             return Ext.util.TextMetrics.Instance(el, fixedWidth);         }     }; }(); Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){     var ml = new Ext.Element(document.createElement('div'));     document.body.appendChild(ml.dom);     ml.position('absolute');     ml.setLeftTop(-1000, -1000);     ml.hide();     if(fixedWidth){         ml.setWidth(fixedWidth);     }     var instance = {         /**          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>          * Returns the size of the specified text based on the internal element's style and width properties          * @param {String} text The text to measure          * @return {Object} An object containing the text's size {width: (width), height: (height)}          */         getSize : function(text){             ml.update(text);             var s = ml.getSize();             ml.update('');             return s;         },         /**          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>          * Binds this TextMetrics instance to an element from which to copy existing CSS styles          * that can affect the size of the rendered text          * @param {String/HTMLElement} el The element, dom node or id          */         bind : function(el){             ml.setStyle(                 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')             );         },         /**          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have          * to set a fixed width in order to accurately measure the text height.          * @param {Number} width The width to set on the element          */         setFixedWidth : function(width){             ml.setWidth(width);         },         /**          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>          * Returns the measured width of the specified text          * @param {String} text The text to measure          * @return {Number} width The width in pixels          */         getWidth : function(text){             ml.dom.style.width = 'auto';             return this.getSize(text).width;         },         /**          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>          * Returns the measured height of the specified text.  For multiline text, be sure to call          * {@link #setFixedWidth} if necessary.          * @param {String} text The text to measure          * @return {Number} height The height in pixels          */         getHeight : function(text){             return this.getSize(text).height;         }     };     instance.bind(bindTo);     return instance; }; Ext.Element.addMethods({     /**      * Returns the width in pixels of the passed text, or the width of the text in this Element.      * @param {String} text The text to measure. Defaults to the innerHTML of the element.      * @param {Number} min (Optional) The minumum value to return.      * @param {Number} max (Optional) The maximum value to return.      * @return {Number} The text width in pixels.      * @member Ext.Element getTextWidth      */     getTextWidth : function(text, min, max){         return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);     } }); /**
  1302.  * @class Ext.util.Cookies
  1303.  * Utility class for managing and interacting with cookies.
  1304.  * @singleton
  1305.  */
  1306. Ext.util.Cookies = {
  1307.     /**
  1308.      * Create a cookie with the specified name and value. Additional settings
  1309.      * for the cookie may be optionally specified (for example: expiration,
  1310.      * access restriction, SSL).
  1311.      * @param {String} name The name of the cookie to set. 
  1312.      * @param {Mixed} value The value to set for the cookie.
  1313.      * @param {Object} expires (Optional) Specify an expiration date the
  1314.      * cookie is to persist until.  Note that the specified Date object will
  1315.      * be converted to Greenwich Mean Time (GMT). 
  1316.      * @param {String} path (Optional) Setting a path on the cookie restricts
  1317.      * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>). 
  1318.      * @param {String} domain (Optional) Setting a domain restricts access to
  1319.      * pages on a given domain (typically used to allow cookie access across
  1320.      * subdomains). For example, "extjs.com" will create a cookie that can be
  1321.      * accessed from any subdomain of extjs.com, including www.extjs.com,
  1322.      * support.extjs.com, etc.
  1323.      * @param {Boolean} secure (Optional) Specify true to indicate that the cookie
  1324.      * should only be accessible via SSL on a page using the HTTPS protocol.
  1325.      * Defaults to <tt>false</tt>. Note that this will only work if the page
  1326.      * calling this code uses the HTTPS protocol, otherwise the cookie will be
  1327.      * created with default options.
  1328.      */
  1329.     set : function(name, value){
  1330.         var argv = arguments;
  1331.         var argc = arguments.length;
  1332.         var expires = (argc > 2) ? argv[2] : null;
  1333.         var path = (argc > 3) ? argv[3] : '/';
  1334.         var domain = (argc > 4) ? argv[4] : null;
  1335.         var secure = (argc > 5) ? argv[5] : false;
  1336.         document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
  1337.     },
  1338.     /**
  1339.      * Retrieves cookies that are accessible by the current page. If a cookie
  1340.      * does not exist, <code>get()</code> returns <tt>null</tt>.  The following
  1341.      * example retrieves the cookie called "valid" and stores the String value
  1342.      * in the variable <tt>validStatus</tt>.
  1343.      * <pre><code>
  1344.      * var validStatus = Ext.util.Cookies.get("valid");
  1345.      * </code></pre>
  1346.      * @param {String} name The name of the cookie to get
  1347.      * @return {Mixed} Returns the cookie value for the specified name;
  1348.      * null if the cookie name does not exist.
  1349.      */
  1350.     get : function(name){
  1351.         var arg = name + "=";
  1352.         var alen = arg.length;
  1353.         var clen = document.cookie.length;
  1354.         var i = 0;
  1355.         var j = 0;
  1356.         while(i < clen){
  1357.             j = i + alen;
  1358.             if(document.cookie.substring(i, j) == arg){
  1359.                 return Ext.util.Cookies.getCookieVal(j);
  1360.             }
  1361.             i = document.cookie.indexOf(" ", i) + 1;
  1362.             if(i === 0){
  1363.                 break;
  1364.             }
  1365.         }
  1366.         return null;
  1367.     },
  1368.     /**
  1369.      * Removes a cookie with the provided name from the browser
  1370.      * if found by setting its expiration date to sometime in the past. 
  1371.      * @param {String} name The name of the cookie to remove
  1372.      */
  1373.     clear : function(name){
  1374.         if(Ext.util.Cookies.get(name)){
  1375.             document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  1376.         }
  1377.     },
  1378.     /**
  1379.      * @private
  1380.      */
  1381.     getCookieVal : function(offset){
  1382.         var endstr = document.cookie.indexOf(";", offset);
  1383.         if(endstr == -1){
  1384.             endstr = document.cookie.length;
  1385.         }
  1386.         return unescape(document.cookie.substring(offset, endstr));
  1387.     }
  1388. };/**  * Framework-wide error-handler.  Developers can override this method to provide  * custom exception-handling.  Framework errors will often extend from the base  * Ext.Error class.  * @param {Object/Error} e The thrown exception object.  */ Ext.handleError = function(e) {     throw e; }; /**  * @class Ext.Error  * @extends Error  * <p>A base error class. Future implementations are intended to provide more  * robust error handling throughout the framework (<b>in the debug build only</b>)  * to check for common errors and problems. The messages issued by this class  * will aid error checking. Error checks will be automatically removed in the  * production build so that performance is not negatively impacted.</p>  * <p>Some sample messages currently implemented:</p><pre> "DataProxy attempted to execute an API-action but found an undefined url / function. Please review your Proxy url/api-configuration."  * </pre><pre> "Could not locate your "root" property in your server response. Please review your JsonReader config to ensure the config-property "root" matches the property your server-response.  See the JsonReader docs for additional assistance."  * </pre>  * <p>An example of the code used for generating error messages:</p><pre><code> try {     generateError({         foo: 'bar'     }); } catch (e) {     console.error(e); } function generateError(data) {     throw new Ext.Error('foo-error', data); }  * </code></pre>  * @param {String} message  */ Ext.Error = function(message) {     // Try to read the message from Ext.Error.lang     this.message = (this.lang[message]) ? this.lang[message] : message; } Ext.Error.prototype = new Error(); Ext.apply(Ext.Error.prototype, {     // protected.  Extensions place their error-strings here.     lang: {},     name: 'Ext.Error',     /**      * getName      * @return {String}      */     getName : function() {         return this.name;     },     /**      * getMessage      * @return {String}      */     getMessage : function() {         return this.message;     },     /**      * toJson      * @return {String}      */     toJson : function() {         return Ext.encode(this);     } });