X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/7a654f8d43fdb43d78b63d90528bed6e86b608cc..6746dc89c47ed01b165cc1152533605f97eb8e8d:/docs/source/Time2.html diff --git a/docs/source/Time2.html b/docs/source/Time2.html index c12966e2..5a9b0788 100644 --- a/docs/source/Time2.html +++ b/docs/source/Time2.html @@ -1,172 +1,452 @@ -Sencha Documentation Project
/**
- * @class Ext.picker.Time
- * @extends Ext.view.BoundList
- * <p>A time picker which provides a list of times from which to choose. This is used by the
- * {@link Ext.form.field.Time} class to allow browsing and selection of valid times, but could also be used
- * with other components.</p>
- * <p>By default, all times starting at midnight and incrementing every 15 minutes will be presented.
- * This list of available times can be controlled using the {@link #minValue}, {@link #maxValue}, and
- * {@link #increment} configuration properties. The format of the times presented in the list can be
- * customized with the {@link #format} config.</p>
- * <p>To handle when the user selects a time from the list, you can subscribe to the {@link #selectionchange}
- * event.</p>
- *
- * {@img Ext.picker.Time/Ext.picker.Time.png Ext.picker.Time component}
- *
- * ## Code
-     new Ext.create('Ext.picker.Time', {
-        width: 60,
-        minValue: Ext.Date.parse('04:30:00 AM', 'h:i:s A'),
-        maxValue: Ext.Date.parse('08:00:00 AM', 'h:i:s A'),
-        renderTo: Ext.getBody()
-    });
- *
- * @constructor
- * Create a new TimePicker
- * @param {Object} config The config object
- *
- * @xtype timepicker
+
+
+
+  
+  The source code
+  
+  
+  
+  
+
+
+  
/**
+ * @class Ext.form.field.Time
+ * @extends Ext.form.field.Picker
+ * <p>Provides a time input field with a time dropdown and automatic time validation.</p>
+ * <p>This field recognizes and uses JavaScript Date objects as its main {@link #value} type (only the time
+ * portion of the date is used; the month/day/year are ignored). In addition, it recognizes string values which
+ * are parsed according to the {@link #format} and/or {@link #altFormats} configs. These may be reconfigured
+ * to use time formats appropriate for the user's locale.</p>
+ * <p>The field may be limited to a certain range of times by using the {@link #minValue} and {@link #maxValue}
+ * configs, and the interval between time options in the dropdown can be changed with the {@link #increment} config.</p>
+ * {@img Ext.form.Time/Ext.form.Time.png Ext.form.Time component}
+ * <p>Example usage:</p>
+ * <pre><code>
+Ext.create('Ext.form.Panel', {
+    title: 'Time Card',
+    width: 300,
+    bodyPadding: 10,
+    renderTo: Ext.getBody(),        
+    items: [{
+        xtype: 'timefield',
+        name: 'in',
+        fieldLabel: 'Time In',
+        minValue: '6:00 AM',
+        maxValue: '8:00 PM',
+        increment: 30,
+        anchor: '100%'
+    }, {
+        xtype: 'timefield',
+        name: 'out',
+        fieldLabel: 'Time Out',
+        minValue: '6:00 AM',
+        maxValue: '8:00 PM',
+        increment: 30,
+        anchor: '100%'
+   }]
+});
+</code></pre>
  */
