Simlet.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /**
  2. * This is a base class for more advanced "simlets" (simulated servers). A simlet is asked
  3. * to provide a response given a {@link Ext.ux.ajax.SimXhr} instance.
  4. */
  5. Ext.define('Ext.ux.ajax.Simlet', function () {
  6. var urlRegex = /([^?#]*)(#.*)?$/,
  7. dateRegex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/,
  8. intRegex = /^[+-]?\d+$/,
  9. floatRegex = /^[+-]?\d+\.\d+$/;
  10. function parseParamValue (value) {
  11. var m;
  12. if (Ext.isDefined(value)) {
  13. value = decodeURIComponent(value);
  14. if (intRegex.test(value)) {
  15. value = parseInt(value, 10);
  16. } else if (floatRegex.test(value)) {
  17. value = parseFloat(value);
  18. } else if (!!(m = dateRegex.exec(value))) {
  19. value = new Date(Date.UTC(+m[1], +m[2]-1, +m[3], +m[4], +m[5], +m[6]));
  20. }
  21. }
  22. return value;
  23. }
  24. return {
  25. alias: 'simlet.basic',
  26. isSimlet: true,
  27. responseProps: ['responseText', 'responseXML', 'status', 'statusText', 'responseHeaders'],
  28. /**
  29. * @cfg {String/Function} responseText
  30. */
  31. /**
  32. * @cfg {String/Function} responseXML
  33. */
  34. /**
  35. * @cfg {Object/Function} responseHeaders
  36. */
  37. /**
  38. * @cfg {Number/Function} status
  39. */
  40. status: 200,
  41. /**
  42. * @cfg {String/Function} statusText
  43. */
  44. statusText: 'OK',
  45. constructor: function (config) {
  46. Ext.apply(this, config);
  47. },
  48. doGet: function (ctx) {
  49. return this.handleRequest(ctx);
  50. },
  51. doPost: function (ctx) {
  52. return this.handleRequest(ctx);
  53. },
  54. doRedirect: function (ctx) {
  55. return false;
  56. },
  57. doDelete: function (ctx) {
  58. var me = this,
  59. xhr = ctx.xhr,
  60. records = xhr.options.records;
  61. me.removeFromData(ctx,records);
  62. },
  63. /**
  64. * Performs the action requested by the given XHR and returns an object to be applied
  65. * on to the XHR (containing `status`, `responseText`, etc.). For the most part,
  66. * this is delegated to `doMethod` methods on this class, such as `doGet`.
  67. *
  68. * @param {Ext.ux.ajax.SimXhr} xhr The simulated XMLHttpRequest instance.
  69. * @return {Object} The response properties to add to the XMLHttpRequest.
  70. */
  71. exec: function (xhr) {
  72. var me = this,
  73. ret = {},
  74. method = 'do' + Ext.String.capitalize(xhr.method.toLowerCase()), // doGet
  75. fn = me[method];
  76. if (fn) {
  77. ret = fn.call(me, me.getCtx(xhr.method, xhr.url, xhr));
  78. } else {
  79. ret = { status: 405, statusText: 'Method Not Allowed' };
  80. }
  81. return ret;
  82. },
  83. getCtx: function (method, url, xhr) {
  84. return {
  85. method: method,
  86. params: this.parseQueryString(url),
  87. url: url,
  88. xhr: xhr
  89. };
  90. },
  91. handleRequest: function(ctx) {
  92. var me = this,
  93. ret = {},
  94. val;
  95. Ext.Array.forEach(me.responseProps, function (prop) {
  96. if (prop in me) {
  97. val = me[prop];
  98. if (Ext.isFunction(val)) {
  99. val = val.call(me, ctx);
  100. }
  101. ret[prop] = val;
  102. }
  103. });
  104. return ret;
  105. },
  106. openRequest: function (method, url, options, async) {
  107. var ctx = this.getCtx(method, url),
  108. redirect = this.doRedirect(ctx),
  109. xhr;
  110. if (options.action === 'destroy'){
  111. method = 'delete';
  112. }
  113. if (redirect) {
  114. xhr = redirect;
  115. } else {
  116. xhr = new Ext.ux.ajax.SimXhr({
  117. mgr: this.manager,
  118. simlet: this,
  119. options: options
  120. });
  121. xhr.open(method, url, async);
  122. }
  123. return xhr;
  124. },
  125. parseQueryString : function (str) {
  126. var m = urlRegex.exec(str),
  127. ret = {},
  128. key,
  129. value,
  130. i, n;
  131. if (m && m[1]) {
  132. var pair, parts = m[1].split('&');
  133. for (i = 0, n = parts.length; i < n; ++i) {
  134. if ((pair = parts[i].split('='))[0]) {
  135. key = decodeURIComponent(pair.shift());
  136. value = parseParamValue((pair.length > 1) ? pair.join('=') : pair[0]);
  137. if (!(key in ret)) {
  138. ret[key] = value;
  139. } else if (Ext.isArray(ret[key])) {
  140. ret[key].push(value);
  141. } else {
  142. ret[key] = [ret[key], value];
  143. }
  144. }
  145. }
  146. }
  147. return ret;
  148. },
  149. redirect: function (method, url, params) {
  150. switch (arguments.length) {
  151. case 2:
  152. if (typeof url == 'string') {
  153. break;
  154. }
  155. params = url;
  156. // fall...
  157. case 1:
  158. url = method;
  159. method = 'GET';
  160. break;
  161. }
  162. if (params) {
  163. url = Ext.urlAppend(url, Ext.Object.toQueryString(params));
  164. }
  165. return this.manager.openRequest(method, url);
  166. },
  167. removeFromData: function(ctx, records) {
  168. var me = this,
  169. data = me.getData(ctx),
  170. model = (ctx.xhr.options.proxy && ctx.xhr.options.proxy.getModel()) || {},
  171. idProperty = model.idProperty || 'id';
  172. Ext.each(records, function(record) {
  173. var id = record.get(idProperty);
  174. for (var i = data.length; i-- > 0;) {
  175. if (data[i][idProperty] === id) {
  176. me.deleteRecord(i);
  177. break;
  178. }
  179. }
  180. });
  181. }
  182. };
  183. }());