3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @docauthor Tommy Maintz <tommy@sencha.com>
18 * 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}.
20 * **NOTE**: This mixin is mainly for internal use and most users should not need to use it directly. It
21 * is more likely you will want to use one of the component classes that import this mixin, such as
22 * {@link Ext.data.Store} or {@link Ext.data.TreeStore}.
24 Ext.define("Ext.util.Sortable", {
26 * @property {Boolean} isSortable
27 * Flag denoting that this object is sortable. Always true.
32 * @property {String} defaultSortDirection
33 * The default sort direction to use if one is not specified.
35 defaultSortDirection: "ASC",
42 * @property {String} sortRoot
43 * The property in each item that contains the data to sort.
47 * Performs initialization of this mixin. Component classes using this mixin should call this method during their
50 initSortable: function() {
55 * @property {Ext.util.MixedCollection} sorters
56 * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
58 me.sorters = Ext.create('Ext.util.AbstractMixedCollection', false, function(item) {
59 return item.id || item.property;
63 me.sorters.addAll(me.decodeSorters(sorters));
68 * Sorts the data in the Store by one or more of its properties. Example usage:
70 * //sort by a single field
71 * myStore.sort('myField', 'DESC');
73 * //sorting by multiple fields
85 * Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates
86 * the actual sorting to its internal {@link Ext.util.MixedCollection}.
88 * When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:
90 * store.sort('myField');
91 * store.sort('myField');
93 * Is equivalent to this code, because Store handles the toggling automatically:
95 * store.sort('myField', 'ASC');
96 * store.sort('myField', 'DESC');
98 * @param {String/Ext.util.Sorter[]} sorters Either a string name of one of the fields in this Store's configured
99 * {@link Ext.data.Model Model}, or an array of sorter configurations.
100 * @param {String} direction The overall direction to sort the data by. Defaults to "ASC".
101 * @return {Ext.util.Sorter[]}
103 sort: function(sorters, direction, where, doSort) {
108 if (Ext.isArray(sorters)) {
111 newSorters = sorters;
113 else if (Ext.isObject(sorters)) {
116 newSorters = [sorters];
118 else if (Ext.isString(sorters)) {
119 sorter = me.sorters.get(sorters);
126 newSorters = [sorter];
128 else if (direction === undefined) {
132 sorter.setDirection(direction);
136 if (newSorters && newSorters.length) {
137 newSorters = me.decodeSorters(newSorters);
138 if (Ext.isString(where)) {
139 if (where === 'prepend') {
140 sorters = me.sorters.clone().items;
143 me.sorters.addAll(newSorters);
144 me.sorters.addAll(sorters);
147 me.sorters.addAll(newSorters);
152 me.sorters.addAll(newSorters);
156 if (doSort !== false) {
157 me.onBeforeSort(newSorters);
159 sorters = me.sorters.items;
160 if (sorters.length) {
161 //construct an amalgamated sorter function which combines all of the Sorters passed
162 sorterFn = function(r1, r2) {
163 var result = sorters[0].sort(r1, r2),
164 length = sorters.length,
167 //if we have more than one sorter, OR any additional sorter functions together
168 for (i = 1; i < length; i++) {
169 result = result || sorters[i].sort.call(this, r1, r2);
182 onBeforeSort: Ext.emptyFn,
186 * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
187 * @param {Object[]} sorters The sorters array
188 * @return {Ext.util.Sorter[]} Array of Ext.util.Sorter objects
190 decodeSorters: function(sorters) {
191 if (!Ext.isArray(sorters)) {
192 if (sorters === undefined) {
199 var length = sorters.length,
200 Sorter = Ext.util.Sorter,
201 fields = this.model ? this.model.prototype.fields : null,
205 for (i = 0; i < length; i++) {
208 if (!(config instanceof Sorter)) {
209 if (Ext.isString(config)) {
215 Ext.applyIf(config, {
216 root : this.sortRoot,
220 //support for 3.x style sorters where a function can be defined as 'fn'
222 config.sorterFn = config.fn;
225 //support a function to be passed as a sorter definition
226 if (typeof config == 'function') {
232 // ensure sortType gets pushed on if necessary
233 if (fields && !config.transform) {
234 field = fields.get(config.property);
235 config.transform = field ? field.sortType : undefined;
237 sorters[i] = Ext.create('Ext.util.Sorter', config);
244 getSorters: function() {
245 return this.sorters.items;