ext-foundation-debug.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:503k
源码类别:

中间件编程

开发平台:

JavaScript

  1.  * @param {String/Array} selector The CSS selector or an array of elements
  2.  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
  3.  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
  4.  * @return {CompositeElementLite/CompositeElement}
  5.  * @member Ext
  6.  * @method select
  7.  */
  8. Ext.select = Ext.Element.select;/**
  9.  * @class Ext.CompositeElementLite
  10.  */
  11. Ext.apply(Ext.CompositeElementLite.prototype, {
  12. addElements : function(els, root){
  13.         if(!els){
  14.             return this;
  15.         }
  16.         if(typeof els == "string"){
  17.             els = Ext.Element.selectorFunction(els, root);
  18.         }
  19.         var yels = this.elements;        
  20.     Ext.each(els, function(e) {
  21.          yels.push(Ext.get(e));
  22.         });
  23.         return this;
  24.     },
  25.     
  26.     /**
  27.     * Clears this composite and adds the elements returned by the passed selector.
  28.     * @param {String/Array} els A string CSS selector, an array of elements or an element
  29.     * @return {CompositeElement} this
  30.     */
  31.     fill : function(els){
  32.         this.elements = [];
  33.         this.add(els);
  34.         return this;
  35.     },
  36.     
  37.     /**
  38.      * Returns the first Element
  39.      * @return {Ext.Element}
  40.      */
  41.     first : function(){
  42.         return this.item(0);
  43.     },   
  44.     
  45.     /**
  46.      * Returns the last Element
  47.      * @return {Ext.Element}
  48.      */
  49.     last : function(){
  50.         return this.item(this.getCount()-1);
  51.     },
  52.     
  53.     /**
  54.      * Returns true if this composite contains the passed element
  55.      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
  56.      * @return Boolean
  57.      */
  58.     contains : function(el){
  59.         return this.indexOf(el) != -1;
  60.     },
  61.     /**
  62.     * Filters this composite to only elements that match the passed selector.
  63.     * @param {String} selector A string CSS selector
  64.     * @return {CompositeElement} this
  65.     */
  66.     filter : function(selector){
  67.         var els = [];
  68.         this.each(function(el){
  69.             if(el.is(selector)){
  70.                 els[els.length] = el.dom;
  71.             }
  72.         });
  73.         this.fill(els);
  74.         return this;
  75.     },          /**
  76.     * Removes the specified element(s).
  77.     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
  78.     * or an array of any of those.
  79.     * @param {Boolean} removeDom (optional) True to also remove the element from the document
  80.     * @return {CompositeElement} this
  81.     */
  82.     removeElement : function(keys, removeDom){
  83.         var me = this,
  84.         els = this.elements,     
  85.      el;     
  86.     Ext.each(keys, function(val){
  87.     if ((el = (els[val] || els[val = me.indexOf(val)]))) {
  88.      if(removeDom){
  89.                     if(el.dom){
  90.                         el.remove();
  91.                     }else{
  92.                         Ext.removeNode(el);
  93.                     }
  94.                 }
  95.      els.splice(val, 1);     
  96. }
  97.     });
  98.         return this;
  99.     }    
  100. }); /**
  101.  * @class Ext.CompositeElement
  102.  * @extends Ext.CompositeElementLite
  103.  * Standard composite class. Creates a Ext.Element for every element in the collection.
  104.  * <br><br>
  105.  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Ext.Element. All Ext.Element
  106.  * actions will be performed on all the elements in this collection.</b>
  107.  * <br><br>
  108.  * All methods return <i>this</i> and can be chained.
  109.  <pre><code>
  110.  var els = Ext.select("#some-el div.some-class", true);
  111.  // or select directly from an existing element
  112.  var el = Ext.get('some-el');
  113.  el.select('div.some-class', true);
  114.  els.setWidth(100); // all elements become 100 width
  115.  els.hide(true); // all elements fade out and hide
  116.  // or
  117.  els.setWidth(100).hide(true);
  118.  </code></pre>
  119.  */
  120. Ext.CompositeElement = function(els, root){
  121.     this.elements = [];
  122.     this.add(els, root);
  123. };
  124. Ext.extend(Ext.CompositeElement, Ext.CompositeElementLite, {
  125.     invoke : function(fn, args){
  126.     Ext.each(this.elements, function(e) {
  127.          Ext.Element.prototype[fn].apply(e, args);
  128.         });
  129.         return this;
  130.     },
  131.     
  132.     /**
  133.     * Adds elements to this composite.
  134.     * @param {String/Array} els A string CSS selector, an array of elements or an element
  135.     * @return {CompositeElement} this
  136.     */
  137.     add : function(els, root){
  138.     if(!els){
  139.             return this;
  140.         }
  141.         if(typeof els == "string"){
  142.             els = Ext.Element.selectorFunction(els, root);
  143.         }
  144.         var yels = this.elements;        
  145.     Ext.each(els, function(e) {
  146.          yels.push(Ext.get(e));
  147.         });
  148.         return this;
  149.     },    
  150.     
  151.     /**
  152.      * Returns the Element object at the specified index
  153.      * @param {Number} index
  154.      * @return {Ext.Element}
  155.      */
  156.     item : function(index){
  157.         return this.elements[index] || null;
  158.     },
  159.     indexOf : function(el){
  160.         return this.elements.indexOf(Ext.get(el));
  161.     },
  162.         
  163.     filter : function(selector){
  164. var me = this,
  165. out = [];
  166. Ext.each(me.elements, function(el) {
  167. if(el.is(selector)){
  168. out.push(Ext.get(el));
  169. }
  170. });
  171. me.elements = out;
  172. return me;
  173. },
  174. /**
  175.     * Calls the passed function passing (el, this, index) for each element in this composite.
  176.     * @param {Function} fn The function to call
  177.     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
  178.     * @return {CompositeElement} this
  179.     */
  180.     each : function(fn, scope){        
  181.         Ext.each(this.elements, function(e,i) {
  182.         return fn.call(scope || e, e, this, i);
  183.         }, this);
  184.         return this;
  185.     }
  186. });
  187. /**
  188.  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
  189.  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
  190.  * {@link Ext.CompositeElementLite CompositeElementLite} object.
  191.  * @param {String/Array} selector The CSS selector or an array of elements
  192.  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
  193.  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
  194.  * @return {CompositeElementLite/CompositeElement}
  195.  * @member Ext.Element
  196.  * @method select
  197.  */
  198. Ext.Element.select = function(selector, unique, root){
  199.     var els;
  200.     if(typeof selector == "string"){
  201.         els = Ext.Element.selectorFunction(selector, root);
  202.     }else if(selector.length !== undefined){
  203.         els = selector;
  204.     }else{
  205.         throw "Invalid selector";
  206.     }
  207.     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
  208. };
  209. /**
  210.  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
  211.  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
  212.  * {@link Ext.CompositeElementLite CompositeElementLite} object.
  213.  * @param {String/Array} selector The CSS selector or an array of elements
  214.  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
  215.  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
  216.  * @return {CompositeElementLite/CompositeElement}
  217.  * @member Ext.Element
  218.  * @method select
  219.  */
  220. Ext.select = Ext.Element.select;(function(){
  221.     var BEFOREREQUEST = "beforerequest",
  222.         REQUESTCOMPLETE = "requestcomplete",
  223.         REQUESTEXCEPTION = "requestexception",
  224.         UNDEFINED = undefined,
  225.         LOAD = 'load',
  226.         POST = 'POST',
  227.         GET = 'GET',
  228.         WINDOW = window;
  229.     
  230.     /**
  231.      * @class Ext.data.Connection
  232.      * @extends Ext.util.Observable
  233.      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
  234.      * either to a configured URL, or to a URL specified at request time.</p>
  235.      * <p>Requests made by this class are asynchronous, and will return immediately. No data from
  236.      * the server will be available to the statement immediately following the {@link #request} call.
  237.      * To process returned data, use a
  238.      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
  239.      * in the request options object,
  240.      * or an {@link #requestcomplete event listener}.</p>
  241.      * <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
  242.      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
  243.      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
  244.      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
  245.      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
  246.      * but removed after the return data has been gathered.</p>
  247.      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
  248.      * server is using JSON to send the return object, then the
  249.      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
  250.      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
  251.      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
  252.      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
  253.      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
  254.      * is created containing a <tt>responseText</tt> property in order to conform to the
  255.      * requirements of event handlers and callbacks.</p>
  256.      * <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>
  257.      * and some server technologies (notably JEE) may require some custom processing in order to
  258.      * retrieve parameter names and parameter values from the packet content.</p>
  259.      * @constructor
  260.      * @param {Object} config a configuration object.
  261.      */
  262.     Ext.data.Connection = function(config){    
  263.         Ext.apply(this, config);
  264.         this.addEvents(
  265.             /**
  266.              * @event beforerequest
  267.              * Fires before a network request is made to retrieve a data object.
  268.              * @param {Connection} conn This Connection object.
  269.              * @param {Object} options The options config object passed to the {@link #request} method.
  270.              */
  271.             BEFOREREQUEST,
  272.             /**
  273.              * @event requestcomplete
  274.              * Fires if the request was successfully completed.
  275.              * @param {Connection} conn This Connection object.
  276.              * @param {Object} response The XHR object containing the response data.
  277.              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
  278.              * for details.
  279.              * @param {Object} options The options config object passed to the {@link #request} method.
  280.              */
  281.             REQUESTCOMPLETE,
  282.             /**
  283.              * @event requestexception
  284.              * Fires if an error HTTP status was returned from the server.
  285.              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
  286.              * for details of HTTP status codes.
  287.              * @param {Connection} conn This Connection object.
  288.              * @param {Object} response The XHR object containing the response data.
  289.              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
  290.              * for details.
  291.              * @param {Object} options The options config object passed to the {@link #request} method.
  292.              */
  293.             REQUESTEXCEPTION
  294.         );
  295.         Ext.data.Connection.superclass.constructor.call(this);
  296.     };
  297.     // private
  298.     function handleResponse(response){
  299.         this.transId = false;
  300.         var options = response.argument.options;
  301.         response.argument = options ? options.argument : null;
  302.         this.fireEvent(REQUESTCOMPLETE, this, response, options);
  303.         if(options.success){
  304.             options.success.call(options.scope, response, options);
  305.         }
  306.         if(options.callback){
  307.             options.callback.call(options.scope, options, true, response);
  308.         }
  309.     }
  310.     // private
  311.     function handleFailure(response, e){
  312.         this.transId = false;
  313.         var options = response.argument.options;
  314.         response.argument = options ? options.argument : null;
  315.         this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
  316.         if(options.failure){
  317.             options.failure.call(options.scope, response, options);
  318.         }
  319.         if(options.callback){
  320.             options.callback.call(options.scope, options, false, response);
  321.         }
  322.     }
  323.     // private
  324.     function doFormUpload(o, ps, url){
  325.         var id = Ext.id(),
  326.             doc = document,
  327.             frame = doc.createElement('iframe'),
  328.             form = Ext.getDom(o.form),
  329.             hiddens = [],
  330.             hd,
  331.             encoding = 'multipart/form-data',
  332.             buf = {
  333.                 target: form.target,
  334.                 method: form.method,
  335.                 encoding: form.encoding,
  336.                 enctype: form.enctype,
  337.                 action: form.action
  338.             };
  339.             
  340.         Ext.apply(frame, {
  341.             id: id,
  342.             name: id,
  343.             className: 'x-hidden',
  344.             src: Ext.SSL_SECURE_URL // for IE
  345.         });     
  346.         doc.body.appendChild(frame);
  347.         
  348.         // This is required so that IE doesn't pop the response up in a new window.
  349.         if(Ext.isIE){
  350.            document.frames[id].name = id;
  351.         }
  352.         
  353.         Ext.apply(form, {
  354.             target: id,
  355.             method: POST,
  356.             enctype: encoding,
  357.             encoding: encoding,
  358.             action: url || buf.action
  359.         });
  360.         
  361.         // add dynamic params            
  362.         ps = Ext.urlDecode(ps, false);
  363.         for(var k in ps){
  364.             if(ps.hasOwnProperty(k)){
  365.                 hd = doc.createElement('input');
  366.                 hd.type = 'hidden';                    
  367.                 hd.value = ps[hd.name = k];
  368.                 form.appendChild(hd);
  369.                 hiddens.push(hd);
  370.             }
  371.         }        
  372.         function cb(){
  373.             var me = this,
  374.                 // bogus response object
  375.                 r = {responseText : '',
  376.                      responseXML : null,
  377.                      argument : o.argument},
  378.                 doc,
  379.                 firstChild;
  380.             try{ 
  381.                 doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
  382.                 if(doc){
  383.                     if(doc.body){
  384.                         if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea                        
  385.                             r.responseText = firstChild.value;
  386.                         }else{
  387.                             r.responseText = doc.body.innerHTML;
  388.                         }
  389.                     }
  390.                     //in IE the document may still have a body even if returns XML.
  391.                     r.responseXML = doc.XMLDocument || doc;
  392.                 }
  393.             }
  394.             catch(e) {}
  395.             Ext.EventManager.removeListener(frame, LOAD, cb, me);
  396.             me.fireEvent(REQUESTCOMPLETE, me, r, o);
  397.             
  398.             function runCallback(fn, scope, args){
  399.                 if(Ext.isFunction(fn)){
  400.                     fn.apply(scope, args);
  401.                 }
  402.             }
  403.             runCallback(o.success, o.scope, [r, o]);
  404.             runCallback(o.callback, o.scope, [o, true, r]);
  405.             if(!me.debugUploads){
  406.                 setTimeout(function(){Ext.removeNode(frame);}, 100);
  407.             }
  408.         }
  409.         Ext.EventManager.on(frame, LOAD, cb, this);
  410.         form.submit();
  411.         
  412.         Ext.apply(form, buf);
  413.         Ext.each(hiddens, function(h) {
  414.             Ext.removeNode(h);
  415.         });
  416.     }
  417.     Ext.extend(Ext.data.Connection, Ext.util.Observable, {
  418.         /**
  419.          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
  420.          * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
  421.          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
  422.          */
  423.         /**
  424.          * @cfg {Object} extraParams (Optional) An object containing properties which are used as
  425.          * extra parameters to each request made by this object. (defaults to undefined)
  426.          */
  427.         /**
  428.          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
  429.          *  to each request made by this object. (defaults to undefined)
  430.          */
  431.         /**
  432.          * @cfg {String} method (Optional) The default HTTP method to be used for requests.
  433.          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
  434.          * otherwise, GET will be used.)
  435.          */
  436.         /**
  437.          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
  438.          */
  439.         timeout : 30000,
  440.         /**
  441.          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
  442.          * @type Boolean
  443.          */
  444.         autoAbort:false,
  445.     
  446.         /**
  447.          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
  448.          * @type Boolean
  449.          */
  450.         disableCaching: true,
  451.         
  452.         /**
  453.          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
  454.          * through a cache buster. Defaults to '_dc'
  455.          * @type String
  456.          */
  457.         disableCachingParam: '_dc',
  458.         
  459.         /**
  460.          * <p>Sends an HTTP request to a remote server.</p>
  461.          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
  462.          * return before the response has been received. Process any returned data
  463.          * in a callback function.</p>
  464.          * <pre><code>
  465. Ext.Ajax.request({
  466.    url: 'ajax_demo/sample.json',
  467.    success: function(response, opts) {
  468.       var obj = Ext.decode(response.responseText);
  469.       console.dir(obj);
  470.    },
  471.    failure: function(response, opts) {
  472.       console.log('server-side failure with status code ' + response.status);
  473.    }
  474. });
  475.          * </code></pre>
  476.          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
  477.          * @param {Object} options An object which may contain the following properties:<ul>
  478.          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
  479.          * which to send the request, or a function to call which returns a URL string. The scope of the
  480.          * function is specified by the <tt>scope</tt> option. Defaults to the configured
  481.          * <tt>{@link #url}</tt>.</div></li>
  482.          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
  483.          * An object containing properties which are used as parameters to the
  484.          * request, a url encoded string or a function to call to get either. The scope of the function
  485.          * is specified by the <tt>scope</tt> option.</div></li>
  486.          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
  487.          * for the request. Defaults to the configured method, or if no method was configured,
  488.          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
  489.          * the method name is case-sensitive and should be all caps.</div></li>
  490.          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
  491.          * function to be called upon receipt of the HTTP response. The callback is
  492.          * called regardless of success or failure and is passed the following
  493.          * parameters:<ul>
  494.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  495.          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
  496.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data. 
  497.          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about 
  498.          * accessing elements of the response.</div></li>
  499.          * </ul></div></li>
  500.          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
  501.          * to be called upon success of the request. The callback is passed the following
  502.          * parameters:<ul>
  503.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
  504.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  505.          * </ul></div></li>
  506.          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
  507.          * to be called upon failure of the request. The callback is passed the
  508.          * following parameters:<ul>
  509.          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
  510.          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
  511.          * </ul></div></li>
  512.          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
  513.          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
  514.          * specified as functions from which to draw values, then this also serves as the scope for those function calls.
  515.          * Defaults to the browser window.</div></li>
  516.          * <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>
  517.          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
  518.          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
  519.          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used 
  520.          * with the <tt>form</tt> option</b>.
  521.          * <p>True if the form object is a file upload (will be set automatically if the form was
  522.          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
  523.          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
  524.          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
  525.          * DOM <tt>&lt;form></tt> element temporarily modified to have its
  526.          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
  527.          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
  528.          * but removed after the return data has been gathered.</p>
  529.          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
  530.          * server is using JSON to send the return object, then the
  531.          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
  532.          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
  533.          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
  534.          * is created containing a <tt>responseText</tt> property in order to conform to the
  535.          * requirements of event handlers and callbacks.</p>
  536.          * <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>
  537.          * and some server technologies (notably JEE) may require some custom processing in order to
  538.          * retrieve parameter names and parameter values from the packet content.</p>
  539.          * </div></li>
  540.          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
  541.          * headers to set for the request.</div></li>
  542.          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
  543.          * to use for the post. Note: This will be used instead of params for the post
  544.          * data. Any params will be appended to the URL.</div></li>
  545.          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
  546.          * data to use as the post. Note: This will be used instead of params for the post
  547.          * data. Any params will be appended to the URL.</div></li>
  548.          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
  549.          * to add a unique cache-buster param to GET requests.</div></li>
  550.          * </ul></p>
  551.          * <p>The options object may also contain any other property which might be needed to perform
  552.          * postprocessing in a callback because it is passed to callback functions.</p>
  553.          * @return {Number} transactionId The id of the server transaction. This may be used
  554.          * to cancel the request.
  555.          */
  556.         request : function(o){
  557.             var me = this;
  558.             if(me.fireEvent(BEFOREREQUEST, me, o)){
  559.                 if (o.el) {
  560.                     if(!Ext.isEmpty(o.indicatorText)){
  561.                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
  562.                     }
  563.                     if(me.indicatorText) {
  564.                         Ext.getDom(o.el).innerHTML = me.indicatorText;                        
  565.                     }
  566.                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
  567.                         Ext.getDom(o.el).innerHTML = response.responseText;
  568.                     });
  569.                 }
  570.                 
  571.                 var p = o.params,
  572.                     url = o.url || me.url,                
  573.                     method,
  574.                     cb = {success: handleResponse,
  575.                           failure: handleFailure,
  576.                           scope: me,
  577.                           argument: {options: o},
  578.                           timeout : o.timeout || me.timeout
  579.                     },
  580.                     form,                    
  581.                     serForm;                    
  582.                   
  583.                      
  584.                 if (Ext.isFunction(p)) {
  585.                     p = p.call(o.scope||WINDOW, o);
  586.                 }
  587.                                                            
  588.                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);    
  589.                 
  590.                 if (Ext.isFunction(url)) {
  591.                     url = url.call(o.scope || WINDOW, o);
  592.                 }
  593.     
  594.                 if((form = Ext.getDom(o.form))){
  595.                     url = url || form.action;
  596.                      if(o.isUpload || /multipart/form-data/i.test(form.getAttribute("enctype"))) { 
  597.                          return doFormUpload.call(me, o, p, url);
  598.                      }
  599.                     serForm = Ext.lib.Ajax.serializeForm(form);                    
  600.                     p = p ? (p + '&' + serForm) : serForm;
  601.                 }
  602.                 
  603.                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
  604.                 
  605.                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
  606.                     var dcp = o.disableCachingParam || me.disableCachingParam;
  607.                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
  608.                 }
  609.                 
  610.                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
  611.                 
  612.                 if(o.autoAbort === true || me.autoAbort) {
  613.                     me.abort();
  614.                 }
  615.                  
  616.                 if((method == GET || o.xmlData || o.jsonData) && p){
  617.                     url = Ext.urlAppend(url, p);  
  618.                     p = '';
  619.                 }
  620.                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
  621.             }else{                
  622.                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
  623.             }
  624.         },
  625.     
  626.         /**
  627.          * Determine whether this object has a request outstanding.
  628.          * @param {Number} transactionId (Optional) defaults to the last transaction
  629.          * @return {Boolean} True if there is an outstanding request.
  630.          */
  631.         isLoading : function(transId){
  632.             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;            
  633.         },
  634.     
  635.         /**
  636.          * Aborts any outstanding request.
  637.          * @param {Number} transactionId (Optional) defaults to the last transaction
  638.          */
  639.         abort : function(transId){
  640.             if(transId || this.isLoading()){
  641.                 Ext.lib.Ajax.abort(transId || this.transId);
  642.             }
  643.         }
  644.     });
  645. })();
  646. /**
  647.  * @class Ext.Ajax
  648.  * @extends Ext.data.Connection
  649.  * <p>The global Ajax request class that provides a simple way to make Ajax requests
  650.  * with maximum flexibility.</p>
  651.  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
  652.  * and override them at the request function level only if necessary.</p>
  653.  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
  654.  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
  655.  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
  656.  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
  657.  * </ul></div>
  658.  * <pre><code>
  659. // Default headers to pass in every request
  660. Ext.Ajax.defaultHeaders = {
  661.     'Powered-By': 'Ext'
  662. };
  663.  * </code></pre> 
  664.  * </p>
  665.  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
  666.  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
  667.  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
  668.  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
  669.  * </ul></div>
  670.  * <pre><code>
  671. // Example: show a spinner during all Ajax requests
  672. Ext.Ajax.on('beforerequest', this.showSpinner, this);
  673. Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
  674. Ext.Ajax.on('requestexception', this.hideSpinner, this);
  675.  * </code></pre> 
  676.  * </p>
  677.  * <p>An example request:</p>
  678.  * <pre><code>
  679. // Basic request
  680. Ext.Ajax.{@link Ext.data.Connection#request request}({
  681.    url: 'foo.php',
  682.    success: someFn,
  683.    failure: otherFn,
  684.    headers: {
  685.        'my-header': 'foo'
  686.    },
  687.    params: { foo: 'bar' }
  688. });
  689. // Simple ajax form submission
  690. Ext.Ajax.{@link Ext.data.Connection#request request}({
  691.     form: 'some-form',
  692.     params: 'foo=bar'
  693. });
  694.  * </code></pre> 
  695.  * </p>
  696.  * @singleton
  697.  */
  698. Ext.Ajax = new Ext.data.Connection({
  699.     /**
  700.      * @cfg {String} url @hide
  701.      */
  702.     /**
  703.      * @cfg {Object} extraParams @hide
  704.      */
  705.     /**
  706.      * @cfg {Object} defaultHeaders @hide
  707.      */
  708.     /**
  709.      * @cfg {String} method (Optional) @hide
  710.      */
  711.     /**
  712.      * @cfg {Number} timeout (Optional) @hide
  713.      */
  714.     /**
  715.      * @cfg {Boolean} autoAbort (Optional) @hide
  716.      */
  717.     /**
  718.      * @cfg {Boolean} disableCaching (Optional) @hide
  719.      */
  720.     /**
  721.      * @property  disableCaching
  722.      * True to add a unique cache-buster param to GET requests. (defaults to true)
  723.      * @type Boolean
  724.      */
  725.     /**
  726.      * @property  url
  727.      * The default URL to be used for requests to the server. (defaults to undefined)
  728.      * If the server receives all requests through one URL, setting this once is easier than
  729.      * entering it on every request.
  730.      * @type String
  731.      */
  732.     /**
  733.      * @property  extraParams
  734.      * An object containing properties which are used as extra parameters to each request made
  735.      * by this object (defaults to undefined). Session information and other data that you need
  736.      * to pass with each request are commonly put here.
  737.      * @type Object
  738.      */
  739.     /**
  740.      * @property  defaultHeaders
  741.      * An object containing request headers which are added to each request made by this object
  742.      * (defaults to undefined).
  743.      * @type Object
  744.      */
  745.     /**
  746.      * @property  method
  747.      * The default HTTP method to be used for requests. Note that this is case-sensitive and
  748.      * should be all caps (defaults to undefined; if not set but params are present will use
  749.      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
  750.      * @type String
  751.      */
  752.     /**
  753.      * @property  timeout
  754.      * The timeout in milliseconds to be used for requests. (defaults to 30000)
  755.      * @type Number
  756.      */
  757.     /**
  758.      * @property  autoAbort
  759.      * Whether a new request should abort any pending requests. (defaults to false)
  760.      * @type Boolean
  761.      */
  762.     autoAbort : false,
  763.     /**
  764.      * Serialize the passed form into a url encoded string
  765.      * @param {String/HTMLElement} form
  766.      * @return {String}
  767.      */
  768.     serializeForm : function(form){
  769.         return Ext.lib.Ajax.serializeForm(form);
  770.     }
  771. });
  772. /**  * @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><tt>update</tt></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 <tt>params</tt> 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 <tt>true</tt>      * 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 <tt>this</tt> reference.) If the      * <tt>params</tt> 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 <tt>discardUrl:true</tt> (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 async 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 <tt>&lt;form></tt> 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 <tt>&lt;iframe></tt> 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 || "javascript:false")       }; /**  * 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  * Default Content renderer. Updates the elements innerHTML with the responseText.  */ Ext.Updater.BasicRenderer = function(){}; Ext.Updater.BasicRenderer.prototype = {     /**      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),      * create an object with a "render(el, response)" method and pass it to setRenderer on the Updater.      * @param {Ext.Element} el The element being rendered      * @param {Object} response 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 == 12) { h = 0; }n"                 + "} else { if (h < 12) { h += 12; }}",             s:"(am|pm)"         },         A: {             g:1,             c:"if (results[{0}] == 'AM') {n"                 + "if (h == 12) { h = 0; }n"                 + "} else { if (h < 12) { h += 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 i = 0,             num = 0,             d = this.clone(),             m = this.getMonth();         for (i = 0, 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.DelayedTask  * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,  * performing setTimeout where a new timeout cancels the old timeout. When called, the  * task will wait the specified time period before executing. If durng that time period,  * the task is called again, the original call will be cancelled. This continues so that  * the function is only called a single time for each iteration.</p>  * <p>This method is especially useful for things like detecting whether a user has finished  * typing in a text field. An example would be performing validation on a keypress. You can  * use this class to buffer the keypress events for a certain number of milliseconds, and  * perform only if they stop for that amount of time.  Usage:</p><pre><code> var task = new Ext.util.DelayedTask(function(){     alert(Ext.getDom('myInputField').value.length); }); // Wait 500ms before calling our function. If the user presses another key  // during that 500ms, it will be cancelled and we'll wait another 500ms. Ext.get('myInputField').on('keypress', function(){     task.{@link #delay}(500);  });  * </code></pre>   * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration  * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will  * also setup a delayed task for you to buffer events.</p>   * @constructor The parameters to this constructor serve as defaults and are not required.  * @param {Function} fn (optional) The default function to timeout  * @param {Object} scope (optional) The default scope of that timeout  * @param {Array} args (optional) The default Array of arguments  */ Ext.util.DelayedTask = function(fn, scope, args){     var me = this,      id,          call = function(){      clearInterval(id);         id = null;         fn.apply(scope, args || []);     };          /**      * Cancels any pending timeout and queues a new one      * @param {Number} delay The milliseconds to delay      * @param {Function} newFn (optional) Overrides function passed to constructor      * @param {Object} newScope (optional) Overrides scope passed to constructor      * @param {Array} newArgs (optional) Overrides args passed to constructor      */     me.delay = function(delay, newFn, newScope, newArgs){         me.cancel();         fn = newFn || fn;         scope = newScope || scope;         args = newArgs || args;         id = setInterval(call, delay);     };     /**      * Cancel the last queued timeout      */     me.cancel = function(){         if(id){             clearInterval(id);             id = null;         }     }; };/**
  773.  * @class Ext.util.MixedCollection
  774.  * @extends Ext.util.Observable
  775.  * A Collection class that maintains both numeric indexes and keys and exposes events.
  776.  * @constructor
  777.  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
  778.  * collection (defaults to false)
  779.  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
  780.  * and return the key value for that item.  This is used when available to look up the key on items that
  781.  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
  782.  * equivalent to providing an implementation for the {@link #getKey} method.
  783.  */
  784. Ext.util.MixedCollection = function(allowFunctions, keyFn){
  785.     this.items = [];
  786.     this.map = {};
  787.     this.keys = [];
  788.     this.length = 0;
  789.     this.addEvents(
  790.         /**
  791.          * @event clear
  792.          * Fires when the collection is cleared.
  793.          */
  794.         "clear",
  795.         /**
  796.          * @event add
  797.          * Fires when an item is added to the collection.
  798.          * @param {Number} index The index at which the item was added.
  799.          * @param {Object} o The item added.
  800.          * @param {String} key The key associated with the added item.
  801.          */
  802.         "add",
  803.         /**
  804.          * @event replace
  805.          * Fires when an item is replaced in the collection.
  806.          * @param {String} key he key associated with the new added.
  807.          * @param {Object} old The item being replaced.
  808.          * @param {Object} new The new item.
  809.          */
  810.         "replace",
  811.         /**
  812.          * @event remove
  813.          * Fires when an item is removed from the collection.
  814.          * @param {Object} o The item being removed.
  815.          * @param {String} key (optional) The key associated with the removed item.
  816.          */
  817.         "remove",
  818.         "sort"
  819.     );
  820.     this.allowFunctions = allowFunctions === true;
  821.     if(keyFn){
  822.         this.getKey = keyFn;
  823.     }
  824.     Ext.util.MixedCollection.superclass.constructor.call(this);
  825. };
  826. Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {
  827.     allowFunctions : false,
  828. /**
  829.  * Adds an item to the collection. Fires the {@link #add} event when complete.
  830.  * @param {String} key <p>The key to associate with the item, or the new item.</p>
  831.  * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
  832.  * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
  833.  * will be able to <i>derive</i> the key for the new item. In this case just pass the new item in
  834.  * this parameter.</p>
  835.  * @param {Object} o The item to add.
  836.  * @return {Object} The item added.
  837.  */
  838.     add: function(key, o){
  839.         if(arguments.length == 1){
  840.             o = arguments[0];
  841.             key = this.getKey(o);
  842.         }
  843.         if(typeof key != 'undefined' && key !== null){
  844.             var old = this.map[key];
  845.             if(typeof old != 'undefined'){
  846.                 return this.replace(key, o);
  847.             }
  848.             this.map[key] = o;
  849.         }
  850.         this.length++;
  851.         this.items.push(o);
  852.         this.keys.push(key);
  853.         this.fireEvent('add', this.length-1, o, key);
  854.         return o;
  855.     },
  856. /**
  857.   * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation
  858.   * simply returns <tt style="font-weight:bold;">item.id</tt> but you can provide your own implementation
  859.   * to return a different value as in the following examples:
  860. <pre><code>
  861. // normal way
  862. var mc = new Ext.util.MixedCollection();
  863. mc.add(someEl.dom.id, someEl);
  864. mc.add(otherEl.dom.id, otherEl);
  865. //and so on
  866. // using getKey
  867. var mc = new Ext.util.MixedCollection();
  868. mc.getKey = function(el){
  869.    return el.dom.id;
  870. };
  871. mc.add(someEl);
  872. mc.add(otherEl);
  873. // or via the constructor
  874. var mc = new Ext.util.MixedCollection(false, function(el){
  875.    return el.dom.id;
  876. });
  877. mc.add(someEl);
  878. mc.add(otherEl);
  879. </code></pre>
  880.  * @param {Object} item The item for which to find the key.
  881.  * @return {Object} The key for the passed item.
  882.  */
  883.     getKey : function(o){
  884.          return o.id;
  885.     },
  886. /**
  887.  * Replaces an item in the collection. Fires the {@link #replace} event when complete.
  888.  * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
  889.  * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
  890.  * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
  891.  * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
  892.  * with one having the same key value, then just pass the replacement item in this parameter.</p>
  893.  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
  894.  * with that key.
  895.  * @return {Object}  The new item.
  896.  */
  897.     replace : function(key, o){
  898.         if(arguments.length == 1){
  899.             o = arguments[0];
  900.             key = this.getKey(o);
  901.         }
  902.         var old = this.map[key];
  903.         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
  904.              return this.add(key, o);
  905.         }
  906.         var index = this.indexOfKey(key);
  907.         this.items[index] = o;
  908.         this.map[key] = o;
  909.         this.fireEvent("replace", key, old, o);
  910.         return o;
  911.     },
  912. /**
  913.  * Adds all elements of an Array or an Object to the collection.
  914.  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
  915.  * an Array of values, each of which are added to the collection.
  916.  */
  917.     addAll : function(objs){
  918.         if(arguments.length > 1 || Ext.isArray(objs)){
  919.             var args = arguments.length > 1 ? arguments : objs;
  920.             for(var i = 0, len = args.length; i < len; i++){
  921.                 this.add(args[i]);
  922.             }
  923.         }else{
  924.             for(var key in objs){
  925.                 if(this.allowFunctions || typeof objs[key] != "function"){
  926.                     this.add(key, objs[key]);
  927.                 }
  928.             }
  929.         }
  930.     },
  931. /**
  932.  * Executes the specified function once for every item in the collection, passing the following arguments:
  933.  * <div class="mdetail-params"><ul>
  934.  * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
  935.  * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
  936.  * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
  937.  * </ul></div>
  938.  * The function should return a boolean value. Returning false from the function will stop the iteration.
  939.  * @param {Function} fn The function to execute for each item.
  940.  * @param {Object} scope (optional) The scope in which to execute the function.
  941.  */
  942.     each : function(fn, scope){
  943.         var items = [].concat(this.items); // each safe for removal
  944.         for(var i = 0, len = items.length; i < len; i++){
  945.             if(fn.call(scope || items[i], items[i], i, len) === false){
  946.                 break;
  947.             }
  948.         }
  949.     },
  950. /**
  951.  * Executes the specified function once for every key in the collection, passing each
  952.  * key, and its associated item as the first two parameters.
  953.  * @param {Function} fn The function to execute for each item.
  954.  * @param {Object} scope (optional) The scope in which to execute the function.
  955.  */
  956.     eachKey : function(fn, scope){
  957.         for(var i = 0, len = this.keys.length; i < len; i++){
  958.             fn.call(scope || window, this.keys[i], this.items[i], i, len);
  959.         }
  960.     },
  961.     /**
  962.      * Returns the first item in the collection which elicits a true return value from the
  963.      * passed selection function.
  964.      * @param {Function} fn The selection function to execute for each item.
  965.      * @param {Object} scope (optional) The scope in which to execute the function.
  966.      * @return {Object} The first item in the collection which returned true from the selection function.
  967.      */
  968.     find : function(fn, scope){
  969.         for(var i = 0, len = this.items.length; i < len; i++){
  970.             if(fn.call(scope || window, this.items[i], this.keys[i])){
  971.                 return this.items[i];
  972.             }
  973.         }
  974.         return null;
  975.     },
  976. /**
  977.  * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
  978.  * @param {Number} index The index to insert the item at.
  979.  * @param {String} key The key to associate with the new item, or the item itself.
  980.  * @param {Object} o (optional) If the second parameter was a key, the new item.
  981.  * @return {Object} The item inserted.
  982.  */
  983.     insert : function(index, key, o){
  984.         if(arguments.length == 2){
  985.             o = arguments[1];
  986.             key = this.getKey(o);
  987.         }
  988.         if(this.containsKey(key)){
  989.             this.suspendEvents();
  990.             this.removeKey(key);
  991.             this.resumeEvents();
  992.         }
  993.         if(index >= this.length){
  994.             return this.add(key, o);
  995.         }
  996.         this.length++;
  997.         this.items.splice(index, 0, o);
  998.         if(typeof key != "undefined" && key !== null){
  999.             this.map[key] = o;
  1000.         }
  1001.         this.keys.splice(index, 0, key);
  1002.         this.fireEvent("add", index, o, key);
  1003.         return o;
  1004.     },
  1005. /**
  1006.  * Remove an item from the collection.
  1007.  * @param {Object} o The item to remove.
  1008.  * @return {Object} The item removed or false if no item was removed.
  1009.  */
  1010.     remove : function(o){
  1011.         return this.removeAt(this.indexOf(o));
  1012.     },
  1013. /**
  1014.  * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
  1015.  * @param {Number} index The index within the collection of the item to remove.
  1016.  * @return {Object} The item removed or false if no item was removed.
  1017.  */
  1018.     removeAt : function(index){
  1019.         if(index < this.length && index >= 0){
  1020.             this.length--;
  1021.             var o = this.items[index];
  1022.             this.items.splice(index, 1);
  1023.             var key = this.keys[index];
  1024.             if(typeof key != "undefined"){
  1025.                 delete this.map[key];
  1026.             }
  1027.             this.keys.splice(index, 1);
  1028.             this.fireEvent("remove", o, key);
  1029.             return o;
  1030.         }
  1031.         return false;
  1032.     },
  1033. /**
  1034.  * Removed an item associated with the passed key fom the collection.
  1035.  * @param {String} key The key of the item to remove.
  1036.  * @return {Object} The item removed or false if no item was removed.
  1037.  */
  1038.     removeKey : function(key){
  1039.         return this.removeAt(this.indexOfKey(key));
  1040.     },
  1041. /**
  1042.  * Returns the number of items in the collection.
  1043.  * @return {Number} the number of items in the collection.
  1044.  */
  1045.     getCount : function(){
  1046.         return this.length;
  1047.     },
  1048. /**
  1049.  * Returns index within the collection of the passed Object.
  1050.  * @param {Object} o The item to find the index of.
  1051.  * @return {Number} index of the item. Returns -1 if not found.
  1052.  */
  1053.     indexOf : function(o){
  1054.         return this.items.indexOf(o);
  1055.     },
  1056. /**
  1057.  * Returns index within the collection of the passed key.
  1058.  * @param {String} key The key to find the index of.
  1059.  * @return {Number} index of the key.
  1060.  */
  1061.     indexOfKey : function(key){
  1062.         return this.keys.indexOf(key);
  1063.     },
  1064. /**
  1065.  * Returns the item associated with the passed key OR index. Key has priority over index.  This is the equivalent
  1066.  * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.
  1067.  * @param {String/Number} key The key or index of the item.
  1068.  * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.
  1069.  * If an item was found, but is a Class, returns <tt>null</tt>.
  1070.  */
  1071.     item : function(key){
  1072.         var mk = this.map[key],
  1073.             item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;
  1074.         return !Ext.isFunction(item) || this.allowFunctions ? item : null; // for prototype!
  1075.     },
  1076. /**
  1077.  * Returns the item at the specified index.
  1078.  * @param {Number} index The index of the item.
  1079.  * @return {Object} The item at the specified index.
  1080.  */
  1081.     itemAt : function(index){
  1082.         return this.items[index];
  1083.     },
  1084. /**
  1085.  * Returns the item associated with the passed key.
  1086.  * @param {String/Number} key The key of the item.
  1087.  * @return {Object} The item associated with the passed key.
  1088.  */
  1089.     key : function(key){
  1090.         return this.map[key];
  1091.     },
  1092. /**
  1093.  * Returns true if the collection contains the passed Object as an item.
  1094.  * @param {Object} o  The Object to look for in the collection.
  1095.  * @return {Boolean} True if the collection contains the Object as an item.
  1096.  */
  1097.     contains : function(o){
  1098.         return this.indexOf(o) != -1;
  1099.     },
  1100. /**
  1101.  * Returns true if the collection contains the passed Object as a key.
  1102.  * @param {String} key The key to look for in the collection.
  1103.  * @return {Boolean} True if the collection contains the Object as a key.
  1104.  */
  1105.     containsKey : function(key){
  1106.         return typeof this.map[key] != "undefined";
  1107.     },
  1108. /**
  1109.  * Removes all items from the collection.  Fires the {@link #clear} event when complete.
  1110.  */
  1111.     clear : function(){
  1112.         this.length = 0;
  1113.         this.items = [];
  1114.         this.keys = [];
  1115.         this.map = {};
  1116.         this.fireEvent("clear");
  1117.     },
  1118. /**
  1119.  * Returns the first item in the collection.
  1120.  * @return {Object} the first item in the collection..
  1121.  */
  1122.     first : function(){
  1123.         return this.items[0];
  1124.     },
  1125. /**
  1126.  * Returns the last item in the collection.
  1127.  * @return {Object} the last item in the collection..
  1128.  */
  1129.     last : function(){
  1130.         return this.items[this.length-1];
  1131.     },
  1132.     // private
  1133.     _sort : function(property, dir, fn){
  1134.         var i,
  1135.             len,
  1136.             dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1,
  1137.             c = [], k = this.keys, items = this.items;
  1138.             
  1139.         fn = fn || function(a, b){
  1140.             return a-b;
  1141.         };
  1142.         for(i = 0, len = items.length; i < len; i++){
  1143.             c[c.length] = {key: k[i], value: items[i], index: i};
  1144.         }
  1145.         c.sort(function(a, b){
  1146.             var v = fn(a[property], b[property]) * dsc;
  1147.             if(v === 0){
  1148.                 v = (a.index < b.index ? -1 : 1);
  1149.             }
  1150.             return v;
  1151.         });
  1152.         for(i = 0, len = c.length; i < len; i++){
  1153.             items[i] = c[i].value;
  1154.             k[i] = c[i].key;
  1155.         }
  1156.         this.fireEvent("sort", this);
  1157.     },
  1158.     /**
  1159.      * Sorts this collection with the passed comparison function
  1160.      * @param {String} direction (optional) "ASC" or "DESC"
  1161.      * @param {Function} fn (optional) comparison function
  1162.      */
  1163.     sort : function(dir, fn){
  1164.         this._sort("value", dir, fn);
  1165.     },
  1166.     /**
  1167.      * Sorts this collection by keys
  1168.      * @param {String} direction (optional) "ASC" or "DESC"
  1169.      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
  1170.      */
  1171.     keySort : function(dir, fn){
  1172.         this._sort("key", dir, fn || function(a, b){
  1173.             var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();
  1174.             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
  1175.         });
  1176.     },
  1177.     /**
  1178.      * Returns a range of items in this collection
  1179.      * @param {Number} startIndex (optional) defaults to 0
  1180.      * @param {Number} endIndex (optional) default to the last item
  1181.      * @return {Array} An array of items
  1182.      */
  1183.     getRange : function(start, end){
  1184.         var items = this.items;
  1185.         if(items.length < 1){
  1186.             return [];
  1187.         }
  1188.         start = start || 0;
  1189.         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
  1190.         var i, r = [];
  1191.         if(start <= end){
  1192.             for(i = start; i <= end; i++) {
  1193.                 r[r.length] = items[i];
  1194.             }
  1195.         }else{
  1196.             for(i = start; i >= end; i--) {
  1197.                 r[r.length] = items[i];
  1198.             }
  1199.         }
  1200.         return r;
  1201.     },
  1202.     /**
  1203.      * Filter the <i>objects</i> in this collection by a specific property.
  1204.      * Returns a new collection that has been filtered.
  1205.      * @param {String} property A property on your objects
  1206.      * @param {String/RegExp} value Either string that the property values
  1207.      * should start with or a RegExp to test against the property
  1208.      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
  1209.      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).
  1210.      * @return {MixedCollection} The new filtered collection
  1211.      */
  1212.     filter : function(property, value, anyMatch, caseSensitive){
  1213.         if(Ext.isEmpty(value, false)){
  1214.             return this.clone();
  1215.         }
  1216.         value = this.createValueMatcher(value, anyMatch, caseSensitive);
  1217.         return this.filterBy(function(o){
  1218.             return o && value.test(o[property]);
  1219.         });
  1220.     },
  1221.     /**
  1222.      * Filter by a function. Returns a <i>new</i> collection that has been filtered.
  1223.      * The passed function will be called with each object in the collection.
  1224.      * If the function returns true, the value is included otherwise it is filtered.
  1225.      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
  1226.      * @param {Object} scope (optional) The scope of the function (defaults to this)
  1227.      * @return {MixedCollection} The new filtered collection
  1228.      */
  1229.     filterBy : function(fn, scope){
  1230.         var r = new Ext.util.MixedCollection();
  1231.         r.getKey = this.getKey;
  1232.         var k = this.keys, it = this.items;
  1233.         for(var i = 0, len = it.length; i < len; i++){
  1234.             if(fn.call(scope||this, it[i], k[i])){
  1235.                 r.add(k[i], it[i]);
  1236.             }
  1237.         }
  1238.         return r;
  1239.     },
  1240.     /**
  1241.      * Finds the index of the first matching object in this collection by a specific property/value.
  1242.      * @param {String} property The name of a property on your objects.
  1243.      * @param {String/RegExp} value A string that the property values
  1244.      * should start with or a RegExp to test against the property.
  1245.      * @param {Number} start (optional) The index to start searching at (defaults to 0).
  1246.      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.
  1247.      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.
  1248.      * @return {Number} The matched index or -1
  1249.      */
  1250.     findIndex : function(property, value, start, anyMatch, caseSensitive){
  1251.         if(Ext.isEmpty(value, false)){
  1252.             return -1;
  1253.         }
  1254.         value = this.createValueMatcher(value, anyMatch, caseSensitive);
  1255.         return this.findIndexBy(function(o){
  1256.             return o && value.test(o[property]);
  1257.         }, null, start);
  1258.     },
  1259.     /**
  1260.      * Find the index of the first matching object in this collection by a function.
  1261.      * If the function returns <i>true</i> it is considered a match.
  1262.      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
  1263.      * @param {Object} scope (optional) The scope of the function (defaults to this).
  1264.      * @param {Number} start (optional) The index to start searching at (defaults to 0).
  1265.      * @return {Number} The matched index or -1
  1266.      */
  1267.     findIndexBy : function(fn, scope, start){
  1268.         var k = this.keys, it = this.items;
  1269.         for(var i = (start||0), len = it.length; i < len; i++){
  1270.             if(fn.call(scope||this, it[i], k[i])){
  1271.                 return i;
  1272.             }
  1273.         }
  1274.         return -1;
  1275.     },
  1276.     // private
  1277.     createValueMatcher : function(value, anyMatch, caseSensitive){
  1278.         if(!value.exec){ // not a regex
  1279.             value = String(value);
  1280.             value = new RegExp((anyMatch === true ? '' : '^') + Ext.escapeRe(value), caseSensitive ? '' : 'i');
  1281.         }
  1282.         return value;
  1283.     },
  1284.     /**
  1285.      * Creates a shallow copy of this collection
  1286.      * @return {MixedCollection}
  1287.      */
  1288.     clone : function(){
  1289.         var r = new Ext.util.MixedCollection();
  1290.         var k = this.keys, it = this.items;
  1291.         for(var i = 0, len = it.length; i < len; i++){
  1292.             r.add(k[i], it[i]);
  1293.         }
  1294.         r.getKey = this.getKey;
  1295.         return r;
  1296.     }
  1297. });
  1298. /**
  1299.  * This method calls {@link #item item()}.
  1300.  * Returns the item associated with the passed key OR index. Key has priority over index.  This is the equivalent
  1301.  * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.
  1302.  * @param {String/Number} key The key or index of the item.
  1303.  * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.
  1304.  * If an item was found, but is a Class, returns <tt>null</tt>.
  1305.  */
  1306. 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(typeof o == "undefined" || o === null){                 return "null";             }else if(Ext.isArray(o)){                 return encodeArray(o);             }else if(Object.prototype.toString.apply(o) === '[object Date]'){                 return Ext.util.JSON.encodeDate(o);             }else if(typeof o == "string"){                 return encodeString(o);             }else if(typeof o == "number"){                 return isFinite(o) ? String(o) : "null";             }else if(typeof o == "boolean"){                 return String(o);             }else {                 var a = ["{"], b, i, v;                 for (i in o) {                     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; /**
  1307.  * @class Ext.util.Format
  1308.  * Reusable data formatting functions
  1309.  * @singleton
  1310.  */
  1311. Ext.util.Format = function(){
  1312.     var trimRe = /^s+|s+$/g;
  1313.     return {
  1314.         /**
  1315.          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
  1316.          * @param {String} value The string to truncate
  1317.          * @param {Number} length The maximum length to allow before truncating
  1318.          * @param {Boolean} word True to try to find a common work break
  1319.          * @return {String} The converted text
  1320.          */
  1321.         ellipsis : function(value, len, word){
  1322.             if(value && value.length > len){
  1323.                 if(word){
  1324.                     var vs = value.substr(0, len - 2);
  1325.                     var index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
  1326.                     if(index == -1 || index < (len - 15)){
  1327.                         return value.substr(0, len - 3) + "...";
  1328.                     }else{
  1329.                         return vs.substr(0, index) + "...";
  1330.                     }
  1331.                 } else{
  1332.                     return value.substr(0, len - 3) + "...";
  1333.                 }
  1334.             }
  1335.             return value;
  1336.         },
  1337.         /**
  1338.          * Checks a reference and converts it to empty string if it is undefined
  1339.          * @param {Mixed} value Reference to check
  1340.          * @return {Mixed} Empty string if converted, otherwise the original value
  1341.          */
  1342.         undef : function(value){
  1343.             return value !== undefined ? value : "";
  1344.         },
  1345.         /**
  1346.          * Checks a reference and converts it to the default value if it's empty
  1347.          * @param {Mixed} value Reference to check
  1348.          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
  1349.          * @return {String}
  1350.          */
  1351.         defaultValue : function(value, defaultValue){
  1352.             return value !== undefined && value !== '' ? value : defaultValue;
  1353.         },
  1354.         /**
  1355.          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
  1356.          * @param {String} value The string to encode
  1357.          * @return {String} The encoded text
  1358.          */
  1359.         htmlEncode : function(value){
  1360.             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
  1361.         },
  1362.         /**
  1363.          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
  1364.          * @param {String} value The string to decode
  1365.          * @return {String} The decoded text
  1366.          */
  1367.         htmlDecode : function(value){
  1368.             return !value ? value : String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");
  1369.         },
  1370.         /**
  1371.          * Trims any whitespace from either side of a string
  1372.          * @param {String} value The text to trim
  1373.          * @return {String} The trimmed text
  1374.          */
  1375.         trim : function(value){
  1376.             return String(value).replace(trimRe, "");
  1377.         },
  1378.         /**
  1379.          * Returns a substring from within an original string
  1380.          * @param {String} value The original text
  1381.          * @param {Number} start The start index of the substring
  1382.          * @param {Number} length The length of the substring
  1383.          * @return {String} The substring
  1384.          */
  1385.         substr : function(value, start, length){
  1386.             return String(value).substr(start, length);
  1387.         },
  1388.         /**
  1389.          * Converts a string to all lower case letters
  1390.          * @param {String} value The text to convert
  1391.          * @return {String} The converted text
  1392.          */
  1393.         lowercase : function(value){
  1394.             return String(value).toLowerCase();
  1395.         },
  1396.         /**
  1397.          * Converts a string to all upper case letters
  1398.          * @param {String} value The text to convert
  1399.          * @return {String} The converted text
  1400.          */
  1401.         uppercase : function(value){
  1402.             return String(value).toUpperCase();
  1403.         },
  1404.         /**
  1405.          * Converts the first character only of a string to upper case
  1406.          * @param {String} value The text to convert
  1407.          * @return {String} The converted text
  1408.          */
  1409.         capitalize : function(value){
  1410.             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
  1411.         },
  1412.         // private
  1413.         call : function(value, fn){
  1414.             if(arguments.length > 2){
  1415.                 var args = Array.prototype.slice.call(arguments, 2);
  1416.                 args.unshift(value);
  1417.                 return eval(fn).apply(window, args);
  1418.             }else{
  1419.                 return eval(fn).call(window, value);
  1420.             }
  1421.         },
  1422.         /**
  1423.          * Format a number as US currency
  1424.          * @param {Number/String} value The numeric value to format
  1425.          * @return {String} The formatted currency string
  1426.          */
  1427.         usMoney : function(v){
  1428.             v = (Math.round((v-0)*100))/100;
  1429.             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
  1430.             v = String(v);
  1431.             var ps = v.split('.');
  1432.             var whole = ps[0];
  1433.             var sub = ps[1] ? '.'+ ps[1] : '.00';
  1434.             var r = /(d+)(d{3})/;
  1435.             while (r.test(whole)) {
  1436.                 whole = whole.replace(r, '$1' + ',' + '$2');
  1437.             }
  1438.             v = whole + sub;
  1439.             if(v.charAt(0) == '-'){
  1440.                 return '-$' + v.substr(1);
  1441.             }
  1442.             return "$" +  v;
  1443.         },
  1444.         /**
  1445.          * Parse a value into a formatted date using the specified format pattern.
  1446.          * @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)
  1447.          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
  1448.          * @return {String} The formatted date string
  1449.          */
  1450.         date : function(v, format){
  1451.             if(!v){
  1452.                 return "";
  1453.             }
  1454.             if(!Ext.isDate(v)){
  1455.                 v = new Date(Date.parse(v));
  1456.             }
  1457.             return v.dateFormat(format || "m/d/Y");
  1458.         },
  1459.         /**
  1460.          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
  1461.          * @param {String} format Any valid date format string
  1462.          * @return {Function} The date formatting function
  1463.          */
  1464.         dateRenderer : function(format){
  1465.             return function(v){
  1466.                 return Ext.util.Format.date(v, format);
  1467.             };
  1468.         },
  1469.         // private
  1470.         stripTagsRE : /</?[^>]+>/gi,
  1471.         
  1472.         /**
  1473.          * Strips all HTML tags
  1474.          * @param {Mixed} value The text from which to strip tags
  1475.          * @return {String} The stripped text
  1476.          */
  1477.         stripTags : function(v){
  1478.             return !v ? v : String(v).replace(this.stripTagsRE, "");
  1479.         },
  1480.         stripScriptsRe : /(?:<script.*?>)((n|r|.)*?)(?:</script>)/ig,
  1481.         /**
  1482.          * Strips all script tags
  1483.          * @param {Mixed} value The text from which to strip script tags
  1484.          * @return {String} The stripped text
  1485.          */
  1486.         stripScripts : function(v){
  1487.             return !v ? v : String(v).replace(this.stripScriptsRe, "");
  1488.         },
  1489.         /**
  1490.          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
  1491.          * @param {Number/String} size The numeric value to format
  1492.          * @return {String} The formatted file size
  1493.          */
  1494.         fileSize : function(size){
  1495.             if(size < 1024) {
  1496.                 return size + " bytes";
  1497.             } else if(size < 1048576) {
  1498.                 return (Math.round(((size*10) / 1024))/10) + " KB";
  1499.             } else {
  1500.                 return (Math.round(((size*10) / 1048576))/10) + " MB";
  1501.             }
  1502.         },
  1503.         /**
  1504.          * It does simple math for use in a template, for example:<pre><code>
  1505.          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
  1506.          * </code></pre>
  1507.          * @return {Function} A function that operates on the passed value.
  1508.          */
  1509.         math : function(){
  1510.             var fns = {};
  1511.             return function(v, a){
  1512.                 if(!fns[a]){
  1513.                     fns[a] = new Function('v', 'return v ' + a + ';');
  1514.                 }
  1515.                 return fns[a](v);
  1516.             }
  1517.         }(),
  1518.         /**
  1519.          * Rounds the passed number to the required decimal precision.
  1520.          * @param {Number/String} value The numeric value to round.
  1521.          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
  1522.          * @return {Number} The rounded value.
  1523.          */
  1524.         round : function(value, precision) {
  1525.             var result = Number(value);
  1526.             if (typeof precision == 'number') {
  1527.                 precision = Math.pow(10, precision);
  1528.                 result = Math.round(value * precision) / precision;
  1529.             }
  1530.             return result;
  1531.         },
  1532.         /**
  1533.          * Formats the number according to the format string.
  1534.          * <div style="margin-left:40px">examples (123456.789):
  1535.          * <div style="margin-left:10px">
  1536.          * 0 - (123456) show only digits, no precision<br>
  1537.          * 0.00 - (123456.78) show only digits, 2 precision<br>
  1538.          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
  1539.          * 0,000 - (123,456) show comma and digits, no precision<br>
  1540.          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
  1541.          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
  1542.          * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.
  1543.          * For example: 0.000,00/i
  1544.          * </div></div>
  1545.          * @param {Number} v The number to format.
  1546.          * @param {String} format The way you would like to format this text.
  1547.          * @return {String} The formatted number.
  1548.          */
  1549.         number: function(v, format) {
  1550.             if(!format){
  1551.         return v;
  1552.     }
  1553.     v = Ext.num(v, NaN);
  1554.             if (isNaN(v)){
  1555.                 return '';
  1556.             }
  1557.     var comma = ',',
  1558.         dec = '.',
  1559.         i18n = false,
  1560.         neg = v < 0;
  1561.     v = Math.abs(v);
  1562.     if(format.substr(format.length - 2) == '/i'){
  1563.         format = format.substr(0, format.length - 2);
  1564.         i18n = true;
  1565.         comma = '.';
  1566.         dec = ',';
  1567.     }
  1568.     var hasComma = format.indexOf(comma) != -1, 
  1569.         psplit = (i18n ? format.replace(/[^d,]/g, '') : format.replace(/[^d.]/g, '')).split(dec);
  1570.     if(1 < psplit.length){
  1571.         v = v.toFixed(psplit[1].length);
  1572.     }else if(2 < psplit.length){
  1573.         throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
  1574.     }else{
  1575.         v = v.toFixed(0);
  1576.     }
  1577.     var fnum = v.toString();
  1578.     if(hasComma){
  1579.         psplit = fnum.split('.');
  1580.         var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;
  1581.         for(var i = 0; i < j; i += n){
  1582.             if(i != 0){
  1583.                 n = 3;
  1584.             }
  1585.             parr[parr.length] = cnum.substr(i, n);
  1586.             m -= 1;
  1587.         }
  1588.         fnum = parr.join(comma);
  1589.         if(psplit[1]){
  1590.             fnum += dec + psplit[1];
  1591.         }
  1592.     }
  1593.     return (neg ? '-' : '') + format.replace(/[d,?.?]+/, fnum);
  1594.         },
  1595.         /**
  1596.          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
  1597.          * @param {String} format Any valid number format string for {@link #number}
  1598.          * @return {Function} The number formatting function
  1599.          */
  1600.         numberRenderer : function(format){
  1601.             return function(v){
  1602.                 return Ext.util.Format.number(v, format);
  1603.             };
  1604.         },
  1605.         /**
  1606.          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
  1607.          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
  1608.          * if the value is 0 or greater than 1.
  1609.          * @param {Number} value The value to compare against
  1610.          * @param {String} singular The singular form of the word
  1611.          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
  1612.          */
  1613.         plural : function(v, s, p){
  1614.             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
  1615.         },
  1616.         
  1617.         /**
  1618.          * Converts newline characters to the HTML tag &lt;br/>
  1619.          * @param {String} The string value to format.
  1620.          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
  1621.          */
  1622.         nl2br : function(v){
  1623.             return v === undefined || v === null ? '' : v.replace(/n/g, '<br/>');
  1624.         }
  1625.     }
  1626. }();/**  * @class Ext.XTemplate  * @extends Ext.Template  * <p>A template class that supports advanced functionality like autofilling arrays, conditional processing with  * basic comparison operators, sub-templates, basic math function support, special built-in template variables,  * inline code execution and more.  XTemplate also provides the templating mechanism built into {@link Ext.DataView}.</p>  * <p>XTemplate supports 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.  The following examples demonstrate all of the supported features.  * 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>  * <p><b>Auto filling of arrays</b><br/>The <tt>tpl</tt> tag and the <tt>for</tt> operator are used  * to process the provided data object. If <tt>for="."</tt> is specified, the data object provided  * is examined. If the variable 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:</p>  * <pre><code> var tpl = new Ext.XTemplate(     '&lt;p>Kids: ',     '&lt;tpl for=".">',         '&lt;p>{name}&lt;/p>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object  * </code></pre>  * <p><b>Scope switching</b><br/>The <tt>for</tt> 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);  * </code></pre>  * <p><b>Access to parent object from within sub-template scope</b><br/>When processing a sub-template, for example while  * looping through a child array, you can access the parent object's members via the <tt>parent</tt> 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 &amp;gt; 1">',  // <-- Note that the &gt; is encoded             '&lt;p>{name}&lt;/p>',             '&lt;p>Dad: {parent.name}&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data); </code></pre>  * <p><b>Array item index and basic math support</b> <br/>While processing an array, the special variable <tt>{#}</tt>  * will provide the current array index + 1 (starts at 1, not 0). Templates also support the basic math operators  * + - * and / that can be applied directly on numeric data values:</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 &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>  * <p><b>Auto-rendering of flat arrays</b> <br/>Flat arrays that contain values (and not objects) can be auto-rendered  * using the special <tt>{.}</tt> 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}'s favorite beverages:&lt;/p>',     '&lt;tpl for="drinks">',        '&lt;div> - {.}&lt;/div>',     '&lt;/tpl>' ); tpl.overwrite(panel.body, data); </code></pre>  * <p><b>Basic conditional logic</b> <br/>Using the <tt>tpl</tt> tag and the <tt>if</tt>  * operator you can provide conditional checks for deciding whether or not to render specific parts of the template.  * Note that there is no <tt>else</tt> operator &mdash; if needed, you should use two opposite <tt>if</tt> statements.  * Properly-encoded attributes are required as seen in the following example:</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 &amp;gt; 1">',  // <-- Note that the &gt; is encoded             '&lt;p>{name}&lt;/p>',         '&lt;/tpl>',     '&lt;/tpl>&lt;/p>' ); tpl.overwrite(panel.body, data); </code></pre>  * <p><b>Ability to execute arbitrary inline code</b> <br/>In an XTemplate, anything between {[ ... ]}  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>  * <p><b>Template member functions</b> <br/>One or more member functions can be defined directly on the config  * 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>',         '&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>', {      isGirl: function(name){          return name == 'Sara Grace';      },      isBaby: function(age){         return age < 1;      } }); tpl.overwrite(panel.body, data); </code></pre>  * @constructor  * @param {String/Array/Object} parts The HTML fragment or an array of fragments to join(""), or multiple arguments  * to join("") that can also include a config object  */ 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){             return "'"+ sep +'('+code+')'+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); };/**
  1627.  * @class Ext.util.CSS
  1628.  * Utility class for manipulating CSS rules
  1629.  * @singleton
  1630.  */
  1631. Ext.util.CSS = function(){
  1632. var rules = null;
  1633.     var doc = document;
  1634.     var camelRe = /(-[a-z])/gi;
  1635.     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
  1636.    return {
  1637.    /**
  1638.     * Creates a stylesheet from a text blob of rules.
  1639.     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
  1640.     * @param {String} cssText The text containing the css rules
  1641.     * @param {String} id An id to add to the stylesheet for later removal
  1642.     * @return {StyleSheet}
  1643.     */
  1644.    createStyleSheet : function(cssText, id){
  1645.        var ss;
  1646.        var head = doc.getElementsByTagName("head")[0];
  1647.        var rules = doc.createElement("style");
  1648.        rules.setAttribute("type", "text/css");
  1649.        if(id){
  1650.            rules.setAttribute("id", id);
  1651.        }
  1652.        if(Ext.isIE){
  1653.            head.appendChild(rules);
  1654.            ss = rules.styleSheet;
  1655.            ss.cssText = cssText;
  1656.        }else{
  1657.            try{
  1658.                 rules.appendChild(doc.createTextNode(cssText));
  1659.            }catch(e){
  1660.                rules.cssText = cssText;
  1661.            }
  1662.            head.appendChild(rules);
  1663.            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
  1664.        }
  1665.        this.cacheStyleSheet(ss);
  1666.        return ss;
  1667.    },
  1668.    /**
  1669.     * Removes a style or link tag by id
  1670.     * @param {String} id The id of the tag
  1671.     */
  1672.    removeStyleSheet : function(id){
  1673.        var existing = doc.getElementById(id);
  1674.        if(existing){
  1675.            existing.parentNode.removeChild(existing);
  1676.        }
  1677.    },
  1678.    /**
  1679.     * Dynamically swaps an existing stylesheet reference for a new one
  1680.     * @param {String} id The id of an existing link tag to remove
  1681.     * @param {String} url The href of the new stylesheet to include
  1682.     */
  1683.    swapStyleSheet : function(id, url){
  1684.        this.removeStyleSheet(id);
  1685.        var ss = doc.createElement("link");
  1686.        ss.setAttribute("rel", "stylesheet");
  1687.        ss.setAttribute("type", "text/css");
  1688.        ss.setAttribute("id", id);
  1689.        ss.setAttribute("href", url);
  1690.        doc.getElementsByTagName("head")[0].appendChild(ss);
  1691.    },
  1692.    
  1693.    /**
  1694.     * Refresh the rule cache if you have dynamically added stylesheets
  1695.     * @return {Object} An object (hash) of rules indexed by selector
  1696.     */
  1697.    refreshCache : function(){
  1698.        return this.getRules(true);
  1699.    },
  1700.    // private
  1701.    cacheStyleSheet : function(ss){
  1702.        if(!rules){
  1703.            rules = {};
  1704.        }
  1705.        try{// try catch for cross domain access issue
  1706.            var ssRules = ss.cssRules || ss.rules;
  1707.            for(var j = ssRules.length-1; j >= 0; --j){
  1708.                rules[ssRules[j].selectorText] = ssRules[j];
  1709.            }
  1710.        }catch(e){}
  1711.    },
  1712.    
  1713.    /**
  1714.     * Gets all css rules for the document
  1715.     * @param {Boolean} refreshCache true to refresh the internal cache
  1716.     * @return {Object} An object (hash) of rules indexed by selector
  1717.     */
  1718.    getRules : function(refreshCache){
  1719.     if(rules === null || refreshCache){
  1720.     rules = {};
  1721.     var ds = doc.styleSheets;
  1722.     for(var i =0, len = ds.length; i < len; i++){
  1723.         try{
  1724.              this.cacheStyleSheet(ds[i]);
  1725.          }catch(e){} 
  1726.         }
  1727.     }
  1728.     return rules;
  1729.     },
  1730.    
  1731.     /**
  1732.     * Gets an an individual CSS rule by selector(s)
  1733.     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
  1734.     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
  1735.     * @return {CSSRule} The CSS rule or null if one is not found
  1736.     */
  1737.    getRule : function(selector, refreshCache){
  1738.     var rs = this.getRules(refreshCache);
  1739.     if(!Ext.isArray(selector)){
  1740.         return rs[selector];
  1741.     }
  1742.     for(var i = 0; i < selector.length; i++){
  1743. if(rs[selector[i]]){
  1744. return rs[selector[i]];
  1745. }
  1746. }
  1747. return null;
  1748.     },
  1749.    
  1750.    
  1751.     /**
  1752.     * Updates a rule property
  1753.     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
  1754.     * @param {String} property The css property
  1755.     * @param {String} value The new value for the property
  1756.     * @return {Boolean} true If a rule was found and updated
  1757.     */
  1758.    updateRule : function(selector, property, value){
  1759.     if(!Ext.isArray(selector)){
  1760.     var rule = this.getRule(selector);
  1761.     if(rule){
  1762.     rule.style[property.replace(camelRe, camelFn)] = value;
  1763.     return true;
  1764.     }
  1765.     }else{
  1766.     for(var i = 0; i < selector.length; i++){
  1767.     if(this.updateRule(selector[i], property, value)){
  1768.     return true;
  1769.     }
  1770.     }
  1771.     }
  1772.     return false;
  1773.     }
  1774.    };
  1775. }();/**  @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     prepareEvent : function(e){         var k = e.getKey();         var h = this.keyToHandler[k];         if(Ext.isSafari2 && h && k >= 37 && k <= 40){             e.stopEvent();         }     },     // 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"     }, /**  * Enable this KeyNav  */ enable: function(){ if(this.disabled){             // ie won't do special keys on keypress, no one else will repeat keys with keydown             // the EventObject will normalize Safari automatically             if(this.isKeydown()){                 this.el.on("keydown", this.relay,  this);             }else{                 this.el.on("keydown", this.prepareEvent,  this);                 this.el.on("keypress", this.relay,  this);             }     this.disabled = false; } }, /**  * Disable this KeyNav  */ disable: function(){ if(!this.disabled){     if(this.isKeydown()){                 this.el.un("keydown", this.relay, this);             }else{                 this.el.un("keydown", this.prepareEvent, this);                 this.el.un("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;     } }; /**
  1776.  * @class Ext.KeyMap
  1777.  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
  1778.  * The constructor accepts the same config object as defined by {@link #addBinding}.
  1779.  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
  1780.  * combination it will call the function with this signature (if the match is a multi-key
  1781.  * combination the callback will still be called only once): (String key, Ext.EventObject e)
  1782.  * A KeyMap can also handle a string representation of keys.<br />
  1783.  * Usage:
  1784.  <pre><code>
  1785. // map one key by key code
  1786. var map = new Ext.KeyMap("my-element", {
  1787.     key: 13, // or Ext.EventObject.ENTER
  1788.     fn: myHandler,
  1789.     scope: myObject
  1790. });
  1791. // map multiple keys to one action by string
  1792. var map = new Ext.KeyMap("my-element", {
  1793.     key: "arnt",
  1794.     fn: myHandler,
  1795.     scope: myObject
  1796. });
  1797. // map multiple keys to multiple actions by strings and array of codes
  1798. var map = new Ext.KeyMap("my-element", [
  1799.     {
  1800.         key: [10,13],
  1801.         fn: function(){ alert("Return was pressed"); }
  1802.     }, {
  1803.         key: "abc",
  1804.         fn: function(){ alert('a, b or c was pressed'); }
  1805.     }, {
  1806.         key: "t",
  1807.         ctrl:true,
  1808.         shift:true,
  1809.         fn: function(){ alert('Control + shift + tab was pressed.'); }
  1810.     }
  1811. ]);
  1812. </code></pre>
  1813.  * <b>Note: A KeyMap starts enabled</b>
  1814.  * @constructor
  1815.  * @param {Mixed} el The element to bind to
  1816.  * @param {Object} config The config (see {@link #addBinding})
  1817.  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
  1818.  */
  1819. Ext.KeyMap = function(el, config, eventName){
  1820.     this.el  = Ext.get(el);
  1821.     this.eventName = eventName || "keydown";
  1822.     this.bindings = [];
  1823.     if(config){
  1824.         this.addBinding(config);
  1825.     }
  1826.     this.enable();
  1827. };
  1828. Ext.KeyMap.prototype = {
  1829.     /**
  1830.      * True to stop the event from bubbling and prevent the default browser action if the
  1831.      * key was handled by the KeyMap (defaults to false)
  1832.      * @type Boolean
  1833.      */
  1834.     stopEvent : false,
  1835.     /**
  1836.      * Add a new binding to this KeyMap. The following config object properties are supported:
  1837.      * <pre>
  1838. Property    Type             Description
  1839. ----------  ---------------  ----------------------------------------------------------------------
  1840. key         String/Array     A single keycode or an array of keycodes to handle
  1841. 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)
  1842. 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)
  1843. 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)
  1844. handler     Function         The function to call when KeyMap finds the expected key combination
  1845. fn          Function         Alias of handler (for backwards-compatibility)
  1846. scope       Object           The scope of the callback function
  1847. 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)
  1848. </pre>
  1849.      *
  1850.      * Usage:
  1851.      * <pre><code>
  1852. // Create a KeyMap
  1853. var map = new Ext.KeyMap(document, {
  1854.     key: Ext.EventObject.ENTER,
  1855.     fn: handleKey,
  1856.     scope: this
  1857. });
  1858. //Add a new binding to the existing KeyMap later
  1859. map.addBinding({
  1860.     key: 'abc',
  1861.     shift: true,
  1862.     fn: handleKey,
  1863.     scope: this
  1864. });
  1865. </code></pre>
  1866.      * @param {Object/Array} config A single KeyMap config or an array of configs
  1867.      */
  1868. addBinding : function(config){
  1869.         if(Ext.isArray(config)){
  1870.             Ext.each(config, function(c){
  1871.                 this.addBinding(c);
  1872.             }, this);
  1873.             return;
  1874.         }
  1875.         var keyCode = config.key,
  1876.             fn = config.fn || config.handler,
  1877.             scope = config.scope;
  1878. if (config.stopEvent) {
  1879.     this.stopEvent = config.stopEvent;    
  1880. }
  1881.         if(typeof keyCode == "string"){
  1882.             var ks = [];
  1883.             var keyString = keyCode.toUpperCase();
  1884.             for(var j = 0, len = keyString.length; j < len; j++){
  1885.                 ks.push(keyString.charCodeAt(j));
  1886.             }
  1887.             keyCode = ks;
  1888.         }
  1889.         var keyArray = Ext.isArray(keyCode);
  1890.         
  1891.         var handler = function(e){
  1892.             if(this.checkModifiers(config, e)){
  1893.                 var k = e.getKey();
  1894.                 if(keyArray){
  1895.                     for(var i = 0, len = keyCode.length; i < len; i++){
  1896.                         if(keyCode[i] == k){
  1897.                           if(this.stopEvent){
  1898.                               e.stopEvent();
  1899.                           }
  1900.                           fn.call(scope || window, k, e);
  1901.                           return;
  1902.                         }
  1903.                     }
  1904.                 }else{
  1905.                     if(k == keyCode){
  1906.                         if(this.stopEvent){
  1907.                            e.stopEvent();
  1908.                         }
  1909.                         fn.call(scope || window, k, e);
  1910.                     }
  1911.                 }
  1912.             }
  1913.         };
  1914.         this.bindings.push(handler);
  1915. },
  1916.     
  1917.     // private
  1918.     checkModifiers: function(config, e){
  1919.         var val, key, keys = ['shift', 'ctrl', 'alt'];
  1920.         for (var i = 0, len = keys.length; i < len; ++i){
  1921.             key = keys[i];
  1922.             val = config[key];
  1923.             if(!(val === undefined || (val === e[key + 'Key']))){
  1924.                 return false;
  1925.             }
  1926.         }
  1927.         return true;
  1928.     },
  1929.     /**
  1930.      * Shorthand for adding a single key listener
  1931.      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
  1932.      * following options:
  1933.      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
  1934.      * @param {Function} fn The function to call
  1935.      * @param {Object} scope (optional) The scope of the function
  1936.      */
  1937.     on : function(key, fn, scope){
  1938.         var keyCode, shift, ctrl, alt;
  1939.         if(typeof key == "object" && !Ext.isArray(key)){
  1940.             keyCode = key.key;
  1941.             shift = key.shift;
  1942.             ctrl = key.ctrl;
  1943.             alt = key.alt;
  1944.         }else{
  1945.             keyCode = key;
  1946.         }
  1947.         this.addBinding({
  1948.             key: keyCode,
  1949.             shift: shift,
  1950.             ctrl: ctrl,
  1951.             alt: alt,
  1952.             fn: fn,
  1953.             scope: scope
  1954.         });
  1955.     },
  1956.     // private
  1957.     handleKeyDown : function(e){
  1958.     if(this.enabled){ //just in case
  1959.          var b = this.bindings;
  1960.          for(var i = 0, len = b.length; i < len; i++){
  1961.              b[i].call(this, e);
  1962.          }
  1963.     }
  1964. },
  1965. /**
  1966.  * Returns true if this KeyMap is enabled
  1967.  * @return {Boolean}
  1968.  */
  1969. isEnabled : function(){
  1970.     return this.enabled;
  1971. },
  1972. /**
  1973.  * Enables this KeyMap
  1974.  */
  1975. enable: function(){
  1976. if(!this.enabled){
  1977.     this.el.on(this.eventName, this.handleKeyDown, this);
  1978.     this.enabled = true;
  1979. }
  1980. },
  1981. /**
  1982.  * Disable this KeyMap
  1983.  */
  1984. disable: function(){
  1985. if(this.enabled){
  1986.     this.el.removeListener(this.eventName, this.handleKeyDown, this);
  1987.     this.enabled = false;
  1988. }
  1989. },
  1990.     
  1991.     /**
  1992.      * Convenience function for setting disabled/enabled by boolean.
  1993.      * @param {Boolean} disabled
  1994.      */
  1995.     setDisabled : function(disabled){
  1996.         this[disabled ? "disable" : "enable"]();
  1997.     }
  1998. };/**  * @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 = {         /**          * 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;         },         /**          * 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')             );         },         /**          * 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);         },         /**          * 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;         },         /**          * 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);     } }); /**
  1999.  * @class Ext.util.Cookies
  2000.  * Utility class for managing and interacting with cookies.
  2001.  * @singleton
  2002.  */
  2003. Ext.util.Cookies = {
  2004.     /**
  2005.      * Create a cookie with the specified name and value. Additional settings
  2006.      * for the cookie may be optionally specified (for example: expiration,
  2007.      * access restriction, SSL).
  2008.      * @param {Object} name
  2009.      * @param {Object} value
  2010.      * @param {Object} expires (Optional) Specify an expiration date the
  2011.      * cookie is to persist until.  Note that the specified Date object will
  2012.      * be converted to Greenwich Mean Time (GMT). 
  2013.      * @param {String} path (Optional) Setting a path on the cookie restricts
  2014.      * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>). 
  2015.      * @param {String} domain (Optional) Setting a domain restricts access to
  2016.      * pages on a given domain (typically used to allow cookie access across
  2017.      * subdomains). For example, "extjs.com" will create a cookie that can be
  2018.      * accessed from any subdomain of extjs.com, including www.extjs.com,
  2019.      * support.extjs.com, etc.
  2020.      * @param {Boolean} secure (Optional) Specify true to indicate that the cookie
  2021.      * should only be accessible via SSL on a page using the HTTPS protocol.
  2022.      * Defaults to <tt>false</tt>. Note that this will only work if the page
  2023.      * calling this code uses the HTTPS protocol, otherwise the cookie will be
  2024.      * created with default options.
  2025.      */
  2026.     set : function(name, value){
  2027.         var argv = arguments;
  2028.         var argc = arguments.length;
  2029.         var expires = (argc > 2) ? argv[2] : null;
  2030.         var path = (argc > 3) ? argv[3] : '/';
  2031.         var domain = (argc > 4) ? argv[4] : null;
  2032.         var secure = (argc > 5) ? argv[5] : false;
  2033.         document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
  2034.     },
  2035.     /**
  2036.      * Retrieves cookies that are accessible by the current page. If a cookie
  2037.      * does not exist, <code>get()</code> returns <tt>null</tt>.  The following
  2038.      * example retrieves the cookie called "valid" and stores the String value
  2039.      * in the variable <tt>validStatus</tt>.
  2040.      * <pre><code>
  2041.      * var validStatus = Ext.util.Cookies.get("valid");
  2042.      * </code></pre>
  2043.      * @param {Object} name The name of the cookie to get
  2044.      * @return {Mixed} Returns the cookie value for the specified name;
  2045.      * null if the cookie name does not exist.
  2046.      */
  2047.     get : function(name){
  2048.         var arg = name + "=";
  2049.         var alen = arg.length;
  2050.         var clen = document.cookie.length;
  2051.         var i = 0;
  2052.         var j = 0;
  2053.         while(i < clen){
  2054.             j = i + alen;
  2055.             if(document.cookie.substring(i, j) == arg){
  2056.                 return Ext.util.Cookies.getCookieVal(j);
  2057.             }
  2058.             i = document.cookie.indexOf(" ", i) + 1;
  2059.             if(i === 0){
  2060.                 break;
  2061.             }
  2062.         }
  2063.         return null;
  2064.     },
  2065.     /**
  2066.      * Removes a cookie with the provided name from the browser
  2067.      * if found.
  2068.      * @param {Object} name The name of the cookie to remove
  2069.      */
  2070.     clear : function(name){
  2071.         if(Ext.util.Cookies.get(name)){
  2072.             document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  2073.         }
  2074.     },
  2075.     /**
  2076.      * @private
  2077.      */
  2078.     getCookieVal : function(offset){
  2079.         var endstr = document.cookie.indexOf(";", offset);
  2080.         if(endstr == -1){
  2081.             endstr = document.cookie.length;
  2082.         }
  2083.         return unescape(document.cookie.substring(offset, endstr));
  2084.     }
  2085. };/**  * 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);     } });