Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / JsonP2.html
diff --git a/docs/source/JsonP2.html b/docs/source/JsonP2.html
new file mode 100644 (file)
index 0000000..3a8dbd5
--- /dev/null
@@ -0,0 +1,336 @@
+<!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
+ *
+ * &lt;p&gt;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.&lt;/p&gt;
+ *
+ * &lt;p&gt;We can get around this using a JsonPProxy. JsonPProxy injects a &amp;lt;script&amp;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:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+&amp;lt;script src=&quot;http://domainB.com/users?callback=someCallback&quot;&amp;gt;&amp;lt;/script&amp;gt;
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;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:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+someCallback({
+    users: [
+        {
+            id: 1,
+            name: &quot;Ed Spencer&quot;,
+            email: &quot;ed@sencha.com&quot;
+        }
+    ]
+});
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;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.&lt;/p&gt;
+ *
+ * &lt;p&gt;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:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+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();
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;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:
+ *
+&lt;pre&gt;&lt;code&gt;
+&amp;lt;script src=&quot;http://domainB.com/users?callback=stcCallback001&quot; id=&quot;stcScript001&quot;&amp;gt;&amp;lt;/script&amp;gt;
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;&lt;u&gt;Customization&lt;/u&gt;&lt;/p&gt;
+ *
+ * &lt;p&gt;Most parts of this script tag can be customized using the {@link #callbackParam}, {@link #callbackPrefix} and
+ * {@link #scriptIdPrefix} configurations. For example:
+ *
+&lt;pre&gt;&lt;code&gt;
+var store = new Ext.data.Store({
+    model: 'User',
+    proxy: {
+        type: 'jsonp',
+        url : 'http://domainB.com/users',
+        callbackParam: 'theCallbackFunction',
+        callbackPrefix: 'ABC',
+        scriptIdPrefix: 'injectedScript'
+    }
+});
+
+store.load();
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;Would inject a script tag like this:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+&amp;lt;script src=&quot;http://domainB.com/users?theCallbackFunction=ABC001&quot; id=&quot;injectedScript001&quot;&amp;gt;&amp;lt;/script&amp;gt;
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;&lt;u&gt;Implementing on the server side&lt;/u&gt;&lt;/p&gt;
+ *
+ * &lt;p&gt;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:&lt;/p&gt;
+ *
+ * &lt;p&gt;Java:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+boolean jsonP = false;
+String cb = request.getParameter(&quot;callback&quot;);
+if (cb != null) {
+    jsonP = true;
+    response.setContentType(&quot;text/javascript&quot;);
+} else {
+    response.setContentType(&quot;application/x-json&quot;);
+}
+Writer out = response.getWriter();
+if (jsonP) {
+    out.write(cb + &quot;(&quot;);
+}
+out.print(dataBlock.toJsonString());
+if (jsonP) {
+    out.write(&quot;);&quot;);
+}
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;PHP:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+$callback = $_REQUEST['callback'];
+
+// Create the output object.
+$output = array('a' =&gt; 'Apple', 'b' =&gt; '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);
+}
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ * &lt;p&gt;ASP.net:&lt;/p&gt;
+ *
+&lt;pre&gt;&lt;code&gt;
+String jsonString = &quot;{success: true}&quot;;
+String cb = Request.Params.Get(&quot;callback&quot;);
+String responseString = &quot;&quot;;
+if (!String.IsNullOrEmpty(cb)) {
+    responseString = cb + &quot;(&quot; + jsonString + &quot;)&quot;;
+} else {
+    responseString = jsonString;
+}
+Response.Write(responseString);
+&lt;/code&gt;&lt;/pre&gt;
+ *
+ */
+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 &lt;script&gt; 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 &amp;&amp; filters.length) {
+            for (i = 0; i &lt; filters.length; i++) {
+                filter = filters[i];
+
+                if (filter.value) {
+                    url = Ext.urlAppend(url, filter.property + &quot;=&quot; + filter.value);
+                }
+            }
+        }
+
+        //if there are any records present, append them to the url also
+        records = request.records;
+
+        if (Ext.isArray(records) &amp;&amp; records.length &gt; 0) {
+            url = Ext.urlAppend(url, Ext.String.format(&quot;{0}={1}&quot;, 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 = &quot;&quot;,
+            i = 0,
+            len = records.length;
+
+        for (; i &lt; len; i++) {
+            encoded += Ext.Object.toQueryString(records[i].data);
+        }
+
+        return encoded;
+    }
+});
+</pre></pre></body></html>
\ No newline at end of file