--- /dev/null
+<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-data.proxy.JsonP'>/**
+</span> * @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 &lt;script&gt; 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>
+&lt;script src="http://domainB.com/users?callback=someCallback"&gt;&lt;/script&gt;
+</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>
+&lt;script src="http://domainB.com/users?callback=stcCallback001" id="stcScript001"&gt;&lt;/script&gt;
+</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>
+&lt;script src="http://domainB.com/users?theCallbackFunction=ABC001" id="injectedScript001"&gt;&lt;/script&gt;
+</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',
+
+<span id='Ext-data.proxy.JsonP-cfg-callbackKey'> /**
+</span> * @cfg {String} callbackKey (Optional) See {@link Ext.data.JsonP#callbackKey}.
+ */
+ callbackKey : 'callback',
+
+<span id='Ext-data.proxy.JsonP-cfg-recordParam'> /**
+</span> * @cfg {String} recordParam
+ * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString').
+ * Defaults to 'records'
+ */
+ recordParam: 'records',
+
+<span id='Ext-data.proxy.JsonP-cfg-autoAppendParams'> /**
+</span> * @cfg {Boolean} autoAppendParams True to automatically append the request's params to the generated url. Defaults to true
+ */
+ autoAppendParams: true,
+
+ constructor: function(){
+ this.addEvents(
+<span id='Ext-data.proxy.JsonP-event-exception'> /**
+</span> * @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);
+ },
+
+<span id='Ext-data.proxy.JsonP-method-doRequest'> /**
+</span> * @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;
+ },
+
+<span id='Ext-data.proxy.JsonP-method-createRequestCallback'> /**
+</span> * @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);
+ },
+
+
+<span id='Ext-data.proxy.JsonP-method-buildUrl'> /**
+</span> * 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();
+ },
+
+<span id='Ext-data.proxy.JsonP-method-abort'> /**
+</span> * Aborts the current server request if one is currently running
+ */
+ abort: function() {
+ var lastRequest = this.lastRequest;
+ if (lastRequest) {
+ Ext.data.JsonP.abort(lastRequest.jsonp);
+ }
+ },
+
+<span id='Ext-data.proxy.JsonP-method-encodeRecords'> /**
+</span> * 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;
+ }
+});
+</pre></pre></body></html>
\ No newline at end of file