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