Ext.apply(Ext, { /** * Returns the current document body as an {@link Ext.core.Element}. * @ignore * @memberOf Ext * @return Ext.core.Element The document body */ getHead : function() { var head; return function() { if (head === undefined) { head = Ext.get(document.getElementsByTagName("head")[0]); } return head; }; }() }); /** * @author Ed Spencer * @class Ext.data.ScriptTagProxy * @extends Ext.data.ServerProxy * *ScriptTagProxy is useful when you need to load data from a domain other than the one your application is running * on. If your application is running on http://domainA.com it cannot use {@link Ext.data.AjaxProxy Ajax} to load its * data from http://domainB.com because cross-domain ajax requests are prohibited by the browser.
* *We can get around this using a ScriptTagProxy. ScriptTagProxy injects a <script> tag into the DOM whenever * an AJAX request would usually be made. Let's say we want to load data from http://domainB.com/users - the script tag * that would be injected might look like this:
** *<script src="http://domainB.com/users?callback=someCallback"></script>
When we inject the tag above, the browser makes a request to that url and includes the response as if it was any * other type of JavaScript include. By passing a callback in the url above, we're telling domainB's server that we * want to be notified when the result comes in and that it should call our callback function with the data it sends * back. So long as the server formats the response to look like this, everything will work:
** *someCallback({ users: [ { id: 1, name: "Ed Spencer", email: "[email protected]" } ] });
As soon as the script finishes loading, the 'someCallback' function that we passed in the url is called with the * JSON object that the server returned.
* *ScriptTagProxy takes care of all of this automatically. It formats the url you pass, adding the callback * parameter automatically. It even creates a temporary callback function, waits for it to be called and then puts * the data into the Proxy making it look just like you loaded it through a normal {@link Ext.data.AjaxProxy AjaxProxy}. * Here's how we might set that up:
** *Ext.regModel('User', { fields: ['id', 'name', 'email'] }); var store = new Ext.data.Store({ model: 'User', proxy: { type: 'scripttag', url : 'http://domainB.com/users' } }); store.load();
That's all we need to do - ScriptTagProxy takes care of the rest. In this case the Proxy will have injected a * script tag like this: *
* *<script src="http://domainB.com/users?callback=stcCallback001" id="stcScript001"></script>
Customization
* *Most parts of this script tag can be customized using the {@link #callbackParam}, {@link #callbackPrefix} and * {@link #scriptIdPrefix} configurations. For example: *
* *var store = new Ext.data.Store({ model: 'User', proxy: { type: 'scripttag', url : 'http://domainB.com/users', callbackParam: 'theCallbackFunction', callbackPrefix: 'ABC', scriptIdPrefix: 'injectedScript' } }); store.load();
Would inject a script tag like this:
** *<script src="http://domainB.com/users?theCallbackFunction=ABC001" id="injectedScript001"></script>
Implementing on the server side
* *The remote server side needs to be configured to return data in this format. Here are suggestions for how you * might achieve this using Java, PHP and ASP.net:
* *Java:
** *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(");"); }
PHP:
** *$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); }
ASP.net:
** */ Ext.define('Ext.data.ScriptTagProxy', { extend: 'Ext.data.ServerProxy', alias: 'proxy.scripttag', statics: { TRANS_ID: 1000 }, defaultWriterType: 'base', /** * @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".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);
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 {String} scriptIdPrefix * The prefix string that is used to create a unique ID for the injected script tag element (defaults to 'stcScript') */ scriptIdPrefix: 'stcScript', /** * @cfg {String} callbackPrefix * The prefix string that is used to create a unique callback function name in the global scope. This can optionally * be modified to give control over how the callback string passed to the remote server is generated. Defaults to 'stcCallback' */ callbackPrefix: 'stcCallback', /** * @cfg {String} recordParam * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString'). * Defaults to 'records' */ recordParam: 'records', /** * Reference to the most recent request made through this Proxy. Used internally to clean up when the Proxy is destroyed * @property lastRequest * @type Ext.data.Request */ lastRequest: undefined, /** * @cfg {Boolean} autoAppendParams True to automatically append the request's params to the generated url. Defaults to true */ autoAppendParams: true, constructor: function(){ this.addEvents( /** * @event exception * Fires when the server returns an exception * @param {Ext.data.Proxy} this * @param {Ext.data.Request} request The request that was sent * @param {Ext.data.Operation} operation The operation that triggered the request */ 'exception' ); Ext.data.ScriptTagProxy.superclass.constructor.apply(this, arguments); }, /** * @private * Performs the read request to the remote domain. ScriptTagProxy does not actually create an Ajax request, * instead we write out a