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