]> git.proxmox.com Git - extjs.git/blame - extjs/modern/modern/src/picker/Date.js
add extjs 6.0.1 sources
[extjs.git] / extjs / modern / modern / src / picker / Date.js
CommitLineData
6527f429
DM
1/**\r
2 * A date picker component which shows a Date Picker on the screen. This class extends from {@link Ext.picker.Picker}\r
3 * and {@link Ext.Sheet} so it is a popup.\r
4 *\r
5 * This component has no required configurations.\r
6 *\r
7 * ## Examples\r
8 *\r
9 * @example miniphone preview\r
10 * var datePicker = Ext.create('Ext.picker.Date');\r
11 * Ext.Viewport.add(datePicker);\r
12 * datePicker.show();\r
13 *\r
14 * You may want to adjust the {@link #yearFrom} and {@link #yearTo} properties:\r
15 *\r
16 * @example miniphone preview\r
17 * var datePicker = Ext.create('Ext.picker.Date', {\r
18 * yearFrom: 2000,\r
19 * yearTo : 2015\r
20 * });\r
21 * Ext.Viewport.add(datePicker);\r
22 * datePicker.show();\r
23 *\r
24 * You can set the value of the {@link Ext.picker.Date} to the current date using `new Date()`:\r
25 *\r
26 * @example miniphone preview\r
27 * var datePicker = Ext.create('Ext.picker.Date', {\r
28 * value: new Date()\r
29 * });\r
30 * Ext.Viewport.add(datePicker);\r
31 * datePicker.show();\r
32 *\r
33 * And you can hide the titles from each of the slots by using the {@link #useTitles} configuration:\r
34 *\r
35 * @example miniphone preview\r
36 * var datePicker = Ext.create('Ext.picker.Date', {\r
37 * useTitles: false\r
38 * });\r
39 * Ext.Viewport.add(datePicker);\r
40 * datePicker.show();\r
41 */\r
42Ext.define('Ext.picker.Date', {\r
43 extend: 'Ext.picker.Picker',\r
44 xtype: 'datepicker',\r
45 alternateClassName: 'Ext.DatePicker',\r
46 requires: ['Ext.util.InputBlocker'],\r
47\r
48 /**\r
49 * @event change\r
50 * Fired when the value of this picker has changed and the done button is pressed.\r
51 * @param {Ext.picker.Date} this This Picker\r
52 * @param {Date} value The date value\r
53 */\r
54\r
55 config: {\r
56 /**\r
57 * @cfg {Number} yearFrom\r
58 * The start year for the date picker. If {@link #yearFrom} is greater than\r
59 * {@link #yearTo} then the order of years will be reversed.\r
60 * @accessor\r
61 */\r
62 yearFrom: 1980,\r
63\r
64 /**\r
65 * @cfg {Number} [yearTo=new Date().getFullYear()]\r
66 * The last year for the date picker. If {@link #yearFrom} is greater than\r
67 * {@link #yearTo} then the order of years will be reversed.\r
68 * @accessor\r
69 */\r
70 yearTo: new Date().getFullYear(),\r
71\r
72 /**\r
73 * @cfg {String} monthText\r
74 * The label to show for the month column.\r
75 * @accessor\r
76 */\r
77 monthText: 'Month',\r
78\r
79 /**\r
80 * @cfg {String} dayText\r
81 * The label to show for the day column.\r
82 * @accessor\r
83 */\r
84 dayText: 'Day',\r
85\r
86 /**\r
87 * @cfg {String} yearText\r
88 * The label to show for the year column.\r
89 * @accessor\r
90 */\r
91 yearText: 'Year',\r
92\r
93 /**\r
94 * @cfg {Array} slotOrder\r
95 * An array of strings that specifies the order of the slots.\r
96 * @accessor\r
97 */\r
98 slotOrder: ['month', 'day', 'year'],\r
99\r
100 /**\r
101 * @cfg {Object/Date} value\r
102 * Default value for the field and the internal {@link Ext.picker.Date} component. Accepts an object of 'year',\r
103 * 'month' and 'day' values, all of which should be numbers, or a {@link Date}.\r
104 *\r
105 * Examples:\r
106 *\r
107 * - `{year: 1989, day: 1, month: 5}` = 1st May 1989\r
108 * - `new Date()` = current date\r
109 * @accessor\r
110 */\r
111\r
112 /**\r
113 * @cfg {Array} slots\r
114 * @hide\r
115 * @accessor\r
116 */\r
117\r
118 /**\r
119 * @cfg {String/Mixed} doneButton\r
120 * Can be either:\r
121 *\r
122 * - A {String} text to be used on the Done button.\r
123 * - An {Object} as config for {@link Ext.Button}.\r
124 * - `false` or `null` to hide it.\r
125 * @accessor\r
126 */\r
127 doneButton: true\r
128 },\r
129\r
130 initialize: function() {\r
131 this.callParent();\r
132\r
133 this.on({\r
134 scope: this,\r
135 delegate: '> slot',\r
136 slotpick: this.onSlotPick\r
137 });\r
138\r
139 this.on({\r
140 scope: this,\r
141 show: this.onSlotPick\r
142 });\r
143 },\r
144\r
145 setValue: function(value, animated) {\r
146 if (Ext.isDate(value)) {\r
147 value = {\r
148 day : value.getDate(),\r
149 month: value.getMonth() + 1,\r
150 year : value.getFullYear()\r
151 };\r
152 }\r
153\r
154 this.callParent([value, animated]);\r
155 this.onSlotPick();\r
156 },\r
157\r
158 getValue: function(useDom) {\r
159 var values = {},\r
160 items = this.getItems().items,\r
161 ln = items.length,\r
162 daysInMonth, day, month, year, item, i;\r
163\r
164 for (i = 0; i < ln; i++) {\r
165 item = items[i];\r
166 if (item instanceof Ext.picker.Slot) {\r
167 values[item.getName()] = item.getValue(useDom);\r
168 }\r
169 }\r
170\r
171 //if all the slots return null, we should not return a date\r
172 if (values.year === null && values.month === null && values.day === null) {\r
173 return null;\r
174 }\r
175\r
176 year = Ext.isNumber(values.year) ? values.year : 1;\r
177 month = Ext.isNumber(values.month) ? values.month : 1;\r
178 day = Ext.isNumber(values.day) ? values.day : 1;\r
179\r
180 if (month && year && month && day) {\r
181 daysInMonth = this.getDaysInMonth(month, year);\r
182 }\r
183 day = (daysInMonth) ? Math.min(day, daysInMonth): day;\r
184\r
185 return new Date(year, month - 1, day);\r
186 },\r
187\r
188 /**\r
189 * Updates the yearFrom configuration\r
190 */\r
191 updateYearFrom: function() {\r
192 if (this.initialized) {\r
193 this.createSlots();\r
194 }\r
195 },\r
196\r
197 /**\r
198 * Updates the yearTo configuration\r
199 */\r
200 updateYearTo: function() {\r
201 if (this.initialized) {\r
202 this.createSlots();\r
203 }\r
204 },\r
205\r
206 /**\r
207 * Updates the monthText configuration\r
208 */\r
209 updateMonthText: function(newMonthText, oldMonthText) {\r
210 var innerItems = this.getInnerItems,\r
211 ln = innerItems.length,\r
212 item, i;\r
213\r
214 //loop through each of the current items and set the title on the correct slice\r
215 if (this.initialized) {\r
216 for (i = 0; i < ln; i++) {\r
217 item = innerItems[i];\r
218\r
219 if ((typeof item.title == "string" && item.title == oldMonthText) || (item.title.html == oldMonthText)) {\r
220 item.setTitle(newMonthText);\r
221 }\r
222 }\r
223 }\r
224 },\r
225\r
226 /**\r
227 * Updates the {@link #dayText} configuration.\r
228 */\r
229 updateDayText: function(newDayText, oldDayText) {\r
230 var innerItems = this.getInnerItems,\r
231 ln = innerItems.length,\r
232 item, i;\r
233\r
234 //loop through each of the current items and set the title on the correct slice\r
235 if (this.initialized) {\r
236 for (i = 0; i < ln; i++) {\r
237 item = innerItems[i];\r
238\r
239 if ((typeof item.title == "string" && item.title == oldDayText) || (item.title.html == oldDayText)) {\r
240 item.setTitle(newDayText);\r
241 }\r
242 }\r
243 }\r
244 },\r
245\r
246 /**\r
247 * Updates the yearText configuration\r
248 */\r
249 updateYearText: function(yearText) {\r
250 var innerItems = this.getInnerItems,\r
251 ln = innerItems.length,\r
252 item, i;\r
253\r
254 //loop through each of the current items and set the title on the correct slice\r
255 if (this.initialized) {\r
256 for (i = 0; i < ln; i++) {\r
257 item = innerItems[i];\r
258\r
259 if (item.title == this.yearText) {\r
260 item.setTitle(yearText);\r
261 }\r
262 }\r
263 }\r
264 },\r
265\r
266 /**\r
267 * @private\r
268 */\r
269 constructor: function() {\r
270 this.callParent(arguments);\r
271 this.createSlots();\r
272 },\r
273\r
274 /**\r
275 * Generates all slots for all years specified by this component, and then sets them on the component\r
276 * @private\r
277 */\r
278 createSlots: function() {\r
279 var me = this,\r
280 slotOrder = me.getSlotOrder(),\r
281 yearsFrom = me.getYearFrom(),\r
282 yearsTo = me.getYearTo(),\r
283 years = [],\r
284 days = [],\r
285 months = [],\r
286 reverse = yearsFrom > yearsTo,\r
287 ln, i, daysInMonth;\r
288\r
289 while (yearsFrom) {\r
290 years.push({\r
291 text : yearsFrom,\r
292 value : yearsFrom\r
293 });\r
294\r
295 if (yearsFrom === yearsTo) {\r
296 break;\r
297 }\r
298\r
299 if (reverse) {\r
300 yearsFrom--;\r
301 } else {\r
302 yearsFrom++;\r
303 }\r
304 }\r
305\r
306 daysInMonth = me.getDaysInMonth(1, new Date().getFullYear());\r
307\r
308 for (i = 0; i < daysInMonth; i++) {\r
309 days.push({\r
310 text : i + 1,\r
311 value : i + 1\r
312 });\r
313 }\r
314\r
315 for (i = 0, ln = Ext.Date.monthNames.length; i < ln; i++) {\r
316 months.push({\r
317 text : Ext.Date.monthNames[i],\r
318 value : i + 1\r
319 });\r
320 }\r
321\r
322 var slots = [];\r
323\r
324 slotOrder.forEach(function (item) {\r
325 slots.push(me.createSlot(item, days, months, years));\r
326 });\r
327\r
328 me.setSlots(slots);\r
329 },\r
330\r
331 /**\r
332 * Returns a slot config for a specified date.\r
333 * @private\r
334 */\r
335 createSlot: function(name, days, months, years) {\r
336 switch (name) {\r
337 case 'year':\r
338 return {\r
339 name: 'year',\r
340 align: 'center',\r
341 data: years,\r
342 title: this.getYearText(),\r
343 flex: 3\r
344 };\r
345 case 'month':\r
346 return {\r
347 name: name,\r
348 align: 'right',\r
349 data: months,\r
350 title: this.getMonthText(),\r
351 flex: 4\r
352 };\r
353 case 'day':\r
354 return {\r
355 name: 'day',\r
356 align: 'center',\r
357 data: days,\r
358 title: this.getDayText(),\r
359 flex: 2\r
360 };\r
361 }\r
362 },\r
363\r
364 onSlotPick: function() {\r
365 var value = this.getValue(true),\r
366 slot = this.getDaySlot(),\r
367 year = value.getFullYear(),\r
368 month = value.getMonth(),\r
369 days = [],\r
370 daysInMonth, i;\r
371\r
372 if (!value || !Ext.isDate(value) || !slot) {\r
373 return;\r
374 }\r
375\r
376 this.callParent(arguments);\r
377\r
378 //get the new days of the month for this new date\r
379 daysInMonth = this.getDaysInMonth(month + 1, year);\r
380 for (i = 0; i < daysInMonth; i++) {\r
381 days.push({\r
382 text: i + 1,\r
383 value: i + 1\r
384 });\r
385 }\r
386\r
387 // We don't need to update the slot days unless it has changed\r
388 if (slot.getStore().getCount() == days.length) {\r
389 return;\r
390 }\r
391\r
392 slot.getStore().setData(days);\r
393\r
394 // Now we have the correct amount of days for the day slot, lets update it\r
395 var store = slot.getStore(),\r
396 viewItems = slot.getViewItems(),\r
397 valueField = slot.getValueField(),\r
398 index, item;\r
399\r
400 index = store.find(valueField, value.getDate());\r
401 if (index == -1) {\r
402 return;\r
403 }\r
404\r
405 item = Ext.get(viewItems[index]);\r
406\r
407 slot.selectedIndex = index;\r
408 slot.scrollToItem(item);\r
409 slot.setValue(slot.getValue(true));\r
410 },\r
411\r
412 getDaySlot: function() {\r
413 var innerItems = this.getInnerItems(),\r
414 ln = innerItems.length,\r
415 i, slot;\r
416\r
417 if (this.daySlot) {\r
418 return this.daySlot;\r
419 }\r
420\r
421 for (i = 0; i < ln; i++) {\r
422 slot = innerItems[i];\r
423 if (slot.isSlot && slot.getName() == "day") {\r
424 this.daySlot = slot;\r
425 return slot;\r
426 }\r
427 }\r
428\r
429 return null;\r
430 },\r
431\r
432 /**\r
433 * @private\r
434 */\r
435 getDaysInMonth: function(month, year) {\r
436 var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\r
437 return month == 2 && this.isLeapYear(year) ? 29 : daysInMonth[month-1];\r
438 },\r
439\r
440 /**\r
441 * @private\r
442 */\r
443 isLeapYear: function(year) {\r
444 return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));\r
445 },\r
446\r
447 onDoneButtonTap: function() {\r
448 var oldValue = this._value,\r
449 newValue = this.getValue(true),\r
450 testValue = newValue;\r
451\r
452 if (Ext.isDate(newValue)) {\r
453 testValue = newValue.toDateString();\r
454 }\r
455 if (Ext.isDate(oldValue)) {\r
456 oldValue = oldValue.toDateString();\r
457 }\r
458\r
459 if (testValue != oldValue) {\r
460 this.fireEvent('change', this, newValue);\r
461 }\r
462\r
463 this.hide();\r
464 Ext.util.InputBlocker.unblockInputs();\r
465 }\r
466});