Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / examples / ux / grid / filter / DateFilter.js
1 /**
2  * @class Ext.ux.grid.filter.DateFilter
3  * @extends Ext.ux.grid.filter.Filter
4  * Filter by a configurable Ext.picker.DatePicker menu
5  * <p><b><u>Example Usage:</u></b></p>
6  * <pre><code>
7 var filters = Ext.create('Ext.ux.grid.GridFilters', {
8     ...
9     filters: [{
10         // required configs
11         type: 'date',
12         dataIndex: 'dateAdded',
13
14         // optional configs
15         dateFormat: 'm/d/Y',  // default
16         beforeText: 'Before', // default
17         afterText: 'After',   // default
18         onText: 'On',         // default
19         pickerOpts: {
20             // any DatePicker configs
21         },
22
23         active: true // default is false
24     }]
25 });
26  * </code></pre>
27  */
28 Ext.define('Ext.ux.grid.filter.DateFilter', {
29     extend: 'Ext.ux.grid.filter.Filter',
30     alias: 'gridfilter.date',
31     uses: ['Ext.picker.Date', 'Ext.menu.Menu'],
32
33     /**
34      * @cfg {String} afterText
35      * Defaults to 'After'.
36      */
37     afterText : 'After',
38     /**
39      * @cfg {String} beforeText
40      * Defaults to 'Before'.
41      */
42     beforeText : 'Before',
43     /**
44      * @cfg {Object} compareMap
45      * Map for assigning the comparison values used in serialization.
46      */
47     compareMap : {
48         before: 'lt',
49         after:  'gt',
50         on:     'eq'
51     },
52     /**
53      * @cfg {String} dateFormat
54      * The date format to return when using getValue.
55      * Defaults to 'm/d/Y'.
56      */
57     dateFormat : 'm/d/Y',
58
59     /**
60      * @cfg {Date} maxDate
61      * Allowable date as passed to the Ext.DatePicker
62      * Defaults to undefined.
63      */
64     /**
65      * @cfg {Date} minDate
66      * Allowable date as passed to the Ext.DatePicker
67      * Defaults to undefined.
68      */
69     /**
70      * @cfg {Array} menuItems
71      * The items to be shown in this menu
72      * Defaults to:<pre>
73      * menuItems : ['before', 'after', '-', 'on'],
74      * </pre>
75      */
76     menuItems : ['before', 'after', '-', 'on'],
77
78     /**
79      * @cfg {Object} menuItemCfgs
80      * Default configuration options for each menu item
81      */
82     menuItemCfgs : {
83         selectOnFocus: true,
84         width: 125
85     },
86
87     /**
88      * @cfg {String} onText
89      * Defaults to 'On'.
90      */
91     onText : 'On',
92
93     /**
94      * @cfg {Object} pickerOpts
95      * Configuration options for the date picker associated with each field.
96      */
97     pickerOpts : {},
98
99     /**
100      * @private
101      * Template method that is to initialize the filter and install required menu items.
102      */
103     init : function (config) {
104         var me = this,
105             pickerCfg, i, len, item, cfg;
106
107         pickerCfg = Ext.apply(me.pickerOpts, {
108             xtype: 'datepicker',
109             minDate: me.minDate,
110             maxDate: me.maxDate,
111             format:  me.dateFormat,
112             listeners: {
113                 scope: me,
114                 select: me.onMenuSelect
115             }
116         });
117
118         me.fields = {};
119         for (i = 0, len = me.menuItems.length; i < len; i++) {
120             item = me.menuItems[i];
121             if (item !== '-') {
122                 cfg = {
123                     itemId: 'range-' + item,
124                     text: me[item + 'Text'],
125                     menu: Ext.create('Ext.menu.Menu', {
126                         items: [
127                             Ext.apply(pickerCfg, {
128                                 itemId: item
129                             })
130                         ]
131                     }),
132                     listeners: {
133                         scope: me,
134                         checkchange: me.onCheckChange
135                     }
136                 };
137                 item = me.fields[item] = Ext.create('Ext.menu.CheckItem', cfg);
138             }
139             //me.add(item);
140             me.menu.add(item);
141         }
142     },
143
144     onCheckChange : function () {
145         this.setActive(this.isActivatable());
146         this.fireEvent('update', this);
147     },
148
149     /**
150      * @private
151      * Handler method called when there is a keyup event on an input
152      * item of this menu.
153      */
154     onInputKeyUp : function (field, e) {
155         var k = e.getKey();
156         if (k == e.RETURN && field.isValid()) {
157             e.stopEvent();
158             this.menu.hide();
159         }
160     },
161
162     /**
163      * Handler for when the DatePicker for a field fires the 'select' event
164      * @param {Ext.picker.Date} picker
165      * @param {Object} picker
166      * @param {Object} date
167      */
168     onMenuSelect : function (picker, date) {
169         var fields = this.fields,
170             field = this.fields[picker.itemId];
171
172         field.setChecked(true);
173
174         if (field == fields.on) {
175             fields.before.setChecked(false, true);
176             fields.after.setChecked(false, true);
177         } else {
178             fields.on.setChecked(false, true);
179             if (field == fields.after && this.getFieldValue('before') < date) {
180                 fields.before.setChecked(false, true);
181             } else if (field == fields.before && this.getFieldValue('after') > date) {
182                 fields.after.setChecked(false, true);
183             }
184         }
185         this.fireEvent('update', this);
186
187         picker.up('menu').hide();
188     },
189
190     /**
191      * @private
192      * Template method that is to get and return the value of the filter.
193      * @return {String} The value of this filter
194      */
195     getValue : function () {
196         var key, result = {};
197         for (key in this.fields) {
198             if (this.fields[key].checked) {
199                 result[key] = this.getFieldValue(key);
200             }
201         }
202         return result;
203     },
204
205     /**
206      * @private
207      * Template method that is to set the value of the filter.
208      * @param {Object} value The value to set the filter
209      * @param {Boolean} preserve true to preserve the checked status
210      * of the other fields.  Defaults to false, unchecking the
211      * other fields
212      */
213     setValue : function (value, preserve) {
214         var key;
215         for (key in this.fields) {
216             if(value[key]){
217                 this.getPicker(key).setValue(value[key]);
218                 this.fields[key].setChecked(true);
219             } else if (!preserve) {
220                 this.fields[key].setChecked(false);
221             }
222         }
223         this.fireEvent('update', this);
224     },
225
226     /**
227      * @private
228      * Template method that is to return <tt>true</tt> if the filter
229      * has enough configuration information to be activated.
230      * @return {Boolean}
231      */
232     isActivatable : function () {
233         var key;
234         for (key in this.fields) {
235             if (this.fields[key].checked) {
236                 return true;
237             }
238         }
239         return false;
240     },
241
242     /**
243      * @private
244      * Template method that is to get and return serialized filter data for
245      * transmission to the server.
246      * @return {Object/Array} An object or collection of objects containing
247      * key value pairs representing the current configuration of the filter.
248      */
249     getSerialArgs : function () {
250         var args = [];
251         for (var key in this.fields) {
252             if(this.fields[key].checked){
253                 args.push({
254                     type: 'date',
255                     comparison: this.compareMap[key],
256                     value: Ext.Date.format(this.getFieldValue(key), this.dateFormat)
257                 });
258             }
259         }
260         return args;
261     },
262
263     /**
264      * Get and return the date menu picker value
265      * @param {String} item The field identifier ('before', 'after', 'on')
266      * @return {Date} Gets the current selected value of the date field
267      */
268     getFieldValue : function(item){
269         return this.getPicker(item).getValue();
270     },
271
272     /**
273      * Gets the menu picker associated with the passed field
274      * @param {String} item The field identifier ('before', 'after', 'on')
275      * @return {Object} The menu picker
276      */
277     getPicker : function(item){
278         return this.fields[item].menu.items.first();
279     },
280
281     /**
282      * Template method that is to validate the provided Ext.data.Record
283      * against the filters configuration.
284      * @param {Ext.data.Record} record The record to validate
285      * @return {Boolean} true if the record is valid within the bounds
286      * of the filter, false otherwise.
287      */
288     validateRecord : function (record) {
289         var key,
290             pickerValue,
291             val = record.get(this.dataIndex),
292             clearTime = Ext.Date.clearTime;
293
294         if(!Ext.isDate(val)){
295             return false;
296         }
297         val = clearTime(val, true).getTime();
298
299         for (key in this.fields) {
300             if (this.fields[key].checked) {
301                 pickerValue = clearTime(this.getFieldValue(key), true).getTime();
302                 if (key == 'before' && pickerValue <= val) {
303                     return false;
304                 }
305                 if (key == 'after' && pickerValue >= val) {
306                     return false;
307                 }
308                 if (key == 'on' && pickerValue != val) {
309                     return false;
310                 }
311             }
312         }
313         return true;
314     }
315 });