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