SimManager.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /**
  2. * This singleton manages simulated Ajax responses. This allows application logic to be
  3. * written unaware that its Ajax calls are being handled by simulations ("simlets"). This
  4. * is currently done by hooking {@link Ext.data.Connection} methods, so all users of that
  5. * class (and {@link Ext.Ajax} since it is a derived class) qualify for simulation.
  6. *
  7. * The requires hooks are inserted when either the {@link #init} method is called or the
  8. * first {@link Ext.ux.ajax.Simlet} is registered. For example:
  9. *
  10. * Ext.onReady(function () {
  11. * initAjaxSim();
  12. *
  13. * // normal stuff
  14. * });
  15. *
  16. * function initAjaxSim () {
  17. * Ext.ux.ajax.SimManager.init({
  18. * delay: 300
  19. * }).register({
  20. * '/app/data/url': {
  21. * type: 'json', // use JsonSimlet (type is like xtype for components)
  22. * data: [
  23. * { foo: 42, bar: 'abc' },
  24. * ...
  25. * ]
  26. * }
  27. * });
  28. * }
  29. *
  30. * As many URL's as desired can be registered and associated with a {@link Ext.ux.ajax.Simlet}. To make
  31. * non-simulated Ajax requests once this singleton is initialized, add a `nosim:true` option
  32. * to the Ajax options:
  33. *
  34. * Ext.Ajax.request({
  35. * url: 'page.php',
  36. * nosim: true, // ignored by normal Ajax request
  37. * params: {
  38. * id: 1
  39. * },
  40. * success: function(response){
  41. * var text = response.responseText;
  42. * // process server response here
  43. * }
  44. * });
  45. */
  46. Ext.define('Ext.ux.ajax.SimManager', {
  47. singleton: true,
  48. requires: [
  49. 'Ext.data.Connection',
  50. 'Ext.ux.ajax.SimXhr',
  51. 'Ext.ux.ajax.Simlet',
  52. 'Ext.ux.ajax.JsonSimlet'
  53. ],
  54. /**
  55. * @cfg {Ext.ux.ajax.Simlet} defaultSimlet
  56. * The {@link Ext.ux.ajax.Simlet} instance to use for non-matching URL's. By default, this will
  57. * return 404. Set this to null to use real Ajax calls for non-matching URL's.
  58. */
  59. /**
  60. * @cfg {String} defaultType
  61. * The default `type` to apply to generic {@link Ext.ux.ajax.Simlet} configuration objects. The
  62. * default is 'basic'.
  63. */
  64. defaultType: 'basic',
  65. /**
  66. * @cfg {Number} delay
  67. * The number of milliseconds to delay before delivering a response to an async request.
  68. */
  69. delay: 150,
  70. /**
  71. * @property {Boolean} ready
  72. * True once this singleton has initialized and applied its Ajax hooks.
  73. * @private
  74. */
  75. ready: false,
  76. constructor: function () {
  77. this.simlets = [];
  78. },
  79. getSimlet: function (url) {
  80. // Strip down to base URL (no query parameters or hash):
  81. var me = this,
  82. index = url.indexOf('?'),
  83. simlets = me.simlets,
  84. len = simlets.length,
  85. i, simlet, simUrl, match;
  86. if (index < 0) {
  87. index = url.indexOf('#');
  88. }
  89. if (index > 0) {
  90. url = url.substring(0, index);
  91. }
  92. for (i = 0; i < len; ++i) {
  93. simlet = simlets[i];
  94. simUrl = simlet.url;
  95. if (simUrl instanceof RegExp) {
  96. match = simUrl.test(url);
  97. } else {
  98. match = simUrl === url;
  99. }
  100. if (match) {
  101. return simlet;
  102. }
  103. }
  104. return me.defaultSimlet;
  105. },
  106. getXhr: function (method, url, options, async) {
  107. var simlet = this.getSimlet(url);
  108. if (simlet) {
  109. return simlet.openRequest(method, url, options, async);
  110. }
  111. return null;
  112. },
  113. /**
  114. * Initializes this singleton and applies configuration options.
  115. * @param {Object} config An optional object with configuration properties to apply.
  116. * @return {Ext.ux.ajax.SimManager} this
  117. */
  118. init: function (config) {
  119. var me = this;
  120. Ext.apply(me, config);
  121. if (!me.ready) {
  122. me.ready = true;
  123. if (!('defaultSimlet' in me)) {
  124. me.defaultSimlet = new Ext.ux.ajax.Simlet({
  125. status: 404,
  126. statusText: 'Not Found'
  127. });
  128. }
  129. me._openRequest = Ext.data.Connection.prototype.openRequest;
  130. Ext.data.request.Ajax.override({
  131. openRequest: function (options, requestOptions, async) {
  132. var xhr = !options.nosim &&
  133. me.getXhr(requestOptions.method, requestOptions.url, options, async);
  134. if (!xhr) {
  135. xhr = this.callParent(arguments);
  136. }
  137. return xhr;
  138. }
  139. });
  140. if (Ext.data.JsonP) {
  141. Ext.data.JsonP.self.override({
  142. createScript: function (url, params, options) {
  143. var fullUrl = Ext.urlAppend(url, Ext.Object.toQueryString(params)),
  144. script = !options.nosim &&
  145. me.getXhr('GET', fullUrl, options, true);
  146. if (!script) {
  147. script = this.callParent(arguments);
  148. }
  149. return script;
  150. },
  151. loadScript: function (request) {
  152. var script = request.script;
  153. if (script.simlet) {
  154. script.jsonpCallback = request.params[request.callbackKey];
  155. script.send(null);
  156. // Ext.data.JsonP will attempt dom removal of a script tag, so emulate its presence
  157. request.script = document.createElement('script');
  158. } else {
  159. this.callParent(arguments);
  160. }
  161. }
  162. });
  163. }
  164. }
  165. return me;
  166. },
  167. openRequest: function (method, url, async) {
  168. var opt = {
  169. method: method,
  170. url: url
  171. };
  172. return this._openRequest.call(Ext.data.Connection.prototype, {}, opt, async);
  173. },
  174. /**
  175. * Registeres one or more {@link Ext.ux.ajax.Simlet} instances.
  176. * @param {Array/Object} simlet Either a {@link Ext.ux.ajax.Simlet} instance or config, an Array
  177. * of such elements or an Object keyed by URL with values that are {@link Ext.ux.ajax.Simlet}
  178. * instances or configs.
  179. */
  180. register: function (simlet) {
  181. var me = this;
  182. me.init();
  183. function reg (one) {
  184. var simlet = one;
  185. if (!simlet.isSimlet) {
  186. simlet = Ext.create('simlet.' + (simlet.type || simlet.stype || me.defaultType), one);
  187. }
  188. me.simlets.push(simlet);
  189. simlet.manager = me;
  190. }
  191. if (Ext.isArray(simlet)) {
  192. Ext.each(simlet, reg);
  193. } else if (simlet.isSimlet || simlet.url) {
  194. reg(simlet);
  195. } else {
  196. Ext.Object.each(simlet, function (url, s) {
  197. s.url = url;
  198. reg(s);
  199. });
  200. }
  201. return me;
  202. }
  203. });