]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * The date grid filter allows you to create a filter selection that limits results\r | |
3 | * to values matching specific date constraints. The filter can be set programmatically or via \r | |
4 | * user input with a configurable {@link Ext.picker.Date DatePicker menu} in the filter section \r | |
5 | * of the column header.\r | |
6 | * \r | |
7 | * Example Date Filter Usage:\r | |
8 | * \r | |
9 | * @example \r | |
10 | * var shows = Ext.create('Ext.data.Store', {\r | |
11 | * fields: ['id','show', {\r | |
12 | * name: 'airDate',\r | |
13 | * type: 'date',\r | |
14 | * dateFormat: 'Y-m-d'\r | |
15 | * }],\r | |
16 | * data: [\r | |
17 | * {id: 0, show: 'Battlestar Galactica', airDate: '1978-09-17'},\r | |
18 | * {id: 1, show: 'Doctor Who', airDate: '1963-11-23'},\r | |
19 | * {id: 2, show: 'Farscape', airDate: '1999-03-19'},\r | |
20 | * {id: 3, show: 'Firefly', airDate: '2002-12-20'},\r | |
21 | * {id: 4, show: 'Star Trek', airDate: '1966-09-08'},\r | |
22 | * {id: 5, show: 'Star Wars: Christmas Special', airDate: '1978-11-17'}\r | |
23 | * ]\r | |
24 | * });\r | |
25 | * \r | |
26 | * Ext.create('Ext.grid.Panel', {\r | |
27 | * renderTo: Ext.getBody(),\r | |
28 | * title: 'Sci-Fi Television',\r | |
29 | * height: 250,\r | |
30 | * width: 375,\r | |
31 | * store: shows,\r | |
32 | * plugins: 'gridfilters',\r | |
33 | * columns: [{\r | |
34 | * dataIndex: 'id',\r | |
35 | * text: 'ID',\r | |
36 | * width: 50\r | |
37 | * },{\r | |
38 | * dataIndex: 'show',\r | |
39 | * text: 'Show',\r | |
40 | * flex: 1 \r | |
41 | * },{\r | |
42 | * xtype: 'datecolumn',\r | |
43 | * dataIndex: 'airDate',\r | |
44 | * text: 'Original Air Date',\r | |
45 | * width: 125,\r | |
46 | * filter: {\r | |
47 | * type: 'date',\r | |
48 | * \r | |
49 | * // optional picker config\r | |
50 | * pickerDefaults: {\r | |
51 | * // any DatePicker configs\r | |
52 | * } \r | |
53 | * }\r | |
54 | * }]\r | |
55 | * }); \r | |
56 | */\r | |
57 | Ext.define('Ext.grid.filters.filter.Date', {\r | |
58 | extend: 'Ext.grid.filters.filter.TriFilter',\r | |
59 | alias: 'grid.filter.date',\r | |
60 | uses: ['Ext.picker.Date', 'Ext.menu.DatePicker'],\r | |
61 | \r | |
62 | type: 'date',\r | |
63 | \r | |
64 | config: {\r | |
65 | //<locale type="object">\r | |
66 | /**\r | |
67 | * @cfg {Object} [fields]\r | |
68 | * Configures field items individually. These properties override those defined\r | |
69 | * by `{@link #itemDefaults}`.\r | |
70 | *\r | |
71 | * Example usage:\r | |
72 | * fields: {\r | |
73 | * gt: { // override fieldCfg options\r | |
74 | * width: 200\r | |
75 | * }\r | |
76 | * },\r | |
77 | */\r | |
78 | fields: {\r | |
79 | lt: {text: 'Before'},\r | |
80 | gt: {text: 'After'},\r | |
81 | eq: {text: 'On'}\r | |
82 | },\r | |
83 | //</locale>\r | |
84 | \r | |
85 | /**\r | |
86 | * @cfg {Object} pickerDefaults\r | |
87 | * Configuration options for the date picker associated with each field.\r | |
88 | */\r | |
89 | pickerDefaults: {\r | |
90 | xtype: 'datepicker',\r | |
91 | border: 0\r | |
92 | },\r | |
93 | \r | |
94 | updateBuffer: 0,\r | |
95 | \r | |
96 | /**\r | |
97 | * @cfg {String} dateFormat\r | |
98 | * The date format to return when using getValue.\r | |
99 | * Defaults to {@link Ext.Date#defaultFormat}.\r | |
100 | */\r | |
101 | dateFormat: undefined\r | |
102 | },\r | |
103 | \r | |
104 | itemDefaults: {\r | |
105 | xtype: 'menucheckitem',\r | |
106 | selectOnFocus: true,\r | |
107 | width: 125,\r | |
108 | menu: {\r | |
109 | layout: 'auto',\r | |
110 | plain: true\r | |
111 | }\r | |
112 | },\r | |
113 | \r | |
114 | /**\r | |
115 | * @cfg {Date} maxDate\r | |
116 | * Allowable date as passed to the Ext.DatePicker\r | |
117 | * Defaults to undefined.\r | |
118 | */\r | |
119 | \r | |
120 | /**\r | |
121 | * @cfg {Date} minDate\r | |
122 | * Allowable date as passed to the Ext.DatePicker\r | |
123 | * Defaults to undefined.\r | |
124 | */\r | |
125 | \r | |
126 | applyDateFormat: function(dateFormat) {\r | |
127 | return dateFormat || Ext.Date.defaultFormat;\r | |
128 | },\r | |
129 | \r | |
130 | /**\r | |
131 | * @private\r | |
132 | * Template method that is to initialize the filter and install required menu items.\r | |
133 | */\r | |
134 | createMenu: function (config) {\r | |
135 | var me = this,\r | |
136 | listeners = {\r | |
137 | scope: me,\r | |
138 | checkchange: me.onCheckChange\r | |
139 | },\r | |
140 | menuItems = me.menuItems,\r | |
141 | fields, itemDefaults, pickerCfg, i, len,\r | |
142 | key, item, cfg, field;\r | |
143 | \r | |
144 | me.callParent(arguments);\r | |
145 | \r | |
146 | itemDefaults = me.getItemDefaults();\r | |
147 | fields = me.getFields();\r | |
148 | \r | |
149 | pickerCfg = Ext.apply({\r | |
150 | minDate: me.minDate,\r | |
151 | maxDate: me.maxDate,\r | |
152 | format: me.dateFormat,\r | |
153 | listeners: {\r | |
154 | scope: me,\r | |
155 | select: me.onMenuSelect\r | |
156 | }\r | |
157 | }, me.getPickerDefaults());\r | |
158 | \r | |
159 | me.fields = {};\r | |
160 | \r | |
161 | for (i = 0, len = menuItems.length; i < len; i++) {\r | |
162 | key = menuItems[i];\r | |
163 | if (key !== '-') {\r | |
164 | cfg = {\r | |
165 | menu: {\r | |
166 | xtype: 'datemenu',\r | |
167 | hideOnClick: false,\r | |
168 | pickerCfg: Ext.apply({\r | |
169 | itemId: key\r | |
170 | }, pickerCfg)\r | |
171 | }\r | |
172 | };\r | |
173 | \r | |
174 | if (itemDefaults) {\r | |
175 | Ext.merge(cfg, itemDefaults);\r | |
176 | }\r | |
177 | \r | |
178 | if (fields) {\r | |
179 | Ext.merge(cfg, fields[key]);\r | |
180 | }\r | |
181 | \r | |
182 | item = me.menu.add(cfg);\r | |
183 | // Date filter types need the field to be the datepicker in TriFilter.setValue().\r | |
184 | field = me.fields[key] = item.down('datepicker');\r | |
185 | field.filter = me.filter[key];\r | |
186 | field.filterKey = key;\r | |
187 | \r | |
188 | item.on(listeners);\r | |
189 | } else {\r | |
190 | me.menu.add(key);\r | |
191 | }\r | |
192 | }\r | |
193 | },\r | |
194 | \r | |
195 | /**\r | |
196 | * Gets the menu picker associated with the passed field\r | |
197 | * @param {String} item The field identifier ('lt', 'gt', 'eq')\r | |
198 | * @return {Object} The menu picker\r | |
199 | */\r | |
200 | getPicker: function (item){\r | |
201 | return this.fields[item];\r | |
202 | },\r | |
203 | \r | |
204 | /**\r | |
205 | * @private\r | |
206 | * Remove the filter from the store but don't update its value or the field UI.\r | |
207 | */\r | |
208 | onCheckChange: function (field, checked) {\r | |
209 | // Only do something if unchecked. If checked, it doesn't mean anything at this point since the column's store filter won't have\r | |
210 | // any value (i.e., if a user checked this from an unchecked state, the corresponding field won't have a value for its filter).\r | |
211 | var filter = field.down('datepicker').filter,\r | |
212 | v;\r | |
213 | \r | |
214 | // Only proceed if unchecked AND there's a filter value (i.e., there's something to do!).\r | |
215 | if (!checked && filter.getValue()) {\r | |
216 | // Normally we just want to remove the filter from the store, not also to null out the filter value. But, we want to call setValue()\r | |
217 | // which will take care of unchecking the top-level menu item if it's been determined that Date* doesn't have any filters.\r | |
218 | v = {};\r | |
219 | v[filter.getOperator()] = null;\r | |
220 | this.setValue(v);\r | |
221 | }\r | |
222 | },\r | |
223 | \r | |
224 | onFilterRemove: function (operator) {\r | |
225 | var v = {};\r | |
226 | \r | |
227 | v[operator] = null;\r | |
228 | this.setValue(v);\r | |
229 | this.fields[operator].up('menuitem').setChecked(false, /*suppressEvents*/ true);\r | |
230 | },\r | |
231 | \r | |
232 | onStateRestore: function(filter) {\r | |
233 | filter.setSerializer(this.getSerializer());\r | |
234 | filter.setConvert(this.convertDateOnly);\r | |
235 | },\r | |
236 | \r | |
237 | getFilterConfig: function(config, key) {\r | |
238 | config = this.callParent([config, key]);\r | |
239 | config.serializer = this.getSerializer();\r | |
240 | config.convert = this.convertDateOnly;\r | |
241 | return config;\r | |
242 | },\r | |
243 | \r | |
244 | convertDateOnly: function(v) {\r | |
245 | var result = null;\r | |
246 | if (v) {\r | |
247 | result = Ext.Date.clearTime(v, true).getTime();\r | |
248 | }\r | |
249 | return result;\r | |
250 | },\r | |
251 | \r | |
252 | getSerializer: function() {\r | |
253 | var me = this;\r | |
254 | return function(data) {\r | |
255 | var value = data.value;\r | |
256 | if (value) {\r | |
257 | data.value = Ext.Date.format(value, me.getDateFormat());\r | |
258 | }\r | |
259 | };\r | |
260 | },\r | |
261 | \r | |
262 | /**\r | |
263 | * Handler for when the DatePicker for a field fires the 'select' event\r | |
264 | * @param {Ext.picker.Date} picker\r | |
265 | * @param {Object} date\r | |
266 | */\r | |
267 | onMenuSelect: function (picker, date) {\r | |
268 | var me = this,\r | |
269 | fields = me.fields,\r | |
270 | filters = me.filter,\r | |
271 | field = fields[picker.itemId],\r | |
272 | gt = fields.gt,\r | |
273 | lt = fields.lt,\r | |
274 | eq = fields.eq,\r | |
275 | v = {};\r | |
276 | \r | |
277 | field.up('menuitem').setChecked(true, /*suppressEvents*/ true);\r | |
278 | \r | |
279 | if (field === eq) {\r | |
280 | lt.up('menuitem').setChecked(false, true);\r | |
281 | gt.up('menuitem').setChecked(false, true);\r | |
282 | } else {\r | |
283 | eq.up('menuitem').setChecked(false, true);\r | |
284 | if (field === gt && (+lt.value < +date)) {\r | |
285 | lt.up('menuitem').setChecked(false, true);\r | |
286 | // Null so filter will be removed from store, but only if it currently has a value.\r | |
287 | // The Trifilter uses the number of removed filters as one of the determinants to determine\r | |
288 | // whether the gridfilter should be active, so don't push a value in unless it's changed.\r | |
289 | if (filters.lt.getValue() != null) {\r | |
290 | v.lt = null;\r | |
291 | }\r | |
292 | } else if (field === lt && (+gt.value > +date)) {\r | |
293 | gt.up('menuitem').setChecked(false, true);\r | |
294 | // Null so filter will be removed from store, but only if it currently has a value.\r | |
295 | // The Trifilter uses the number of removed filters as one of the determinants to determine\r | |
296 | // whether the gridfilter should be active, so don't push a value in unless it's changed.\r | |
297 | if (filters.gt.getValue() != null) {\r | |
298 | v.gt = null;\r | |
299 | }\r | |
300 | }\r | |
301 | }\r | |
302 | \r | |
303 | v[field.filterKey] = date;\r | |
304 | me.setValue(v);\r | |
305 | \r | |
306 | picker.up('menu').hide();\r | |
307 | }\r | |
308 | });\r | |
309 | \r |