X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6e39d509471fe9b4e2660e0d1631b350d0c66f40..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/docs/source/JsonP2.html diff --git a/docs/source/JsonP2.html b/docs/source/JsonP2.html new file mode 100644 index 00000000..3a8dbd5e --- /dev/null +++ b/docs/source/JsonP2.html @@ -0,0 +1,336 @@ +
\ No newline at end of file/** + * @author Ed Spencer + * @class Ext.data.proxy.JsonP + * @extends Ext.data.proxy.Server + * + * <p>JsonPProxy 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.proxy.Ajax Ajax} to load its + * data from http://domainB.com because cross-domain ajax requests are prohibited by the browser.</p> + * + * <p>We can get around this using a JsonPProxy. JsonPProxy 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:</p> + * +<pre><code> +<script src="http://domainB.com/users?callback=someCallback"></script> +</code></pre> + * + * <p>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:</p> + * +<pre><code> +someCallback({ + users: [ + { + id: 1, + name: "Ed Spencer", + email: "ed@sencha.com" + } + ] +}); +</code></pre> + * + * <p>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.</p> + * + * <p>JsonPProxy 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.proxy.Ajax AjaxProxy}. + * Here's how we might set that up:</p> + * +<pre><code> +Ext.define('User', { + extend: 'Ext.data.Model', + fields: ['id', 'name', 'email'] +}); + +var store = new Ext.data.Store({ + model: 'User', + proxy: { + type: 'jsonp', + url : 'http://domainB.com/users' + } +}); + +store.load(); +</code></pre> + * + * <p>That's all we need to do - JsonPProxy takes care of the rest. In this case the Proxy will have injected a + * script tag like this: + * +<pre><code> +<script src="http://domainB.com/users?callback=stcCallback001" id="stcScript001"></script> +</code></pre> + * + * <p><u>Customization</u></p> + * + * <p>Most parts of this script tag can be customized using the {@link #callbackParam}, {@link #callbackPrefix} and + * {@link #scriptIdPrefix} configurations. For example: + * +<pre><code> +var store = new Ext.data.Store({ + model: 'User', + proxy: { + type: 'jsonp', + url : 'http://domainB.com/users', + callbackParam: 'theCallbackFunction', + callbackPrefix: 'ABC', + scriptIdPrefix: 'injectedScript' + } +}); + +store.load(); +</code></pre> + * + * <p>Would inject a script tag like this:</p> + * +<pre><code> +<script src="http://domainB.com/users?theCallbackFunction=ABC001" id="injectedScript001"></script> +</code></pre> + * + * <p><u>Implementing on the server side</u></p> + * + * <p>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:</p> + * + * <p>Java:</p> + * +<pre><code> +boolean jsonP = false; +String cb = request.getParameter("callback"); +if (cb != null) { + jsonP = true; + response.setContentType("text/javascript"); +} else { + response.setContentType("application/x-json"); +} +Writer out = response.getWriter(); +if (jsonP) { + out.write(cb + "("); +} +out.print(dataBlock.toJsonString()); +if (jsonP) { + out.write(");"); +} +</code></pre> + * + * <p>PHP:</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>ASP.net:</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> + * + */ +Ext.define('Ext.data.proxy.JsonP', { + extend: 'Ext.data.proxy.Server', + alternateClassName: 'Ext.data.ScriptTagProxy', + alias: ['proxy.jsonp', 'proxy.scripttag'], + requires: ['Ext.data.JsonP'], + + defaultWriterType: 'base', + + /** + * @cfg {String} callbackKey (Optional) See {@link Ext.data.JsonP#callbackKey}. + */ + callbackKey : 'callback', + + /** + * @cfg {String} recordParam + * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString'). + * Defaults to 'records' + */ + recordParam: 'records', + + /** + * @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.Proxy} this + * @param {Ext.data.Request} request The request that was sent + * @param {Ext.data.Operation} operation The operation that triggered the request + */ + 'exception' + ); + this.callParent(arguments); + }, + + /** + * @private + * Performs the read request to the remote domain. JsonPProxy does not actually create an Ajax request, + * instead we write out a <script> tag based on the configuration of the internal Ext.data.Request object + * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute + * @param {Function} callback A callback function to execute when the Operation has been completed + * @param {Object} scope The scope to execute the callback in + */ + doRequest: function(operation, callback, scope) { + //generate the unique IDs for this request + var me = this, + writer = me.getWriter(), + request = me.buildRequest(operation), + params = request.params; + + if (operation.allowWrite()) { + request = writer.write(request); + } + + //apply JsonPProxy-specific attributes to the Request + Ext.apply(request, { + callbackKey: me.callbackKey, + timeout: me.timeout, + scope: me, + disableCaching: false, // handled by the proxy + callback: me.createRequestCallback(request, operation, callback, scope) + }); + + // prevent doubling up + if (me.autoAppendParams) { + request.params = {}; + } + + request.jsonp = Ext.data.JsonP.request(request); + // restore on the request + request.params = params; + operation.setStarted(); + me.lastRequest = request; + + return request; + }, + + /** + * @private + * Creates and returns the function that is called when the request has completed. The returned function + * should accept a Response object, which contains the response to be read by the configured Reader. + * The third argument is the callback that should be called after the request has been completed and the Reader has decoded + * the response. This callback will typically be the callback passed by a store, e.g. in proxy.read(operation, theCallback, scope) + * theCallback refers to the callback argument received by this function. + * See {@link #doRequest} for details. + * @param {Ext.data.Request} request The Request object + * @param {Ext.data.Operation} operation The Operation being executed + * @param {Function} callback The callback function to be called when the request completes. This is usually the callback + * passed to doRequest + * @param {Object} scope The scope in which to execute the callback function + * @return {Function} The callback function + */ + createRequestCallback: function(request, operation, callback, scope) { + var me = this; + + return function(success, response, errorType) { + delete me.lastRequest; + me.processResponse(success, operation, request, response, callback, scope); + }; + }, + + // inherit docs + setException: function(operation, response) { + operation.setException(operation.request.jsonp.errorType); + }, + + + /** + * Generates a url based on a given Ext.data.Request object. Adds the params and callback function name to the url + * @param {Ext.data.Request} request The request object + * @return {String} The url + */ + buildUrl: function(request) { + var me = this, + url = me.callParent(arguments), + params = Ext.apply({}, request.params), + filters = params.filters, + records, + filter, i; + + delete params.filters; + + if (me.autoAppendParams) { + url = Ext.urlAppend(url, Ext.Object.toQueryString(params)); + } + + if (filters && filters.length) { + for (i = 0; i < filters.length; i++) { + filter = filters[i]; + + if (filter.value) { + url = Ext.urlAppend(url, filter.property + "=" + filter.value); + } + } + } + + //if there are any records present, append them to the url also + records = request.records; + + if (Ext.isArray(records) && records.length > 0) { + url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.recordParam, me.encodeRecords(records))); + } + + return url; + }, + + //inherit docs + destroy: function() { + this.abort(); + this.callParent(); + }, + + /** + * Aborts the current server request if one is currently running + */ + abort: function() { + var lastRequest = this.lastRequest; + if (lastRequest) { + Ext.data.JsonP.abort(lastRequest.jsonp); + } + }, + + /** + * Encodes an array of records into a string suitable to be appended to the script src url. This is broken + * out into its own function so that it can be easily overridden. + * @param {Array} records The records array + * @return {String} The encoded records string + */ + encodeRecords: function(records) { + var encoded = "", + i = 0, + len = records.length; + + for (; i < len; i++) { + encoded += Ext.Object.toQueryString(records[i].data); + } + + return encoded; + } +}); +