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 * @class Ext.form.field.Time
17 * @extends Ext.form.field.Picker
18 * <p>Provides a time input field with a time dropdown and automatic time validation.</p>
19 * <p>This field recognizes and uses JavaScript Date objects as its main {@link #value} type (only the time
20 * portion of the date is used; the month/day/year are ignored). In addition, it recognizes string values which
21 * are parsed according to the {@link #format} and/or {@link #altFormats} configs. These may be reconfigured
22 * to use time formats appropriate for the user's locale.</p>
23 * <p>The field may be limited to a certain range of times by using the {@link #minValue} and {@link #maxValue}
24 * configs, and the interval between time options in the dropdown can be changed with the {@link #increment} config.</p>
25 * {@img Ext.form.Time/Ext.form.Time.png Ext.form.Time component}
26 * <p>Example usage:</p>
28 Ext.create('Ext.form.Panel', {
32 renderTo: Ext.getBody(),
36 fieldLabel: 'Time In',
44 fieldLabel: 'Time Out',
53 Ext.define('Ext.form.field.Time', {
54 extend:'Ext.form.field.Picker',
55 alias: 'widget.timefield',
56 requires: ['Ext.form.field.Date', 'Ext.picker.Time', 'Ext.view.BoundListKeyNav', 'Ext.Date'],
57 alternateClassName: ['Ext.form.TimeField', 'Ext.form.Time'],
60 * @cfg {String} triggerCls
61 * An additional CSS class used to style the trigger button. The trigger will always get the
62 * {@link #triggerBaseCls} by default and <tt>triggerCls</tt> will be <b>appended</b> if specified.
63 * Defaults to <tt>'x-form-time-trigger'</tt> for the Time field trigger.
65 triggerCls: Ext.baseCSSPrefix + 'form-time-trigger',
68 * @cfg {Date/String} minValue
69 * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string
70 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
74 * @cfg {Date/String} maxValue
75 * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string
76 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
80 * @cfg {String} minText
81 * The error text to display when the entered time is before {@link #minValue} (defaults to
82 * 'The time in this field must be equal to or after {0}').
84 minText : "The time in this field must be equal to or after {0}",
87 * @cfg {String} maxText
88 * The error text to display when the entered time is after {@link #maxValue} (defaults to
89 * 'The time in this field must be equal to or before {0}').
91 maxText : "The time in this field must be equal to or before {0}",
94 * @cfg {String} invalidText
95 * The error text to display when the time in the field is invalid (defaults to
96 * '{value} is not a valid time').
98 invalidText : "{0} is not a valid time",
101 * @cfg {String} format
102 * The default time format string which can be overriden for localization support. The format must be
103 * valid according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time
104 * format try 'H:i' instead.
109 * @cfg {String} submitFormat The date format string which will be submitted to the server.
110 * The format must be valid according to {@link Ext.Date#parse} (defaults to <tt>{@link #format}</tt>).
114 * @cfg {String} altFormats
115 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
116 * format (defaults to 'g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A').
118 altFormats : "g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A",
121 * @cfg {Number} increment
122 * The number of minutes between each time value in the list (defaults to 15).
127 * @cfg {Number} pickerMaxHeight
128 * The maximum height of the {@link Ext.picker.Time} dropdown. Defaults to 300.
130 pickerMaxHeight: 300,
133 * @cfg {Boolean} selectOnTab
134 * Whether the Tab key should select the currently highlighted item. Defaults to <tt>true</tt>.
140 * This is the date to use when generating time values in the absence of either minValue
141 * or maxValue. Using the current date causes DST issues on DST boundary dates, so this is an
142 * arbitrary "safe" date that can be any date aside from DST boundary dates.
144 initDate: '1/1/2008',
145 initDateFormat: 'j/n/Y',
148 initComponent: function() {
161 initValue: function() {
165 // If a String value was supplied, try to convert it to a proper Date object
166 if (Ext.isString(value)) {
167 me.value = me.rawToValue(value);
174 * Replaces any existing {@link #minValue} with the new time and refreshes the picker's range.
175 * @param {Date/String} value The minimum time that can be selected
177 setMinValue: function(value) {
180 me.setLimit(value, true);
182 picker.setMinValue(me.minValue);
187 * Replaces any existing {@link #maxValue} with the new time and refreshes the picker's range.
188 * @param {Date/String} value The maximum time that can be selected
190 setMaxValue: function(value) {
193 me.setLimit(value, false);
195 picker.setMaxValue(me.maxValue);
201 * Updates either the min or max value. Converts the user's value into a Date object whose
202 * year/month/day is set to the {@link #initDate} so that only the time fields are significant.
204 setLimit: function(value, isMin) {
207 if (Ext.isString(value)) {
208 d = me.parseDate(value);
210 else if (Ext.isDate(value)) {
214 val = Ext.Date.clearTime(new Date(me.initDate));
215 val.setHours(d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
216 me[isMin ? 'minValue' : 'maxValue'] = val;
220 rawToValue: function(rawValue) {
221 return this.parseDate(rawValue) || rawValue || null;
224 valueToRaw: function(value) {
225 return this.formatDate(this.parseDate(value));
229 * Runs all of Time's validations and returns an array of any errors. Note that this first
230 * runs Text's validations, so the returned array is an amalgamation of all field errors.
231 * The additional validation checks are testing that the time format is valid, that the chosen
232 * time is within the {@link #minValue} and {@link #maxValue} constraints set.
233 * @param {Mixed} value The value to get errors for (defaults to the current field value)
234 * @return {Array} All validation errors for this field
236 getErrors: function(value) {
238 format = Ext.String.format,
239 errors = me.callParent(arguments),
240 minValue = me.minValue,
241 maxValue = me.maxValue,
244 value = me.formatDate(value || me.processRawValue(me.getRawValue()));
246 if (value === null || value.length < 1) { // if it's blank and textfield didn't flag it then it's valid
250 date = me.parseDate(value);
252 errors.push(format(me.invalidText, value, me.format));
256 if (minValue && date < minValue) {
257 errors.push(format(me.minText, me.formatDate(minValue)));
260 if (maxValue && date > maxValue) {
261 errors.push(format(me.maxText, me.formatDate(maxValue)));
267 formatDate: function() {
268 return Ext.form.field.Date.prototype.formatDate.apply(this, arguments);
273 * Parses an input value into a valid Date object.
274 * @param {String/Date} value
276 parseDate: function(value) {
277 if (!value || Ext.isDate(value)) {
282 val = me.safeParse(value, me.format),
283 altFormats = me.altFormats,
284 altFormatsArray = me.altFormatsArray,
288 if (!val && altFormats) {
289 altFormatsArray = altFormatsArray || altFormats.split('|');
290 len = altFormatsArray.length;
291 for (; i < len && !val; ++i) {
292 val = me.safeParse(value, altFormatsArray[i]);
298 safeParse: function(value, format){
304 if (utilDate.formatContainsDateInfo(format)) {
305 // assume we've been given a full date
306 result = utilDate.parse(value, format);
308 // Use our initial safe date
309 parsedDate = utilDate.parse(me.initDate + ' ' + value, me.initDateFormat + ' ' + format);
318 getSubmitValue: function() {
320 format = me.submitFormat || me.format,
321 value = me.getValue();
323 return value ? Ext.Date.format(value, format) : null;
328 * Creates the {@link Ext.picker.Time}
330 createPicker: function() {
332 picker = Ext.create('Ext.picker.Time', {
338 minValue: me.minValue,
339 maxValue: me.maxValue,
340 increment: me.increment,
342 ownerCt: this.ownerCt,
343 renderTo: document.body,
344 maxHeight: me.pickerMaxHeight,
345 focusOnToFront: false
348 me.mon(picker.getSelectionModel(), {
349 selectionchange: me.onListSelect,
358 * Enables the key nav for the Time picker when it is expanded.
359 * TODO this is largely the same logic as ComboBox, should factor out.
361 onExpand: function() {
363 keyNav = me.pickerKeyNav,
364 selectOnTab = me.selectOnTab,
365 picker = me.getPicker(),
366 lastSelected = picker.getSelectionModel().lastSelected,
370 keyNav = me.pickerKeyNav = Ext.create('Ext.view.BoundListKeyNav', this.inputEl, {
375 if(me.picker.highlightedItem) {
376 this.selectHighlighted(e);
382 // Tab key event is allowed to propagate to field
386 // stop tab monitoring from Ext.form.field.Trigger so it doesn't short-circuit selectOnTab
388 me.ignoreMonitorTab = true;
391 Ext.defer(keyNav.enable, 1, keyNav); //wait a bit so it doesn't react to the down arrow opening the picker
393 // Highlight the last selected item and scroll it into view
395 itemNode = picker.getNode(lastSelected);
397 picker.highlightItem(itemNode);
398 picker.el.scrollChildIntoView(itemNode, false);
405 * Disables the key nav for the Time picker when it is collapsed.
407 onCollapse: function() {
409 keyNav = me.pickerKeyNav;
412 me.ignoreMonitorTab = false;
418 * Clears the highlighted item in the picker on change.
419 * This prevents the highlighted item from being selected instead of the custom typed in value when the tab key is pressed.
421 onChange: function() {
425 me.callParent(arguments);
427 picker.clearHighlight();
433 * Handles a time being selected from the Time picker.
435 onListSelect: function(list, recordArray) {
437 record = recordArray[0],
438 val = record ? record.get('date') : null;
440 me.fireEvent('select', me, val);
441 me.picker.clearHighlight();