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

中间件编程

开发平台:

JavaScript

  1.     /**
  2.      * Callback for write actions
  3.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
  4.      * @param {Object} trans The request transaction object
  5.      * @param {Object} res The server response
  6.      * @private
  7.      */
  8.     onWrite : function(action, trans, res, rs) {
  9.         var reader = trans.reader;
  10.         try {
  11.             // though we already have a response object here in STP, run through readResponse to catch any meta-data exceptions.
  12.             reader.readResponse(action, res);
  13.         } catch (e) {
  14.             this.fireEvent('exception', this, 'response', action, trans, res, e);
  15.             trans.callback.call(trans.scope||window, null, res, false);
  16.             return;
  17.         }
  18.         if(!res[reader.meta.successProperty] === true){
  19.             this.fireEvent('exception', this, 'remote', action, trans, res, rs);
  20.             trans.callback.call(trans.scope||window, null, res, false);
  21.             return;
  22.         }
  23.         this.fireEvent("write", this, action, res[reader.meta.root], res, rs, trans.arg );
  24.         trans.callback.call(trans.scope||window, res[reader.meta.root], res, true);
  25.     },
  26.     // private
  27.     isLoading : function(){
  28.         return this.trans ? true : false;
  29.     },
  30.     /**
  31.      * Abort the current server request.
  32.      */
  33.     abort : function(){
  34.         if(this.isLoading()){
  35.             this.destroyTrans(this.trans);
  36.         }
  37.     },
  38.     // private
  39.     destroyTrans : function(trans, isLoaded){
  40.         this.head.removeChild(document.getElementById(trans.scriptId));
  41.         clearTimeout(trans.timeoutId);
  42.         if(isLoaded){
  43.             window[trans.cb] = undefined;
  44.             try{
  45.                 delete window[trans.cb];
  46.             }catch(e){}
  47.         }else{
  48.             // if hasn't been loaded, wait for load to remove it to prevent script error
  49.             window[trans.cb] = function(){
  50.                 window[trans.cb] = undefined;
  51.                 try{
  52.                     delete window[trans.cb];
  53.                 }catch(e){}
  54.             };
  55.         }
  56.     },
  57.     // private
  58.     handleFailure : function(trans){
  59.         this.trans = false;
  60.         this.destroyTrans(trans, false);
  61.         if (trans.action === Ext.data.Api.actions.read) {
  62.             // @deprecated firing loadexception
  63.             this.fireEvent("loadexception", this, null, trans.arg);
  64.         }
  65.         this.fireEvent('exception', this, 'response', trans.action, {
  66.             response: null,
  67.             options: trans.arg
  68.         });
  69.         trans.callback.call(trans.scope||window, null, trans.arg, false);
  70.     },
  71.     // inherit docs
  72.     destroy: function(){
  73.         this.abort();
  74.         Ext.data.ScriptTagProxy.superclass.destroy.call(this);
  75.     }
  76. });/**
  77.  * @class Ext.data.HttpProxy
  78.  * @extends Ext.data.DataProxy
  79.  * <p>An implementation of {@link Ext.data.DataProxy} that processes data requests within the same
  80.  * domain of the originating page.</p>
  81.  * <p><b>Note</b>: this class cannot be used to retrieve data from a domain other
  82.  * than the domain from which the running page was served. For cross-domain requests, use a
  83.  * {@link Ext.data.ScriptTagProxy ScriptTagProxy}.</p>
  84.  * <p>Be aware that to enable the browser to parse an XML document, the server must set
  85.  * the Content-Type header in the HTTP response to "<tt>text/xml</tt>".</p>
  86.  * @constructor
  87.  * @param {Object} conn
  88.  * An {@link Ext.data.Connection} object, or options parameter to {@link Ext.Ajax#request}.
  89.  * <p>Note that if this HttpProxy is being used by a (@link Ext.data.Store Store}, then the
  90.  * Store's call to {@link #load} will override any specified <tt>callback</tt> and <tt>params</tt>
  91.  * options. In this case, use the Store's {@link Ext.data.Store#events events} to modify parameters,
  92.  * or react to loading events. The Store's {@link Ext.data.Store#baseParams baseParams} may also be
  93.  * used to pass parameters known at instantiation time.</p>
  94.  * <p>If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make
  95.  * the request.</p>
  96.  */
  97. Ext.data.HttpProxy = function(conn){
  98.     Ext.data.HttpProxy.superclass.constructor.call(this, conn);
  99.     /**
  100.      * The Connection object (Or options parameter to {@link Ext.Ajax#request}) which this HttpProxy
  101.      * uses to make requests to the server. Properties of this object may be changed dynamically to
  102.      * change the way data is requested.
  103.      * @property
  104.      */
  105.     this.conn = conn;
  106.     // nullify the connection url.  The url param has been copied to 'this' above.  The connection
  107.     // url will be set during each execution of doRequest when buildUrl is called.  This makes it easier for users to override the
  108.     // connection url during beforeaction events (ie: beforeload, beforesave, etc).  The connection url will be nullified
  109.     // after each request as well.  Url is always re-defined during doRequest.
  110.     this.conn.url = null;
  111.     this.useAjax = !conn || !conn.events;
  112.     //private.  A hash containing active requests, keyed on action [Ext.data.Api.actions.create|read|update|destroy]
  113.     var actions = Ext.data.Api.actions;
  114.     this.activeRequest = {};
  115.     for (var verb in actions) {
  116.         this.activeRequest[actions[verb]] = undefined;
  117.     }
  118. };
  119. Ext.extend(Ext.data.HttpProxy, Ext.data.DataProxy, {
  120.     /**
  121.      * @cfg {Boolean} restful
  122.      * <p>If set to <tt>true</tt>, a {@link Ext.data.Record#phantom non-phantom} record's
  123.      * {@link Ext.data.Record#id id} will be appended to the url (defaults to <tt>false</tt>).</p><br>
  124.      * <p>The url is built based upon the action being executed <tt>[load|create|save|destroy]</tt>
  125.      * using the commensurate <tt>{@link #api}</tt> property, or if undefined default to the
  126.      * configured {@link Ext.data.Store}.{@link Ext.data.Store#url url}.</p><br>
  127.      * <p>Some MVC (e.g., Ruby on Rails, Merb and Django) support this style of segment based urls
  128.      * where the segments in the URL follow the Model-View-Controller approach.</p><pre><code>
  129.      * someSite.com/controller/action/id
  130.      * </code></pre>
  131.      * Where the segments in the url are typically:<div class="mdetail-params"><ul>
  132.      * <li>The first segment : represents the controller class that should be invoked.</li>
  133.      * <li>The second segment : represents the class function, or method, that should be called.</li>
  134.      * <li>The third segment : represents the ID (a variable typically passed to the method).</li>
  135.      * </ul></div></p>
  136.      * <p>For example:</p>
  137.      * <pre><code>
  138. api: {
  139.     load :    '/controller/load',
  140.     create :  '/controller/new',  // Server MUST return idProperty of new record
  141.     save :    '/controller/update',
  142.     destroy : '/controller/destroy_action'
  143. }
  144. // Alternatively, one can use the object-form to specify each API-action
  145. api: {
  146.     load: {url: 'read.php', method: 'GET'},
  147.     create: 'create.php',
  148.     destroy: 'destroy.php',
  149.     save: 'update.php'
  150. }
  151.      */
  152.     /**
  153.      * Return the {@link Ext.data.Connection} object being used by this Proxy.
  154.      * @return {Connection} The Connection object. This object may be used to subscribe to events on
  155.      * a finer-grained basis than the DataProxy events.
  156.      */
  157.     getConnection : function() {
  158.         return this.useAjax ? Ext.Ajax : this.conn;
  159.     },
  160.     /**
  161.      * Used for overriding the url used for a single request.  Designed to be called during a beforeaction event.  Calling setUrl
  162.      * will override any urls set via the api configuration parameter.  Set the optional parameter makePermanent to set the url for
  163.      * all subsequent requests.  If not set to makePermanent, the next request will use the same url or api configuration defined
  164.      * in the initial proxy configuration.
  165.      * @param {String} url
  166.      * @param {Boolean} makePermanent (Optional) [false]
  167.      *
  168.      * (e.g.: beforeload, beforesave, etc).
  169.      */
  170.     setUrl : function(url, makePermanent) {
  171.         this.conn.url = url;
  172.         if (makePermanent === true) {
  173.             this.url = url;
  174.             Ext.data.Api.prepare(this);
  175.         }
  176.     },
  177.     /**
  178.      * HttpProxy implementation of DataProxy#doRequest
  179.      * @param {String} action The crud action type (create, read, update, destroy)
  180.      * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
  181.      * @param {Object} params An object containing properties which are to be used as HTTP parameters
  182.      * for the request to the remote server.
  183.      * @param {Ext.data.DataReader} reader The Reader object which converts the data
  184.      * object into a block of Ext.data.Records.
  185.      * @param {Function} callback
  186.      * <div class="sub-desc"><p>A function to be called after the request.
  187.      * The <tt>callback</tt> is passed the following arguments:<ul>
  188.      * <li><tt>r</tt> : Ext.data.Record[] The block of Ext.data.Records.</li>
  189.      * <li><tt>options</tt>: Options object from the action request</li>
  190.      * <li><tt>success</tt>: Boolean success indicator</li></ul></p></div>
  191.      * @param {Object} scope The scope in which to call the callback
  192.      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
  193.      */
  194.     doRequest : function(action, rs, params, reader, cb, scope, arg) {
  195.         var  o = {
  196.             method: (this.api[action]) ? this.api[action]['method'] : undefined,
  197.             request: {
  198.                 callback : cb,
  199.                 scope : scope,
  200.                 arg : arg
  201.             },
  202.             reader: reader,
  203.             callback : this.createCallback(action, rs),
  204.             scope: this
  205.         };
  206.         // Sample the request data:  If it's an object, then it hasn't been json-encoded yet.
  207.         // Transmit data using jsonData config of Ext.Ajax.request
  208.         if (typeof(params[reader.meta.root]) === 'object') {
  209.             o.jsonData = params;
  210.         } else {
  211.             o.params = params || {};
  212.         }
  213.         // Set the connection url.  If this.conn.url is not null here,
  214.         // the user may have overridden the url during a beforeaction event-handler.
  215.         // this.conn.url is nullified after each request.
  216.         if (this.conn.url === null) {
  217.             this.conn.url = this.buildUrl(action, rs);
  218.         }
  219.         else if (this.restful === true && rs instanceof Ext.data.Record && !rs.phantom) {
  220.             this.conn.url += '/' + rs.id;
  221.         }
  222.         if(this.useAjax){
  223.             Ext.applyIf(o, this.conn);
  224.             // If a currently running request is found for this action, abort it.
  225.             if (this.activeRequest[action]) {
  226.                 // Disabled aborting activeRequest while implementing REST.  activeRequest[action] will have to become an array
  227.                 //Ext.Ajax.abort(this.activeRequest[action]);
  228.             }
  229.             this.activeRequest[action] = Ext.Ajax.request(o);
  230.         }else{
  231.             this.conn.request(o);
  232.         }
  233.         // request is sent, nullify the connection url in preparation for the next request
  234.         this.conn.url = null;
  235.     },
  236.     /**
  237.      * Returns a callback function for a request.  Note a special case is made for the
  238.      * read action vs all the others.
  239.      * @param {String} action [create|update|delete|load]
  240.      * @param {Ext.data.Record[]} rs The Store-recordset being acted upon
  241.      * @private
  242.      */
  243.     createCallback : function(action, rs) {
  244.         return function(o, success, response) {
  245.             this.activeRequest[action] = undefined;
  246.             if (!success) {
  247.                 if (action === Ext.data.Api.actions.read) {
  248.                     // @deprecated: fire loadexception for backwards compat.
  249.                     this.fireEvent('loadexception', this, o, response);
  250.                 }
  251.                 this.fireEvent('exception', this, 'response', action, o, response);
  252.                 o.request.callback.call(o.request.scope, null, o.request.arg, false);
  253.                 return;
  254.             }
  255.             if (action === Ext.data.Api.actions.read) {
  256.                 this.onRead(action, o, response);
  257.             } else {
  258.                 this.onWrite(action, o, response, rs);
  259.             }
  260.         }
  261.     },
  262.     /**
  263.      * Callback for read action
  264.      * @param {String} action Action name as per {@link Ext.data.Api.actions#read}.
  265.      * @param {Object} o The request transaction object
  266.      * @param {Object} res The server response
  267.      * @private
  268.      */
  269.     onRead : function(action, o, response) {
  270.         var result;
  271.         try {
  272.             result = o.reader.read(response);
  273.         }catch(e){
  274.             // @deprecated: fire old loadexception for backwards-compat.
  275.             this.fireEvent('loadexception', this, o, response, e);
  276.             this.fireEvent('exception', this, 'response', action, o, response, e);
  277.             o.request.callback.call(o.request.scope, null, o.request.arg, false);
  278.             return;
  279.         }
  280.         if (result.success === false) {
  281.             // @deprecated: fire old loadexception for backwards-compat.
  282.             this.fireEvent('loadexception', this, o, response);
  283.             // Get DataReader read-back a response-object to pass along to exception event
  284.             var res = o.reader.readResponse(action, response);
  285.             this.fireEvent('exception', this, 'remote', action, o, res, null);
  286.         }
  287.         else {
  288.             this.fireEvent('load', this, o, o.request.arg);
  289.         }
  290.         o.request.callback.call(o.request.scope, result, o.request.arg, result.success);
  291.     },
  292.     /**
  293.      * Callback for write actions
  294.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
  295.      * @param {Object} trans The request transaction object
  296.      * @param {Object} res The server response
  297.      * @private
  298.      */
  299.     onWrite : function(action, o, response, rs) {
  300.         var reader = o.reader;
  301.         var res;
  302.         try {
  303.             res = reader.readResponse(action, response);
  304.         } catch (e) {
  305.             this.fireEvent('exception', this, 'response', action, o, response, e);
  306.             o.request.callback.call(o.request.scope, null, o.request.arg, false);
  307.             return;
  308.         }
  309.         if (res[reader.meta.successProperty] === false) {
  310.             this.fireEvent('exception', this, 'remote', action, o, res, rs);
  311.         } else {
  312.             this.fireEvent('write', this, action, res[reader.meta.root], res, rs, o.request.arg);
  313.         }
  314.         o.request.callback.call(o.request.scope, res[reader.meta.root], res, res[reader.meta.successProperty]);
  315.     },
  316.     // inherit docs
  317.     destroy: function(){
  318.         if(!this.useAjax){
  319.             this.conn.abort();
  320.         }else if(this.activeRequest){
  321.             var actions = Ext.data.Api.actions;
  322.             for (var verb in actions) {
  323.                 if(this.activeRequest[actions[verb]]){
  324.                     Ext.Ajax.abort(this.activeRequest[actions[verb]]);
  325.                 }
  326.             }
  327.         }
  328.         Ext.data.HttpProxy.superclass.destroy.call(this);
  329.     }
  330. });/**
  331.  * @class Ext.data.MemoryProxy
  332.  * @extends Ext.data.DataProxy
  333.  * An implementation of Ext.data.DataProxy that simply passes the data specified in its constructor
  334.  * to the Reader when its load method is called.
  335.  * @constructor
  336.  * @param {Object} data The data object which the Reader uses to construct a block of Ext.data.Records.
  337.  */
  338. Ext.data.MemoryProxy = function(data){
  339.     // Must define a dummy api with "read" action to satisfy DataProxy#doRequest and Ext.data.Api#prepare *before* calling super
  340.     var api = {};
  341.     api[Ext.data.Api.actions.read] = true;
  342.     Ext.data.MemoryProxy.superclass.constructor.call(this, {
  343.         api: api
  344.     });
  345.     this.data = data;
  346. };
  347. Ext.extend(Ext.data.MemoryProxy, Ext.data.DataProxy, {
  348.     /**
  349.      * @event loadexception
  350.      * Fires if an exception occurs in the Proxy during data loading. Note that this event is also relayed
  351.      * through {@link Ext.data.Store}, so you can listen for it directly on any Store instance.
  352.      * @param {Object} this
  353.      * @param {Object} arg The callback's arg object passed to the {@link #load} function
  354.      * @param {Object} null This parameter does not apply and will always be null for MemoryProxy
  355.      * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data
  356.      */
  357.        /**
  358.      * MemoryProxy implementation of DataProxy#doRequest
  359.      * @param {String} action
  360.      * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
  361.      * @param {Object} params An object containing properties which are to be used as HTTP parameters
  362.      * for the request to the remote server.
  363.      * @param {Ext.data.DataReader} reader The Reader object which converts the data
  364.      * object into a block of Ext.data.Records.
  365.      * @param {Function} callback The function into which to pass the block of Ext.data.Records.
  366.      * The function must be passed <ul>
  367.      * <li>The Record block object</li>
  368.      * <li>The "arg" argument from the load function</li>
  369.      * <li>A boolean success indicator</li>
  370.      * </ul>
  371.      * @param {Object} scope The scope in which to call the callback
  372.      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
  373.      */
  374.     doRequest : function(action, rs, params, reader, callback, scope, arg) {
  375.         // No implementation for CRUD in MemoryProxy.  Assumes all actions are 'load'
  376.         params = params || {};
  377.         var result;
  378.         try {
  379.             result = reader.readRecords(this.data);
  380.         }catch(e){
  381.             // @deprecated loadexception
  382.             this.fireEvent("loadexception", this, null, arg, e);
  383.             this.fireEvent('exception', this, 'response', action, arg, null, e);
  384.             callback.call(scope, null, arg, false);
  385.             return;
  386.         }
  387.         callback.call(scope, result, arg, true);
  388.     }
  389. });/**  * @class Ext.data.JsonWriter  * @extends Ext.data.DataWriter  * DataWriter extension for writing an array or single {@link Ext.data.Record} object(s) in preparation for executing a remote CRUD action.  */ Ext.data.JsonWriter = function(config) {     Ext.data.JsonWriter.superclass.constructor.call(this, config);     // careful to respect "returnJson", renamed to "encode"     if (this.returnJson != undefined) {         this.encode = this.returnJson;     } } Ext.extend(Ext.data.JsonWriter, Ext.data.DataWriter, {     /**      * @cfg {Boolean} returnJson <b>Deprecated.  Use {@link Ext.data.JsonWriter#encode} instead.      */     returnJson : undefined,     /**      * @cfg {Boolean} encode <tt>true</tt> to {@link Ext.util.JSON#encode encode} the      * {@link Ext.data.DataWriter#toHash hashed data}. Defaults to <tt>true</tt>.  When using      * {@link Ext.data.DirectProxy}, set this to <tt>false</tt> since Ext.Direct.JsonProvider will perform      * its own json-encoding.  In addition, if you're using {@link Ext.data.HttpProxy}, setting to <tt>false</tt>      * will cause HttpProxy to transmit data using the <b>jsonData</b> configuration-params of {@link Ext.Ajax#request}      * instead of <b>params</b>.  When using a {@link Ext.data.Store#restful} Store, some serverside frameworks are      * tuned to expect data through the jsonData mechanism.  In those cases, one will want to set <b>encode: <tt>false</tt></b>      */     encode : true,     /**      * Final action of a write event.  Apply the written data-object to params.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]      * @param {Record[]} rs      * @param {Object} http params      * @param {Object} data object populated according to DataReader meta-data "root" and "idProperty"      */     render : function(action, rs, params, data) {         Ext.apply(params, data);         if (this.encode === true) { // <-- @deprecated returnJson             if (Ext.isArray(rs) && data[this.meta.idProperty]) {                 params[this.meta.idProperty] = Ext.encode(params[this.meta.idProperty]);             }             params[this.meta.root] = Ext.encode(params[this.meta.root]);         }     },     /**      * createRecord      * @protected      * @param {Ext.data.Record} rec      */     createRecord : function(rec) {         return this.toHash(rec);     },     /**      * updateRecord      * @protected      * @param {Ext.data.Record} rec      */     updateRecord : function(rec) {         return this.toHash(rec);     },     /**      * destroyRecord      * @protected      * @param {Ext.data.Record} rec      */     destroyRecord : function(rec) {         return rec.id;     } });/**  * @class Ext.data.JsonReader  * @extends Ext.data.DataReader  * <p>Data reader class to create an Array of {@link Ext.data.Record} objects from a JSON response  * based on mappings in a provided {@link Ext.data.Record} constructor.</p>  * <p>Example code:</p>  * <pre><code> var Employee = Ext.data.Record.create([     {name: 'firstname'},                  // map the Record's "firstname" field to the row object's key of the same name     {name: 'job', mapping: 'occupation'}  // map the Record's "job" field to the row object's "occupation" key ]); var myReader = new Ext.data.JsonReader(     {                             // The metadata property, with configuration options:         totalProperty: "results", //   the property which contains the total dataset size (optional)         root: "rows",             //   the property which contains an Array of record data objects         idProperty: "id"          //   the property within each row object that provides an ID for the record (optional)     },     Employee  // {@link Ext.data.Record} constructor that provides mapping for JSON object ); </code></pre>  * <p>This would consume a JSON data object of the form:</p><pre><code> {     results: 2,  // Reader's configured totalProperty     rows: [      // Reader's configured root         { id: 1, firstname: 'Bill', occupation: 'Gardener' },         // a row object         { id: 2, firstname: 'Ben' , occupation: 'Horticulturalist' }  // another row object     ] } </code></pre>  * <p><b><u>Automatic configuration using metaData</u></b></p>  * <p>It is possible to change a JsonReader's metadata at any time by including a <b><tt>metaData</tt></b>  * property in the JSON data object. If the JSON data object has a <b><tt>metaData</tt></b> property, a  * {@link Ext.data.Store Store} object using this Reader will reconfigure itself to use the newly provided  * field definition and fire its {@link Ext.data.Store#metachange metachange} event. The metachange event  * handler may interrogate the <b><tt>metaData</tt></b> property to perform any configuration required.  * Note that reconfiguring a Store potentially invalidates objects which may refer to Fields or Records  * which no longer exist.</p>  * <p>The <b><tt>metaData</tt></b> property in the JSON data object may contain:</p>  * <div class="mdetail-params"><ul>  * <li>any of the configuration options for this class</li>  * <li>a <b><tt>{@link Ext.data.Record#fields fields}</tt></b> property which the JsonReader will  * use as an argument to the {@link Ext.data.Record#create data Record create method} in order to  * configure the layout of the Records it will produce.</li>  * <li>a <b><tt>{@link Ext.data.Store#sortInfo sortInfo}</tt></b> property which the JsonReader will  * use to set the {@link Ext.data.Store}'s {@link Ext.data.Store#sortInfo sortInfo} property</li>  * <li>any user-defined properties needed</li>  * </ul></div>  * <p>To use this facility to send the same data as the example above (without having to code the creation  * of the Record constructor), you would create the JsonReader like this:</p><pre><code> var myReader = new Ext.data.JsonReader(); </code></pre>  * <p>The first data packet from the server would configure the reader by containing a  * <b><tt>metaData</tt></b> property <b>and</b> the data. For example, the JSON data object might take  * the form:</p> <pre><code> {     metaData: {         idProperty: 'id',         root: 'rows',         totalProperty: 'results',         fields: [             {name: 'name'},             {name: 'job', mapping: 'occupation'}         ],         sortInfo: {field: 'name', direction:'ASC'}, // used by store to set its sortInfo         foo: 'bar' // custom property     },     results: 2,     rows: [ // an Array         { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },         { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' }     ] } </code></pre>  * @cfg {String} totalProperty [total] Name of the property from which to retrieve the total number of records  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being  * paged from the remote server.  Defaults to <tt>total</tt>.  * @cfg {String} successProperty [success] Name of the property from which to  * retrieve the success attribute. Defaults to <tt>success</tt>.  See  * {@link Ext.data.DataProxy}.{@link Ext.data.DataProxy#exception exception}  * for additional information.  * @cfg {String} root [undefined] <b>Required</b>.  The name of the property  * which contains the Array of row objects.  Defaults to <tt>undefined</tt>.  * An exception will be thrown if the root property is undefined. The data packet  * value for this property should be an empty array to clear the data or show  * no data.  * @cfg {String} idProperty [id] Name of the property within a row object that contains a record identifier value.  Defaults to <tt>id</tt>  * @constructor  * Create a new JsonReader  * @param {Object} meta Metadata configuration options.  * @param {Array/Object} recordType  * <p>Either an Array of {@link Ext.data.Field Field} definition objects (which  * will be passed to {@link Ext.data.Record#create}, or a {@link Ext.data.Record Record}  * constructor created from {@link Ext.data.Record#create}.</p>  */ Ext.data.JsonReader = function(meta, recordType){     meta = meta || {};     // default idProperty, successProperty & totalProperty -> "id", "success", "total"     Ext.applyIf(meta, {         idProperty: 'id',         successProperty: 'success',         totalProperty: 'total'     });     Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields); }; Ext.extend(Ext.data.JsonReader, Ext.data.DataReader, {     /**      * This JsonReader's metadata as passed to the constructor, or as passed in      * the last data packet's <b><tt>metaData</tt></b> property.      * @type Mixed      * @property meta      */     /**      * This method is only used by a DataProxy which has retrieved data from a remote server.      * @param {Object} response The XHR object which contains the JSON data in its responseText.      * @return {Object} data A data block which is used by an Ext.data.Store object as      * a cache of Ext.data.Records.      */     read : function(response){         var json = response.responseText;         var o = Ext.decode(json);         if(!o) {             throw {message: "JsonReader.read: Json object not found"};         }         return this.readRecords(o);     },     // private function a store will implement     onMetaChange : function(meta, recordType, o){     },     /**      * @ignore      */     simpleAccess: function(obj, subsc) {         return obj[subsc];     },     /**      * @ignore      */     getJsonAccessor: function(){         var re = /[[.]/;         return function(expr) {             try {                 return(re.test(expr)) ?                 new Function("obj", "return obj." + expr) :                 function(obj){                     return obj[expr];                 };             } catch(e){}             return Ext.emptyFn;         };     }(),     /**      * Create a data block containing Ext.data.Records from a JSON object.      * @param {Object} o An object which contains an Array of row objects in the property specified      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'      * which contains the total size of the dataset.      * @return {Object} data A data block which is used by an Ext.data.Store object as      * a cache of Ext.data.Records.      */     readRecords : function(o){         /**          * After any data loads, the raw JSON data is available for further custom processing.  If no data is          * loaded or there is a load exception this property will be undefined.          * @type Object          */         this.jsonData = o;         if(o.metaData){             delete this.ef;             this.meta = o.metaData;             this.recordType = Ext.data.Record.create(o.metaData.fields);             this.onMetaChange(this.meta, this.recordType, o);         }         var s = this.meta, Record = this.recordType,             f = Record.prototype.fields, fi = f.items, fl = f.length, v;         // Generate extraction functions for the totalProperty, the root, the id, and for each field         this.buildExtractors();         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;         if(s.totalProperty){             v = parseInt(this.getTotal(o), 10);             if(!isNaN(v)){                 totalRecords = v;             }         }         if(s.successProperty){             v = this.getSuccess(o);             if(v === false || v === 'false'){                 success = false;             }         }         var records = [];         for(var i = 0; i < c; i++){             var n = root[i];             var record = new Record(this.extractValues(n, fi, fl), this.getId(n));             record.json = n;             records[i] = record;         }         return {             success : success,             records : records,             totalRecords : totalRecords         };     },     // private     buildExtractors : function() {         if(this.ef){             return;         }         var s = this.meta, Record = this.recordType,             f = Record.prototype.fields, fi = f.items, fl = f.length;         if(s.totalProperty) {             this.getTotal = this.getJsonAccessor(s.totalProperty);         }         if(s.successProperty) {             this.getSuccess = this.getJsonAccessor(s.successProperty);         }         this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};         if (s.id || s.idProperty) {             var g = this.getJsonAccessor(s.id || s.idProperty);             this.getId = function(rec) {                 var r = g(rec);                 return (r === undefined || r === "") ? null : r;             };         } else {             this.getId = function(){return null;};         }         var ef = [];         for(var i = 0; i < fl; i++){             f = fi[i];             var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;             ef.push(this.getJsonAccessor(map));         }         this.ef = ef;     },     // private extractValues     extractValues: function(data, items, len) {         var f, values = {};         for(var j = 0; j < len; j++){             f = items[j];             var v = this.ef[j](data);             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, data);         }         return values;     },     /**      * Decode a json response from server.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]      * @param {Object} response      */     readResponse : function(action, response) {         var o = (response.responseText !== undefined) ? Ext.decode(response.responseText) : response;         if(!o) {             throw new Ext.data.JsonReader.Error('response');         }         if (Ext.isEmpty(o[this.meta.successProperty])) {             throw new Ext.data.JsonReader.Error('successProperty-response', this.meta.successProperty);         }         // TODO, separate empty and undefined exceptions.         if ((action === Ext.data.Api.actions.create || action === Ext.data.Api.actions.update)) {             if (Ext.isEmpty(o[this.meta.root])) {                 throw new Ext.data.JsonReader.Error('root-emtpy', this.meta.root);             }             else if (o[this.meta.root] === undefined) {                 throw new Ext.data.JsonReader.Error('root-undefined-response', this.meta.root);             }         }         // make sure extraction functions are defined.         this.ef = this.buildExtractors();         return o;     } }); /**  * @class Ext.data.JsonReader.Error  * Error class for JsonReader  */ Ext.data.JsonReader.Error = Ext.extend(Ext.Error, {     constructor : function(message, arg) {         this.arg = arg;         Ext.Error.call(this, message);     },     name : 'Ext.data.JsonReader' }); Ext.apply(Ext.data.JsonReader.Error.prototype, {     lang: {         'response': "An error occurred while json-decoding your server response",         'successProperty-response': 'Could not locate your "successProperty" in your server response.  Please review your JsonReader config to ensure the config-property "successProperty" matches the property in your server-response.  See the JsonReader docs.',         'root-undefined-response': '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.',         'root-undefined-config': 'Your JsonReader was configured without a "root" property.  Please review your JsonReader config and make sure to define the root property.  See the JsonReader docs.',         'idProperty-undefined' : 'Your JsonReader was configured without an "idProperty"  Please review your JsonReader configuration and ensure the "idProperty" is set (e.g.: "id").  See the JsonReader docs.',         'root-emtpy': 'Data was expected to be returned by the server in the "root" property of the response.  Please review your JsonReader configuration to ensure the "root" property matches that returned in the server-response.  See JsonReader docs.'     } }); /**  * @class Ext.data.ArrayReader  * @extends Ext.data.JsonReader  * <p>Data reader class to create an Array of {@link Ext.data.Record} objects from an Array.  * Each element of that Array represents a row of data fields. The  * fields are pulled into a Record object using as a subscript, the <code>mapping</code> property  * of the field definition if it exists, or the field's ordinal position in the definition.</p>  * <p>Example code:</p>  * <pre><code> var Employee = Ext.data.Record.create([     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index. ]); var myReader = new Ext.data.ArrayReader({     {@link #idIndex}: 0 }, Employee); </code></pre>  * <p>This would consume an Array like this:</p>  * <pre><code> [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]  * </code></pre>  * @constructor  * Create a new ArrayReader  * @param {Object} meta Metadata configuration options.  * @param {Array/Object} recordType  * <p>Either an Array of {@link Ext.data.Field Field} definition objects (which  * will be passed to {@link Ext.data.Record#create}, or a {@link Ext.data.Record Record}  * constructor created from {@link Ext.data.Record#create}.</p>  */ Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {     /**      * @cfg {String} successProperty      * @hide      */     /**      * @cfg {Number} id (optional) The subscript within row Array that provides an ID for the Record.      * Deprecated. Use {@link #idIndex} instead.      */     /**      * @cfg {Number} idIndex (optional) The subscript within row Array that provides an ID for the Record.      */     /**      * Create a data block containing Ext.data.Records from an Array.      * @param {Object} o An Array of row objects which represents the dataset.      * @return {Object} data A data block which is used by an Ext.data.Store object as      * a cache of Ext.data.Records.      */     readRecords : function(o){         this.arrayData = o;         var s = this.meta,             sid = s ? Ext.num(s.idIndex, s.id) : null,             recordType = this.recordType,              fields = recordType.prototype.fields,             records = [],             v;         if(!this.getRoot) {             this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p) {return p;};             if(s.totalProperty) {                 this.getTotal = this.getJsonAccessor(s.totalProperty);             }         }         var root = this.getRoot(o);         for(var i = 0; i < root.length; i++) {             var n = root[i];             var values = {};             var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);             for(var j = 0, jlen = fields.length; j < jlen; j++) {                 var f = fields.items[j];                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;                 v = n[k] !== undefined ? n[k] : f.defaultValue;                 v = f.convert(v, n);                 values[f.name] = v;             }             var record = new recordType(values, id);             record.json = n;             records[records.length] = record;         }         var totalRecords = records.length;         if(s.totalProperty) {             v = parseInt(this.getTotal(o), 10);             if(!isNaN(v)) {                 totalRecords = v;             }         }         return {             records : records,             totalRecords : totalRecords         };     } });/**  * @class Ext.data.ArrayStore  * @extends Ext.data.Store  * <p>Formerly known as "SimpleStore".</p>  * <p>Small helper class to make creating {@link Ext.data.Store}s from Array data easier.  * An ArrayStore will be automatically configured with a {@link Ext.data.ArrayReader}.</p>  * <p>A store configuration would be something like:<pre><code> var store = new Ext.data.ArrayStore({     // store configs     autoDestroy: true,     storeId: 'myStore',     // reader configs     idIndex: 0,       fields: [        'company',        {name: 'price', type: 'float'},        {name: 'change', type: 'float'},        {name: 'pctChange', type: 'float'},        {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}     ] });  * </code></pre></p>  * <p>This store is configured to consume a returned object of the form:<pre><code> var myData = [     ['3m Co',71.72,0.02,0.03,'9/1 12:00am'],     ['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],     ['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am'],     ['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],     ['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am'] ];  * </code></pre>  * An object literal of this form could also be used as the {@link #data} config option.</p>  * <p><b>*Note:</b> Although not listed here, this class accepts all of the configuration options of   * <b>{@link Ext.data.ArrayReader ArrayReader}</b>.</p>  * @constructor  * @param {Object} config  * @xtype arraystore  */ Ext.data.ArrayStore = Ext.extend(Ext.data.Store, {     /**      * @cfg {Ext.data.DataReader} reader @hide      */     constructor: function(config){         Ext.data.ArrayStore.superclass.constructor.call(this, Ext.apply(config, {             reader: new Ext.data.ArrayReader(config)         }));     },     loadData : function(data, append){         if(this.expandData === true){             var r = [];             for(var i = 0, len = data.length; i < len; i++){                 r[r.length] = [data[i]];             }             data = r;         }         Ext.data.ArrayStore.superclass.loadData.call(this, data, append);     } }); Ext.reg('arraystore', Ext.data.ArrayStore); // backwards compat Ext.data.SimpleStore = Ext.data.ArrayStore; Ext.reg('simplestore', Ext.data.SimpleStore);/**  * @class Ext.data.JsonStore  * @extends Ext.data.Store  * <p>Small helper class to make creating {@link Ext.data.Store}s from JSON data easier.  * A JsonStore will be automatically configured with a {@link Ext.data.JsonReader}.</p>  * <p>A store configuration would be something like:<pre><code> var store = new Ext.data.JsonStore({     // store configs     autoDestroy: true,     url: 'get-images.php',     storeId: 'myStore',     // reader configs     root: 'images',     idProperty: 'name',       fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}] });  * </code></pre></p>  * <p>This store is configured to consume a returned object of the form:<pre><code> {     images: [         {name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},         {name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}     ] }  * </code></pre>  * An object literal of this form could also be used as the {@link #data} config option.</p>  * <p><b>*Note:</b> Although not listed here, this class accepts all of the configuration options of   * <b>{@link Ext.data.JsonReader JsonReader}</b>.</p>  * @constructor  * @param {Object} config  * @xtype jsonstore  */ Ext.data.JsonStore = Ext.extend(Ext.data.Store, {     /**      * @cfg {Ext.data.DataReader} reader @hide      */     constructor: function(config){         Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(config, {             reader: new Ext.data.JsonReader(config)         }));     } }); Ext.reg('jsonstore', Ext.data.JsonStore);/**  * @class Ext.data.XmlWriter  * @extends Ext.data.DataWriter  * DataWriter extension for writing an array or single {@link Ext.data.Record} object(s) in preparation for executing a remote CRUD action via XML.  */ Ext.data.XmlWriter = Ext.extend(Ext.data.DataWriter, {     /**      * Final action of a write event.  Apply the written data-object to params.      * @param {String} action [Ext.data.Api.create|read|update|destroy]      * @param {Record[]} rs      * @param {Object} http params      * @param {Object} data object populated according to DataReader meta-data "root" and "idProperty"      */     render : function(action, rs, params, data) {         // no impl.     },     /**      * createRecord      * @param {Ext.data.Record} rec      */     createRecord : function(rec) {         // no impl     },     /**      * updateRecord      * @param {Ext.data.Record} rec      */     updateRecord : function(rec) {         // no impl.     },     /**      * destroyRecord      * @param {Ext.data.Record} rec      */     destroyRecord : function(rec) {         // no impl     } });/**  * @class Ext.data.XmlReader  * @extends Ext.data.DataReader  * <p>Data reader class to create an Array of {@link Ext.data.Record} objects from an XML document  * based on mappings in a provided {@link Ext.data.Record} constructor.</p>  * <p><b>Note</b>: that in order for the browser to parse a returned XML document, the Content-Type  * header in the HTTP response must be set to "text/xml" or "application/xml".</p>  * <p>Example code:</p>  * <pre><code> var Employee = Ext.data.Record.create([    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it is the same as "name"    {name: 'occupation'}                 // This field will use "occupation" as the mapping. ]); var myReader = new Ext.data.XmlReader({    totalRecords: "results", // The element which contains the total dataset size (optional)    record: "row",           // The repeated element which contains row information    id: "id"                 // The element within the row that provides an ID for the record (optional) }, Employee); </code></pre>  * <p>  * This would consume an XML file like this:  * <pre><code> &lt;?xml version="1.0" encoding="UTF-8"?> &lt;dataset>  &lt;results>2&lt;/results>  &lt;row>    &lt;id>1&lt;/id>    &lt;name>Bill&lt;/name>    &lt;occupation>Gardener&lt;/occupation>  &lt;/row>  &lt;row>    &lt;id>2&lt;/id>    &lt;name>Ben&lt;/name>    &lt;occupation>Horticulturalist&lt;/occupation>  &lt;/row> &lt;/dataset> </code></pre>  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being  * paged from the remote server.  * @cfg {String} record The DomQuery path to the repeated element which contains record information.  * @cfg {String} success The DomQuery path to the success attribute used by forms.  * @cfg {String} idPath The DomQuery path relative from the record element to the element that contains  * a record identifier value.  * @constructor  * Create a new XmlReader.  * @param {Object} meta Metadata configuration options  * @param {Object} recordType Either an Array of field definition objects as passed to  * {@link Ext.data.Record#create}, or a Record constructor object created using {@link Ext.data.Record#create}.  */ Ext.data.XmlReader = function(meta, recordType){     meta = meta || {};     Ext.data.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields); }; Ext.extend(Ext.data.XmlReader, Ext.data.DataReader, {     /**      * This method is only used by a DataProxy which has retrieved data from a remote server.      * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected      * to contain a property called <tt>responseXML</tt> which refers to an XML document object.      * @return {Object} records A data block which is used by an {@link Ext.data.Store} as      * a cache of Ext.data.Records.      */     read : function(response){         var doc = response.responseXML;         if(!doc) {             throw {message: "XmlReader.read: XML Document not available"};         }         return this.readRecords(doc);     },     /**      * Create a data block containing Ext.data.Records from an XML document.      * @param {Object} doc A parsed XML document.      * @return {Object} records A data block which is used by an {@link Ext.data.Store} as      * a cache of Ext.data.Records.      */     readRecords : function(doc){         /**          * After any data loads/reads, the raw XML Document is available for further custom processing.          * @type XMLDocument          */         this.xmlData = doc;         var root = doc.documentElement || doc;         var q = Ext.DomQuery;         var recordType = this.recordType, fields = recordType.prototype.fields;         var sid = this.meta.idPath || this.meta.id;         var totalRecords = 0, success = true;         if(this.meta.totalRecords){             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);         }         if(this.meta.success){             var sv = q.selectValue(this.meta.success, root, true);             success = sv !== false && sv !== 'false';         }         var records = [];         var ns = q.select(this.meta.record, root);         for(var i = 0, len = ns.length; i < len; i++) {             var n = ns[i];             var values = {};             var id = sid ? q.selectValue(sid, n) : undefined;             for(var j = 0, jlen = fields.length; j < jlen; j++){                 var f = fields.items[j];                 var v = q.selectValue(Ext.value(f.mapping, f.name, true), n, f.defaultValue);                 v = f.convert(v, n);                 values[f.name] = v;             }             var record = new recordType(values, id);             record.node = n;             records[records.length] = record;         }         return {             success : success,             records : records,             totalRecords : totalRecords || records.length         };     },     // TODO: implement readResponse for XmlReader     readResponse : Ext.emptyFn });/**
  390.  * @class Ext.data.XmlStore
  391.  * @extends Ext.data.Store
  392.  * <p>Small helper class to make creating {@link Ext.data.Store}s from XML data easier.
  393.  * A XmlStore will be automatically configured with a {@link Ext.data.XmlReader}.</p>
  394.  * <p>A store configuration would be something like:<pre><code>
  395. var store = new Ext.data.XmlStore({
  396.     // store configs
  397.     autoDestroy: true,
  398.     storeId: 'myStore',
  399.     url: 'sheldon.xml', // automatically configures a HttpProxy
  400.     // reader configs
  401.     record: 'Item', // records will have an "Item" tag
  402.     idPath: 'ASIN',
  403.     totalRecords: '@TotalResults'
  404.     fields: [
  405.         // set up the fields mapping into the xml doc
  406.         // The first needs mapping, the others are very basic
  407.         {name: 'Author', mapping: 'ItemAttributes > Author'},
  408.         'Title', 'Manufacturer', 'ProductGroup'
  409.     ]
  410. });
  411.  * </code></pre></p>
  412.  * <p>This store is configured to consume a returned object of the form:<pre><code>
  413. &#60?xml version="1.0" encoding="UTF-8"?>
  414. &#60ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2009-05-15">
  415.     &#60Items>
  416.         &#60Request>
  417.             &#60IsValid>True&#60/IsValid>
  418.             &#60ItemSearchRequest>
  419.                 &#60Author>Sidney Sheldon&#60/Author>
  420.                 &#60SearchIndex>Books&#60/SearchIndex>
  421.             &#60/ItemSearchRequest>
  422.         &#60/Request>
  423.         &#60TotalResults>203&#60/TotalResults>
  424.         &#60TotalPages>21&#60/TotalPages>
  425.         &#60Item>
  426.             &#60ASIN>0446355453&#60/ASIN>
  427.             &#60DetailPageURL>
  428.                 http://www.amazon.com/
  429.             &#60/DetailPageURL>
  430.             &#60ItemAttributes>
  431.                 &#60Author>Sidney Sheldon&#60/Author>
  432.                 &#60Manufacturer>Warner Books&#60/Manufacturer>
  433.                 &#60ProductGroup>Book&#60/ProductGroup>
  434.                 &#60Title>Master of the Game&#60/Title>
  435.             &#60/ItemAttributes>
  436.         &#60/Item>
  437.     &#60/Items>
  438. &#60/ItemSearchResponse>
  439.  * </code></pre>
  440.  * An object literal of this form could also be used as the {@link #data} config option.</p>
  441.  * <p><b>Note:</b> Although not listed here, this class accepts all of the configuration options of 
  442.  * <b>{@link Ext.data.XmlReader XmlReader}</b>.</p>
  443.  * @constructor
  444.  * @param {Object} config
  445.  * @xtype xmlstore
  446.  */
  447. Ext.data.XmlStore = Ext.extend(Ext.data.Store, {
  448.     /**
  449.      * @cfg {Ext.data.DataReader} reader @hide
  450.      */
  451.     constructor: function(config){
  452.         Ext.data.XmlStore.superclass.constructor.call(this, Ext.apply(config, {
  453.             reader: new Ext.data.XmlReader(config)
  454.         }));
  455.     }
  456. });
  457. Ext.reg('xmlstore', Ext.data.XmlStore);/**
  458.  * @class Ext.data.GroupingStore
  459.  * @extends Ext.data.Store
  460.  * A specialized store implementation that provides for grouping records by one of the available fields. This
  461.  * is usually used in conjunction with an {@link Ext.grid.GroupingView} to proved the data model for
  462.  * a grouped GridPanel.
  463.  * @constructor
  464.  * Creates a new GroupingStore.
  465.  * @param {Object} config A config object containing the objects needed for the Store to access data,
  466.  * and read the data into Records.
  467.  * @xtype groupingstore
  468.  */
  469. Ext.data.GroupingStore = Ext.extend(Ext.data.Store, {
  470.     
  471.     //inherit docs
  472.     constructor: function(config){
  473.         Ext.data.GroupingStore.superclass.constructor.call(this, config);
  474.         this.applyGroupField();
  475.     },
  476.     
  477.     /**
  478.      * @cfg {String} groupField
  479.      * The field name by which to sort the store's data (defaults to '').
  480.      */
  481.     /**
  482.      * @cfg {Boolean} remoteGroup
  483.      * True if the grouping should apply on the server side, false if it is local only (defaults to false).  If the
  484.      * grouping is local, it can be applied immediately to the data.  If it is remote, then it will simply act as a
  485.      * helper, automatically sending the grouping field name as the 'groupBy' param with each XHR call.
  486.      */
  487.     remoteGroup : false,
  488.     /**
  489.      * @cfg {Boolean} groupOnSort
  490.      * True to sort the data on the grouping field when a grouping operation occurs, false to sort based on the
  491.      * existing sort info (defaults to false).
  492.      */
  493.     groupOnSort:false,
  494. groupDir : 'ASC',
  495.     /**
  496.      * Clears any existing grouping and refreshes the data using the default sort.
  497.      */
  498.     clearGrouping : function(){
  499.         this.groupField = false;
  500.         if(this.remoteGroup){
  501.             if(this.baseParams){
  502.                 delete this.baseParams.groupBy;
  503.             }
  504.             var lo = this.lastOptions;
  505.             if(lo && lo.params){
  506.                 delete lo.params.groupBy;
  507.             }
  508.             this.reload();
  509.         }else{
  510.             this.applySort();
  511.             this.fireEvent('datachanged', this);
  512.         }
  513.     },
  514.     /**
  515.      * Groups the data by the specified field.
  516.      * @param {String} field The field name by which to sort the store's data
  517.      * @param {Boolean} forceRegroup (optional) True to force the group to be refreshed even if the field passed
  518.      * in is the same as the current grouping field, false to skip grouping on the same field (defaults to false)
  519.      */
  520.     groupBy : function(field, forceRegroup, direction){
  521. direction = direction ? (String(direction).toUpperCase() == 'DESC' ? 'DESC' : 'ASC') : this.groupDir;
  522.         if(this.groupField == field && this.groupDir == direction && !forceRegroup){
  523.             return; // already grouped by this field
  524.         }
  525.         this.groupField = field;
  526. this.groupDir = direction;
  527.         this.applyGroupField();
  528.         if(this.groupOnSort){
  529.             this.sort(field, direction);
  530.             return;
  531.         }
  532.         if(this.remoteGroup){
  533.             this.reload();
  534.         }else{
  535.             var si = this.sortInfo || {};
  536.             if(si.field != field || si.direction != direction){
  537.                 this.applySort();
  538.             }else{
  539.                 this.sortData(field, direction);
  540.             }
  541.             this.fireEvent('datachanged', this);
  542.         }
  543.     },
  544.     
  545.     // private
  546.     applyGroupField: function(){
  547.         if(this.remoteGroup){
  548.             if(!this.baseParams){
  549.                 this.baseParams = {};
  550.             }
  551.             this.baseParams.groupBy = this.groupField;
  552.             this.baseParams.groupDir = this.groupDir;
  553.         }
  554.     },
  555.     // private
  556.     applySort : function(){
  557.         Ext.data.GroupingStore.superclass.applySort.call(this);
  558.         if(!this.groupOnSort && !this.remoteGroup){
  559.             var gs = this.getGroupState();
  560.             if(gs && (gs != this.sortInfo.field || this.groupDir != this.sortInfo.direction)){
  561.                 this.sortData(this.groupField, this.groupDir);
  562.             }
  563.         }
  564.     },
  565.     // private
  566.     applyGrouping : function(alwaysFireChange){
  567.         if(this.groupField !== false){
  568.             this.groupBy(this.groupField, true, this.groupDir);
  569.             return true;
  570.         }else{
  571.             if(alwaysFireChange === true){
  572.                 this.fireEvent('datachanged', this);
  573.             }
  574.             return false;
  575.         }
  576.     },
  577.     // private
  578.     getGroupState : function(){
  579.         return this.groupOnSort && this.groupField !== false ?
  580.                (this.sortInfo ? this.sortInfo.field : undefined) : this.groupField;
  581.     }
  582. });
  583. Ext.reg('groupingstore', Ext.data.GroupingStore);/**
  584.  * @class Ext.data.DirectProxy
  585.  * @extends Ext.data.DataProxy
  586.  */
  587. Ext.data.DirectProxy = function(config){
  588.     Ext.apply(this, config);
  589.     if(typeof this.paramOrder == 'string'){
  590.         this.paramOrder = this.paramOrder.split(/[s,|]/);
  591.     }
  592.     Ext.data.DirectProxy.superclass.constructor.call(this, config);
  593. };
  594. Ext.extend(Ext.data.DirectProxy, Ext.data.DataProxy, {
  595.     /**
  596.      * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. A list of params to be executed
  597.      * server side.  Specify the params in the order in which they must be executed on the server-side
  598.      * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
  599.      * comma, or pipe. For example,
  600.      * any of the following would be acceptable:<pre><code>
  601. paramOrder: ['param1','param2','param3']
  602. paramOrder: 'param1 param2 param3'
  603. paramOrder: 'param1,param2,param3'
  604. paramOrder: 'param1|param2|param'
  605.      </code></pre>
  606.      */
  607.     paramOrder: undefined,
  608.     /**
  609.      * @cfg {Boolean} paramsAsHash
  610.      * Send parameters as a collection of named arguments (defaults to <tt>true</tt>). Providing a
  611.      * <tt>{@link #paramOrder}</tt> nullifies this configuration.
  612.      */
  613.     paramsAsHash: true,
  614.     /**
  615.      * @cfg {Function} directFn
  616.      * Function to call when executing a request.  directFn is a simple alternative to defining the api configuration-parameter
  617.      * for Store's which will not implement a full CRUD api.
  618.      */
  619.     directFn : undefined,
  620.     // protected
  621.     doRequest : function(action, rs, params, reader, callback, scope, options) {
  622.         var args = [];
  623.         var directFn = this.api[action] || this.directFn;
  624.         switch (action) {
  625.             case Ext.data.Api.actions.create:
  626.                 args.push(params[reader.meta.root]); // <-- create(Hash)
  627.                 break;
  628.             case Ext.data.Api.actions.read:
  629.                 if(this.paramOrder){
  630.                     for(var i = 0, len = this.paramOrder.length; i < len; i++){
  631.                         args.push(params[this.paramOrder[i]]);
  632.                     }
  633.                 }else if(this.paramsAsHash){
  634.                     args.push(params);
  635.                 }
  636.                 break;
  637.             case Ext.data.Api.actions.update:
  638.                 args.push(params[reader.meta.idProperty]);  // <-- save(Integer/Integer[], Hash/Hash[])
  639.                 args.push(params[reader.meta.root]);
  640.                 break;
  641.             case Ext.data.Api.actions.destroy:
  642.                 args.push(params[reader.meta.root]);        // <-- destroy(Int/Int[])
  643.                 break;
  644.         }
  645.         var trans = {
  646.             params : params || {},
  647.             callback : callback,
  648.             scope : scope,
  649.             arg : options,
  650.             reader: reader
  651.         };
  652.         args.push(this.createCallback(action, rs, trans), this);
  653.         directFn.apply(window, args);
  654.     },
  655.     // private
  656.     createCallback : function(action, rs, trans) {
  657.         return function(result, res) {
  658.             if (!res.status) {
  659.                 // @deprecated fire loadexception
  660.                 if (action === Ext.data.Api.actions.read) {
  661.                     this.fireEvent("loadexception", this, trans, res, null);
  662.                 }
  663.                 this.fireEvent('exception', this, 'remote', action, trans, res, null);
  664.                 trans.callback.call(trans.scope, null, trans.arg, false);
  665.                 return;
  666.             }
  667.             if (action === Ext.data.Api.actions.read) {
  668.                 this.onRead(action, trans, result, res);
  669.             } else {
  670.                 this.onWrite(action, trans, result, res, rs);
  671.             }
  672.         };
  673.     },
  674.     /**
  675.      * Callback for read actions
  676.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
  677.      * @param {Object} trans The request transaction object
  678.      * @param {Object} res The server response
  679.      * @private
  680.      */
  681.     onRead : function(action, trans, result, res) {
  682.         var records;
  683.         try {
  684.             records = trans.reader.readRecords(result);
  685.         }
  686.         catch (ex) {
  687.             // @deprecated: Fire old loadexception for backwards-compat.
  688.             this.fireEvent("loadexception", this, trans, res, ex);
  689.             this.fireEvent('exception', this, 'response', action, trans, res, ex);
  690.             trans.callback.call(trans.scope, null, trans.arg, false);
  691.             return;
  692.         }
  693.         this.fireEvent("load", this, res, trans.arg);
  694.         trans.callback.call(trans.scope, records, trans.arg, true);
  695.     },
  696.     /**
  697.      * Callback for write actions
  698.      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
  699.      * @param {Object} trans The request transaction object
  700.      * @param {Object} res The server response
  701.      * @private
  702.      */
  703.     onWrite : function(action, trans, result, res, rs) {
  704.         this.fireEvent("write", this, action, result, res, rs, trans.arg);
  705.         trans.callback.call(trans.scope, result, res, true);
  706.     }
  707. });
  708. /**
  709.  * @class Ext.data.DirectStore
  710.  * @extends Ext.data.Store
  711.  * <p>Small helper class to create an {@link Ext.data.Store} configured with an
  712.  * {@link Ext.data.DirectProxy} and {@link Ext.data.JsonReader} to make interacting
  713.  * with an {@link Ext.Direct} Server-side {@link Ext.direct.Provider Provider} easier.
  714.  * To create a different proxy/reader combination create a basic {@link Ext.data.Store}
  715.  * configured as needed.</p>
  716.  *
  717.  * <p><b>*Note:</b> Although they are not listed, this class inherits all of the config options of:</p>
  718.  * <div><ul class="mdetail-params">
  719.  * <li><b>{@link Ext.data.Store Store}</b></li>
  720.  * <div class="sub-desc"><ul class="mdetail-params">
  721.  *
  722.  * </ul></div>
  723.  * <li><b>{@link Ext.data.JsonReader JsonReader}</b></li>
  724.  * <div class="sub-desc"><ul class="mdetail-params">
  725.  * <li><tt><b>{@link Ext.data.JsonReader#root root}</b></tt></li>
  726.  * <li><tt><b>{@link Ext.data.JsonReader#idProperty idProperty}</b></tt></li>
  727.  * <li><tt><b>{@link Ext.data.JsonReader#totalProperty totalProperty}</b></tt></li>
  728.  * </ul></div>
  729.  *
  730.  * <li><b>{@link Ext.data.DirectProxy DirectProxy}</b></li>
  731.  * <div class="sub-desc"><ul class="mdetail-params">
  732.  * <li><tt><b>{@link Ext.data.DirectProxy#directFn directFn}</b></tt></li>
  733.  * <li><tt><b>{@link Ext.data.DirectProxy#paramOrder paramOrder}</b></tt></li>
  734.  * <li><tt><b>{@link Ext.data.DirectProxy#paramsAsHash paramsAsHash}</b></tt></li>
  735.  * </ul></div>
  736.  * </ul></div>
  737.  *
  738.  * @xtype directstore
  739.  *
  740.  * @constructor
  741.  * @param {Object} config
  742.  */
  743. Ext.data.DirectStore = function(c){
  744.     // each transaction upon a singe record will generatie a distinct Direct transaction since Direct queues them into one Ajax request.
  745.     c.batchTransactions = false;
  746.     Ext.data.DirectStore.superclass.constructor.call(this, Ext.apply(c, {
  747.         proxy: (typeof(c.proxy) == 'undefined') ? new Ext.data.DirectProxy(Ext.copyTo({}, c, 'paramOrder,paramsAsHash,directFn,api')) : c.proxy,
  748.         reader: (typeof(c.reader) == 'undefined' && typeof(c.fields) == 'object') ? new Ext.data.JsonReader(Ext.copyTo({}, c, 'totalProperty,root,idProperty'), c.fields) : c.reader
  749.     }));
  750. };
  751. Ext.extend(Ext.data.DirectStore, Ext.data.Store, {});
  752. Ext.reg('directstore', Ext.data.DirectStore); /**
  753.  * @class Ext.Direct
  754.  * @extends Ext.util.Observable
  755.  * <p><b><u>Overview</u></b></p>
  756.  * 
  757.  * <p>Ext.Direct aims to streamline communication between the client and server
  758.  * by providing a single interface that reduces the amount of common code
  759.  * typically required to validate data and handle returned data packets
  760.  * (reading data, error conditions, etc).</p>
  761.  *  
  762.  * <p>The Ext.direct namespace includes several classes for a closer integration
  763.  * with the server-side. The Ext.data namespace also includes classes for working
  764.  * with Ext.data.Stores which are backed by data from an Ext.Direct method.</p>
  765.  * 
  766.  * <p><b><u>Specification</u></b></p>
  767.  * 
  768.  * <p>For additional information consult the 
  769.  * <a href="http://extjs.com/products/extjs/direct.php">Ext.Direct Specification</a>.</p>
  770.  *   
  771.  * <p><b><u>Providers</u></b></p>
  772.  * 
  773.  * <p>Ext.Direct uses a provider architecture, where one or more providers are
  774.  * used to transport data to and from the server. There are several providers
  775.  * that exist in the core at the moment:</p><div class="mdetail-params"><ul>
  776.  * 
  777.  * <li>{@link Ext.direct.JsonProvider JsonProvider} for simple JSON operations</li>
  778.  * <li>{@link Ext.direct.PollingProvider PollingProvider} for repeated requests</li>
  779.  * <li>{@link Ext.direct.RemotingProvider RemotingProvider} exposes server side
  780.  * on the client.</li>
  781.  * </ul></div>
  782.  * 
  783.  * <p>A provider does not need to be invoked directly, providers are added via
  784.  * {@link Ext.Direct}.{@link Ext.Direct#add add}.</p>
  785.  * 
  786.  * <p><b><u>Router</u></b></p>
  787.  * 
  788.  * <p>Ext.Direct utilizes a "router" on the server to direct requests from the client
  789.  * to the appropriate server-side method. Because the Ext.Direct API is completely
  790.  * platform-agnostic, you could completely swap out a Java based server solution
  791.  * and replace it with one that uses C# without changing the client side JavaScript
  792.  * at all.</p>
  793.  * 
  794.  * <p><b><u>Server side events</u></b></p>
  795.  * 
  796.  * <p>Custom events from the server may be handled by the client by adding
  797.  * listeners, for example:</p>
  798.  * <pre><code>
  799. {"type":"event","name":"message","data":"Successfully polled at: 11:19:30 am"}
  800. // add a handler for a 'message' event sent by the server 
  801. Ext.Direct.on('message', function(e){
  802.     out.append(String.format('&lt;p>&lt;i>{0}&lt;/i>&lt;/p>', e.data));
  803.             out.el.scrollTo('t', 100000, true);
  804. });
  805.  * </code></pre>
  806.  * @singleton
  807.  */
  808. Ext.Direct = Ext.extend(Ext.util.Observable, {
  809.     /**
  810.      * Each event type implements a getData() method. The default event types are:
  811.      * <div class="mdetail-params"><ul>
  812.      * <li><b><tt>event</tt></b> : Ext.Direct.Event</li>
  813.      * <li><b><tt>exception</tt></b> : Ext.Direct.ExceptionEvent</li>
  814.      * <li><b><tt>rpc</tt></b> : Ext.Direct.RemotingEvent</li>
  815.      * </ul></div>
  816.      * @property eventTypes
  817.      * @type Object
  818.      */
  819.     /**
  820.      * Four types of possible exceptions which can occur:
  821.      * <div class="mdetail-params"><ul>
  822.      * <li><b><tt>Ext.Direct.exceptions.TRANSPORT</tt></b> : 'xhr'</li>
  823.      * <li><b><tt>Ext.Direct.exceptions.PARSE</tt></b> : 'parse'</li>
  824.      * <li><b><tt>Ext.Direct.exceptions.LOGIN</tt></b> : 'login'</li>
  825.      * <li><b><tt>Ext.Direct.exceptions.SERVER</tt></b> : 'exception'</li>
  826.      * </ul></div>
  827.      * @property exceptions
  828.      * @type Object
  829.      */
  830.     exceptions: {
  831.         TRANSPORT: 'xhr',
  832.         PARSE: 'parse',
  833.         LOGIN: 'login',
  834.         SERVER: 'exception'
  835.     },
  836.     
  837.     // private
  838.     constructor: function(){
  839.         this.addEvents(
  840.             /**
  841.              * @event event
  842.              * Fires after an event.
  843.              * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
  844.              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
  845.              */
  846.             'event',
  847.             /**
  848.              * @event exception
  849.              * Fires after an event exception.
  850.              * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
  851.              */
  852.             'exception'
  853.         );
  854.         this.transactions = {};
  855.         this.providers = {};
  856.     },
  857.     /**
  858.      * Adds an Ext.Direct Provider and creates the proxy or stub methods to execute server-side methods.
  859.      * If the provider is not already connected, it will auto-connect.
  860.      * <pre><code>
  861. var pollProv = new Ext.direct.PollingProvider({
  862.     url: 'php/poll2.php'
  863. }); 
  864. Ext.Direct.addProvider(
  865.     {
  866.         "type":"remoting",       // create a {@link Ext.direct.RemotingProvider} 
  867.         "url":"php/router.php", // url to connect to the Ext.Direct server-side router.
  868.         "actions":{              // each property within the actions object represents a Class 
  869.             "TestAction":[       // array of methods within each server side Class   
  870.             {
  871.                 "name":"doEcho", // name of method
  872.                 "len":1
  873.             },{
  874.                 "name":"multiply",
  875.                 "len":1
  876.             },{
  877.                 "name":"doForm",
  878.                 "formHandler":true, // handle form on server with Ext.Direct.Transaction 
  879.                 "len":1
  880.             }]
  881.         },
  882.         "namespace":"myApplication",// namespace to create the Remoting Provider in
  883.     },{
  884.         type: 'polling', // create a {@link Ext.direct.PollingProvider} 
  885.         url:  'php/poll.php'
  886.     },
  887.     pollProv // reference to previously created instance
  888. );
  889.      * </code></pre>
  890.      * @param {Object/Array} provider Accepts either an Array of Provider descriptions (an instance
  891.      * or config object for a Provider) or any number of Provider descriptions as arguments.  Each
  892.      * Provider description instructs Ext.Direct how to create client-side stub methods.
  893.      */
  894.     addProvider : function(provider){        
  895.         var a = arguments;
  896.         if(a.length > 1){
  897.             for(var i = 0, len = a.length; i < len; i++){
  898.                 this.addProvider(a[i]);
  899.             }
  900.             return;
  901.         }
  902.         
  903.         // if provider has not already been instantiated
  904.         if(!provider.events){
  905.             provider = new Ext.Direct.PROVIDERS[provider.type](provider);
  906.         }
  907.         provider.id = provider.id || Ext.id();
  908.         this.providers[provider.id] = provider;
  909.         provider.on('data', this.onProviderData, this);
  910.         provider.on('exception', this.onProviderException, this);
  911.         if(!provider.isConnected()){
  912.             provider.connect();
  913.         }
  914.         return provider;
  915.     },
  916.     /**
  917.      * Retrieve a {@link Ext.direct.Provider provider} by the
  918.      * <b><tt>{@link Ext.direct.Provider#id id}</tt></b> specified when the provider is
  919.      * {@link #addProvider added}.
  920.      * @param {String} id Unique identifier assigned to the provider when calling {@link #addProvider} 
  921.      */
  922.     getProvider : function(id){
  923.         return this.providers[id];
  924.     },
  925.     removeProvider : function(id){
  926.         var provider = id.id ? id : this.providers[id.id];
  927.         provider.un('data', this.onProviderData, this);
  928.         provider.un('exception', this.onProviderException, this);
  929.         delete this.providers[provider.id];
  930.         return provider;
  931.     },
  932.     addTransaction: function(t){
  933.         this.transactions[t.tid] = t;
  934.         return t;
  935.     },
  936.     removeTransaction: function(t){
  937.         delete this.transactions[t.tid || t];
  938.         return t;
  939.     },
  940.     getTransaction: function(tid){
  941.         return this.transactions[tid.tid || tid];
  942.     },
  943.     onProviderData : function(provider, e){
  944.         if(Ext.isArray(e)){
  945.             for(var i = 0, len = e.length; i < len; i++){
  946.                 this.onProviderData(provider, e[i]);
  947.             }
  948.             return;
  949.         }
  950.         if(e.name && e.name != 'event' && e.name != 'exception'){
  951.             this.fireEvent(e.name, e);
  952.         }else if(e.type == 'exception'){
  953.             this.fireEvent('exception', e);
  954.         }
  955.         this.fireEvent('event', e, provider);
  956.     },
  957.     createEvent : function(response, extraProps){
  958.         return new Ext.Direct.eventTypes[response.type](Ext.apply(response, extraProps));
  959.     }
  960. });
  961. // overwrite impl. with static instance
  962. Ext.Direct = new Ext.Direct();
  963. Ext.Direct.TID = 1;
  964. Ext.Direct.PROVIDERS = {};/**
  965.  * @class Ext.Direct.Transaction
  966.  * @extends Object
  967.  * <p>Supporting Class for Ext.Direct (not intended to be used directly).</p>
  968.  * @constructor
  969.  * @param {Object} config
  970.  */
  971. Ext.Direct.Transaction = function(config){
  972.     Ext.apply(this, config);
  973.     this.tid = ++Ext.Direct.TID;
  974.     this.retryCount = 0;
  975. };
  976. Ext.Direct.Transaction.prototype = {
  977.     send: function(){
  978.         this.provider.queueTransaction(this);
  979.     },
  980.     retry: function(){
  981.         this.retryCount++;
  982.         this.send();
  983.     },
  984.     getProvider: function(){
  985.         return this.provider;
  986.     }
  987. };Ext.Direct.Event = function(config){
  988.     Ext.apply(this, config);
  989. }
  990. Ext.Direct.Event.prototype = {
  991.     status: true,
  992.     getData: function(){
  993.         return this.data;
  994.     }
  995. };
  996. Ext.Direct.RemotingEvent = Ext.extend(Ext.Direct.Event, {
  997.     type: 'rpc',
  998.     getTransaction: function(){
  999.         return this.transaction || Ext.Direct.getTransaction(this.tid);
  1000.     }
  1001. });
  1002. Ext.Direct.ExceptionEvent = Ext.extend(Ext.Direct.RemotingEvent, {
  1003.     status: false,
  1004.     type: 'exception'
  1005. });
  1006. Ext.Direct.eventTypes = {
  1007.     'rpc':  Ext.Direct.RemotingEvent,
  1008.     'event':  Ext.Direct.Event,
  1009.     'exception':  Ext.Direct.ExceptionEvent
  1010. };
  1011. /**
  1012.  * @class Ext.direct.Provider
  1013.  * @extends Ext.util.Observable
  1014.  * <p>Ext.direct.Provider is an abstract class meant to be extended.</p>
  1015.  * 
  1016.  * <p>For example ExtJs implements the following subclasses:</p>
  1017.  * <pre><code>
  1018. Provider
  1019. |
  1020. +---{@link Ext.direct.JsonProvider JsonProvider} 
  1021.     |
  1022.     +---{@link Ext.direct.PollingProvider PollingProvider}   
  1023.     |
  1024.     +---{@link Ext.direct.RemotingProvider RemotingProvider}   
  1025.  * </code></pre>
  1026.  * @abstract
  1027.  */
  1028. Ext.direct.Provider = Ext.extend(Ext.util.Observable, {    
  1029.     /**
  1030.      * @cfg {String} id
  1031.      * The unique id of the provider (defaults to an {@link Ext#id auto-assigned id}).
  1032.      * You should assign an id if you need to be able to access the provider later and you do
  1033.      * not have an object reference available, for example:
  1034.      * <pre><code>
  1035. Ext.Direct.addProvider(
  1036.     {
  1037.         type: 'polling',
  1038.         url:  'php/poll.php',
  1039.         id:   'poll-provider'
  1040.     }
  1041. );
  1042.      
  1043. var p = {@link Ext.Direct Ext.Direct}.{@link Ext.Direct#getProvider getProvider}('poll-provider');
  1044. p.disconnect();
  1045.      * </code></pre>
  1046.      */
  1047.         
  1048.     /**
  1049.      * @cfg {Number} priority
  1050.      * Priority of the request. Lower is higher priority, <tt>0</tt> means "duplex" (always on).
  1051.      * All Providers default to <tt>1</tt> except for PollingProvider which defaults to <tt>3</tt>.
  1052.      */    
  1053.     priority: 1,
  1054.     /**
  1055.      * @cfg {String} type
  1056.      * <b>Required</b>, <tt>undefined</tt> by default.  The <tt>type</tt> of provider specified
  1057.      * to {@link Ext.Direct Ext.Direct}.{@link Ext.Direct#addProvider addProvider} to create a
  1058.      * new Provider. Acceptable values by default are:<div class="mdetail-params"><ul>
  1059.      * <li><b><tt>polling</tt></b> : {@link Ext.direct.PollingProvider PollingProvider}</li>
  1060.      * <li><b><tt>remoting</tt></b> : {@link Ext.direct.RemotingProvider RemotingProvider}</li>
  1061.      * </ul></div>
  1062.      */    
  1063.  
  1064.     // private
  1065.     constructor : function(config){
  1066.         Ext.apply(this, config);
  1067.         this.addEvents(
  1068.             /**
  1069.              * @event connect
  1070.              * Fires when the Provider connects to the server-side
  1071.              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
  1072.              */            
  1073.             'connect',
  1074.             /**
  1075.              * @event disconnect
  1076.              * Fires when the Provider disconnects from the server-side
  1077.              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
  1078.              */            
  1079.             'disconnect',
  1080.             /**
  1081.              * @event data
  1082.              * Fires when the Provider receives data from the server-side
  1083.              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
  1084.              * @param {event} e The {@link Ext.Direct#eventTypes Ext.Direct.Event type} that occurred.
  1085.              */            
  1086.             'data',
  1087.             /**
  1088.              * @event exception
  1089.              * Fires when the Provider receives an exception from the server-side
  1090.              */                        
  1091.             'exception'
  1092.         );
  1093.         Ext.direct.Provider.superclass.constructor.call(this, config);
  1094.     },
  1095.     /**
  1096.      * Returns whether or not the server-side is currently connected.
  1097.      * Abstract method for subclasses to implement.
  1098.      */
  1099.     isConnected: function(){
  1100.         return false;
  1101.     },
  1102.     /**
  1103.      * Abstract methods for subclasses to implement.
  1104.      */
  1105.     connect: Ext.emptyFn,
  1106.     
  1107.     /**
  1108.      * Abstract methods for subclasses to implement.
  1109.      */
  1110.     disconnect: Ext.emptyFn
  1111. });
  1112. /**
  1113.  * @class Ext.direct.JsonProvider
  1114.  * @extends Ext.direct.Provider
  1115.  */
  1116. Ext.direct.JsonProvider = Ext.extend(Ext.direct.Provider, {
  1117.     parseResponse: function(xhr){
  1118.         if(!Ext.isEmpty(xhr.responseText)){
  1119.             if(typeof xhr.responseText == 'object'){
  1120.                 return xhr.responseText;
  1121.             }
  1122.             return Ext.decode(xhr.responseText);
  1123.         }
  1124.         return null;
  1125.     },
  1126.     getEvents: function(xhr){
  1127.         var data = null;
  1128.         try{
  1129.             data = this.parseResponse(xhr);
  1130.         }catch(e){
  1131.             var event = new Ext.Direct.ExceptionEvent({
  1132.                 data: e,
  1133.                 xhr: xhr,
  1134.                 code: Ext.Direct.exceptions.PARSE,
  1135.                 message: 'Error parsing json response: nn ' + data
  1136.             })
  1137.             return [event];
  1138.         }
  1139.         var events = [];
  1140.         if(Ext.isArray(data)){
  1141.             for(var i = 0, len = data.length; i < len; i++){
  1142.                 events.push(Ext.Direct.createEvent(data[i]));
  1143.             }
  1144.         }else{
  1145.             events.push(Ext.Direct.createEvent(data));
  1146.         }
  1147.         return events;
  1148.     }
  1149. });/**
  1150.  * @class Ext.direct.PollingProvider
  1151.  * @extends Ext.direct.JsonProvider
  1152.  *
  1153.  * <p>Provides for repetitive polling of the server at distinct {@link #interval intervals}.
  1154.  * The initial request for data originates from the client, and then is responded to by the
  1155.  * server.</p>
  1156.  * 
  1157.  * <p>All configurations for the PollingProvider should be generated by the server-side
  1158.  * API portion of the Ext.Direct stack.</p>
  1159.  *
  1160.  * <p>An instance of PollingProvider may be created directly via the new keyword or by simply
  1161.  * specifying <tt>type = 'polling'</tt>.  For example:</p>
  1162.  * <pre><code>
  1163. var pollA = new Ext.direct.PollingProvider({
  1164.     type:'polling',
  1165.     url: 'php/pollA.php',
  1166. });
  1167. Ext.Direct.addProvider(pollA);
  1168. pollA.disconnect();
  1169. Ext.Direct.addProvider(
  1170.     {
  1171.         type:'polling',
  1172.         url: 'php/pollB.php',
  1173.         id: 'pollB-provider'
  1174.     }
  1175. );
  1176. var pollB = Ext.Direct.getProvider('pollB-provider');
  1177.  * </code></pre>
  1178.  */
  1179. Ext.direct.PollingProvider = Ext.extend(Ext.direct.JsonProvider, {
  1180.     /**
  1181.      * @cfg {Number} priority
  1182.      * Priority of the request (defaults to <tt>3</tt>). See {@link Ext.direct.Provider#priority}.
  1183.      */
  1184.     // override default priority
  1185.     priority: 3,
  1186.     
  1187.     /**
  1188.      * @cfg {Number} interval
  1189.      * How often to poll the server-side in milliseconds (defaults to <tt>3000</tt> - every
  1190.      * 3 seconds).
  1191.      */
  1192.     interval: 3000,
  1193.     /**
  1194.      * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
  1195.      * on every polling request
  1196.      */
  1197.     
  1198.     /**
  1199.      * @cfg {String/Function} url
  1200.      * The url which the PollingProvider should contact with each request. This can also be
  1201.      * an imported Ext.Direct method which will accept the baseParams as its only argument.
  1202.      */
  1203.     // private
  1204.     constructor : function(config){
  1205.         Ext.direct.PollingProvider.superclass.constructor.call(this, config);
  1206.         this.addEvents(
  1207.             /**
  1208.              * @event beforepoll
  1209.              * Fired immediately before a poll takes place, an event handler can return false
  1210.              * in order to cancel the poll.
  1211.              * @param {Ext.direct.PollingProvider}
  1212.              */
  1213.             'beforepoll',            
  1214.             /**
  1215.              * @event poll
  1216.              * This event has not yet been implemented.
  1217.              * @param {Ext.direct.PollingProvider}
  1218.              */
  1219.             'poll'
  1220.         );
  1221.     },
  1222.     // inherited
  1223.     isConnected: function(){
  1224.         return !!this.pollTask;
  1225.     },
  1226.     /**
  1227.      * Connect to the server-side and begin the polling process. To handle each
  1228.      * response subscribe to the data event.
  1229.      */
  1230.     connect: function(){
  1231.         if(this.url && !this.pollTask){
  1232.             this.pollTask = Ext.TaskMgr.start({
  1233.                 run: function(){
  1234.                     if(this.fireEvent('beforepoll', this) !== false){
  1235.                         if(typeof this.url == 'function'){
  1236.                             this.url(this.baseParams);
  1237.                         }else{
  1238.                             Ext.Ajax.request({
  1239.                                 url: this.url,
  1240.                                 callback: this.onData,
  1241.                                 scope: this,
  1242.                                 params: this.baseParams
  1243.                             });
  1244.                         }
  1245.                     }
  1246.                 },
  1247.                 interval: this.interval,
  1248.                 scope: this
  1249.             });
  1250.             this.fireEvent('connect', this);
  1251.         }else if(!this.url){
  1252.             throw 'Error initializing PollingProvider, no url configured.';
  1253.         }
  1254.     },
  1255.     /**
  1256.      * Disconnect from the server-side and stop the polling process. The disconnect
  1257.      * event will be fired on a successful disconnect.
  1258.      */
  1259.     disconnect: function(){
  1260.         if(this.pollTask){
  1261.             Ext.TaskMgr.stop(this.pollTask);
  1262.             delete this.pollTask;
  1263.             this.fireEvent('disconnect', this);
  1264.         }
  1265.     },
  1266.     // private
  1267.     onData: function(opt, success, xhr){
  1268.         if(success){
  1269.             var events = this.getEvents(xhr);
  1270.             for(var i = 0, len = events.length; i < len; i++){
  1271.                 var e = events[i];
  1272.                 this.fireEvent('data', this, e);
  1273.             }
  1274.         }else{
  1275.             var e = new Ext.Direct.ExceptionEvent({
  1276.                 data: e,
  1277.                 code: Ext.Direct.exceptions.TRANSPORT,
  1278.                 message: 'Unable to connect to the server.',
  1279.                 xhr: xhr
  1280.             });
  1281.             this.fireEvent('data', this, e);
  1282.         }
  1283.     }
  1284. });
  1285. Ext.Direct.PROVIDERS['polling'] = Ext.direct.PollingProvider;/**
  1286.  * @class Ext.direct.RemotingProvider
  1287.  * @extends Ext.direct.JsonProvider
  1288.  * 
  1289.  * <p>The {@link Ext.direct.RemotingProvider RemotingProvider} exposes access to
  1290.  * server side methods on the client (a remote procedure call (RPC) type of
  1291.  * connection where the client can initiate a procedure on the server).</p>
  1292.  * 
  1293.  * <p>This allows for code to be organized in a fashion that is maintainable,
  1294.  * while providing a clear path between client and server, something that is
  1295.  * not always apparent when using URLs.</p>
  1296.  * 
  1297.  * <p>To accomplish this the server-side needs to describe what classes and methods
  1298.  * are available on the client-side. This configuration will typically be
  1299.  * outputted by the server-side Ext.Direct stack when the API description is built.</p>
  1300.  */
  1301. Ext.direct.RemotingProvider = Ext.extend(Ext.direct.JsonProvider, {       
  1302.     /**
  1303.      * @cfg {Object} actions
  1304.      * Object literal defining the server side actions and methods. For example, if
  1305.      * the Provider is configured with:
  1306.      * <pre><code>
  1307. "actions":{ // each property within the 'actions' object represents a server side Class 
  1308.     "TestAction":[ // array of methods within each server side Class to be   
  1309.     {              // stubbed out on client
  1310.         "name":"doEcho", 
  1311.         "len":1            
  1312.     },{
  1313.         "name":"multiply",// name of method
  1314.         "len":2           // The number of parameters that will be used to create an
  1315.                           // array of data to send to the server side function.
  1316.                           // Ensure the server sends back a Number, not a String. 
  1317.     },{
  1318.         "name":"doForm",
  1319.         "formHandler":true, // direct the client to use specialized form handling method 
  1320.         "len":1
  1321.     }]
  1322. }
  1323.      * </code></pre>
  1324.      * <p>Note that a Store is not required, a server method can be called at any time.
  1325.      * In the following example a <b>client side</b> handler is used to call the
  1326.      * server side method "multiply" in the server-side "TestAction" Class:</p>
  1327.      * <pre><code>
  1328. TestAction.multiply(
  1329.     2, 4, // pass two arguments to server, so specify len=2
  1330.     // callback function after the server is called
  1331.     // result: the result returned by the server
  1332.     //      e: Ext.Direct.RemotingEvent object
  1333.     function(result, e){
  1334.         var t = e.getTransaction();
  1335.         var action = t.action; // server side Class called
  1336.         var method = t.method; // server side method called
  1337.         if(e.status){
  1338.             var answer = Ext.encode(result); // 8
  1339.     
  1340.         }else{
  1341.             var msg = e.message; // failure message
  1342.         }
  1343.     }
  1344. );
  1345.      * </code></pre>
  1346.      * In the example above, the server side "multiply" function will be passed two
  1347.      * arguments (2 and 4).  The "multiply" method should return the value 8 which will be
  1348.      * available as the <tt>result</tt> in the example above. 
  1349.      */
  1350.     
  1351.     /**
  1352.      * @cfg {String/Object} namespace
  1353.      * Namespace for the Remoting Provider (defaults to the browser global scope of <i>window</i>).
  1354.      * Explicitly specify the namespace Object, or specify a String to have a
  1355.      * {@link Ext#namespace namespace created} implicitly.
  1356.      */
  1357.     
  1358.     /**
  1359.      * @cfg {String} url
  1360.      * <b>Required<b>. The url to connect to the {@link Ext.Direct} server-side router. 
  1361.      */
  1362.     
  1363.     /**
  1364.      * @cfg {String} enableUrlEncode
  1365.      * Specify which param will hold the arguments for the method.
  1366.      * Defaults to <tt>'data'</tt>.
  1367.      */
  1368.     
  1369.     /**
  1370.      * @cfg {Number/Boolean} enableBuffer
  1371.      * <p><tt>true</tt> or <tt>false</tt> to enable or disable combining of method
  1372.      * calls. If a number is specified this is the amount of time in milliseconds
  1373.      * to wait before sending a batched request (defaults to <tt>10</tt>).</p>
  1374.      * <br><p>Calls which are received within the specified timeframe will be
  1375.      * concatenated together and sent in a single request, optimizing the
  1376.      * application by reducing the amount of round trips that have to be made
  1377.      * to the server.</p>
  1378.      */
  1379.     enableBuffer: 10,
  1380.     
  1381.     /**
  1382.      * @cfg {Number} maxRetries
  1383.      * Number of times to re-attempt delivery on failure of a call.
  1384.      */
  1385.     maxRetries: 1,
  1386.     constructor : function(config){
  1387.         Ext.direct.RemotingProvider.superclass.constructor.call(this, config);
  1388.         this.addEvents(
  1389.             /**
  1390.              * @event beforecall
  1391.              * Fires immediately before the client-side sends off the RPC call.
  1392.              * By returning false from an event handler you can prevent the call from
  1393.              * executing.
  1394.              * @param {Ext.direct.RemotingProvider} provider
  1395.              * @param {Ext.Direct.Transaction} transaction
  1396.              */            
  1397.             'beforecall',
  1398.             /**
  1399.              * @event call
  1400.              * Fires immediately after the request to the server-side is sent. This does
  1401.              * NOT fire after the response has come back from the call.
  1402.              * @param {Ext.direct.RemotingProvider} provider
  1403.              * @param {Ext.Direct.Transaction} transaction
  1404.              */            
  1405.             'call'
  1406.         );
  1407.         this.namespace = (typeof this.namespace === 'string') ? Ext.ns(this.namespace) : this.namespace || window;
  1408.         this.transactions = {};
  1409.         this.callBuffer = [];
  1410.     },
  1411.     // private
  1412.     initAPI : function(){
  1413.         var o = this.actions;
  1414.         for(var c in o){
  1415.             var cls = this.namespace[c] || (this.namespace[c] = {});
  1416.             var ms = o[c];
  1417.             for(var i = 0, len = ms.length; i < len; i++){
  1418.                 var m = ms[i];
  1419.                 cls[m.name] = this.createMethod(c, m);
  1420.             }
  1421.         }
  1422.     },
  1423.     // inherited
  1424.     isConnected: function(){
  1425.         return !!this.connected;
  1426.     },
  1427.     connect: function(){
  1428.         if(this.url){
  1429.             this.initAPI();
  1430.             this.connected = true;
  1431.             this.fireEvent('connect', this);
  1432.         }else if(!this.url){
  1433.             throw 'Error initializing RemotingProvider, no url configured.';
  1434.         }
  1435.     },
  1436.     disconnect: function(){
  1437.         if(this.connected){
  1438.             this.connected = false;
  1439.             this.fireEvent('disconnect', this);
  1440.         }
  1441.     },
  1442.     onData: function(opt, success, xhr){
  1443.         if(success){
  1444.             var events = this.getEvents(xhr);
  1445.             for(var i = 0, len = events.length; i < len; i++){
  1446.                 var e = events[i];
  1447.                 var t = this.getTransaction(e);
  1448.                 this.fireEvent('data', this, e);
  1449.                 if(t){
  1450.                     this.doCallback(t, e, true);
  1451.                     Ext.Direct.removeTransaction(t);
  1452.                 }
  1453.             }
  1454.         }else{
  1455.             var ts = [].concat(opt.ts);
  1456.             for(var i = 0, len = ts.length; i < len; i++){
  1457.                 var t = this.getTransaction(ts[i]);
  1458.                 if(t && t.retryCount < this.maxRetries){
  1459.                     t.retry();
  1460.                 }else{
  1461.                     var e = new Ext.Direct.ExceptionEvent({
  1462.                         data: e,
  1463.                         transaction: t,
  1464.                         code: Ext.Direct.exceptions.TRANSPORT,
  1465.                         message: 'Unable to connect to the server.',
  1466.                         xhr: xhr
  1467.                     });
  1468.                     this.fireEvent('data', this, e);
  1469.                     if(t){
  1470.                         this.doCallback(t, e, false);
  1471.                         Ext.Direct.removeTransaction(t);
  1472.                     }
  1473.                 }
  1474.             }
  1475.         }
  1476.     },
  1477.     getCallData: function(t){
  1478.         return {
  1479.             action: t.action,
  1480.             method: t.method,
  1481.             data: t.data,
  1482.             type: 'rpc',
  1483.             tid: t.tid
  1484.         };
  1485.     },
  1486.     doSend : function(data){
  1487.         var o = {
  1488.             url: this.url,
  1489.             callback: this.onData,
  1490.             scope: this,
  1491.             ts: data
  1492.         };
  1493.         // send only needed data
  1494.         var callData;
  1495.         if(Ext.isArray(data)){
  1496.             callData = [];
  1497.             for(var i = 0, len = data.length; i < len; i++){
  1498.                 callData.push(this.getCallData(data[i]));
  1499.             }
  1500.         }else{
  1501.             callData = this.getCallData(data);
  1502.         }
  1503.         if(this.enableUrlEncode){
  1504.             var params = {};
  1505.             params[typeof this.enableUrlEncode == 'string' ? this.enableUrlEncode : 'data'] = Ext.encode(callData);
  1506.             o.params = params;
  1507.         }else{
  1508.             o.jsonData = callData;
  1509.         }
  1510.         Ext.Ajax.request(o);
  1511.     },
  1512.     combineAndSend : function(){
  1513.         var len = this.callBuffer.length;
  1514.         if(len > 0){
  1515.             this.doSend(len == 1 ? this.callBuffer[0] : this.callBuffer);
  1516.             this.callBuffer = [];
  1517.         }
  1518.     },
  1519.     queueTransaction: function(t){
  1520.         if(t.form){
  1521.             this.processForm(t);
  1522.             return;
  1523.         }
  1524.         this.callBuffer.push(t);
  1525.         if(this.enableBuffer){
  1526.             if(!this.callTask){
  1527.                 this.callTask = new Ext.util.DelayedTask(this.combineAndSend, this);
  1528.             }
  1529.             this.callTask.delay(typeof this.enableBuffer == 'number' ? this.enableBuffer : 10);
  1530.         }else{
  1531.             this.combineAndSend();
  1532.         }
  1533.     },
  1534.     doCall : function(c, m, args){
  1535.         var data = null, hs = args[m.len], scope = args[m.len+1];
  1536.         if(m.len !== 0){
  1537.             data = args.slice(0, m.len);
  1538.         }
  1539.         var t = new Ext.Direct.Transaction({
  1540.             provider: this,
  1541.             args: args,
  1542.             action: c,
  1543.             method: m.name,
  1544.             data: data,
  1545.             cb: scope && Ext.isFunction(hs) ? hs.createDelegate(scope) : hs
  1546.         });
  1547.         if(this.fireEvent('beforecall', this, t) !== false){
  1548.             Ext.Direct.addTransaction(t);
  1549.             this.queueTransaction(t);
  1550.             this.fireEvent('call', this, t);
  1551.         }