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