-Ext.define('Ext.picker.Time', {
-    extend: 'Ext.view.BoundList',
-    alias: 'widget.timepicker',
-    requires: ['Ext.data.Store', 'Ext.Date'],
+Ext.define('Ext.form.field.Time', {
+    extend:'Ext.form.field.Picker',
+    alias: 'widget.timefield',
+    requires: ['Ext.form.field.Date', 'Ext.picker.Time', 'Ext.view.BoundListKeyNav', 'Ext.Date'],
+    alternateClassName: ['Ext.form.TimeField', 'Ext.form.Time'],
 
-    /**
-     * @cfg {Date} minValue
-     * The minimum time to be shown in the list of times. This must be a Date object (only the time fields
-     * will be used); no parsing of String values will be done. Defaults to undefined.
+    /**
+     * @cfg {String} triggerCls
+     * An additional CSS class used to style the trigger button.  The trigger will always get the
+     * {@link #triggerBaseCls} by default and <tt>triggerCls</tt> will be <b>appended</b> if specified.
+     * Defaults to <tt>'x-form-time-trigger'</tt> for the Time field trigger.
      */
+    triggerCls: Ext.baseCSSPrefix + 'form-time-trigger',
 
-    /**
-     * @cfg {Date} maxValue
-     * The maximum time to be shown in the list of times. This must be a Date object (only the time fields
-     * will be used); no parsing of String values will be done. Defaults to undefined.
+    /**
+     * @cfg {Date/String} minValue
+     * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string
+     * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
      */
 
-    /**
-     * @cfg {Number} increment
-     * The number of minutes between each time value in the list (defaults to 15).
+    /**
+     * @cfg {Date/String} maxValue
+     * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string
+     * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
      */
-    increment: 15,
 
-    /**
+    /**
+     * @cfg {String} minText
+     * The error text to display when the entered time is before {@link #minValue} (defaults to
+     * 'The time in this field must be equal to or after {0}').
+     */
+    minText : "The time in this field must be equal to or after {0}",
+
+    /**
+     * @cfg {String} maxText
+     * The error text to display when the entered time is after {@link #maxValue} (defaults to
+     * 'The time in this field must be equal to or before {0}').
+     */
+    maxText : "The time in this field must be equal to or before {0}",
+
+    /**
+     * @cfg {String} invalidText
+     * The error text to display when the time in the field is invalid (defaults to
+     * '{value} is not a valid time').
+     */
+    invalidText : "{0} is not a valid time",
+
+    /**
      * @cfg {String} format
-     * The default time format string which can be overriden for localization support. The format must be
-     * valid according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time
+     * The default time format string which can be overriden for localization support.  The format must be
+     * valid according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM').  For 24-hour time
      * format try 'H:i' instead.
      */
     format : "g:i A",
 
-    /**
-     * @hide
-     * The field in the implicitly-generated Model objects that gets displayed in the list. This is
-     * an internal field name only and is not useful to change via config.
+    /**
+     * @cfg {String} submitFormat The date format string which will be submitted to the server.
+     * The format must be valid according to {@link Ext.Date#parse} (defaults to <tt>{@link #format}</tt>).
      */
-    displayField: 'disp',
 
-    /**
-     * @private
-     * Year, month, and day that all times will be normalized into internally.
+    /**
+     * @cfg {String} altFormats
+     * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
+     * 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').
+     */
+    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",
+
+    /**
+     * @cfg {Number} increment
+     * The number of minutes between each time value in the list (defaults to 15).
      */
-    initDate: [2008,1,1],
+    increment: 15,
 
-    componentCls: Ext.baseCSSPrefix + 'timepicker',
+    /**
+     * @cfg {Number} pickerMaxHeight
+     * The maximum height of the {@link Ext.picker.Time} dropdown. Defaults to 300.
+     */
+    pickerMaxHeight: 300,
 
-    /**
-     * @hide
+    /**
+     * @cfg {Boolean} selectOnTab
+     * Whether the Tab key should select the currently highlighted item. Defaults to <tt>true</tt>.
      */
-    loadingText: '',
+    selectOnTab: true,
+
+    /**
+     * @private
+     * This is the date to use when generating time values in the absence of either minValue
+     * or maxValue.  Using the current date causes DST issues on DST boundary dates, so this is an
+     * arbitrary "safe" date that can be any date aside from DST boundary dates.
+     */
+    initDate: '1/1/2008',
+    initDateFormat: 'j/n/Y',
+
 
     initComponent: function() {
         var me = this,
-            dateUtil = Ext.Date,
-            clearTime = dateUtil.clearTime,
-            initDate = me.initDate.join('/');
+            min = me.minValue,
+            max = me.maxValue;
+        if (min) {
+            me.setMinValue(min);
+        }
+        if (max) {
+            me.setMaxValue(max);
+        }
+        this.callParent();
+    },
 
-        // Set up absolute min and max for the entire day
-        me.absMin = clearTime(new Date(initDate));
-        me.absMax = dateUtil.add(clearTime(new Date(initDate)), 'mi', (24 * 60) - 1);
+    initValue: function() {
+        var me = this,
+            value = me.value;
 
-        me.store = me.createStore();
-        me.updateList();
+        // If a String value was supplied, try to convert it to a proper Date object
+        if (Ext.isString(value)) {
+            me.value = me.rawToValue(value);
+        }
 
-        this.callParent();
+        me.callParent();
     },
 
-    /**
-     * Set the {@link #minValue} and update the list of available times. This must be a Date
-     * object (only the time fields will be used); no parsing of String values will be done.
-     * @param {Date} value
+    /**
+     * Replaces any existing {@link #minValue} with the new time and refreshes the picker's range.
+     * @param {Date/String} value The minimum time that can be selected
      */
     setMinValue: function(value) {
-        this.minValue = value;
-        this.updateList();
+        var me = this,
+            picker = me.picker;
+        me.setLimit(value, true);
+        if (picker) {
+            picker.setMinValue(me.minValue);
+        }
     },
 
-    /**
-     * Set the {@link #maxValue} and update the list of available times. This must be a Date
-     * object (only the time fields will be used); no parsing of String values will be done.
-     * @param {Date} value
+    /**
+     * Replaces any existing {@link #maxValue} with the new time and refreshes the picker's range.
+     * @param {Date/String} value The maximum time that can be selected
      */
     setMaxValue: function(value) {
-        this.maxValue = value;
-        this.updateList();
+        var me = this,
+            picker = me.picker;
+        me.setLimit(value, false);
+        if (picker) {
+            picker.setMaxValue(me.maxValue);
+        }
     },
 
-    /**
+    /**
      * @private
-     * Sets the year/month/day of the given Date object to the {@link #initDate}, so that only
-     * the time fields are significant. This makes values suitable for time comparison.
-     * @param {Date} date
+     * Updates either the min or max value. Converts the user's value into a Date object whose
+     * year/month/day is set to the {@link #initDate} so that only the time fields are significant.
      */
-    normalizeDate: function(date) {
-        var initDate = this.initDate;
-        date.setFullYear(initDate[0], initDate[1] - 1, initDate[2]);
-        return date;
+    setLimit: function(value, isMin) {
+        var me = this,
+            d, val;
+        if (Ext.isString(value)) {
+            d = me.parseDate(value);
+        }
+        else if (Ext.isDate(value)) {
+            d = value;
+        }
+        if (d) {
+            val = Ext.Date.clearTime(new Date(me.initDate));
+            val.setHours(d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
+            me[isMin ? 'minValue' : 'maxValue'] = val;
+        }
+    },
+
+    rawToValue: function(rawValue) {
+        return this.parseDate(rawValue) || rawValue || null;
     },
 
-    /**
-     * Update the list of available times in the list to be constrained within the
-     * {@link #minValue} and {@link #maxValue}.
+    valueToRaw: function(value) {
+        return this.formatDate(this.parseDate(value));
+    },
+
+    /**
+     * Runs all of Time's validations and returns an array of any errors. Note that this first
+     * runs Text's validations, so the returned array is an amalgamation of all field errors.
+     * The additional validation checks are testing that the time format is valid, that the chosen
+     * time is within the {@link #minValue} and {@link #maxValue} constraints set.
+     * @param {Mixed} value The value to get errors for (defaults to the current field value)
+     * @return {Array} All validation errors for this field
      */
-    updateList: function() {
+    getErrors: function(value) {
         var me = this,
-            min = me.normalizeDate(me.minValue || me.absMin),
-            max = me.normalizeDate(me.maxValue || me.absMax);
+            format = Ext.String.format,
+            errors = me.callParent(arguments),
+            minValue = me.minValue,
+            maxValue = me.maxValue,
+            date;
 
-        me.store.filterBy(function(record) {
-            var date = record.get('date');
-            return date >= min && date <= max;
-        });
+        value = me.formatDate(value || me.processRawValue(me.getRawValue()));
+
+        if (value === null || value.length < 1) { // if it's blank and textfield didn't flag it then it's valid
+             return errors;
+        }
+
+        date = me.parseDate(value);
+        if (!date) {
+            errors.push(format(me.invalidText, value, me.format));
+            return errors;
+        }
+
+        if (minValue && date < minValue) {
+            errors.push(format(me.minText, me.formatDate(minValue)));
+        }
+
+        if (maxValue && date > maxValue) {
+            errors.push(format(me.maxText, me.formatDate(maxValue)));
+        }
+
+        return errors;
     },
 
-    /**
+    formatDate: function() {
+        return Ext.form.field.Date.prototype.formatDate.apply(this, arguments);
+    },
+
+    /**
      * @private
-     * Creates the internal {@link Ext.data.Store} that contains the available times. The store
-     * is loaded with all possible times, and it is later filtered to hide those times outside
-     * the minValue/maxValue.
+     * Parses an input value into a valid Date object.
+     * @param {String/Date} value
      */
-    createStore: function() {
+    parseDate: function(value) {
+        if (!value || Ext.isDate(value)) {
+            return value;
+        }
+
+        var me = this,
+            val = me.safeParse(value, me.format),
+            altFormats = me.altFormats,
+            altFormatsArray = me.altFormatsArray,
+            i = 0,
+            len;
+
+        if (!val && altFormats) {
+            altFormatsArray = altFormatsArray || altFormats.split('|');
+            len = altFormatsArray.length;
+            for (; i < len && !val; ++i) {
+                val = me.safeParse(value, altFormatsArray[i]);
+            }
+        }
+        return val;
+    },
+
+    safeParse: function(value, format){
         var me = this,
             utilDate = Ext.Date,
-            times = [],
-            min = me.absMin,
-            max = me.absMax;
-
-        while(min <= max){
-            times.push({
-                disp: utilDate.dateFormat(min, me.format),
-                date: min
-            });
-            min = utilDate.add(min, 'mi', me.increment);
+            parsedDate,
+            result = null;
+
+        if (utilDate.formatContainsDateInfo(format)) {
+            // assume we've been given a full date
+            result = utilDate.parse(value, format);
+        } else {
+            // Use our initial safe date
+            parsedDate = utilDate.parse(me.initDate + ' ' + value, me.initDateFormat + ' ' + format);
+            if (parsedDate) {
+                result = parsedDate;
+            }
         }
+        return result;
+    },
+
+    // @private
+    getSubmitValue: function() {
+        var me = this,
+            format = me.submitFormat || me.format,
+            value = me.getValue();
 
-        return Ext.create('Ext.data.Store', {
-            fields: ['disp', 'date'],
-            data: times
+        return value ? Ext.Date.format(value, format) : null;
+    },
+
+    /**
+     * @private
+     * Creates the {@link Ext.picker.Time}
+     */
+    createPicker: function() {
+        var me = this,
+            picker = Ext.create('Ext.picker.Time', {
+                selModel: {
+                    mode: 'SINGLE'
+                },
+                floating: true,
+                hidden: true,
+                minValue: me.minValue,
+                maxValue: me.maxValue,
+                increment: me.increment,
+                format: me.format,
+                ownerCt: this.ownerCt,
+                renderTo: document.body,
+                maxHeight: me.pickerMaxHeight,
+                focusOnToFront: false
+            });
+
+        me.mon(picker.getSelectionModel(), {
+            selectionchange: me.onListSelect,
+            scope: me
         });
-    }
 
+        return picker;
+    },
+
+    /**
+     * @private
+     * Enables the key nav for the Time picker when it is expanded.
+     * TODO this is largely the same logic as ComboBox, should factor out.
+     */
+    onExpand: function() {
+        var me = this,
+            keyNav = me.pickerKeyNav,
+            selectOnTab = me.selectOnTab,
+            picker = me.getPicker(),
+            lastSelected = picker.getSelectionModel().lastSelected,
+            itemNode;
+
+        if (!keyNav) {
+            keyNav = me.pickerKeyNav = Ext.create('Ext.view.BoundListKeyNav', this.inputEl, {
+                boundList: picker,
+                forceKeyDown: true,
+                tab: function(e) {
+                    if (selectOnTab) {
+                        if(me.picker.highlightedItem) {
+                            this.selectHighlighted(e);
+                        } else {
+                            me.collapse();
+                        }
+                        me.triggerBlur();
+                    }
+                    // Tab key event is allowed to propagate to field
+                    return true;
+                }
+            });
+            // stop tab monitoring from Ext.form.field.Trigger so it doesn't short-circuit selectOnTab
+            if (selectOnTab) {
+                me.ignoreMonitorTab = true;
+            }
+        }
+        Ext.defer(keyNav.enable, 1, keyNav); //wait a bit so it doesn't react to the down arrow opening the picker
+
+        // Highlight the last selected item and scroll it into view
+        if (lastSelected) {
+            itemNode = picker.getNode(lastSelected);
+            if (itemNode) {
+                picker.highlightItem(itemNode);
+                picker.el.scrollChildIntoView(itemNode, false);
+            }
+        }
+    },
+
+    /**
+     * @private
+     * Disables the key nav for the Time picker when it is collapsed.
+     */
+    onCollapse: function() {
+        var me = this,
+            keyNav = me.pickerKeyNav;
+        if (keyNav) {
+            keyNav.disable();
+            me.ignoreMonitorTab = false;
+        }
+    },
+
+    /**
+     * @private
+     * Clears the highlighted item in the picker on change.
+     * This prevents the highlighted item from being selected instead of the custom typed in value when the tab key is pressed.
+     */
+    onChange: function() {
+        var me = this,
+            picker = me.picker;
+
+        me.callParent(arguments);
+        if(picker) {
+            picker.clearHighlight();
+        }
+    },
+
+    /**
+     * @private
+     * Handles a time being selected from the Time picker.
+     */
+    onListSelect: function(list, recordArray) {
+        var me = this,
+            record = recordArray[0],
+            val = record ? record.get('date') : null;
+        me.setValue(val);
+        me.fireEvent('select', me, val);
+        me.picker.clearHighlight();
+        me.collapse();
+        me.inputEl.focus();
+    }
 });
-
\ No newline at end of file + +
+ +