PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/assets/www/touch/src/data/proxy/JsonP.js

https://bitbucket.org/tokomode/exapp
JavaScript | 288 lines | 77 code | 24 blank | 187 comment | 8 complexity | d4a26a723e18c98d04edbd61bd3c3185 MD5 | raw file
  1. /**
  2. * @author Ed Spencer
  3. * @aside guide proxies
  4. *
  5. * The JsonP proxy is useful when you need to load data from a domain other than the one your application is running on. If
  6. * your application is running on http://domainA.com it cannot use {@link Ext.data.proxy.Ajax Ajax} to load its data
  7. * from http://domainB.com because cross-domain ajax requests are prohibited by the browser.
  8. *
  9. * We can get around this using a JsonP proxy. JsonP proxy injects a `<script>` tag into the DOM whenever an AJAX request
  10. * would usually be made. Let's say we want to load data from http://domainB.com/users - the script tag that would be
  11. * injected might look like this:
  12. *
  13. * <script src="http://domainB.com/users?callback=someCallback"></script>
  14. *
  15. * When we inject the tag above, the browser makes a request to that url and includes the response as if it was any
  16. * other type of JavaScript include. By passing a callback in the url above, we're telling domainB's server that we want
  17. * to be notified when the result comes in and that it should call our callback function with the data it sends back. So
  18. * long as the server formats the response to look like this, everything will work:
  19. *
  20. * someCallback({
  21. * users: [
  22. * {
  23. * id: 1,
  24. * name: "Ed Spencer",
  25. * email: "ed@sencha.com"
  26. * }
  27. * ]
  28. * });
  29. *
  30. * As soon as the script finishes loading, the 'someCallback' function that we passed in the url is called with the JSON
  31. * object that the server returned.
  32. *
  33. * JsonP proxy takes care of all of this automatically. It formats the url you pass, adding the callback parameter
  34. * automatically. It even creates a temporary callback function, waits for it to be called and then puts the data into
  35. * the Proxy making it look just like you loaded it through a normal {@link Ext.data.proxy.Ajax AjaxProxy}. Here's how
  36. * we might set that up:
  37. *
  38. * Ext.define('User', {
  39. * extend: 'Ext.data.Model',
  40. * config: {
  41. * fields: ['id', 'name', 'email']
  42. * }
  43. * });
  44. *
  45. * var store = Ext.create('Ext.data.Store', {
  46. * model: 'User',
  47. * proxy: {
  48. * type: 'jsonp',
  49. * url : 'http://domainB.com/users'
  50. * }
  51. * });
  52. *
  53. * store.load();
  54. *
  55. * That's all we need to do - JsonP proxy takes care of the rest. In this case the Proxy will have injected a script tag
  56. * like this:
  57. *
  58. * <script src="http://domainB.com/users?callback=callback1"></script>
  59. *
  60. * # Customization
  61. *
  62. * This script tag can be customized using the {@link #callbackKey} configuration. For example:
  63. *
  64. * var store = Ext.create('Ext.data.Store', {
  65. * model: 'User',
  66. * proxy: {
  67. * type: 'jsonp',
  68. * url : 'http://domainB.com/users',
  69. * callbackKey: 'theCallbackFunction'
  70. * }
  71. * });
  72. *
  73. * store.load();
  74. *
  75. * Would inject a script tag like this:
  76. *
  77. * <script src="http://domainB.com/users?theCallbackFunction=callback1"></script>
  78. *
  79. * # Implementing on the server side
  80. *
  81. * The remote server side needs to be configured to return data in this format. Here are suggestions for how you might
  82. * achieve this using Java, PHP and ASP.net:
  83. *
  84. * Java:
  85. *
  86. * boolean jsonP = false;
  87. * String cb = request.getParameter("callback");
  88. * if (cb != null) {
  89. * jsonP = true;
  90. * response.setContentType("text/javascript");
  91. * } else {
  92. * response.setContentType("application/x-json");
  93. * }
  94. * Writer out = response.getWriter();
  95. * if (jsonP) {
  96. * out.write(cb + "(");
  97. * }
  98. * out.print(dataBlock.toJsonString());
  99. * if (jsonP) {
  100. * out.write(");");
  101. * }
  102. *
  103. * PHP:
  104. *
  105. * $callback = $_REQUEST['callback'];
  106. *
  107. * // Create the output object.
  108. * $output = array('a' => 'Apple', 'b' => 'Banana');
  109. *
  110. * //start output
  111. * if ($callback) {
  112. * header('Content-Type: text/javascript');
  113. * echo $callback . '(' . json_encode($output) . ');';
  114. * } else {
  115. * header('Content-Type: application/x-json');
  116. * echo json_encode($output);
  117. * }
  118. *
  119. * ASP.net:
  120. *
  121. * String jsonString = "{success: true}";
  122. * String cb = Request.Params.Get("callback");
  123. * String responseString = "";
  124. * if (!String.IsNullOrEmpty(cb)) {
  125. * responseString = cb + "(" + jsonString + ")";
  126. * } else {
  127. * responseString = jsonString;
  128. * }
  129. * Response.Write(responseString);
  130. */
  131. Ext.define('Ext.data.proxy.JsonP', {
  132. extend: 'Ext.data.proxy.Server',
  133. alternateClassName: 'Ext.data.ScriptTagProxy',
  134. alias: ['proxy.jsonp', 'proxy.scripttag'],
  135. requires: ['Ext.data.JsonP'],
  136. config: {
  137. defaultWriterType: 'base',
  138. /**
  139. * @cfg {String} callbackKey
  140. * See {@link Ext.data.JsonP#callbackKey}.
  141. * @accessor
  142. */
  143. callbackKey : 'callback',
  144. /**
  145. * @cfg {String} recordParam
  146. * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString').
  147. * @accessor
  148. */
  149. recordParam: 'records',
  150. /**
  151. * @cfg {Boolean} autoAppendParams
  152. * `true` to automatically append the request's params to the generated url.
  153. * @accessor
  154. */
  155. autoAppendParams: true
  156. },
  157. /**
  158. * Performs the read request to the remote domain. JsonP proxy does not actually create an Ajax request,
  159. * instead we write out a `<script>` tag based on the configuration of the internal Ext.data.Request object
  160. * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute.
  161. * @param {Function} callback A callback function to execute when the Operation has been completed.
  162. * @param {Object} scope The scope to execute the callback in.
  163. * @return {Object}
  164. * @protected
  165. */
  166. doRequest: function(operation, callback, scope) {
  167. // <debug>
  168. var action = operation.getAction();
  169. if (action !== 'read') {
  170. Ext.Logger.error('JsonP proxies can only be used to read data.');
  171. }
  172. // </debug>
  173. //generate the unique IDs for this request
  174. var me = this,
  175. request = me.buildRequest(operation),
  176. params = request.getParams();
  177. // apply JsonP proxy-specific attributes to the Request
  178. request.setConfig({
  179. callbackKey: me.getCallbackKey(),
  180. timeout: me.getTimeout(),
  181. scope: me,
  182. callback: me.createRequestCallback(request, operation, callback, scope)
  183. });
  184. // Prevent doubling up because the params are already added to the url in buildUrl
  185. if (me.getAutoAppendParams()) {
  186. request.setParams({});
  187. }
  188. request.setJsonP(Ext.data.JsonP.request(request.getCurrentConfig()));
  189. // Set the params back once we have made the request though
  190. request.setParams(params);
  191. operation.setStarted();
  192. me.lastRequest = request;
  193. return request;
  194. },
  195. /**
  196. * @private
  197. * Creates and returns the function that is called when the request has completed. The returned function
  198. * should accept a Response object, which contains the response to be read by the configured Reader.
  199. * The third argument is the callback that should be called after the request has been completed and the Reader has decoded
  200. * the response. This callback will typically be the callback passed by a store, e.g. in proxy.read(operation, theCallback, scope)
  201. * theCallback refers to the callback argument received by this function.
  202. * See {@link #doRequest} for details.
  203. * @param {Ext.data.Request} request The Request object.
  204. * @param {Ext.data.Operation} operation The Operation being executed.
  205. * @param {Function} callback The callback function to be called when the request completes. This is usually the callback
  206. * passed to doRequest.
  207. * @param {Object} scope The scope in which to execute the callback function.
  208. * @return {Function} The callback function.
  209. */
  210. createRequestCallback: function(request, operation, callback, scope) {
  211. var me = this;
  212. return function(success, response, errorType) {
  213. delete me.lastRequest;
  214. me.processResponse(success, operation, request, response, callback, scope);
  215. };
  216. },
  217. // @inheritdoc
  218. setException: function(operation, response) {
  219. operation.setException(operation.getRequest().getJsonP().errorType);
  220. },
  221. /**
  222. * Generates a url based on a given Ext.data.Request object. Adds the params and callback function name to the url
  223. * @param {Ext.data.Request} request The request object.
  224. * @return {String} The url.
  225. */
  226. buildUrl: function(request) {
  227. var me = this,
  228. url = me.callParent(arguments),
  229. params = Ext.apply({}, request.getParams()),
  230. filters = params.filters,
  231. records,
  232. filter, i, value;
  233. delete params.filters;
  234. if (me.getAutoAppendParams()) {
  235. url = Ext.urlAppend(url, Ext.Object.toQueryString(params));
  236. }
  237. if (filters && filters.length) {
  238. for (i = 0; i < filters.length; i++) {
  239. filter = filters[i];
  240. value = filter.getValue();
  241. if (value) {
  242. url = Ext.urlAppend(url, filter.getProperty() + "=" + value);
  243. }
  244. }
  245. }
  246. return url;
  247. },
  248. /**
  249. * @inheritdoc
  250. */
  251. destroy: function() {
  252. this.abort();
  253. this.callParent(arguments);
  254. },
  255. /**
  256. * Aborts the current server request if one is currently running.
  257. */
  258. abort: function() {
  259. var lastRequest = this.lastRequest;
  260. if (lastRequest) {
  261. Ext.data.JsonP.abort(lastRequest.getJsonP());
  262. }
  263. }
  264. });