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