Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / grid / multiple-sorting.js
1 Ext.Loader.setConfig({enabled: true});
2
3 Ext.Loader.setPath('Ext.ux', '../ux/');
4
5 Ext.require([
6     'Ext.data.*',
7     'Ext.grid.*',
8     'Ext.util.*',
9     'Ext.toolbar.*',
10     'Ext.ux.ToolbarDroppable',
11     'Ext.ux.BoxReorderer'
12 ]);
13
14 Ext.onReady(function() {
15    //The following functions are used to get the sorting data from the toolbar and apply it to the store
16     /**
17      * Tells the store to sort itself according to our sort data
18      */
19     function doSort() {
20         store.sort(getSorters());
21     }
22
23     /**
24      * Callback handler used when a sorter button is clicked or reordered
25      * @param {Ext.Button} button The button that was clicked
26      * @param {Boolean} changeDirection True to change direction (default). Set to false for reorder
27      * operations as we wish to preserve ordering there
28      */
29     function changeSortDirection(button, changeDirection) {
30         var sortData = button.sortData,
31             iconCls  = button.iconCls;
32         
33         if (sortData) {
34             if (changeDirection !== false) {
35                 button.sortData.direction = Ext.String.toggle(button.sortData.direction, "ASC", "DESC");
36                 button.setIconCls(Ext.String.toggle(iconCls, "sort-asc", "sort-desc"));
37             }
38             store.clearFilter();
39             doSort();
40         }
41     }
42
43     /**
44      * Returns an array of sortData from the sorter buttons
45      * @return {Array} Ordered sort data from each of the sorter buttons
46      */
47     function getSorters() {
48         var sorters = [];
49  
50         Ext.each(tbar.query('button'), function(button) {
51             sorters.push(button.sortData);
52         }, this);
53
54         return sorters;
55     }
56
57     /**
58      * Convenience function for creating Toolbar Buttons that are tied to sorters
59      * @param {Object} config Optional config object
60      * @return {Object} The new Button configuration
61      */
62     function createSorterButtonConfig(config) {
63         config = config || {};
64         Ext.applyIf(config, {
65             listeners: {
66                 click: function(button, e) {
67                     changeSortDirection(button, true);
68                 }
69             },
70             iconCls: 'sort-' + config.sortData.direction.toLowerCase(),
71             reorderable: true,
72             xtype: 'button'
73         });
74         return config;
75     }
76
77     /**
78      * Returns an array of fake data
79      * @param {Number} count The number of fake rows to create data for
80      * @return {Array} The fake record data, suitable for usage with an ArrayReader
81      */
82     function createFakeData(count) {
83         var firstNames   = ['Ed', 'Tommy', 'Aaron', 'Abe', 'Jamie', 'Adam', 'Dave', 'David', 'Jay', 'Nicolas', 'Nige'],
84             lastNames    = ['Spencer', 'Maintz', 'Conran', 'Elias', 'Avins', 'Mishcon', 'Kaneda', 'Davis', 'Robinson', 'Ferrero', 'White'],
85             ratings      = [1, 2, 3, 4, 5],
86             salaries     = [100, 400, 900, 1500, 1000000];
87
88         var data = [];
89         for (var i = 0; i < (count || 25); i++) {
90             var ratingId    = Math.floor(Math.random() * ratings.length),
91                 salaryId    = Math.floor(Math.random() * salaries.length),
92                 firstNameId = Math.floor(Math.random() * firstNames.length),
93                 lastNameId  = Math.floor(Math.random() * lastNames.length),
94
95                 rating      = ratings[ratingId],
96                 salary      = salaries[salaryId],
97                 name        = Ext.String.format("{0} {1}", firstNames[firstNameId], lastNames[lastNameId]);
98
99             data.push([rating, salary, name]);
100         }
101         return data;
102     }
103
104     // create the data store
105     Ext.define('Employee', {
106         extend: 'Ext.data.Model',
107         fields: [
108            {name: 'rating', type: 'int'},
109            {name: 'salary', type: 'float'},
110            {name: 'name'}
111         ]
112     });
113
114     var store = Ext.create('Ext.data.Store', {
115         model: 'Employee',
116         proxy: {
117             type: 'memory',
118             data: createFakeData(25),
119             reader: {
120                 type: 'array'
121             }
122         },
123         autoLoad: true
124     });
125
126     var reorderer = Ext.create('Ext.ux.BoxReorderer', {
127         listeners: {
128             scope: this,
129             Drop: function(r, c, button) { //update sort direction when button is dropped
130                 changeSortDirection(button, false);
131             }
132         }
133     });
134
135     var droppable = Ext.create('Ext.ux.ToolbarDroppable', {
136         /**
137          * Creates the new toolbar item from the drop event
138          */
139         createItem: function(data) {
140             var header = data.header,
141                 headerCt = header.ownerCt,
142                 reorderer = headerCt.reorderer;
143             
144             // Hide the drop indicators of the standard HeaderDropZone
145             // in case user had a pending valid drop in 
146             if (reorderer) {
147                 reorderer.dropZone.invalidateDrop();
148             }
149
150             return createSorterButtonConfig({
151                 text: header.text,
152                 sortData: {
153                     property: header.dataIndex,
154                     direction: "ASC"
155                 }
156             });
157         },
158
159         /**
160          * Custom canDrop implementation which returns true if a column can be added to the toolbar
161          * @param {Object} data Arbitrary data from the drag source. For a HeaderContainer, it will
162          * contain a header property which is the Header being dragged.
163          * @return {Boolean} True if the drop is allowed
164          */
165         canDrop: function(dragSource, event, data) {
166             var sorters = getSorters(),
167                 header  = data.header,
168                 length = sorters.length,
169                 entryIndex = this.calculateEntryIndex(event),
170                 targetItem = this.toolbar.getComponent(entryIndex),
171                 i;
172
173             // Group columns have no dataIndex and therefore cannot be sorted
174             // If target isn't reorderable it could not be replaced
175             if (!header.dataIndex || (targetItem && targetItem.reorderable === false)) {
176                 return false;
177             }
178
179             for (i = 0; i < length; i++) {
180                 if (sorters[i].property == header.dataIndex) {
181                     return false;
182                 }
183             }
184             return true;
185         },
186
187         afterLayout: doSort
188     });
189
190     //create the toolbar with the 2 plugins
191     var tbar = Ext.create('Ext.toolbar.Toolbar', {
192         items  : [{
193             xtype: 'tbtext',
194             text: 'Sorting order:',
195             reorderable: false
196         }, '-'],
197         plugins: [reorderer, droppable]
198     });
199
200     tbar.add(createSorterButtonConfig({
201         text: 'Rating',
202         sortData: {
203             property: 'rating',
204             direction: 'DESC'
205         }
206     }));
207
208     tbar.add(createSorterButtonConfig({
209         text: 'Salary',
210         sortData: {
211             property: 'salary',
212             direction: 'ASC'
213         }
214     }));
215
216     // create the Grid
217     var grid = Ext.create('Ext.grid.Panel', {
218         tbar : tbar,
219         store: store,
220         columns: [
221             {
222                 text: 'Name',
223                 flex:1 ,
224                 sortable: false,
225                 dataIndex: 'name'
226             },{
227                 text: 'Rating',
228                 width: 125,
229                 sortable: false,
230                 dataIndex: 'rating'
231             },{
232                 text: 'Salary',
233                 width: 125,
234                 sortable: false,
235                 dataIndex: 'salary',
236                 align: 'right',
237                 renderer: Ext.util.Format.usMoney
238             }
239         ],
240         stripeRows: true,
241         height: 350,
242         width : 600,
243         title : 'Array Grid',
244         renderTo: 'grid-example',
245         listeners: {
246             scope: this,
247             //here we tell the toolbar's droppable plugin that it can accept items from the columns' dragdrop group
248             afterrender: function(grid) {
249                 var headerCt = grid.child("headercontainer"),
250                     //the plugin position depends on browser see Ext.grid.header.Container sources
251                     dragProxy = headerCt.plugins[0].dragZone || headerCt.plugins[1].dragZone;
252
253                 droppable.addDDGroup(dragProxy.ddGroup);
254                 doSort();
255             }
256         }
257     });
258 });