3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @docauthor Jason Johnston <jason@sencha.com>
18 * Provides a date input field with a {@link Ext.picker.Date date picker} dropdown and automatic date
21 * This field recognizes and uses the JavaScript Date object as its main {@link #value} type. In addition,
22 * it recognizes string values which are parsed according to the {@link #format} and/or {@link #altFormats}
23 * configs. These may be reconfigured to use date formats appropriate for the user's locale.
25 * The field may be limited to a certain range of dates by using the {@link #minValue}, {@link #maxValue},
26 * {@link #disabledDays}, and {@link #disabledDates} config parameters. These configurations will be used both
27 * in the field's validation, and in the date picker dropdown by preventing invalid dates from being selected.
32 * Ext.create('Ext.form.Panel', {
33 * renderTo: Ext.getBody(),
42 * maxValue: new Date() // limited to the current date or prior
48 * value: new Date() // defaults to today
52 * # Date Formats Examples
54 * This example shows a couple of different date format parsing scenarios. Both use custom date format
55 * configurations; the first one matches the configured `format` while the second matches the `altFormats`.
58 * Ext.create('Ext.form.Panel', {
59 * renderTo: Ext.getBody(),
68 * // The value matches the format; will be parsed and displayed using that format.
76 * // The value does not match the format, but does match an altFormat; will be parsed
77 * // using the altFormat and displayed using the format.
79 * altFormats: 'm,d,Y|m.d.Y',
84 Ext.define('Ext.form.field.Date', {
85 extend:'Ext.form.field.Picker',
86 alias: 'widget.datefield',
87 requires: ['Ext.picker.Date'],
88 alternateClassName: ['Ext.form.DateField', 'Ext.form.Date'],
91 * @cfg {String} format
92 * The default date format string which can be overriden for localization support. The format must be valid
93 * according to {@link Ext.Date#parse}.
97 * @cfg {String} altFormats
98 * Multiple date formats separated by "|" to try when parsing a user input value and it does not match the defined
101 altFormats : "m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d|n-j|n/j",
103 * @cfg {String} disabledDaysText
104 * The tooltip to display when the date falls on a disabled day.
106 disabledDaysText : "Disabled",
108 * @cfg {String} disabledDatesText
109 * The tooltip text to display when the date falls on a disabled date.
111 disabledDatesText : "Disabled",
113 * @cfg {String} minText
114 * The error text to display when the date in the cell is before {@link #minValue}.
116 minText : "The date in this field must be equal to or after {0}",
118 * @cfg {String} maxText
119 * The error text to display when the date in the cell is after {@link #maxValue}.
121 maxText : "The date in this field must be equal to or before {0}",
123 * @cfg {String} invalidText
124 * The error text to display when the date in the field is invalid.
126 invalidText : "{0} is not a valid date - it must be in the format {1}",
128 * @cfg {String} [triggerCls='x-form-date-trigger']
129 * An additional CSS class used to style the trigger button. The trigger will always get the class 'x-form-trigger'
130 * and triggerCls will be **appended** if specified (default class displays a calendar icon).
132 triggerCls : Ext.baseCSSPrefix + 'form-date-trigger',
134 * @cfg {Boolean} showToday
135 * false to hide the footer area of the Date picker containing the Today button and disable the keyboard handler for
136 * spacebar that selects the current date.
140 * @cfg {Date/String} minValue
141 * The minimum allowed date. Can be either a Javascript date object or a string date in a valid format.
144 * @cfg {Date/String} maxValue
145 * The maximum allowed date. Can be either a Javascript date object or a string date in a valid format.
148 * @cfg {Number[]} disabledDays
149 * An array of days to disable, 0 based. Some examples:
151 * // disable Sunday and Saturday:
152 * disabledDays: [0, 6]
153 * // disable weekdays:
154 * disabledDays: [1,2,3,4,5]
157 * @cfg {String[]} disabledDates
158 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so
159 * they are very powerful. Some examples:
161 * // disable these exact dates:
162 * disabledDates: ["03/08/2003", "09/16/2003"]
163 * // disable these days for every year:
164 * disabledDates: ["03/08", "09/16"]
165 * // only match the beginning (useful if you are using short years):
166 * disabledDates: ["^03/08"]
167 * // disable every day in March 2006:
168 * disabledDates: ["03/../2006"]
169 * // disable every day in every March:
170 * disabledDates: ["^03"]
172 * Note that the format of the dates included in the array should exactly match the {@link #format} config. In order
173 * to support regular expressions, if you are using a {@link #format date format} that has "." in it, you will have
174 * to escape the dot when restricting dates. For example: `["03\\.08\\.03"]`.
178 * @cfg {String} submitFormat
179 * The date format string which will be submitted to the server. The format must be valid according to {@link
180 * Ext.Date#parse} (defaults to {@link #format}).
183 // in the absence of a time value, a default value of 12 noon will be used
184 // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
185 initTime: '12', // 24 hour format
189 matchFieldWidth: false,
191 * @cfg {Number} startDay
192 * Day index at which the week should begin, 0-based (defaults to Sunday)
196 initComponent : function(){
198 isString = Ext.isString,
204 me.minValue = me.parseDate(min);
207 me.maxValue = me.parseDate(max);
209 me.disabledDatesRE = null;
210 me.initDisabledDays();
215 initValue: function() {
219 // If a String value was supplied, try to convert it to a proper Date
220 if (Ext.isString(value)) {
221 me.value = me.rawToValue(value);
228 initDisabledDays : function(){
229 if(this.disabledDates){
230 var dd = this.disabledDates,
234 Ext.each(dd, function(d, i){
235 re += Ext.isDate(d) ? '^' + Ext.String.escapeRegex(d.dateFormat(this.format)) + '$' : dd[i];
240 this.disabledDatesRE = new RegExp(re + ')');
245 * Replaces any existing disabled dates with new values and refreshes the Date picker.
246 * @param {String[]} disabledDates An array of date strings (see the {@link #disabledDates} config for details on
247 * supported values) used to disable a pattern of dates.
249 setDisabledDates : function(dd){
253 me.disabledDates = dd;
254 me.initDisabledDays();
256 picker.setDisabledDates(me.disabledDatesRE);
261 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the Date picker.
262 * @param {Number[]} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config for details on
265 setDisabledDays : function(dd){
266 var picker = this.picker;
268 this.disabledDays = dd;
270 picker.setDisabledDays(dd);
275 * Replaces any existing {@link #minValue} with the new value and refreshes the Date picker.
276 * @param {Date} value The minimum date that can be selected
278 setMinValue : function(dt){
281 minValue = (Ext.isString(dt) ? me.parseDate(dt) : dt);
283 me.minValue = minValue;
285 picker.minText = Ext.String.format(me.minText, me.formatDate(me.minValue));
286 picker.setMinDate(minValue);
291 * Replaces any existing {@link #maxValue} with the new value and refreshes the Date picker.
292 * @param {Date} value The maximum date that can be selected
294 setMaxValue : function(dt){
297 maxValue = (Ext.isString(dt) ? me.parseDate(dt) : dt);
299 me.maxValue = maxValue;
301 picker.maxText = Ext.String.format(me.maxText, me.formatDate(me.maxValue));
302 picker.setMaxDate(maxValue);
307 * Runs all of Date's validations and returns an array of any errors. Note that this first runs Text's validations,
308 * so the returned array is an amalgamation of all field errors. The additional validation checks are testing that
309 * the date format is valid, that the chosen date is within the min and max date constraints set, that the date
310 * chosen is not in the disabledDates regex and that the day chosed is not one of the disabledDays.
311 * @param {Object} [value] The value to get errors for (defaults to the current field value)
312 * @return {String[]} All validation errors for this field
314 getErrors: function(value) {
316 format = Ext.String.format,
317 clearTime = Ext.Date.clearTime,
318 errors = me.callParent(arguments),
319 disabledDays = me.disabledDays,
320 disabledDatesRE = me.disabledDatesRE,
321 minValue = me.minValue,
322 maxValue = me.maxValue,
323 len = disabledDays ? disabledDays.length : 0,
330 value = me.formatDate(value || me.processRawValue(me.getRawValue()));
332 if (value === null || value.length < 1) { // if it's blank and textfield didn't flag it then it's valid
337 value = me.parseDate(value);
339 errors.push(format(me.invalidText, svalue, me.format));
343 time = value.getTime();
344 if (minValue && time < clearTime(minValue).getTime()) {
345 errors.push(format(me.minText, me.formatDate(minValue)));
348 if (maxValue && time > clearTime(maxValue).getTime()) {
349 errors.push(format(me.maxText, me.formatDate(maxValue)));
353 day = value.getDay();
355 for(; i < len; i++) {
356 if (day === disabledDays[i]) {
357 errors.push(me.disabledDaysText);
363 fvalue = me.formatDate(value);
364 if (disabledDatesRE && disabledDatesRE.test(fvalue)) {
365 errors.push(format(me.disabledDatesText, fvalue));
371 rawToValue: function(rawValue) {
372 return this.parseDate(rawValue) || rawValue || null;
375 valueToRaw: function(value) {
376 return this.formatDate(this.parseDate(value));
381 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid date,
382 * using {@link #format} as the date format, according to the same rules as {@link Ext.Date#parse} (the default
383 * format used is "m/d/Y").
387 * //All of these calls set the same date value (May 4, 2006)
389 * //Pass a date object:
390 * var dt = new Date('5/4/2006');
391 * dateField.setValue(dt);
393 * //Pass a date string (default format):
394 * dateField.setValue('05/04/2006');
396 * //Pass a date string (custom format):
397 * dateField.format = 'Y-m-d';
398 * dateField.setValue('2006-05-04');
400 * @param {String/Date} date The date or valid date string
401 * @return {Ext.form.field.Date} this
405 * Attempts to parse a given string value using a given {@link Ext.Date#parse date format}.
406 * @param {String} value The value to attempt to parse
407 * @param {String} format A valid date format (see {@link Ext.Date#parse})
408 * @return {Date} The parsed Date object, or null if the value could not be successfully parsed.
410 safeParse : function(value, format) {
416 if (utilDate.formatContainsHourInfo(format)) {
417 // if parse format contains hour information, no DST adjustment is necessary
418 result = utilDate.parse(value, format);
420 // set time to 12 noon, then clear the time
421 parsedDate = utilDate.parse(value + ' ' + me.initTime, format + ' ' + me.initTimeFormat);
423 result = utilDate.clearTime(parsedDate);
430 getSubmitValue: function() {
431 var format = this.submitFormat || this.format,
432 value = this.getValue();
434 return value ? Ext.Date.format(value, format) : '';
440 parseDate : function(value) {
441 if(!value || Ext.isDate(value)){
446 val = me.safeParse(value, me.format),
447 altFormats = me.altFormats,
448 altFormatsArray = me.altFormatsArray,
452 if (!val && altFormats) {
453 altFormatsArray = altFormatsArray || altFormats.split('|');
454 len = altFormatsArray.length;
455 for (; i < len && !val; ++i) {
456 val = me.safeParse(value, altFormatsArray[i]);
463 formatDate : function(date){
464 return Ext.isDate(date) ? Ext.Date.dateFormat(date, this.format) : date;
467 createPicker: function() {
469 format = Ext.String.format;
471 return Ext.create('Ext.picker.Date', {
474 renderTo: document.body,
478 minDate: me.minValue,
479 maxDate: me.maxValue,
480 disabledDatesRE: me.disabledDatesRE,
481 disabledDatesText: me.disabledDatesText,
482 disabledDays: me.disabledDays,
483 disabledDaysText: me.disabledDaysText,
485 showToday: me.showToday,
486 startDay: me.startDay,
487 minText: format(me.minText, me.formatDate(me.minValue)),
488 maxText: format(me.maxText, me.formatDate(me.maxValue)),
501 onSelect: function(m, d) {
505 me.fireEvent('select', me, d);
511 * Sets the Date picker's value to match the current field value when expanding.
513 onExpand: function() {
514 var value = this.getValue();
515 this.picker.setValue(Ext.isDate(value) ? value : new Date());
520 * Focuses the field when collapsing the Date picker.
522 onCollapse: function() {
523 this.focus(false, 60);
527 beforeBlur : function(){
529 v = me.parseDate(me.getRawValue()),
530 focusTask = me.focusTask;
543 * @cfg {Boolean} grow
547 * @cfg {Number} growMin
551 * @cfg {Number} growMax