Sortable.html 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-util-Sortable'>/**
  19. </span> * @docauthor Tommy Maintz &lt;tommy@sencha.com&gt;
  20. *
  21. * A mixin which allows a data component to be sorted. This is used by e.g. {@link Ext.data.Store} and {@link Ext.data.TreeStore}.
  22. *
  23. * **NOTE**: This mixin is mainly for internal use and most users should not need to use it directly. It
  24. * is more likely you will want to use one of the component classes that import this mixin, such as
  25. * {@link Ext.data.Store} or {@link Ext.data.TreeStore}.
  26. */
  27. Ext.define(&quot;Ext.util.Sortable&quot;, {
  28. <span id='Ext-util-Sortable-property-isSortable'> /**
  29. </span> * @property {Boolean} isSortable
  30. * `true` in this class to identify an object as an instantiated Sortable, or subclass thereof.
  31. */
  32. isSortable: true,
  33. <span id='Ext-util-Sortable-property-defaultSortDirection'> /**
  34. </span> * @property {String} defaultSortDirection
  35. * The default sort direction to use if one is not specified.
  36. */
  37. defaultSortDirection: &quot;ASC&quot;,
  38. requires: [
  39. 'Ext.util.Sorter'
  40. ],
  41. <span id='Ext-util-Sortable-property-sortRoot'> /**
  42. </span> * @property {String} sortRoot
  43. * The property in each item that contains the data to sort.
  44. */
  45. <span id='Ext-util-Sortable-method-initSortable'> /**
  46. </span> * Performs initialization of this mixin. Component classes using this mixin should call this method during their
  47. * own initialization.
  48. */
  49. initSortable: function() {
  50. var me = this,
  51. sorters = me.sorters;
  52. <span id='Ext-util-Sortable-property-sorters'> /**
  53. </span> * @property {Ext.util.MixedCollection} sorters
  54. * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
  55. */
  56. me.sorters = new Ext.util.AbstractMixedCollection(false, function(item) {
  57. return item.id || item.property;
  58. });
  59. if (sorters) {
  60. me.sorters.addAll(me.decodeSorters(sorters));
  61. }
  62. },
  63. <span id='Ext-util-Sortable-method-sort'> /**
  64. </span> * Sorts the data in the Store by one or more of its properties. Example usage:
  65. *
  66. * //sort by a single field
  67. * myStore.sort('myField', 'DESC');
  68. *
  69. * //sorting by multiple fields
  70. * myStore.sort([
  71. * {
  72. * property : 'age',
  73. * direction: 'ASC'
  74. * },
  75. * {
  76. * property : 'name',
  77. * direction: 'DESC'
  78. * }
  79. * ]);
  80. *
  81. * Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates
  82. * the actual sorting to its internal {@link Ext.util.MixedCollection}.
  83. *
  84. * When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:
  85. *
  86. * store.sort('myField');
  87. * store.sort('myField');
  88. *
  89. * Is equivalent to this code, because Store handles the toggling automatically:
  90. *
  91. * store.sort('myField', 'ASC');
  92. * store.sort('myField', 'DESC');
  93. *
  94. * @param {String/Ext.util.Sorter[]} [sorters] Either a string name of one of the fields in this Store's configured
  95. * {@link Ext.data.Model Model}, or an array of sorter configurations.
  96. * @param {String} [direction=&quot;ASC&quot;] The overall direction to sort the data by.
  97. * @return {Ext.util.Sorter[]}
  98. */
  99. sort: function(sorters, direction, where, doSort) {
  100. var me = this,
  101. sorter, sorterFn,
  102. newSorters;
  103. if (Ext.isArray(sorters)) {
  104. doSort = where;
  105. where = direction;
  106. newSorters = sorters;
  107. }
  108. else if (Ext.isObject(sorters)) {
  109. doSort = where;
  110. where = direction;
  111. newSorters = [sorters];
  112. }
  113. else if (Ext.isString(sorters)) {
  114. sorter = me.sorters.get(sorters);
  115. if (!sorter) {
  116. sorter = {
  117. property : sorters,
  118. direction: direction
  119. };
  120. newSorters = [sorter];
  121. }
  122. else if (direction === undefined) {
  123. sorter.toggle();
  124. }
  125. else {
  126. sorter.setDirection(direction);
  127. }
  128. }
  129. if (newSorters &amp;&amp; newSorters.length) {
  130. newSorters = me.decodeSorters(newSorters);
  131. if (Ext.isString(where)) {
  132. if (where === 'prepend') {
  133. sorters = me.sorters.clone().items;
  134. me.sorters.clear();
  135. me.sorters.addAll(newSorters);
  136. me.sorters.addAll(sorters);
  137. }
  138. else {
  139. me.sorters.addAll(newSorters);
  140. }
  141. }
  142. else {
  143. me.sorters.clear();
  144. me.sorters.addAll(newSorters);
  145. }
  146. }
  147. if (doSort !== false) {
  148. me.onBeforeSort(newSorters);
  149. sorters = me.sorters.items;
  150. if (sorters.length) {
  151. // Sort using a generated sorter function which combines all of the Sorters passed
  152. me.doSort(me.generateComparator());
  153. }
  154. }
  155. return sorters;
  156. },
  157. <span id='Ext-util-Sortable-method-generateComparator'> /**
  158. </span> * &lt;p&gt;Returns a comparator function which compares two items and returns -1, 0, or 1 depending
  159. * on the currently defined set of {@link #sorters}.&lt;/p&gt;
  160. * &lt;p&gt;If there are no {@link #sorters} defined, it returns a function which returns &lt;code&gt;0&lt;/code&gt; meaning that no sorting will occur.&lt;/p&gt;
  161. */
  162. generateComparator: function() {
  163. var sorters = this.sorters.getRange();
  164. return sorters.length ? this.createComparator(sorters) : this.emptyComparator;
  165. },
  166. createComparator: function(sorters) {
  167. return function(r1, r2) {
  168. var result = sorters[0].sort(r1, r2),
  169. length = sorters.length,
  170. i = 1;
  171. // if we have more than one sorter, OR any additional sorter functions together
  172. for (; i &lt; length; i++) {
  173. result = result || sorters[i].sort.call(this, r1, r2);
  174. }
  175. return result;
  176. };
  177. },
  178. emptyComparator: function(){
  179. return 0;
  180. },
  181. onBeforeSort: Ext.emptyFn,
  182. <span id='Ext-util-Sortable-method-decodeSorters'> /**
  183. </span> * @private
  184. * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
  185. * @param {Object[]} sorters The sorters array
  186. * @return {Ext.util.Sorter[]} Array of Ext.util.Sorter objects
  187. */
  188. decodeSorters: function(sorters) {
  189. if (!Ext.isArray(sorters)) {
  190. if (sorters === undefined) {
  191. sorters = [];
  192. } else {
  193. sorters = [sorters];
  194. }
  195. }
  196. var length = sorters.length,
  197. Sorter = Ext.util.Sorter,
  198. fields = this.model ? this.model.prototype.fields : null,
  199. field,
  200. config, i;
  201. for (i = 0; i &lt; length; i++) {
  202. config = sorters[i];
  203. if (!(config instanceof Sorter)) {
  204. if (Ext.isString(config)) {
  205. config = {
  206. property: config
  207. };
  208. }
  209. Ext.applyIf(config, {
  210. root : this.sortRoot,
  211. direction: &quot;ASC&quot;
  212. });
  213. //support for 3.x style sorters where a function can be defined as 'fn'
  214. if (config.fn) {
  215. config.sorterFn = config.fn;
  216. }
  217. //support a function to be passed as a sorter definition
  218. if (typeof config == 'function') {
  219. config = {
  220. sorterFn: config
  221. };
  222. }
  223. // ensure sortType gets pushed on if necessary
  224. if (fields &amp;&amp; !config.transform) {
  225. field = fields.get(config.property);
  226. config.transform = field ? field.sortType : undefined;
  227. }
  228. sorters[i] = new Ext.util.Sorter(config);
  229. }
  230. }
  231. return sorters;
  232. },
  233. getSorters: function() {
  234. return this.sorters.items;
  235. },
  236. <span id='Ext-util-Sortable-method-getFirstSorter'> /**
  237. </span> * Gets the first sorter from the sorters collection, excluding
  238. * any groupers that may be in place
  239. * @protected
  240. * @return {Ext.util.Sorter} The sorter, null if none exist
  241. */
  242. getFirstSorter: function(){
  243. var sorters = this.sorters.items,
  244. len = sorters.length,
  245. i = 0,
  246. sorter;
  247. for (; i &lt; len; ++i) {
  248. sorter = sorters[i];
  249. if (!sorter.isGrouper) {
  250. return sorter;
  251. }
  252. }
  253. return null;
  254. }
  255. });</pre>
  256. </body>
  257. </html>