multiple-sorting.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. Ext.Loader.setConfig({enabled: true});
  2. Ext.Loader.setPath('Ext.ux', '../ux/');
  3. Ext.require([
  4. 'Ext.data.*',
  5. 'Ext.grid.*',
  6. 'Ext.util.*',
  7. 'Ext.toolbar.*',
  8. 'Ext.ux.ToolbarDroppable',
  9. 'Ext.ux.BoxReorderer'
  10. ]);
  11. Ext.onReady(function() {
  12. //The following functions are used to get the sorting data from the toolbar and apply it to the store
  13. /**
  14. * Tells the store to sort itself according to our sort data
  15. */
  16. function doSort() {
  17. store.sort(getSorters());
  18. }
  19. /**
  20. * Callback handler used when a sorter button is clicked or reordered
  21. * @param {Ext.Button} button The button that was clicked
  22. * @param {Boolean} changeDirection True to change direction (default). Set to false for reorder
  23. * operations as we wish to preserve ordering there
  24. */
  25. function changeSortDirection(button, changeDirection) {
  26. var sortData = button.sortData,
  27. iconCls = button.iconCls;
  28. if (sortData) {
  29. if (changeDirection !== false) {
  30. button.sortData.direction = Ext.String.toggle(button.sortData.direction, "ASC", "DESC");
  31. button.setIconCls(Ext.String.toggle(iconCls, "sort-asc", "sort-desc"));
  32. }
  33. store.clearFilter();
  34. doSort();
  35. }
  36. }
  37. /**
  38. * Returns an array of sortData from the sorter buttons
  39. * @return {Array} Ordered sort data from each of the sorter buttons
  40. */
  41. function getSorters() {
  42. var sorters = [];
  43. Ext.each(tbar.query('button'), function(button) {
  44. sorters.push(button.sortData);
  45. }, this);
  46. return sorters;
  47. }
  48. /**
  49. * Convenience function for creating Toolbar Buttons that are tied to sorters
  50. * @param {Object} config Optional config object
  51. * @return {Object} The new Button configuration
  52. */
  53. function createSorterButtonConfig(config) {
  54. config = config || {};
  55. Ext.applyIf(config, {
  56. listeners: {
  57. click: function(button, e) {
  58. changeSortDirection(button, true);
  59. }
  60. },
  61. iconCls: 'sort-' + config.sortData.direction.toLowerCase(),
  62. reorderable: true,
  63. xtype: 'button'
  64. });
  65. return config;
  66. }
  67. /**
  68. * Returns an array of fake data
  69. * @param {Number} count The number of fake rows to create data for
  70. * @return {Array} The fake record data, suitable for usage with an ArrayReader
  71. */
  72. function createFakeData(count) {
  73. var firstNames = ['Ed', 'Tommy', 'Aaron', 'Abe', 'Jamie', 'Adam', 'Dave', 'David', 'Jay', 'Nicolas', 'Nige'],
  74. lastNames = ['Spencer', 'Maintz', 'Conran', 'Elias', 'Avins', 'Mishcon', 'Kaneda', 'Davis', 'Robinson', 'Ferrero', 'White'],
  75. ratings = [1, 2, 3, 4, 5],
  76. salaries = [100, 400, 900, 1500, 1000000];
  77. var data = [];
  78. for (var i = 0; i < (count || 25); i++) {
  79. var ratingId = Math.floor(Math.random() * ratings.length),
  80. salaryId = Math.floor(Math.random() * salaries.length),
  81. firstNameId = Math.floor(Math.random() * firstNames.length),
  82. lastNameId = Math.floor(Math.random() * lastNames.length),
  83. rating = ratings[ratingId],
  84. salary = salaries[salaryId],
  85. name = Ext.String.format("{0} {1}", firstNames[firstNameId], lastNames[lastNameId]);
  86. data.push([rating, salary, name]);
  87. }
  88. return data;
  89. }
  90. // create the data store
  91. Ext.define('Employee', {
  92. extend: 'Ext.data.Model',
  93. fields: [
  94. {name: 'rating', type: 'int'},
  95. {name: 'salary', type: 'float'},
  96. {name: 'name'}
  97. ]
  98. });
  99. var store = Ext.create('Ext.data.Store', {
  100. model: 'Employee',
  101. proxy: {
  102. type: 'memory',
  103. data: createFakeData(25),
  104. reader: {
  105. type: 'array'
  106. }
  107. },
  108. autoLoad: true
  109. });
  110. var reorderer = Ext.create('Ext.ux.BoxReorderer', {
  111. listeners: {
  112. scope: this,
  113. Drop: function(r, c, button) { //update sort direction when button is dropped
  114. changeSortDirection(button, false);
  115. }
  116. }
  117. });
  118. var droppable = Ext.create('Ext.ux.ToolbarDroppable', {
  119. /**
  120. * Creates the new toolbar item from the drop event
  121. */
  122. createItem: function(data) {
  123. var header = data.header,
  124. headerCt = header.ownerCt,
  125. reorderer = headerCt.reorderer;
  126. // Hide the drop indicators of the standard HeaderDropZone
  127. // in case user had a pending valid drop in
  128. if (reorderer) {
  129. reorderer.dropZone.invalidateDrop();
  130. }
  131. return createSorterButtonConfig({
  132. text: header.text,
  133. sortData: {
  134. property: header.dataIndex,
  135. direction: "ASC"
  136. }
  137. });
  138. },
  139. /**
  140. * Custom canDrop implementation which returns true if a column can be added to the toolbar
  141. * @param {Object} data Arbitrary data from the drag source. For a HeaderContainer, it will
  142. * contain a header property which is the Header being dragged.
  143. * @return {Boolean} True if the drop is allowed
  144. */
  145. canDrop: function(dragSource, event, data) {
  146. var sorters = getSorters(),
  147. header = data.header,
  148. length = sorters.length,
  149. entryIndex = this.calculateEntryIndex(event),
  150. targetItem = this.toolbar.getComponent(entryIndex),
  151. i;
  152. // Group columns have no dataIndex and therefore cannot be sorted
  153. // If target isn't reorderable it could not be replaced
  154. if (!header.dataIndex || (targetItem && targetItem.reorderable === false)) {
  155. return false;
  156. }
  157. for (i = 0; i < length; i++) {
  158. if (sorters[i].property == header.dataIndex) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. },
  164. afterLayout: doSort
  165. });
  166. //create the toolbar with the 2 plugins
  167. var tbar = Ext.create('Ext.toolbar.Toolbar', {
  168. items : [{
  169. xtype: 'tbtext',
  170. text: 'Sorting order:',
  171. reorderable: false
  172. }, createSorterButtonConfig({
  173. text: 'Rating',
  174. sortData: {
  175. property: 'rating',
  176. direction: 'DESC'
  177. }
  178. }), createSorterButtonConfig({
  179. text: 'Salary',
  180. sortData: {
  181. property: 'salary',
  182. direction: 'ASC'
  183. }
  184. })],
  185. plugins: [reorderer, droppable]
  186. });
  187. // create the Grid
  188. var grid = Ext.create('Ext.grid.Panel', {
  189. tbar : tbar,
  190. store: store,
  191. columns: [
  192. {
  193. text: 'Name',
  194. flex:1 ,
  195. sortable: false,
  196. dataIndex: 'name'
  197. },{
  198. text: 'Rating',
  199. width: 125,
  200. sortable: false,
  201. dataIndex: 'rating'
  202. },{
  203. text: 'Salary',
  204. width: 125,
  205. sortable: false,
  206. dataIndex: 'salary',
  207. align: 'right',
  208. renderer: Ext.util.Format.usMoney
  209. }
  210. ],
  211. stripeRows: true,
  212. height: 350,
  213. width : 600,
  214. title : 'Array Grid',
  215. renderTo: 'grid-example',
  216. listeners: {
  217. scope: this,
  218. // wait for the first layout to access the headerCt (we only want this once):
  219. single: true,
  220. // tell the toolbar's droppable plugin that it accepts items from the columns' dragdrop group
  221. afterlayout: function(grid) {
  222. var headerCt = grid.child("headercontainer");
  223. droppable.addDDGroup(headerCt.reorderer.dragZone.ddGroup);
  224. doSort();
  225. }
  226. }
  227. });
  228. });