Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / ScriptTagProxy.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js"><div id="cls-Ext.data.ScriptTagProxy"></div>/**\r
9  * @class Ext.data.ScriptTagProxy\r
10  * @extends Ext.data.DataProxy\r
11  * An implementation of Ext.data.DataProxy that reads a data object from a URL which may be in a domain\r
12  * other than the originating domain of the running page.<br>\r
13  * <p>\r
14  * <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
15  * of the running page, you must use this class, rather than HttpProxy.</b><br>\r
16  * <p>\r
17  * The content passed back from a server resource requested by a ScriptTagProxy <b>must</b> be executable JavaScript\r
18  * source code because it is used as the source inside a &lt;script> tag.<br>\r
19  * <p>\r
20  * In order for the browser to process the returned data, the server must wrap the data object\r
21  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.\r
22  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy\r
23  * depending on whether the callback name was passed:\r
24  * <p>\r
25  * <pre><code>\r
26 boolean scriptTag = false;\r
27 String cb = request.getParameter("callback");\r
28 if (cb != null) {\r
29     scriptTag = true;\r
30     response.setContentType("text/javascript");\r
31 } else {\r
32     response.setContentType("application/x-json");\r
33 }\r
34 Writer out = response.getWriter();\r
35 if (scriptTag) {\r
36     out.write(cb + "(");\r
37 }\r
38 out.print(dataBlock.toJsonString());\r
39 if (scriptTag) {\r
40     out.write(");");\r
41 }\r
42 </code></pre>\r
43  *\r
44  * @constructor\r
45  * @param {Object} config A configuration object.\r
46  */\r
47 Ext.data.ScriptTagProxy = function(config){\r
48     Ext.apply(this, config);\r
49 \r
50     Ext.data.ScriptTagProxy.superclass.constructor.call(this, config);\r
51 \r
52     this.head = document.getElementsByTagName("head")[0];\r
53 \r
54     <div id="event-Ext.data.ScriptTagProxy-loadexception"></div>/**\r
55      * @event loadexception\r
56      * <b>Deprecated</b> in favor of 'exception' event.\r
57      * Fires if an exception occurs in the Proxy during data loading.  This event can be fired for one of two reasons:\r
58      * <ul><li><b>The load call timed out.</b>  This means the load callback did not execute within the time limit\r
59      * specified by {@link #timeout}.  In this case, this event will be raised and the\r
60      * fourth parameter (read error) will be null.</li>\r
61      * <li><b>The load succeeded but the reader could not read the response.</b>  This means the server returned\r
62      * data, but the configured Reader threw an error while reading the data.  In this case, this event will be\r
63      * raised and the caught error will be passed along as the fourth parameter of this event.</li></ul>\r
64      * Note that this event is also relayed through {@link Ext.data.Store}, so you can listen for it directly\r
65      * on any Store instance.\r
66      * @param {Object} this\r
67      * @param {Object} options The loading options that were specified (see {@link #load} for details).  If the load\r
68      * call timed out, this parameter will be null.\r
69      * @param {Object} arg The callback's arg object passed to the {@link #load} function\r
70      * @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data.\r
71      * If the remote request returns success: false, this parameter will be null.\r
72      */\r
73 };\r
74 \r
75 Ext.data.ScriptTagProxy.TRANS_ID = 1000;\r
76 \r
77 Ext.extend(Ext.data.ScriptTagProxy, Ext.data.DataProxy, {\r
78     <div id="cfg-Ext.data.ScriptTagProxy-url"></div>/**\r
79      * @cfg {String} url The URL from which to request the data object.\r
80      */\r
81     <div id="cfg-Ext.data.ScriptTagProxy-timeout"></div>/**\r
82      * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.\r
83      */\r
84     timeout : 30000,\r
85     <div id="cfg-Ext.data.ScriptTagProxy-callbackParam"></div>/**\r
86      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells\r
87      * the server the name of the callback function set up by the load call to process the returned data object.\r
88      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate\r
89      * javascript output which calls this named function passing the data object as its only parameter.\r
90      */\r
91     callbackParam : "callback",\r
92     <div id="cfg-Ext.data.ScriptTagProxy-nocache"></div>/**\r
93      *  @cfg {Boolean} nocache (optional) Defaults to true. Disable caching by adding a unique parameter\r
94      * name to the request.\r
95      */\r
96     nocache : true,\r
97 \r
98     <div id="method-Ext.data.ScriptTagProxy-doRequest"></div>/**\r
99      * HttpProxy implementation of DataProxy#doRequest\r
100      * @param {String} action\r
101      * @param {Ext.data.Record/Ext.data.Record[]} rs If action is <tt>read</tt>, rs will be null\r
102      * @param {Object} params An object containing properties which are to be used as HTTP parameters\r
103      * for the request to the remote server.\r
104      * @param {Ext.data.DataReader} reader The Reader object which converts the data\r
105      * object into a block of Ext.data.Records.\r
106      * @param {Function} callback The function into which to pass the block of Ext.data.Records.\r
107      * The function must be passed <ul>\r
108      * <li>The Record block object</li>\r
109      * <li>The "arg" argument from the load function</li>\r
110      * <li>A boolean success indicator</li>\r
111      * </ul>\r
112      * @param {Object} scope The scope in which to call the callback\r
113      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.\r
114      */\r
115     doRequest : function(action, rs, params, reader, callback, scope, arg) {\r
116         var p = Ext.urlEncode(Ext.apply(params, this.extraParams));\r
117 \r
118         var url = this.buildUrl(action, rs);\r
119         if (!url) {\r
120             throw new Ext.data.Api.Error('invalid-url', url);\r
121         }\r
122         url = Ext.urlAppend(url, p);\r
123 \r
124         if(this.nocache){\r
125             url = Ext.urlAppend(url, '_dc=' + (new Date().getTime()));\r
126         }\r
127         var transId = ++Ext.data.ScriptTagProxy.TRANS_ID;\r
128         var trans = {\r
129             id : transId,\r
130             action: action,\r
131             cb : "stcCallback"+transId,\r
132             scriptId : "stcScript"+transId,\r
133             params : params,\r
134             arg : arg,\r
135             url : url,\r
136             callback : callback,\r
137             scope : scope,\r
138             reader : reader\r
139         };\r
140         window[trans.cb] = this.createCallback(action, rs, trans);\r
141         url += String.format("&{0}={1}", this.callbackParam, trans.cb);\r
142         if(this.autoAbort !== false){\r
143             this.abort();\r
144         }\r
145 \r
146         trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);\r
147 \r
148         var script = document.createElement("script");\r
149         script.setAttribute("src", url);\r
150         script.setAttribute("type", "text/javascript");\r
151         script.setAttribute("id", trans.scriptId);\r
152         this.head.appendChild(script);\r
153 \r
154         this.trans = trans;\r
155     },\r
156 \r
157     // @private createCallback\r
158     createCallback : function(action, rs, trans) {\r
159         var self = this;\r
160         return function(res) {\r
161             self.trans = false;\r
162             self.destroyTrans(trans, true);\r
163             if (action === Ext.data.Api.actions.read) {\r
164                 self.onRead.call(self, action, trans, res);\r
165             } else {\r
166                 self.onWrite.call(self, action, trans, res, rs);\r
167             }\r
168         };\r
169     },\r
170     /**\r
171      * Callback for read actions\r
172      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]\r
173      * @param {Object} trans The request transaction object\r
174      * @param {Object} res The server response\r
175      * @private\r
176      */\r
177     onRead : function(action, trans, res) {\r
178         var result;\r
179         try {\r
180             result = trans.reader.readRecords(res);\r
181         }catch(e){\r
182             // @deprecated: fire loadexception\r
183             this.fireEvent("loadexception", this, trans, res, e);\r
184 \r
185             this.fireEvent('exception', this, 'response', action, trans, res, e);\r
186             trans.callback.call(trans.scope||window, null, trans.arg, false);\r
187             return;\r
188         }\r
189         if (result.success === false) {\r
190             // @deprecated: fire old loadexception for backwards-compat.\r
191             this.fireEvent('loadexception', this, trans, res);\r
192 \r
193             this.fireEvent('exception', this, 'remote', action, trans, res, null);\r
194         } else {\r
195             this.fireEvent("load", this, res, trans.arg);\r
196         }\r
197         trans.callback.call(trans.scope||window, result, trans.arg, result.success);\r
198     },\r
199     /**\r
200      * Callback for write actions\r
201      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]\r
202      * @param {Object} trans The request transaction object\r
203      * @param {Object} res The server response\r
204      * @private\r
205      */\r
206     onWrite : function(action, trans, res, rs) {\r
207         var reader = trans.reader;\r
208         try {\r
209             // though we already have a response object here in STP, run through readResponse to catch any meta-data exceptions.\r
210             reader.readResponse(action, res);\r
211         } catch (e) {\r
212             this.fireEvent('exception', this, 'response', action, trans, res, e);\r
213             trans.callback.call(trans.scope||window, null, res, false);\r
214             return;\r
215         }\r
216         if(!res[reader.meta.successProperty] === true){\r
217             this.fireEvent('exception', this, 'remote', action, trans, res, rs);\r
218             trans.callback.call(trans.scope||window, null, res, false);\r
219             return;\r
220         }\r
221         this.fireEvent("write", this, action, res[reader.meta.root], res, rs, trans.arg );\r
222         trans.callback.call(trans.scope||window, res[reader.meta.root], res, true);\r
223     },\r
224 \r
225     // private\r
226     isLoading : function(){\r
227         return this.trans ? true : false;\r
228     },\r
229 \r
230     <div id="method-Ext.data.ScriptTagProxy-abort"></div>/**\r
231      * Abort the current server request.\r
232      */\r
233     abort : function(){\r
234         if(this.isLoading()){\r
235             this.destroyTrans(this.trans);\r
236         }\r
237     },\r
238 \r
239     // private\r
240     destroyTrans : function(trans, isLoaded){\r
241         this.head.removeChild(document.getElementById(trans.scriptId));\r
242         clearTimeout(trans.timeoutId);\r
243         if(isLoaded){\r
244             window[trans.cb] = undefined;\r
245             try{\r
246                 delete window[trans.cb];\r
247             }catch(e){}\r
248         }else{\r
249             // if hasn't been loaded, wait for load to remove it to prevent script error\r
250             window[trans.cb] = function(){\r
251                 window[trans.cb] = undefined;\r
252                 try{\r
253                     delete window[trans.cb];\r
254                 }catch(e){}\r
255             };\r
256         }\r
257     },\r
258 \r
259     // private\r
260     handleFailure : function(trans){\r
261         this.trans = false;\r
262         this.destroyTrans(trans, false);\r
263         if (trans.action === Ext.data.Api.actions.read) {\r
264             // @deprecated firing loadexception\r
265             this.fireEvent("loadexception", this, null, trans.arg);\r
266         }\r
267 \r
268         this.fireEvent('exception', this, 'response', trans.action, {\r
269             response: null,\r
270             options: trans.arg\r
271         });\r
272         trans.callback.call(trans.scope||window, null, trans.arg, false);\r
273     },\r
274 \r
275     // inherit docs\r
276     destroy: function(){\r
277         this.abort();\r
278         Ext.data.ScriptTagProxy.superclass.destroy.call(this);\r
279     }\r
280 });</pre>    \r
281 </body>\r
282 </html>