Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Sortable.html
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      * Flag denoting that this object is sortable. Always true.
31      */
32     isSortable: true,
33
34 <span id='Ext-util-Sortable-property-defaultSortDirection'>    /**
35 </span>     * @property {String} defaultSortDirection
36      * The default sort direction to use if one is not specified.
37      */
38     defaultSortDirection: &quot;ASC&quot;,
39
40     requires: [
41         'Ext.util.Sorter'
42     ],
43
44 <span id='Ext-util-Sortable-property-sortRoot'>    /**
45 </span>     * @property {String} sortRoot
46      * The property in each item that contains the data to sort.
47      */
48
49 <span id='Ext-util-Sortable-method-initSortable'>    /**
50 </span>     * Performs initialization of this mixin. Component classes using this mixin should call this method during their
51      * own initialization.
52      */
53     initSortable: function() {
54         var me = this,
55             sorters = me.sorters;
56
57 <span id='Ext-util-Sortable-property-sorters'>        /**
58 </span>         * @property {Ext.util.MixedCollection} sorters
59          * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
60          */
61         me.sorters = Ext.create('Ext.util.AbstractMixedCollection', false, function(item) {
62             return item.id || item.property;
63         });
64
65         if (sorters) {
66             me.sorters.addAll(me.decodeSorters(sorters));
67         }
68     },
69
70 <span id='Ext-util-Sortable-method-sort'>    /**
71 </span>     * Sorts the data in the Store by one or more of its properties. Example usage:
72      *
73      *     //sort by a single field
74      *     myStore.sort('myField', 'DESC');
75      *
76      *     //sorting by multiple fields
77      *     myStore.sort([
78      *         {
79      *             property : 'age',
80      *             direction: 'ASC'
81      *         },
82      *         {
83      *             property : 'name',
84      *             direction: 'DESC'
85      *         }
86      *     ]);
87      *
88      * Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates
89      * the actual sorting to its internal {@link Ext.util.MixedCollection}.
90      *
91      * When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:
92      *
93      *     store.sort('myField');
94      *     store.sort('myField');
95      *
96      * Is equivalent to this code, because Store handles the toggling automatically:
97      *
98      *     store.sort('myField', 'ASC');
99      *     store.sort('myField', 'DESC');
100      *
101      * @param {String/Ext.util.Sorter[]} sorters Either a string name of one of the fields in this Store's configured
102      * {@link Ext.data.Model Model}, or an array of sorter configurations.
103      * @param {String} direction The overall direction to sort the data by. Defaults to &quot;ASC&quot;.
104      * @return {Ext.util.Sorter[]}
105      */
106     sort: function(sorters, direction, where, doSort) {
107         var me = this,
108             sorter, sorterFn,
109             newSorters;
110
111         if (Ext.isArray(sorters)) {
112             doSort = where;
113             where = direction;
114             newSorters = sorters;
115         }
116         else if (Ext.isObject(sorters)) {
117             doSort = where;
118             where = direction;
119             newSorters = [sorters];
120         }
121         else if (Ext.isString(sorters)) {
122             sorter = me.sorters.get(sorters);
123
124             if (!sorter) {
125                 sorter = {
126                     property : sorters,
127                     direction: direction
128                 };
129                 newSorters = [sorter];
130             }
131             else if (direction === undefined) {
132                 sorter.toggle();
133             }
134             else {
135                 sorter.setDirection(direction);
136             }
137         }
138
139         if (newSorters &amp;&amp; newSorters.length) {
140             newSorters = me.decodeSorters(newSorters);
141             if (Ext.isString(where)) {
142                 if (where === 'prepend') {
143                     sorters = me.sorters.clone().items;
144
145                     me.sorters.clear();
146                     me.sorters.addAll(newSorters);
147                     me.sorters.addAll(sorters);
148                 }
149                 else {
150                     me.sorters.addAll(newSorters);
151                 }
152             }
153             else {
154                 me.sorters.clear();
155                 me.sorters.addAll(newSorters);
156             }
157         }
158
159         if (doSort !== false) {
160             me.onBeforeSort(newSorters);
161             
162             sorters = me.sorters.items;
163             if (sorters.length) {
164                 //construct an amalgamated sorter function which combines all of the Sorters passed
165                 sorterFn = function(r1, r2) {
166                     var result = sorters[0].sort(r1, r2),
167                         length = sorters.length,
168                         i;
169
170                         //if we have more than one sorter, OR any additional sorter functions together
171                         for (i = 1; i &lt; length; i++) {
172                             result = result || sorters[i].sort.call(this, r1, r2);
173                         }
174
175                     return result;
176                 };
177
178                 me.doSort(sorterFn);
179             }
180         }
181
182         return sorters;
183     },
184
185     onBeforeSort: Ext.emptyFn,
186
187 <span id='Ext-util-Sortable-method-decodeSorters'>    /**
188 </span>     * @private
189      * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
190      * @param {Object[]} sorters The sorters array
191      * @return {Ext.util.Sorter[]} Array of Ext.util.Sorter objects
192      */
193     decodeSorters: function(sorters) {
194         if (!Ext.isArray(sorters)) {
195             if (sorters === undefined) {
196                 sorters = [];
197             } else {
198                 sorters = [sorters];
199             }
200         }
201
202         var length = sorters.length,
203             Sorter = Ext.util.Sorter,
204             fields = this.model ? this.model.prototype.fields : null,
205             field,
206             config, i;
207
208         for (i = 0; i &lt; length; i++) {
209             config = sorters[i];
210
211             if (!(config instanceof Sorter)) {
212                 if (Ext.isString(config)) {
213                     config = {
214                         property: config
215                     };
216                 }
217
218                 Ext.applyIf(config, {
219                     root     : this.sortRoot,
220                     direction: &quot;ASC&quot;
221                 });
222
223                 //support for 3.x style sorters where a function can be defined as 'fn'
224                 if (config.fn) {
225                     config.sorterFn = config.fn;
226                 }
227
228                 //support a function to be passed as a sorter definition
229                 if (typeof config == 'function') {
230                     config = {
231                         sorterFn: config
232                     };
233                 }
234
235                 // ensure sortType gets pushed on if necessary
236                 if (fields &amp;&amp; !config.transform) {
237                     field = fields.get(config.property);
238                     config.transform = field ? field.sortType : undefined;
239                 }
240                 sorters[i] = Ext.create('Ext.util.Sorter', config);
241             }
242         }
243
244         return sorters;
245     },
246
247     getSorters: function() {
248         return this.sorters.items;
249     }
250 });</pre>
251 </body>
252 </html>