DataSimlet.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * This base class is used to handle data preparation (e.g., sorting, filtering and
  3. * group summary).
  4. */
  5. Ext.define('Ext.ux.ajax.DataSimlet', function () {
  6. function makeSortFn (def, cmp) {
  7. var order = def.direction,
  8. sign = (order && order.toUpperCase() === 'DESC') ? -1 : 1;
  9. return function (leftRec, rightRec) {
  10. var lhs = leftRec[def.property],
  11. rhs = rightRec[def.property],
  12. c = (lhs < rhs) ? -1 : ((rhs < lhs) ? 1 : 0);
  13. if (c || !cmp) {
  14. return c * sign;
  15. }
  16. return cmp(leftRec, rightRec);
  17. };
  18. }
  19. function makeSortFns (defs, cmp) {
  20. for (var sortFn = cmp, i = defs && defs.length; i; ) {
  21. sortFn = makeSortFn(defs[--i], sortFn);
  22. }
  23. return sortFn;
  24. }
  25. return {
  26. extend: 'Ext.ux.ajax.Simlet',
  27. buildNodes: function (node, path) {
  28. var me = this,
  29. nodeData = {
  30. data: []
  31. },
  32. len = node.length,
  33. children, i, child, name;
  34. me.nodes[path] = nodeData;
  35. for (i = 0; i < len; ++i) {
  36. nodeData.data.push(child = node[i]);
  37. name = child.text || child.title;
  38. child.id = path ? path + '/' + name : name;
  39. children = child.children;
  40. if (!(child.leaf = !children)) {
  41. delete child.children;
  42. me.buildNodes(children, child.id);
  43. }
  44. }
  45. },
  46. deleteRecord : function(pos) {
  47. if(this.data && typeof this.data !== 'function') {
  48. Ext.Array.removeAt(this.data,pos);
  49. }
  50. },
  51. fixTree: function (ctx, tree) {
  52. var me = this,
  53. node = ctx.params.node,
  54. nodes;
  55. if (!(nodes = me.nodes)) {
  56. me.nodes = nodes = {};
  57. me.buildNodes(tree, '');
  58. }
  59. node = nodes[node];
  60. if (node) {
  61. if (me.node) {
  62. me.node.sortedData = me.sortedData;
  63. me.node.currentOrder = me.currentOrder;
  64. }
  65. me.node = node;
  66. me.data = node.data;
  67. me.sortedData = node.sortedData;
  68. me.currentOrder = node.currentOrder;
  69. } else {
  70. me.data = null;
  71. }
  72. },
  73. getData: function (ctx) {
  74. var me = this,
  75. params = ctx.params,
  76. order = (params.filter || '') + (params.group || '') + '-' + (params.sort || '') + '-' + (params.dir || ''),
  77. tree = me.tree,
  78. dynamicData,
  79. data, fields, sortFn;
  80. if (tree) {
  81. me.fixTree(ctx, tree);
  82. }
  83. data = me.data;
  84. if (typeof data === 'function') {
  85. dynamicData = true;
  86. data = data.call(this, ctx);
  87. }
  88. // If order is '--' then it means we had no order passed, due to the string concat above
  89. if (!data || order === '--') {
  90. return data || [];
  91. }
  92. if (!dynamicData && order == me.currentOrder) {
  93. return me.sortedData;
  94. }
  95. ctx.filterSpec = params.filter && Ext.decode(params.filter);
  96. ctx.groupSpec = params.group && Ext.decode(params.group);
  97. fields = params.sort;
  98. if (params.dir) {
  99. fields = [{ direction: params.dir, property: fields }];
  100. } else {
  101. fields = Ext.decode(params.sort);
  102. }
  103. if (ctx.filterSpec) {
  104. var filters = new Ext.util.FilterCollection();
  105. filters.add(this.processFilters(ctx.filterSpec));
  106. data = Ext.Array.filter(data, filters.getFilterFn());
  107. }
  108. sortFn = makeSortFns((ctx.sortSpec = fields));
  109. if (ctx.groupSpec) {
  110. sortFn = makeSortFns([ctx.groupSpec], sortFn);
  111. }
  112. // If a straight Ajax request, data may not be an array.
  113. // If an Array, preserve 'physical' order of raw data...
  114. data = Ext.isArray(data) ? data.slice(0) : data;
  115. if (sortFn) {
  116. Ext.Array.sort(data, sortFn);
  117. }
  118. me.sortedData = data;
  119. me.currentOrder = order;
  120. return data;
  121. },
  122. processFilters: Ext.identityFn,
  123. getPage: function (ctx, data) {
  124. var ret = data,
  125. length = data.length,
  126. start = ctx.params.start || 0,
  127. end = ctx.params.limit ? Math.min(length, start + ctx.params.limit) : length;
  128. if (start || end < length) {
  129. ret = ret.slice(start, end);
  130. }
  131. return ret;
  132. },
  133. getGroupSummary: function (groupField, rows, ctx) {
  134. return rows[0];
  135. },
  136. getSummary: function (ctx, data, page) {
  137. var me = this,
  138. groupField = ctx.groupSpec.property,
  139. accum,
  140. todo = {},
  141. summary = [],
  142. fieldValue,
  143. lastFieldValue;
  144. Ext.each(page, function (rec) {
  145. fieldValue = rec[groupField];
  146. todo[fieldValue] = true;
  147. });
  148. function flush () {
  149. if (accum) {
  150. summary.push(me.getGroupSummary(groupField, accum, ctx));
  151. accum = null;
  152. }
  153. }
  154. // data is ordered primarily by the groupField, so one pass can pick up all
  155. // the summaries one at a time.
  156. Ext.each(data, function (rec) {
  157. fieldValue = rec[groupField];
  158. if (lastFieldValue !== fieldValue) {
  159. flush();
  160. lastFieldValue = fieldValue;
  161. }
  162. if (!todo[fieldValue]) {
  163. // if we have even 1 summary, we have summarized all that we need
  164. // (again because data and page are ordered by groupField)
  165. return !summary.length;
  166. }
  167. if (accum) {
  168. accum.push(rec);
  169. } else {
  170. accum = [rec];
  171. }
  172. return true;
  173. });
  174. flush(); // make sure that last pesky summary goes...
  175. return summary;
  176. }
  177. };
  178. }());