-/**\r
- * @class Ext.data.ScriptTagProxy\r
- * @extends Ext.data.DataProxy\r
- * An implementation of Ext.data.DataProxy that reads a data object from a URL which may be in a domain\r
- * other than the originating domain of the running page.<br>\r
- * <p>\r
- * <b>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain\r
- * of the running page, you must use this class, rather than HttpProxy.</b><br>\r
- * <p>\r
- * The content passed back from a server resource requested by a ScriptTagProxy <b>must</b> be executable JavaScript\r
- * source code because it is used as the source inside a <script> tag.<br>\r
- * <p>\r
- * In order for the browser to process the returned data, the server must wrap the data object\r
- * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.\r
- * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy\r
- * depending on whether the callback name was passed:\r
- * <p>\r
- * <pre><code>\r
-boolean scriptTag = false;\r
-String cb = request.getParameter("callback");\r
-if (cb != null) {\r
- scriptTag = true;\r
- response.setContentType("text/javascript");\r
-} else {\r
- response.setContentType("application/x-json");\r
-}\r
-Writer out = response.getWriter();\r
-if (scriptTag) {\r
- out.write(cb + "(");\r
-}\r
-out.print(dataBlock.toJsonString());\r
-if (scriptTag) {\r
- out.write(");");\r
-}\r
-</code></pre>\r
- * <p>Below is a PHP example to do the same thing:</p><pre><code>\r
-$callback = $_REQUEST['callback'];\r
-\r
-// Create the output object.\r
-$output = array('a' => 'Apple', 'b' => 'Banana');\r
-\r
-//start output\r
-if ($callback) {\r
- header('Content-Type: text/javascript');\r
- echo $callback . '(' . json_encode($output) . ');';\r
-} else {\r
- header('Content-Type: application/x-json');\r
- echo json_encode($output);\r
-}\r
-</code></pre>\r
- *\r
- * @constructor\r
- * @param {Object} config A configuration object.\r
- */\r
-Ext.data.ScriptTagProxy = function(config){\r
- Ext.apply(this, config);\r
-\r
- Ext.data.ScriptTagProxy.superclass.constructor.call(this, config);\r
-\r
- this.head = document.getElementsByTagName("head")[0];\r
-\r
- /**\r
- * @event loadexception\r
- * <b>Deprecated</b> in favor of 'exception' event.\r
- * Fires if an exception occurs in the Proxy during data loading. This event can be fired for one of two reasons:\r
- * <ul><li><b>The load call timed out.</b> This means the load callback did not execute within the time limit\r
- * specified by {@link #timeout}. In this case, this event will be raised and the\r
- * fourth parameter (read error) will be null.</li>\r
- * <li><b>The load succeeded but the reader could not read the response.</b> This means the server returned\r
- * data, but the configured Reader threw an error while reading the data. In this case, this event will be\r
- * raised and the caught error will be passed along as the fourth parameter of this event.</li></ul>\r
- * Note that this event is also relayed through {@link Ext.data.Store}, so you can listen for it directly\r
- * on any Store instance.\r
- * @param {Object} this\r
- * @param {Object} options The loading options that were specified (see {@link #load} for details). If the load\r
- * call timed out, this parameter will be null.\r
- * @param {Object} arg The callback's arg object passed to the {@link #load} function\r
- * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data.\r
- * If the remote request returns success: false, this parameter will be null.\r
- */\r
-};\r
-\r
-Ext.data.ScriptTagProxy.TRANS_ID = 1000;\r
-\r
-Ext.extend(Ext.data.ScriptTagProxy, Ext.data.DataProxy, {\r
- /**\r
- * @cfg {String} url The URL from which to request the data object.\r
- */\r
- /**\r
- * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.\r
- */\r
- timeout : 30000,\r
- /**\r
- * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells\r
- * the server the name of the callback function set up by the load call to process the returned data object.\r
- * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate\r
- * javascript output which calls this named function passing the data object as its only parameter.\r
- */\r
- callbackParam : "callback",\r
- /**\r
- * @cfg {Boolean} nocache (optional) Defaults to true. Disable caching by adding a unique parameter\r
- * name to the request.\r
- */\r
- nocache : true,\r
-\r
- /**\r
- * HttpProxy implementation of DataProxy#doRequest\r
- * @param {String} action\r
- * @param {Ext.data.Record/Ext.data.Record[]} rs If action is <tt>read</tt>, rs will be null\r
- * @param {Object} params An object containing properties which are to be used as HTTP parameters\r
- * for the request to the remote server.\r
- * @param {Ext.data.DataReader} reader The Reader object which converts the data\r
- * object into a block of Ext.data.Records.\r
- * @param {Function} callback The function into which to pass the block of Ext.data.Records.\r
- * The function must be passed <ul>\r
- * <li>The Record block object</li>\r
- * <li>The "arg" argument from the load function</li>\r
- * <li>A boolean success indicator</li>\r
- * </ul>\r
- * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.\r
- * @param {Object} arg An optional argument which is passed to the callback as its second parameter.\r
- */\r
- doRequest : function(action, rs, params, reader, callback, scope, arg) {\r
- var p = Ext.urlEncode(Ext.apply(params, this.extraParams));\r
-\r
- var url = this.buildUrl(action, rs);\r
- if (!url) {\r
- throw new Ext.data.Api.Error('invalid-url', url);\r
- }\r
- url = Ext.urlAppend(url, p);\r
-\r
- if(this.nocache){\r
- url = Ext.urlAppend(url, '_dc=' + (new Date().getTime()));\r
- }\r
- var transId = ++Ext.data.ScriptTagProxy.TRANS_ID;\r
- var trans = {\r
- id : transId,\r
- action: action,\r
- cb : "stcCallback"+transId,\r
- scriptId : "stcScript"+transId,\r
- params : params,\r
- arg : arg,\r
- url : url,\r
- callback : callback,\r
- scope : scope,\r
- reader : reader\r
- };\r
- window[trans.cb] = this.createCallback(action, rs, trans);\r
- url += String.format("&{0}={1}", this.callbackParam, trans.cb);\r
- if(this.autoAbort !== false){\r
- this.abort();\r
- }\r
-\r
- trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);\r
-\r
- var script = document.createElement("script");\r
- script.setAttribute("src", url);\r
- script.setAttribute("type", "text/javascript");\r
- script.setAttribute("id", trans.scriptId);\r
- this.head.appendChild(script);\r
-\r
- this.trans = trans;\r
- },\r
-\r
- // @private createCallback\r
- createCallback : function(action, rs, trans) {\r
- var self = this;\r
- return function(res) {\r
- self.trans = false;\r
- self.destroyTrans(trans, true);\r
- if (action === Ext.data.Api.actions.read) {\r
- self.onRead.call(self, action, trans, res);\r
- } else {\r
- self.onWrite.call(self, action, trans, res, rs);\r
- }\r
- };\r
- },\r
- /**\r
- * Callback for read actions\r
- * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]\r
- * @param {Object} trans The request transaction object\r
- * @param {Object} res The server response\r
- * @protected\r
- */\r
- onRead : function(action, trans, res) {\r
- var result;\r
- try {\r
- result = trans.reader.readRecords(res);\r
- }catch(e){\r
- // @deprecated: fire loadexception\r
- this.fireEvent("loadexception", this, trans, res, e);\r
-\r
- this.fireEvent('exception', this, 'response', action, trans, res, e);\r
- trans.callback.call(trans.scope||window, null, trans.arg, false);\r
- return;\r
- }\r
- if (result.success === false) {\r
- // @deprecated: fire old loadexception for backwards-compat.\r
- this.fireEvent('loadexception', this, trans, res);\r
-\r
- this.fireEvent('exception', this, 'remote', action, trans, res, null);\r
- } else {\r
- this.fireEvent("load", this, res, trans.arg);\r
- }\r
- trans.callback.call(trans.scope||window, result, trans.arg, result.success);\r
- },\r
- /**\r
- * Callback for write actions\r
- * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]\r
- * @param {Object} trans The request transaction object\r
- * @param {Object} res The server response\r
- * @protected\r
- */\r
- onWrite : function(action, trans, response, rs) {\r
- var reader = trans.reader;\r
- try {\r
- // though we already have a response object here in STP, run through readResponse to catch any meta-data exceptions.\r
- var res = reader.readResponse(action, response);\r
- } catch (e) {\r
- this.fireEvent('exception', this, 'response', action, trans, res, e);\r
- trans.callback.call(trans.scope||window, null, res, false);\r
- return;\r
- }\r
- if(!res.success === true){\r
- this.fireEvent('exception', this, 'remote', action, trans, res, rs);\r
- trans.callback.call(trans.scope||window, null, res, false);\r
- return;\r
- }\r
- this.fireEvent("write", this, action, res.data, res, rs, trans.arg );\r
- trans.callback.call(trans.scope||window, res.data, res, true);\r
- },\r
-\r
- // private\r
- isLoading : function(){\r
- return this.trans ? true : false;\r
- },\r
-\r
- /**\r
- * Abort the current server request.\r
- */\r
- abort : function(){\r
- if(this.isLoading()){\r
- this.destroyTrans(this.trans);\r
- }\r
- },\r
-\r
- // private\r
- destroyTrans : function(trans, isLoaded){\r
- this.head.removeChild(document.getElementById(trans.scriptId));\r
- clearTimeout(trans.timeoutId);\r
- if(isLoaded){\r
- window[trans.cb] = undefined;\r
- try{\r
- delete window[trans.cb];\r
- }catch(e){}\r
- }else{\r
- // if hasn't been loaded, wait for load to remove it to prevent script error\r
- window[trans.cb] = function(){\r
- window[trans.cb] = undefined;\r
- try{\r
- delete window[trans.cb];\r
- }catch(e){}\r
- };\r
- }\r
- },\r
-\r
- // private\r
- handleFailure : function(trans){\r
- this.trans = false;\r
- this.destroyTrans(trans, false);\r
- if (trans.action === Ext.data.Api.actions.read) {\r
- // @deprecated firing loadexception\r
- this.fireEvent("loadexception", this, null, trans.arg);\r
- }\r
-\r
- this.fireEvent('exception', this, 'response', trans.action, {\r
- response: null,\r
- options: trans.arg\r
- });\r
- trans.callback.call(trans.scope||window, null, trans.arg, false);\r
- },\r
-\r
- // inherit docs\r
- destroy: function(){\r
- this.abort();\r
- Ext.data.ScriptTagProxy.superclass.destroy.call(this);\r
- }\r
-});/**\r
- * @class Ext.data.HttpProxy\r
- * @extends Ext.data.DataProxy\r
- * <p>An implementation of {@link Ext.data.DataProxy} that processes data requests within the same\r
- * domain of the originating page.</p>\r
- * <p><b>Note</b>: this class cannot be used to retrieve data from a domain other\r
- * than the domain from which the running page was served. For cross-domain requests, use a\r
- * {@link Ext.data.ScriptTagProxy ScriptTagProxy}.</p>\r
- * <p>Be aware that to enable the browser to parse an XML document, the server must set\r
- * the Content-Type header in the HTTP response to "<tt>text/xml</tt>".</p>\r
- * @constructor\r
- * @param {Object} conn\r
- * An {@link Ext.data.Connection} object, or options parameter to {@link Ext.Ajax#request}.\r
- * <p>Note that if this HttpProxy is being used by a {@link Ext.data.Store Store}, then the\r
- * Store's call to {@link #load} will override any specified <tt>callback</tt> and <tt>params</tt>\r
- * options. In this case, use the Store's {@link Ext.data.Store#events events} to modify parameters,\r
- * or react to loading events. The Store's {@link Ext.data.Store#baseParams baseParams} may also be\r
- * used to pass parameters known at instantiation time.</p>\r
- * <p>If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make\r
- * the request.</p>\r
- */\r
-Ext.data.HttpProxy = function(conn){\r
- Ext.data.HttpProxy.superclass.constructor.call(this, conn);\r
-\r
- /**\r
- * The Connection object (Or options parameter to {@link Ext.Ajax#request}) which this HttpProxy\r
- * uses to make requests to the server. Properties of this object may be changed dynamically to\r
- * change the way data is requested.\r
- * @property\r
- */\r
- this.conn = conn;\r
-\r
- // nullify the connection url. The url param has been copied to 'this' above. The connection\r
- // url will be set during each execution of doRequest when buildUrl is called. This makes it easier for users to override the\r
- // connection url during beforeaction events (ie: beforeload, beforewrite, etc).\r
- // Url is always re-defined during doRequest.\r
- this.conn.url = null;\r
-\r
- this.useAjax = !conn || !conn.events;\r
-\r
- // A hash containing active requests, keyed on action [Ext.data.Api.actions.create|read|update|destroy]\r
- var actions = Ext.data.Api.actions;\r
- this.activeRequest = {};\r
- for (var verb in actions) {\r
- this.activeRequest[actions[verb]] = undefined;\r
- }\r
-};\r
-\r
-Ext.extend(Ext.data.HttpProxy, Ext.data.DataProxy, {\r
- /**\r
- * Return the {@link Ext.data.Connection} object being used by this Proxy.\r
- * @return {Connection} The Connection object. This object may be used to subscribe to events on\r
- * a finer-grained basis than the DataProxy events.\r
- */\r
- getConnection : function() {\r
- return this.useAjax ? Ext.Ajax : this.conn;\r
- },\r
-\r
- /**\r
- * Used for overriding the url used for a single request. Designed to be called during a beforeaction event. Calling setUrl\r
- * will override any urls set via the api configuration parameter. Set the optional parameter makePermanent to set the url for\r
- * all subsequent requests. If not set to makePermanent, the next request will use the same url or api configuration defined\r
- * in the initial proxy configuration.\r
- * @param {String} url\r
- * @param {Boolean} makePermanent (Optional) [false]\r
- *\r
- * (e.g.: beforeload, beforesave, etc).\r
- */\r
- setUrl : function(url, makePermanent) {\r
- this.conn.url = url;\r
- if (makePermanent === true) {\r
- this.url = url;\r
- this.api = null;\r
- Ext.data.Api.prepare(this);\r
- }\r
- },\r
-\r
- /**\r
- * HttpProxy implementation of DataProxy#doRequest\r
- * @param {String} action The crud action type (create, read, update, destroy)\r
- * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null\r
- * @param {Object} params An object containing properties which are to be used as HTTP parameters\r
- * for the request to the remote server.\r
- * @param {Ext.data.DataReader} reader The Reader object which converts the data\r
- * object into a block of Ext.data.Records.\r
- * @param {Function} callback\r
- * <div class="sub-desc"><p>A function to be called after the request.\r
- * The <tt>callback</tt> is passed the following arguments:<ul>\r
- * <li><tt>r</tt> : Ext.data.Record[] The block of Ext.data.Records.</li>\r
- * <li><tt>options</tt>: Options object from the action request</li>\r
- * <li><tt>success</tt>: Boolean success indicator</li></ul></p></div>\r
- * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.\r
- * @param {Object} arg An optional argument which is passed to the callback as its second parameter.\r
- * @protected\r
- */\r
- doRequest : function(action, rs, params, reader, cb, scope, arg) {\r
- var o = {\r
- method: (this.api[action]) ? this.api[action]['method'] : undefined,\r
- request: {\r
- callback : cb,\r
- scope : scope,\r
- arg : arg\r
- },\r
- reader: reader,\r
- callback : this.createCallback(action, rs),\r
- scope: this\r
- };\r
-\r
- // If possible, transmit data using jsonData || xmlData on Ext.Ajax.request (An installed DataWriter would have written it there.).\r
- // Use std HTTP params otherwise.\r
- if (params.jsonData) {\r
- o.jsonData = params.jsonData;\r
- } else if (params.xmlData) {\r
- o.xmlData = params.xmlData;\r
- } else {\r
- o.params = params || {};\r
- }\r
- // Set the connection url. If this.conn.url is not null here,\r
- // the user must have overridden the url during a beforewrite/beforeload event-handler.\r
- // this.conn.url is nullified after each request.\r
- this.conn.url = this.buildUrl(action, rs);\r
-\r
- if(this.useAjax){\r
-\r
- Ext.applyIf(o, this.conn);\r
-\r
- // If a currently running request is found for this action, abort it.\r
- if (this.activeRequest[action]) {\r
- ////\r
- // Disabled aborting activeRequest while implementing REST. activeRequest[action] will have to become an array\r
- // TODO ideas anyone?\r
- //\r
- //Ext.Ajax.abort(this.activeRequest[action]);\r
- }\r
- this.activeRequest[action] = Ext.Ajax.request(o);\r
- }else{\r
- this.conn.request(o);\r
- }\r
- // request is sent, nullify the connection url in preparation for the next request\r
- this.conn.url = null;\r
- },\r
-\r
- /**\r
- * Returns a callback function for a request. Note a special case is made for the\r
- * read action vs all the others.\r
- * @param {String} action [create|update|delete|load]\r
- * @param {Ext.data.Record[]} rs The Store-recordset being acted upon\r
- * @private\r
- */\r
- createCallback : function(action, rs) {\r
- return function(o, success, response) {\r
- this.activeRequest[action] = undefined;\r
- if (!success) {\r
- if (action === Ext.data.Api.actions.read) {\r
- // @deprecated: fire loadexception for backwards compat.\r
- // TODO remove in 3.1\r
- this.fireEvent('loadexception', this, o, response);\r
- }\r
- this.fireEvent('exception', this, 'response', action, o, response);\r
- o.request.callback.call(o.request.scope, null, o.request.arg, false);\r
- return;\r
- }\r
- if (action === Ext.data.Api.actions.read) {\r
- this.onRead(action, o, response);\r
- } else {\r
- this.onWrite(action, o, response, rs);\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * Callback for read action\r
- * @param {String} action Action name as per {@link Ext.data.Api.actions#read}.\r
- * @param {Object} o The request transaction object\r
- * @param {Object} res The server response\r
- * @fires loadexception (deprecated)\r
- * @fires exception\r
- * @fires load\r
- * @protected\r
- */\r
- onRead : function(action, o, response) {\r
- var result;\r
- try {\r
- result = o.reader.read(response);\r
- }catch(e){\r
- // @deprecated: fire old loadexception for backwards-compat.\r
- // TODO remove in 3.1\r
- this.fireEvent('loadexception', this, o, response, e);\r
-\r
- this.fireEvent('exception', this, 'response', action, o, response, e);\r
- o.request.callback.call(o.request.scope, null, o.request.arg, false);\r
- return;\r
- }\r
- if (result.success === false) {\r
- // @deprecated: fire old loadexception for backwards-compat.\r
- // TODO remove in 3.1\r
- this.fireEvent('loadexception', this, o, response);\r
-\r
- // Get DataReader read-back a response-object to pass along to exception event\r
- var res = o.reader.readResponse(action, response);\r
- this.fireEvent('exception', this, 'remote', action, o, res, null);\r
- }\r
- else {\r
- this.fireEvent('load', this, o, o.request.arg);\r
- }\r
- // TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance\r
- // the calls to request.callback(...) in each will have to be made identical.\r
- // NOTE reader.readResponse does not currently return Ext.data.Response\r
- o.request.callback.call(o.request.scope, result, o.request.arg, result.success);\r
- },\r
- /**\r
- * Callback for write actions\r
- * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]\r
- * @param {Object} trans The request transaction object\r
- * @param {Object} res The server response\r
- * @fires exception\r
- * @fires write\r
- * @protected\r
- */\r
- onWrite : function(action, o, response, rs) {\r
- var reader = o.reader;\r
- var res;\r
- try {\r
- res = reader.readResponse(action, response);\r
- } catch (e) {\r
- this.fireEvent('exception', this, 'response', action, o, response, e);\r
- o.request.callback.call(o.request.scope, null, o.request.arg, false);\r
- return;\r
- }\r
- if (res.success === false) {\r
- this.fireEvent('exception', this, 'remote', action, o, res, rs);\r
- } else {\r
- this.fireEvent('write', this, action, res.data, res, rs, o.request.arg);\r
- }\r
- // TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance\r
- // the calls to request.callback(...) in each will have to be made similar.\r
- // NOTE reader.readResponse does not currently return Ext.data.Response\r
- o.request.callback.call(o.request.scope, res.data, res, res.success);\r
- },\r
-\r
- // inherit docs\r
- destroy: function(){\r
- if(!this.useAjax){\r
- this.conn.abort();\r
- }else if(this.activeRequest){\r
- var actions = Ext.data.Api.actions;\r
- for (var verb in actions) {\r
- if(this.activeRequest[actions[verb]]){\r
- Ext.Ajax.abort(this.activeRequest[actions[verb]]);\r
- }\r
- }\r
- }\r
- Ext.data.HttpProxy.superclass.destroy.call(this);\r
- }\r
-});/**\r
- * @class Ext.data.MemoryProxy\r
- * @extends Ext.data.DataProxy\r
- * An implementation of Ext.data.DataProxy that simply passes the data specified in its constructor\r
- * to the Reader when its load method is called.\r
- * @constructor\r
- * @param {Object} data The data object which the Reader uses to construct a block of Ext.data.Records.\r
- */\r
-Ext.data.MemoryProxy = function(data){\r
- // Must define a dummy api with "read" action to satisfy DataProxy#doRequest and Ext.data.Api#prepare *before* calling super\r
- var api = {};\r
- api[Ext.data.Api.actions.read] = true;\r
- Ext.data.MemoryProxy.superclass.constructor.call(this, {\r
- api: api\r
- });\r
- this.data = data;\r
-};\r
-\r
-Ext.extend(Ext.data.MemoryProxy, Ext.data.DataProxy, {\r
- /**\r
- * @event loadexception\r
- * Fires if an exception occurs in the Proxy during data loading. Note that this event is also relayed\r
- * through {@link Ext.data.Store}, so you can listen for it directly on any Store instance.\r
- * @param {Object} this\r
- * @param {Object} arg The callback's arg object passed to the {@link #load} function\r
- * @param {Object} null This parameter does not apply and will always be null for MemoryProxy\r
- * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data\r
- */\r
-\r
- /**\r
- * MemoryProxy implementation of DataProxy#doRequest\r
- * @param {String} action\r
- * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null\r
- * @param {Object} params An object containing properties which are to be used as HTTP parameters\r
- * for the request to the remote server.\r
- * @param {Ext.data.DataReader} reader The Reader object which converts the data\r
- * object into a block of Ext.data.Records.\r
- * @param {Function} callback The function into which to pass the block of Ext.data.Records.\r
- * The function must be passed <ul>\r
- * <li>The Record block object</li>\r
- * <li>The "arg" argument from the load function</li>\r
- * <li>A boolean success indicator</li>\r
- * </ul>\r
- * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.\r
- * @param {Object} arg An optional argument which is passed to the callback as its second parameter.\r
- */\r
- doRequest : function(action, rs, params, reader, callback, scope, arg) {\r
- // No implementation for CRUD in MemoryProxy. Assumes all actions are 'load'\r
- params = params || {};\r
- var result;\r
- try {\r
- result = reader.readRecords(this.data);\r
- }catch(e){\r
- // @deprecated loadexception\r
- this.fireEvent("loadexception", this, null, arg, e);\r
-\r
- this.fireEvent('exception', this, 'response', action, arg, null, e);\r
- callback.call(scope, null, arg, false);\r
- return;\r
- }\r
- callback.call(scope, result, arg, true);\r
- }\r
-});
\ No newline at end of file
+/**
+ * @class Ext.data.ScriptTagProxy
+ * @extends Ext.data.DataProxy
+ * An implementation of Ext.data.DataProxy that reads a data object from a URL which may be in a domain
+ * other than the originating domain of the running page.<br>
+ * <p>
+ * <b>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
+ * of the running page, you must use this class, rather than HttpProxy.</b><br>
+ * <p>
+ * The content passed back from a server resource requested by a ScriptTagProxy <b>must</b> be executable JavaScript
+ * source code because it is used as the source inside a <script> tag.<br>
+ * <p>
+ * In order for the browser to process the returned data, the server must wrap the data object
+ * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
+ * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
+ * depending on whether the callback name was passed:
+ * <p>
+ * <pre><code>
+boolean scriptTag = false;
+String cb = request.getParameter("callback");
+if (cb != null) {
+ scriptTag = true;
+ response.setContentType("text/javascript");
+} else {
+ response.setContentType("application/x-json");
+}
+Writer out = response.getWriter();
+if (scriptTag) {
+ out.write(cb + "(");
+}
+out.print(dataBlock.toJsonString());
+if (scriptTag) {
+ out.write(");");
+}
+</code></pre>
+ * <p>Below is a PHP example to do the same thing:</p><pre><code>
+$callback = $_REQUEST['callback'];
+
+// Create the output object.
+$output = array('a' => 'Apple', 'b' => 'Banana');
+
+//start output
+if ($callback) {
+ header('Content-Type: text/javascript');
+ echo $callback . '(' . json_encode($output) . ');';
+} else {
+ header('Content-Type: application/x-json');
+ echo json_encode($output);
+}
+</code></pre>
+ * <p>Below is the ASP.Net code to do the same thing:</p><pre><code>
+String jsonString = "{success: true}";
+String cb = Request.Params.Get("callback");
+String responseString = "";
+if (!String.IsNullOrEmpty(cb)) {
+ responseString = cb + "(" + jsonString + ")";
+} else {
+ responseString = jsonString;
+}
+Response.Write(responseString);
+</code></pre>
+ *
+ * @constructor
+ * @param {Object} config A configuration object.
+ */
+Ext.data.ScriptTagProxy = function(config){
+ Ext.apply(this, config);
+
+ Ext.data.ScriptTagProxy.superclass.constructor.call(this, config);
+
+ this.head = document.getElementsByTagName("head")[0];
+
+ /**
+ * @event loadexception
+ * <b>Deprecated</b> in favor of 'exception' event.
+ * Fires if an exception occurs in the Proxy during data loading. This event can be fired for one of two reasons:
+ * <ul><li><b>The load call timed out.</b> This means the load callback did not execute within the time limit
+ * specified by {@link #timeout}. In this case, this event will be raised and the
+ * fourth parameter (read error) will be null.</li>
+ * <li><b>The load succeeded but the reader could not read the response.</b> This means the server returned
+ * data, but the configured Reader threw an error while reading the data. In this case, this event will be
+ * raised and the caught error will be passed along as the fourth parameter of this event.</li></ul>
+ * Note that this event is also relayed through {@link Ext.data.Store}, so you can listen for it directly
+ * on any Store instance.
+ * @param {Object} this
+ * @param {Object} options The loading options that were specified (see {@link #load} for details). If the load
+ * call timed out, this parameter will be null.
+ * @param {Object} arg The callback's arg object passed to the {@link #load} function
+ * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data.
+ * If the remote request returns success: false, this parameter will be null.
+ */
+};
+
+Ext.data.ScriptTagProxy.TRANS_ID = 1000;
+
+Ext.extend(Ext.data.ScriptTagProxy, Ext.data.DataProxy, {
+ /**
+ * @cfg {String} url The URL from which to request the data object.
+ */
+ /**
+ * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
+ */
+ timeout : 30000,
+ /**
+ * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
+ * the server the name of the callback function set up by the load call to process the returned data object.
+ * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
+ * javascript output which calls this named function passing the data object as its only parameter.
+ */
+ callbackParam : "callback",
+ /**
+ * @cfg {Boolean} nocache (optional) Defaults to true. Disable caching by adding a unique parameter
+ * name to the request.
+ */
+ nocache : true,
+
+ /**
+ * HttpProxy implementation of DataProxy#doRequest
+ * @param {String} action
+ * @param {Ext.data.Record/Ext.data.Record[]} rs If action is <tt>read</tt>, rs will be null
+ * @param {Object} params An object containing properties which are to be used as HTTP parameters
+ * for the request to the remote server.
+ * @param {Ext.data.DataReader} reader The Reader object which converts the data
+ * object into a block of Ext.data.Records.
+ * @param {Function} callback The function into which to pass the block of Ext.data.Records.
+ * The function must be passed <ul>
+ * <li>The Record block object</li>
+ * <li>The "arg" argument from the load function</li>
+ * <li>A boolean success indicator</li>
+ * </ul>
+ * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+ * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+ */
+ doRequest : function(action, rs, params, reader, callback, scope, arg) {
+ var p = Ext.urlEncode(Ext.apply(params, this.extraParams));
+
+ var url = this.buildUrl(action, rs);
+ if (!url) {
+ throw new Ext.data.Api.Error('invalid-url', url);
+ }
+ url = Ext.urlAppend(url, p);
+
+ if(this.nocache){
+ url = Ext.urlAppend(url, '_dc=' + (new Date().getTime()));
+ }
+ var transId = ++Ext.data.ScriptTagProxy.TRANS_ID;
+ var trans = {
+ id : transId,
+ action: action,
+ cb : "stcCallback"+transId,
+ scriptId : "stcScript"+transId,
+ params : params,
+ arg : arg,
+ url : url,
+ callback : callback,
+ scope : scope,
+ reader : reader
+ };
+ window[trans.cb] = this.createCallback(action, rs, trans);
+ url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+ if(this.autoAbort !== false){
+ this.abort();
+ }
+
+ trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
+
+ var script = document.createElement("script");
+ script.setAttribute("src", url);
+ script.setAttribute("type", "text/javascript");
+ script.setAttribute("id", trans.scriptId);
+ this.head.appendChild(script);
+
+ this.trans = trans;
+ },
+
+ // @private createCallback
+ createCallback : function(action, rs, trans) {
+ var self = this;
+ return function(res) {
+ self.trans = false;
+ self.destroyTrans(trans, true);
+ if (action === Ext.data.Api.actions.read) {
+ self.onRead.call(self, action, trans, res);
+ } else {
+ self.onWrite.call(self, action, trans, res, rs);
+ }
+ };
+ },
+ /**
+ * Callback for read actions
+ * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
+ * @param {Object} trans The request transaction object
+ * @param {Object} res The server response
+ * @protected
+ */
+ onRead : function(action, trans, res) {
+ var result;
+ try {
+ result = trans.reader.readRecords(res);
+ }catch(e){
+ // @deprecated: fire loadexception
+ this.fireEvent("loadexception", this, trans, res, e);
+
+ this.fireEvent('exception', this, 'response', action, trans, res, e);
+ trans.callback.call(trans.scope||window, null, trans.arg, false);
+ return;
+ }
+ if (result.success === false) {
+ // @deprecated: fire old loadexception for backwards-compat.
+ this.fireEvent('loadexception', this, trans, res);
+
+ this.fireEvent('exception', this, 'remote', action, trans, res, null);
+ } else {
+ this.fireEvent("load", this, res, trans.arg);
+ }
+ trans.callback.call(trans.scope||window, result, trans.arg, result.success);
+ },
+ /**
+ * Callback for write actions
+ * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
+ * @param {Object} trans The request transaction object
+ * @param {Object} res The server response
+ * @protected
+ */
+ onWrite : function(action, trans, response, rs) {
+ var reader = trans.reader;
+ try {
+ // though we already have a response object here in STP, run through readResponse to catch any meta-data exceptions.
+ var res = reader.readResponse(action, response);
+ } catch (e) {
+ this.fireEvent('exception', this, 'response', action, trans, res, e);
+ trans.callback.call(trans.scope||window, null, res, false);
+ return;
+ }
+ if(!res.success === true){
+ this.fireEvent('exception', this, 'remote', action, trans, res, rs);
+ trans.callback.call(trans.scope||window, null, res, false);
+ return;
+ }
+ this.fireEvent("write", this, action, res.data, res, rs, trans.arg );
+ trans.callback.call(trans.scope||window, res.data, res, true);
+ },
+
+ // private
+ isLoading : function(){
+ return this.trans ? true : false;
+ },
+
+ /**
+ * Abort the current server request.
+ */
+ abort : function(){
+ if(this.isLoading()){
+ this.destroyTrans(this.trans);
+ }
+ },
+
+ // private
+ destroyTrans : function(trans, isLoaded){
+ this.head.removeChild(document.getElementById(trans.scriptId));
+ clearTimeout(trans.timeoutId);
+ if(isLoaded){
+ window[trans.cb] = undefined;
+ try{
+ delete window[trans.cb];
+ }catch(e){}
+ }else{
+ // if hasn't been loaded, wait for load to remove it to prevent script error
+ window[trans.cb] = function(){
+ window[trans.cb] = undefined;
+ try{
+ delete window[trans.cb];
+ }catch(e){}
+ };
+ }
+ },
+
+ // private
+ handleFailure : function(trans){
+ this.trans = false;
+ this.destroyTrans(trans, false);
+ if (trans.action === Ext.data.Api.actions.read) {
+ // @deprecated firing loadexception
+ this.fireEvent("loadexception", this, null, trans.arg);
+ }
+
+ this.fireEvent('exception', this, 'response', trans.action, {
+ response: null,
+ options: trans.arg
+ });
+ trans.callback.call(trans.scope||window, null, trans.arg, false);
+ },
+
+ // inherit docs
+ destroy: function(){
+ this.abort();
+ Ext.data.ScriptTagProxy.superclass.destroy.call(this);
+ }
+});/**
+ * @class Ext.data.HttpProxy
+ * @extends Ext.data.DataProxy
+ * <p>An implementation of {@link Ext.data.DataProxy} that processes data requests within the same
+ * domain of the originating page.</p>
+ * <p><b>Note</b>: this class cannot be used to retrieve data from a domain other
+ * than the domain from which the running page was served. For cross-domain requests, use a
+ * {@link Ext.data.ScriptTagProxy ScriptTagProxy}.</p>
+ * <p>Be aware that to enable the browser to parse an XML document, the server must set
+ * the Content-Type header in the HTTP response to "<tt>text/xml</tt>".</p>
+ * @constructor
+ * @param {Object} conn
+ * An {@link Ext.data.Connection} object, or options parameter to {@link Ext.Ajax#request}.
+ * <p>Note that if this HttpProxy is being used by a {@link Ext.data.Store Store}, then the
+ * Store's call to {@link #load} will override any specified <tt>callback</tt> and <tt>params</tt>
+ * options. In this case, use the Store's {@link Ext.data.Store#events events} to modify parameters,
+ * or react to loading events. The Store's {@link Ext.data.Store#baseParams baseParams} may also be
+ * used to pass parameters known at instantiation time.</p>
+ * <p>If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make
+ * the request.</p>
+ */
+Ext.data.HttpProxy = function(conn){
+ Ext.data.HttpProxy.superclass.constructor.call(this, conn);
+
+ /**
+ * The Connection object (Or options parameter to {@link Ext.Ajax#request}) which this HttpProxy
+ * uses to make requests to the server. Properties of this object may be changed dynamically to
+ * change the way data is requested.
+ * @property
+ */
+ this.conn = conn;
+
+ // nullify the connection url. The url param has been copied to 'this' above. The connection
+ // url will be set during each execution of doRequest when buildUrl is called. This makes it easier for users to override the
+ // connection url during beforeaction events (ie: beforeload, beforewrite, etc).
+ // Url is always re-defined during doRequest.
+ this.conn.url = null;
+
+ this.useAjax = !conn || !conn.events;
+
+ // A hash containing active requests, keyed on action [Ext.data.Api.actions.create|read|update|destroy]
+ var actions = Ext.data.Api.actions;
+ this.activeRequest = {};
+ for (var verb in actions) {
+ this.activeRequest[actions[verb]] = undefined;
+ }
+};
+
+Ext.extend(Ext.data.HttpProxy, Ext.data.DataProxy, {
+ /**
+ * Return the {@link Ext.data.Connection} object being used by this Proxy.
+ * @return {Connection} The Connection object. This object may be used to subscribe to events on
+ * a finer-grained basis than the DataProxy events.
+ */
+ getConnection : function() {
+ return this.useAjax ? Ext.Ajax : this.conn;
+ },
+
+ /**
+ * Used for overriding the url used for a single request. Designed to be called during a beforeaction event. Calling setUrl
+ * will override any urls set via the api configuration parameter. Set the optional parameter makePermanent to set the url for
+ * all subsequent requests. If not set to makePermanent, the next request will use the same url or api configuration defined
+ * in the initial proxy configuration.
+ * @param {String} url
+ * @param {Boolean} makePermanent (Optional) [false]
+ *
+ * (e.g.: beforeload, beforesave, etc).
+ */
+ setUrl : function(url, makePermanent) {
+ this.conn.url = url;
+ if (makePermanent === true) {
+ this.url = url;
+ this.api = null;
+ Ext.data.Api.prepare(this);
+ }
+ },
+
+ /**
+ * HttpProxy implementation of DataProxy#doRequest
+ * @param {String} action The crud action type (create, read, update, destroy)
+ * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
+ * @param {Object} params An object containing properties which are to be used as HTTP parameters
+ * for the request to the remote server.
+ * @param {Ext.data.DataReader} reader The Reader object which converts the data
+ * object into a block of Ext.data.Records.
+ * @param {Function} callback
+ * <div class="sub-desc"><p>A function to be called after the request.
+ * The <tt>callback</tt> is passed the following arguments:<ul>
+ * <li><tt>r</tt> : Ext.data.Record[] The block of Ext.data.Records.</li>
+ * <li><tt>options</tt>: Options object from the action request</li>
+ * <li><tt>success</tt>: Boolean success indicator</li></ul></p></div>
+ * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+ * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+ * @protected
+ */
+ doRequest : function(action, rs, params, reader, cb, scope, arg) {
+ var o = {
+ method: (this.api[action]) ? this.api[action]['method'] : undefined,
+ request: {
+ callback : cb,
+ scope : scope,
+ arg : arg
+ },
+ reader: reader,
+ callback : this.createCallback(action, rs),
+ scope: this
+ };
+
+ // If possible, transmit data using jsonData || xmlData on Ext.Ajax.request (An installed DataWriter would have written it there.).
+ // Use std HTTP params otherwise.
+ if (params.jsonData) {
+ o.jsonData = params.jsonData;
+ } else if (params.xmlData) {
+ o.xmlData = params.xmlData;
+ } else {
+ o.params = params || {};
+ }
+ // Set the connection url. If this.conn.url is not null here,
+ // the user must have overridden the url during a beforewrite/beforeload event-handler.
+ // this.conn.url is nullified after each request.
+ this.conn.url = this.buildUrl(action, rs);
+
+ if(this.useAjax){
+
+ Ext.applyIf(o, this.conn);
+
+ // If a currently running request is found for this action, abort it.
+ if (this.activeRequest[action]) {
+ ////
+ // Disabled aborting activeRequest while implementing REST. activeRequest[action] will have to become an array
+ // TODO ideas anyone?
+ //
+ //Ext.Ajax.abort(this.activeRequest[action]);
+ }
+ this.activeRequest[action] = Ext.Ajax.request(o);
+ }else{
+ this.conn.request(o);
+ }
+ // request is sent, nullify the connection url in preparation for the next request
+ this.conn.url = null;
+ },
+
+ /**
+ * Returns a callback function for a request. Note a special case is made for the
+ * read action vs all the others.
+ * @param {String} action [create|update|delete|load]
+ * @param {Ext.data.Record[]} rs The Store-recordset being acted upon
+ * @private
+ */
+ createCallback : function(action, rs) {
+ return function(o, success, response) {
+ this.activeRequest[action] = undefined;
+ if (!success) {
+ if (action === Ext.data.Api.actions.read) {
+ // @deprecated: fire loadexception for backwards compat.
+ // TODO remove
+ this.fireEvent('loadexception', this, o, response);
+ }
+ this.fireEvent('exception', this, 'response', action, o, response);
+ o.request.callback.call(o.request.scope, null, o.request.arg, false);
+ return;
+ }
+ if (action === Ext.data.Api.actions.read) {
+ this.onRead(action, o, response);
+ } else {
+ this.onWrite(action, o, response, rs);
+ }
+ };
+ },
+
+ /**
+ * Callback for read action
+ * @param {String} action Action name as per {@link Ext.data.Api.actions#read}.
+ * @param {Object} o The request transaction object
+ * @param {Object} res The server response
+ * @fires loadexception (deprecated)
+ * @fires exception
+ * @fires load
+ * @protected
+ */
+ onRead : function(action, o, response) {
+ var result;
+ try {
+ result = o.reader.read(response);
+ }catch(e){
+ // @deprecated: fire old loadexception for backwards-compat.
+ // TODO remove
+ this.fireEvent('loadexception', this, o, response, e);
+
+ this.fireEvent('exception', this, 'response', action, o, response, e);
+ o.request.callback.call(o.request.scope, null, o.request.arg, false);
+ return;
+ }
+ if (result.success === false) {
+ // @deprecated: fire old loadexception for backwards-compat.
+ // TODO remove
+ this.fireEvent('loadexception', this, o, response);
+
+ // Get DataReader read-back a response-object to pass along to exception event
+ var res = o.reader.readResponse(action, response);
+ this.fireEvent('exception', this, 'remote', action, o, res, null);
+ }
+ else {
+ this.fireEvent('load', this, o, o.request.arg);
+ }
+ // TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance
+ // the calls to request.callback(...) in each will have to be made identical.
+ // NOTE reader.readResponse does not currently return Ext.data.Response
+ o.request.callback.call(o.request.scope, result, o.request.arg, result.success);
+ },
+ /**
+ * Callback for write actions
+ * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
+ * @param {Object} trans The request transaction object
+ * @param {Object} res The server response
+ * @fires exception
+ * @fires write
+ * @protected
+ */
+ onWrite : function(action, o, response, rs) {
+ var reader = o.reader;
+ var res;
+ try {
+ res = reader.readResponse(action, response);
+ } catch (e) {
+ this.fireEvent('exception', this, 'response', action, o, response, e);
+ o.request.callback.call(o.request.scope, null, o.request.arg, false);
+ return;
+ }
+ if (res.success === true) {
+ this.fireEvent('write', this, action, res.data, res, rs, o.request.arg);
+ } else {
+ this.fireEvent('exception', this, 'remote', action, o, res, rs);
+ }
+ // TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance
+ // the calls to request.callback(...) in each will have to be made similar.
+ // NOTE reader.readResponse does not currently return Ext.data.Response
+ o.request.callback.call(o.request.scope, res.data, res, res.success);
+ },
+
+ // inherit docs
+ destroy: function(){
+ if(!this.useAjax){
+ this.conn.abort();
+ }else if(this.activeRequest){
+ var actions = Ext.data.Api.actions;
+ for (var verb in actions) {
+ if(this.activeRequest[actions[verb]]){
+ Ext.Ajax.abort(this.activeRequest[actions[verb]]);
+ }
+ }
+ }
+ Ext.data.HttpProxy.superclass.destroy.call(this);
+ }
+});/**
+ * @class Ext.data.MemoryProxy
+ * @extends Ext.data.DataProxy
+ * An implementation of Ext.data.DataProxy that simply passes the data specified in its constructor
+ * to the Reader when its load method is called.
+ * @constructor
+ * @param {Object} data The data object which the Reader uses to construct a block of Ext.data.Records.
+ */
+Ext.data.MemoryProxy = function(data){
+ // Must define a dummy api with "read" action to satisfy DataProxy#doRequest and Ext.data.Api#prepare *before* calling super
+ var api = {};
+ api[Ext.data.Api.actions.read] = true;
+ Ext.data.MemoryProxy.superclass.constructor.call(this, {
+ api: api
+ });
+ this.data = data;
+};
+
+Ext.extend(Ext.data.MemoryProxy, Ext.data.DataProxy, {
+ /**
+ * @event loadexception
+ * Fires if an exception occurs in the Proxy during data loading. Note that this event is also relayed
+ * through {@link Ext.data.Store}, so you can listen for it directly on any Store instance.
+ * @param {Object} this
+ * @param {Object} arg The callback's arg object passed to the {@link #load} function
+ * @param {Object} null This parameter does not apply and will always be null for MemoryProxy
+ * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data
+ */
+
+ /**
+ * MemoryProxy implementation of DataProxy#doRequest
+ * @param {String} action
+ * @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
+ * @param {Object} params An object containing properties which are to be used as HTTP parameters
+ * for the request to the remote server.
+ * @param {Ext.data.DataReader} reader The Reader object which converts the data
+ * object into a block of Ext.data.Records.
+ * @param {Function} callback The function into which to pass the block of Ext.data.Records.
+ * The function must be passed <ul>
+ * <li>The Record block object</li>
+ * <li>The "arg" argument from the load function</li>
+ * <li>A boolean success indicator</li>
+ * </ul>
+ * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+ * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+ */
+ doRequest : function(action, rs, params, reader, callback, scope, arg) {
+ // No implementation for CRUD in MemoryProxy. Assumes all actions are 'load'
+ params = params || {};
+ var result;
+ try {
+ result = reader.readRecords(this.data);
+ }catch(e){
+ // @deprecated loadexception
+ this.fireEvent("loadexception", this, null, arg, e);
+
+ this.fireEvent('exception', this, 'response', action, arg, null, e);
+ callback.call(scope, null, arg, false);
+ return;
+ }
+ callback.call(scope, result, arg, true);
+ }
+});/**
+ * @class Ext.data.Types
+ * <p>This is s static class containing the system-supplied data types which may be given to a {@link Ext.data.Field Field}.<p/>
+ * <p>The properties in this class are used as type indicators in the {@link Ext.data.Field Field} class, so to
+ * test whether a Field is of a certain type, compare the {@link Ext.data.Field#type type} property against properties
+ * of this class.</p>
+ * <p>Developers may add their own application-specific data types to this class. Definition names must be UPPERCASE.
+ * each type definition must contain three properties:</p>
+ * <div class="mdetail-params"><ul>
+ * <li><code>convert</code> : <i>Function</i><div class="sub-desc">A function to convert raw data values from a data block into the data
+ * to be stored in the Field. The function is passed the collowing parameters:
+ * <div class="mdetail-params"><ul>
+ * <li><b>v</b> : Mixed<div class="sub-desc">The data value as read by the Reader, if undefined will use
+ * the configured <tt>{@link Ext.data.Field#defaultValue defaultValue}</tt>.</div></li>
+ * <li><b>rec</b> : Mixed<div class="sub-desc">The data object containing the row as read by the Reader.
+ * Depending on the Reader type, this could be an Array ({@link Ext.data.ArrayReader ArrayReader}), an object
+ * ({@link Ext.data.JsonReader JsonReader}), or an XML element ({@link Ext.data.XMLReader XMLReader}).</div></li>
+ * </ul></div></div></li>
+ * <li><code>sortType</code> : <i>Function</i> <div class="sub-desc">A function to convert the stored data into comparable form, as defined by {@link Ext.data.SortTypes}.</div></li>
+ * <li><code>type</code> : <i>String</i> <div class="sub-desc">A textual data type name.</div></li>
+ * </ul></div>
+ * <p>For example, to create a VELatLong field (See the Microsoft Bing Mapping API) containing the latitude/longitude value of a datapoint on a map from a JsonReader data block
+ * which contained the properties <code>lat</code> and <code>long</code>, you would define a new data type like this:</p>
+ *<pre><code>
+// Add a new Field data type which stores a VELatLong object in the Record.
+Ext.data.Types.VELATLONG = {
+ convert: function(v, data) {
+ return new VELatLong(data.lat, data.long);
+ },
+ sortType: function(v) {
+ return v.Latitude; // When sorting, order by latitude
+ },
+ type: 'VELatLong'
+};
+</code></pre>
+ * <p>Then, when declaring a Record, use <pre><code>
+var types = Ext.data.Types; // allow shorthand type access
+UnitRecord = Ext.data.Record.create([
+ { name: 'unitName', mapping: 'UnitName' },
+ { name: 'curSpeed', mapping: 'CurSpeed', type: types.INT },
+ { name: 'latitude', mapping: 'lat', type: types.FLOAT },
+ { name: 'latitude', mapping: 'lat', type: types.FLOAT },
+ { name: 'position', type: types.VELATLONG }
+]);
+</code></pre>
+ * @singleton
+ */
+Ext.data.Types = new function(){
+ var st = Ext.data.SortTypes;
+ Ext.apply(this, {
+ /**
+ * @type Regexp
+ * @property stripRe
+ * A regular expression for stripping non-numeric characters from a numeric value. Defaults to <tt>/[\$,%]/g</tt>.
+ * This should be overridden for localization.
+ */
+ stripRe: /[\$,%]/g,
+
+ /**
+ * @type Object.
+ * @property AUTO
+ * This data type means that no conversion is applied to the raw data before it is placed into a Record.
+ */
+ AUTO: {
+ convert: function(v){ return v; },
+ sortType: st.none,
+ type: 'auto'
+ },
+
+ /**
+ * @type Object.
+ * @property STRING
+ * This data type means that the raw data is converted into a String before it is placed into a Record.
+ */
+ STRING: {
+ convert: function(v){ return (v === undefined || v === null) ? '' : String(v); },
+ sortType: st.asUCString,
+ type: 'string'
+ },
+
+ /**
+ * @type Object.
+ * @property INT
+ * This data type means that the raw data is converted into an integer before it is placed into a Record.
+ * <p>The synonym <code>INTEGER</code> is equivalent.</p>
+ */
+ INT: {
+ convert: function(v){
+ return v !== undefined && v !== null && v !== '' ?
+ parseInt(String(v).replace(Ext.data.Types.stripRe, ''), 10) : 0;
+ },
+ sortType: st.none,
+ type: 'int'
+ },
+
+ /**
+ * @type Object.
+ * @property FLOAT
+ * This data type means that the raw data is converted into a number before it is placed into a Record.
+ * <p>The synonym <code>NUMBER</code> is equivalent.</p>
+ */
+ FLOAT: {
+ convert: function(v){
+ return v !== undefined && v !== null && v !== '' ?
+ parseFloat(String(v).replace(Ext.data.Types.stripRe, ''), 10) : 0;
+ },
+ sortType: st.none,
+ type: 'float'
+ },
+
+ /**
+ * @type Object.
+ * @property BOOL
+ * <p>This data type means that the raw data is converted into a boolean before it is placed into
+ * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
+ * <p>The synonym <code>BOOLEAN</code> is equivalent.</p>
+ */
+ BOOL: {
+ convert: function(v){ return v === true || v === 'true' || v == 1; },
+ sortType: st.none,
+ type: 'bool'
+ },
+
+ /**
+ * @type Object.
+ * @property DATE
+ * This data type means that the raw data is converted into a Date before it is placed into a Record.
+ * The date format is specified in the constructor of the {@link Ext.data.Field} to which this type is
+ * being applied.
+ */
+ DATE: {
+ convert: function(v){
+ var df = this.dateFormat;
+ if(!v){
+ return null;
+ }
+ if(Ext.isDate(v)){
+ return v;
+ }
+ if(df){
+ if(df == 'timestamp'){
+ return new Date(v*1000);
+ }
+ if(df == 'time'){
+ return new Date(parseInt(v, 10));
+ }
+ return Date.parseDate(v, df);
+ }
+ var parsed = Date.parse(v);
+ return parsed ? new Date(parsed) : null;
+ },
+ sortType: st.asDate,
+ type: 'date'
+ }
+ });
+
+ Ext.apply(this, {
+ /**
+ * @type Object.
+ * @property BOOLEAN
+ * <p>This data type means that the raw data is converted into a boolean before it is placed into
+ * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
+ * <p>The synonym <code>BOOL</code> is equivalent.</p>
+ */
+ BOOLEAN: this.BOOL,
+ /**
+ * @type Object.
+ * @property INTEGER
+ * This data type means that the raw data is converted into an integer before it is placed into a Record.
+ * <p>The synonym <code>INT</code> is equivalent.</p>
+ */
+ INTEGER: this.INT,
+ /**
+ * @type Object.
+ * @property NUMBER
+ * This data type means that the raw data is converted into a number before it is placed into a Record.
+ * <p>The synonym <code>FLOAT</code> is equivalent.</p>
+ */
+ NUMBER: this.FLOAT
+ });
+};
\ No newline at end of file