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 * @class Ext.util.Sortable
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 library 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 * @docauthor Tommy Maintz <tommy@sencha.com>
26 Ext.define("Ext.util.Sortable", {
28 * @property isSortable
30 * Flag denoting that this object is sortable. Always true.
35 * The default sort direction to use if one is not specified (defaults to "ASC")
36 * @property defaultSortDirection
39 defaultSortDirection: "ASC",
46 * The property in each item that contains the data to sort.
51 * Performs initialization of this mixin. Component classes using this mixin should call this method
52 * during their own initialization.
54 initSortable: function() {
59 * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
61 * @type Ext.util.MixedCollection
63 me.sorters = Ext.create('Ext.util.AbstractMixedCollection', false, function(item) {
64 return item.id || item.property;
68 me.sorters.addAll(me.decodeSorters(sorters));
73 * <p>Sorts the data in the Store by one or more of its properties. Example usage:</p>
75 //sort by a single field
76 myStore.sort('myField', 'DESC');
78 //sorting by multiple fields
90 * <p>Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates the actual
91 * sorting to its internal {@link Ext.util.MixedCollection}.</p>
92 * <p>When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:</p>
94 store.sort('myField');
95 store.sort('myField');
97 * <p>Is equivalent to this code, because Store handles the toggling automatically:</p>
99 store.sort('myField', 'ASC');
100 store.sort('myField', 'DESC');
102 * @param {String|Array} sorters Either a string name of one of the fields in this Store's configured {@link Ext.data.Model Model},
103 * or an Array of sorter configurations.
104 * @param {String} direction The overall direction to sort the data by. Defaults to "ASC".
106 sort: function(sorters, direction, where, doSort) {
111 if (Ext.isArray(sorters)) {
114 newSorters = sorters;
116 else if (Ext.isObject(sorters)) {
119 newSorters = [sorters];
121 else if (Ext.isString(sorters)) {
122 sorter = me.sorters.get(sorters);
129 newSorters = [sorter];
131 else if (direction === undefined) {
135 sorter.setDirection(direction);
139 if (newSorters && newSorters.length) {
140 newSorters = me.decodeSorters(newSorters);
141 if (Ext.isString(where)) {
142 if (where === 'prepend') {
143 sorters = me.sorters.clone().items;
146 me.sorters.addAll(newSorters);
147 me.sorters.addAll(sorters);
150 me.sorters.addAll(newSorters);
155 me.sorters.addAll(newSorters);
158 if (doSort !== false) {
159 me.onBeforeSort(newSorters);
163 if (doSort !== false) {
164 sorters = me.sorters.items;
165 if (sorters.length) {
166 //construct an amalgamated sorter function which combines all of the Sorters passed
167 sorterFn = function(r1, r2) {
168 var result = sorters[0].sort(r1, r2),
169 length = sorters.length,
172 //if we have more than one sorter, OR any additional sorter functions together
173 for (i = 1; i < length; i++) {
174 result = result || sorters[i].sort.call(this, r1, r2);
187 onBeforeSort: Ext.emptyFn,
191 * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
192 * @param {Array} sorters The sorters array
193 * @return {Array} Array of Ext.util.Sorter objects
195 decodeSorters: function(sorters) {
196 if (!Ext.isArray(sorters)) {
197 if (sorters === undefined) {
204 var length = sorters.length,
205 Sorter = Ext.util.Sorter,
206 fields = this.model ? this.model.prototype.fields : null,
210 for (i = 0; i < length; i++) {
213 if (!(config instanceof Sorter)) {
214 if (Ext.isString(config)) {
220 Ext.applyIf(config, {
221 root : this.sortRoot,
225 //support for 3.x style sorters where a function can be defined as 'fn'
227 config.sorterFn = config.fn;
230 //support a function to be passed as a sorter definition
231 if (typeof config == 'function') {
237 // ensure sortType gets pushed on if necessary
238 if (fields && !config.transform) {
239 field = fields.get(config.property);
240 config.transform = field ? field.sortType : undefined;
242 sorters[i] = Ext.create('Ext.util.Sorter', config);
249 getSorters: function() {
250 return this.sorters.items;