[控件]unigui移动端下Unidatepicker时间显示解决方案
http://tz10000.com/kong-jian-unigui-yi-dong-duan-xia-unidatepicker-shi-jian-xian-shi-jie-jue-fang-an.html
用unigui搞移动端,需求上需要采用日期,但是默认是不支持时间选择的,怎么办?
只能改造了@~@。
1.下载以下JS文件放到程序files目录下。
https://raw.githubusercontent.com/tomalex0/senchatouch-datetimepickerv2/master/ux/DateTime.js
https://raw.githubusercontent.com/tomalex0/senchatouch-datetimepickerv2/master/ux/DateTimePicker.js
2.在CustomFiles项目加入如下内容。
files/DateTime.js
files/DateTimePicker.js
3.调整时间格式,如下。
UnimDatePicker1.DateFormat := "dd/MM/yyyy H:i"
4.对控件添加以下事件。
1. UnimDatePicker1 -> ClientEvents -> UniEvents .. beforeInit fn:
function beforeInit(sender, config)
{
config.picker = Ext.create('Ext.ux.picker.DateTime', {
useTitles: false,
doneButton: true,
cancelButton: true,
minuteInterval : 1,
//slotOrder: ['month', 'day', 'year','hour','minute'],
toolbar: {
//items : datetimepickettoolbaritems
}
});
Ext.Date.patterns={CustomFormat: "d/m/Y H:i"}; // <------------
}
2. UnimDatePicker1 -> ClientEvents -> ExtEvents -> function change:
function change(sender, newDate, oldDate, eOpts)
{
ajaxRequest(sender, '_dateChange', ['val='+Ext.Date.format(newDate, Ext.Date.patterns.CustomFormat)])
}
3. UnimDatePicker1 -> OnAjaxEvent:
procedure TMainmForm.UnimDatePicker1AjaxEvent(Sender: TComponent;
EventName: string; Params: TUniStrings);
var
newDateTime : TDateTime;
Fmt: TFormatSettings;
begin
if EventName = '_dateChange' then
begin
Fmt.ShortDateFormat:='dd/mm/yyyy';
Fmt.DateSeparator :='/';
Fmt.LongTimeFormat :='hh:mm';
Fmt.TimeSeparator :=':';
newDateTime := StrToDateTime(Params.Values['val'], Fmt);
//ShowMessage(DateTimeToStr(newDateTime));
end;
end;
https://raw.githubusercontent.com/tomalex0/senchatouch-datetimepickerv2/master/ux/DateTime.js
Ext.define('Ext.ux.picker.DateTime', { extend: 'Ext.picker.Picker', xtype: 'datetimepicker', alternateClassName: 'Ext.ux.DateTimePicker', requires: ['Ext.DateExtras'], config: { /** * @cfg {Number} yearFrom * The start year for the date picker. * @accessor */ yearFrom: 1980, /** * @cfg {Number} yearTo * The last year for the date picker. * @default the current year (new Date().getFullYear()) * @accessor */ yearTo: new Date().getFullYear(), /** * @cfg {String} monthText * The label to show for the month column. * @accessor */ monthText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'M' : 'Month', /** * @cfg {String} dayText * The label to show for the day column. * @accessor */ dayText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'j' : 'Day', /** * @cfg {String} yearText * The label to show for the year column. * @accessor */ yearText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'Y' : 'Year', /** * @cfg {String} hourText * The label to show for the hour column. Defaults to 'Hour'. */ hourText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'H' : 'Hour', /** * @cfg {String} minuteText * The label to show for the minute column. Defaults to 'Minute'. */ minuteText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'i' : 'Minute', /** * @cfg {String} ampmText * The label to show for the ampm column. Defaults to 'AM/PM'. */ ampmText: (Ext.os.deviceType.toLowerCase() == "phone") ? 'A' : 'AM/PM', /** * @cfg {Array} slotOrder * An array of strings that specifies the order of the slots. * @accessor */ slotOrder: ['month', 'day', 'year','hour','minute','ampm'], /** * @cfg {Int} minuteInterval * @accessor */ minuteInterval : 15, /** * @cfg {Boolean} ampm * @accessor */ ampm : false, /** * @cfg {Boolean} displayUTC * If set to true, displays UTC time in the DatePicker * @accessor */ displayUTC: false }, initialize: function() { this.callParent(); this.on({ scope: this, delegate: '> slot', slotpick: this.onSlotPick }); }, setValue: function(value, animated) { if (Ext.isDate(value)) { // See if we should display in UTC if (this.getDisplayUTC()) { ampm = 'AM'; currentHours = hour = value.getUTCHours(); if(this.getAmpm()){ if (currentHours > 12) { ampm = "PM"; hour -= 12; } else if(currentHours == 12) { ampm = "PM"; } else if(currentHours == 0) { hour = 12; } } value = { day : value.getUTCDate(), month: value.getUTCMonth() + 1, year : value.getUTCFullYear(), hour : hour, minute : value.getUTCMinutes(), ampm : ampm }; // Display in local timezone } else { ampm = 'AM'; currentHours = hour = value.getHours(); if(this.getAmpm()){ if (currentHours > 12) { ampm = "PM"; hour -= 12; } else if(currentHours == 12) { ampm = "PM"; } else if(currentHours == 0) { hour = 12; } } value = { day : value.getDate(), month: value.getMonth() + 1, year : value.getFullYear(), hour : hour, minute : value.getMinutes(), ampm : ampm }; } } this.callParent([value, animated]); }, getValue: function() { var values = {}, daysInMonth, day, hour, minute, items = this.getItems().items, ln = items.length, item, i; for (i = 0; i < ln; i++) { item = items[i]; if (item instanceof Ext.picker.Slot) { values[item.getName()] = item.getValue(true); } } daysInMonth = this.getDaysInMonth(values.month, values.year); day = Math.min(values.day, daysInMonth),hour = values.hour, minute = values.minute; var yearval = (isNaN(values.year)) ? new Date().getFullYear() : values.year, monthval = (isNaN(values.month)) ? (new Date().getMonth()) : (values.month - 1), dayval = (isNaN(day)) ? (new Date().getDate()) : day, hourval = (isNaN(hour)) ? new Date().getHours() : hour, minuteval = (isNaN(minute)) ? new Date().getMinutes() : minute; if(values.ampm && values.ampm == "PM" && hourval<12){ hourval = hourval + 12; } if(values.ampm && values.ampm == "AM" && hourval == 12){ hourval = 0; } // Return the proper values based upon UTC if (this.getDisplayUTC()) { return new Date(Date.UTC(yearval, monthval, dayval, hourval, minuteval)); } else { return new Date(yearval, monthval, dayval, hourval, minuteval); } }, /** * Updates the yearFrom configuration */ updateYearFrom: function() { if (this.initialized) { this.createSlots(); } }, /** * Updates the yearTo configuration */ updateYearTo: function() { if (this.initialized) { this.createSlots(); } }, /** * Updates the monthText configuration */ updateMonthText: function(newMonthText, oldMonthText) { var innerItems = this.getInnerItems, ln = innerItems.length, item, i; //loop through each of the current items and set the title on the correct slice if (this.initialized) { for (i = 0; i < ln; i++) { item = innerItems[i]; if ((typeof item.title == "string" && item.title == oldMonthText) || (item.title.html == oldMonthText)) { item.setTitle(newMonthText); } } } }, /** * Updates the dayText configuraton */ updateDayText: function(newDayText, oldDayText) { var innerItems = this.getInnerItems, ln = innerItems.length, item, i; //loop through each of the current items and set the title on the correct slice if (this.initialized) { for (i = 0; i < ln; i++) { item = innerItems[i]; if ((typeof item.title == "string" && item.title == oldDayText) || (item.title.html == oldDayText)) { item.setTitle(newDayText); } } } }, /** * Updates the yearText configuration */ updateYearText: function(yearText) { var innerItems = this.getInnerItems, ln = innerItems.length, item, i; //loop through each of the current items and set the title on the correct slice if (this.initialized) { for (i = 0; i < ln; i++) { item = innerItems[i]; if (item.title == this.yearText) { item.setTitle(yearText); } } } }, // @private constructor: function() { this.callParent(arguments); this.createSlots(); }, /** * Generates all slots for all years specified by this component, and then sets them on the component * @private */ createSlots: function() { var me = this, slotOrder = this.getSlotOrder(), yearsFrom = me.getYearFrom(), yearsTo = me.getYearTo(), years = [], days = [], months = [], hours = [], minutes = [], ampm= [], ln, tmp, i, daysInMonth; if(!this.getAmpm()){ var index = slotOrder.indexOf('ampm'); if(index >= 0){ slotOrder.splice(index); } } // swap values if user mixes them up. if (yearsFrom > yearsTo) { tmp = yearsFrom; yearsFrom = yearsTo; yearsTo = tmp; } for (i = yearsFrom; i <= yearsTo; i++) { years.push({ text: i, value: i }); } daysInMonth = this.getDaysInMonth(1, new Date().getFullYear()); for (i = 0; i < daysInMonth; i++) { days.push({ text: i + 1, value: i + 1 }); } for (i = 0, ln = Ext.Date.monthNames.length; i < ln; i++) { months.push({ text: (Ext.os.deviceType.toLowerCase() == "phone") ? Ext.Date.monthNames[i].substring(0,3) : Ext.Date.monthNames[i], value: i + 1 }); } var hourLimit = (this.getAmpm()) ? 12 : 23; var hourStart = (this.getAmpm()) ? 1 : 0; for(i=hourStart;i<=hourLimit;i++){ hours.push({ text: this.pad2(i), value: i }); } for(i=0;i<60;i+=this.getMinuteInterval()){ minutes.push({ text: this.pad2(i), value: i }); } ampm.push({ text: 'AM', value: 'AM' },{ text: 'PM', value: 'PM' }); var slots = []; slotOrder.forEach(function(item) { slots.push(this.createSlot(item, days, months, years,hours,minutes,ampm)); }, this); me.setSlots(slots); }, /** * Returns a slot config for a specified date. * @private */ createSlot: function(name, days, months, years,hours,minutes,ampm) { var isPhone = (Ext.os.deviceType.toLowerCase() == "phone"), align = (isPhone) ? 'left' : 'center'; switch (name) { case 'year': return { name: 'year', align: align, data: years, title: this.getYearText(), flex: isPhone ? 1.3 : 3 }; case 'month': return { name: name, align: isPhone ? 'left' : 'right', data: months, title: this.getMonthText(), flex: isPhone ? 1.2 : 4 }; case 'day': return { name: 'day', align: align, data: days, title: this.getDayText(), flex: isPhone ? 0.9 : 2 }; case 'hour': return { name: 'hour', align: align, data: hours, title: this.getHourText(), flex: isPhone ? 0.9 : 2 }; case 'minute': return { name: 'minute', align: align, data: minutes, title: this.getMinuteText(), flex: isPhone ? 0.9 : 2 }; case 'ampm': return { name: 'ampm', align: align, data: ampm, title: this.getAmpmText(), flex: isPhone ? 1.1 : 2 }; } }, onSlotPick: function(pickedSlot, oldValue, htmlNode, eOpts) { // We don't actually get passed the new value. I think this is an ST2 bug. Instead we get passed the slot, // the oldValue, the node in the slot which was moved to, and options for the event. // // However looking at the code that fires the slotpick event, the slot.selectedIndex is always set there // We can therefore use this to pull the underlying value that was picked out of the slot's store var pickedValue = pickedSlot.getStore().getAt(pickedSlot.selectedIndex).get(pickedSlot.getValueField()); pickedSlot.setValue(pickedValue); if(pickedSlot.getName() === 'month' || pickedSlot.getName() === 'year') { this.repopulateDaySlot(); } }, repopulateDaySlot: function() { var slot = this.getDaySlot(), days = [], month = this.getSlotByName('month').getValue(), year = this.getSlotByName('year').getValue(), daysInMonth; // Get the new days of the month for this new date daysInMonth = this.getDaysInMonth(month, year); for (var i = 0; i < daysInMonth; i++) { days.push({ text: i + 1, value: i + 1 }); } // We dont need to update the slot days unless it has changed if (slot.getData().length == days.length) { return; } slot.setData(days); }, getSlotByName: function(name) { return this.down('pickerslot[name=' + name + ']'); }, getDaySlot: function() { return this.getSlotByName('day'); }, // @private getDaysInMonth: function(month, year) { var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; return month == 2 && this.isLeapYear(year) ? 29 : daysInMonth[month-1]; }, // @private isLeapYear: function(year) { return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year))); }, pad2 : function(number) { return (number < 10 ? '0' : '') + number ; } });
https://raw.githubusercontent.com/tomalex0/senchatouch-datetimepickerv2/master/ux/DateTimePicker.js
/** * @aside guide forms * * This is a specialized field which shows a {@link Ext.ux.picker.DateTime} when tapped. If it has a predefined value, * or a value is selected in the {@link Ext.ux.picker.DateTime}, it will be displayed like a normal {@link Ext.field.Text} * (but not selectable/changable). * * Ext.create('Ext.ux.field.DateTimePicker', { * label: 'Birthday', * value: new Date() * }); * * {@link Ext.ux.field.DateTimePicker} fields are very simple to implement, and have no required configurations. * * ## Examples * * It can be very useful to set a default {@link #value} configuration on {@link Ext.ux.field.DateTimePicker} fields. In * this example, we set the {@link #value} to be the current date. You can also use the {@link #setValue} method to * update the value at any time. * * @example miniphone preview * Ext.create('Ext.form.Panel', { * fullscreen: true, * items: [ * { * xtype: 'fieldset', * items: [ * { * xtype: 'datetimepickerfield', * label: 'Birthday', * name: 'birthday', * value: new Date() * } * ] * }, * { * xtype: 'toolbar', * docked: 'bottom', * items: [ * { xtype: 'spacer' }, * { * text: 'setValue', * handler: function() { * var datetimepickerfield = Ext.ComponentQuery.query('datetimepickerfield')[0]; * * var randomNumber = function(from, to) { * return Math.floor(Math.random() * (to - from + 1) + from); * }; * * datetimepickerfield.setValue({ * month: randomNumber(0, 11), * day : randomNumber(0, 28), * year : randomNumber(1980, 2011) * }); * } * }, * { xtype: 'spacer' } * ] * } * ] * }); * * When you need to retrieve the date from the {@link Ext.ux.field.DateTimePicker}, you can either use the {@link #getValue} or * {@link #getFormattedValue} methods: * * @example preview * Ext.create('Ext.form.Panel', { * fullscreen: true, * items: [ * { * xtype: 'fieldset', * items: [ * { * xtype: 'datetimepickerfield', * label: 'Birthday', * name: 'birthday', * value: new Date() * } * ] * }, * { * xtype: 'toolbar', * docked: 'bottom', * items: [ * { * text: 'getValue', * handler: function() { * var datetimepickerfield = Ext.ComponentQuery.query('datetimepickerfield')[0]; * Ext.Msg.alert(null, datetimepickerfield.getValue()); * } * }, * { xtype: 'spacer' }, * { * text: 'getFormattedValue', * handler: function() { * var datetimepickerfield = Ext.ComponentQuery.query('datetimepickerfield')[0]; * Ext.Msg.alert(null, datetimepickerfield.getFormattedValue()); * } * } * ] * } * ] * }); * * */ Ext.define('Ext.ux.field.DateTimePicker', { extend: 'Ext.field.Text', alternateClassName: 'Ext.form.DateTimePicker', xtype: 'datetimepickerfield', requires: [ 'Ext.ux.picker.DateTime', 'Ext.DateExtras' ], /** * @event change * Fires when a date is selected * @param {Ext.ux.field.DateTimePicker} this * @param {Date} date The new date */ config: { ui: 'select', /** * @cfg {Object/Ext.ux.picker.DateTime} picker * An object that is used when creating the internal {@link Ext.ux.picker.DateTime} component or a direct instance of {@link Ext.ux.picker.DateTime} * Defaults to true * @accessor */ picker: true, /** * @cfg {Boolean} * @hide * @accessor */ clearIcon: false, /** * @cfg {Object/Date} value * Default value for the field and the internal {@link Ext.ux.picker.DateTime} component. Accepts an object of 'year', * 'month' and 'day' values, all of which should be numbers, or a {@link Date}. * * Example: {year: 1989, day: 1, month: 5} = 1st May 1989 or new Date() * @accessor */ /** * @cfg {Boolean} destroyPickerOnHide * Whether or not to destroy the picker widget on hide. This save memory if it's not used frequently, * but increase delay time on the next show due to re-instantiation. Defaults to false * @accessor */ destroyPickerOnHide: false, /** * @cfg {String} dateTimeFormat The format to be used when displaying the date in this field. * Accepts any valid datetime format. You can view formats over in the {@link Ext.Date} documentation. * Defaults to `Ext.util.Format.defaultDateFormat`. */ dateTimeFormat: 'm/d/Y h:i:A', /** * @cfg {Object} * @hide */ component: { useMask: true } }, initialize: function() { this.callParent(); this.getComponent().on({ scope: this, masktap: 'onMaskTap' }); this.getComponent().input.dom.disabled = true; }, syncEmptyCls: Ext.emptyFn, applyValue: function(value) { if (!Ext.isDate(value) && !Ext.isObject(value)) { value = null; } if (Ext.isObject(value)) { value = new Date(value.year, value.month - 1, value.day,value.hour,value.minute); } return value; }, updateValue: function(newValue) { var picker = this._picker; if (picker && picker.isPicker) { picker.setValue(newValue); } // Ext.Date.format expects a Date if (newValue !== null) { this.getComponent().setValue(Ext.Date.format(newValue, this.getDateTimeFormat() || Ext.util.Format.defaultDateFormat)); } else { this.getComponent().setValue(''); } if (this._picker && this._picker instanceof Ext.ux.picker.DateTime) { this._picker.setValue(newValue); } }, /** * Updates the date format in the field. * @private */ updateDateFormat: function(newDateFormat, oldDateFormat) { var value = this.getValue(); if (newDateFormat != oldDateFormat && Ext.isDate(value) && this._picker && this._picker instanceof Ext.ux.picker.DateTime) { this.getComponent().setValue(Ext.Date.format(value, newDateFormat || Ext.util.Format.defaultDateFormat)); } }, /** * Returns the {@link Date} value of this field. * If you wanted a formated date * @return {Date} The date selected */ getValue: function() { if (this._picker && this._picker instanceof Ext.ux.picker.DateTime) { return this._picker.getValue(); } return this._value; }, /** * Returns the value of the field formatted using the specified format. If it is not specified, it will default to * {@link #dateFormat} and then {@link Ext.util.Format#defaultDateFormat}. * @param {String} format The format to be returned * @return {String} The formatted date */ getFormattedValue: function(format) { var value = this.getValue(); console.log(this.getDateTimeFormat(),"format"); return (Ext.isDate(value)) ? Ext.Date.format(value, format || this.getDateTimeFormat() || Ext.util.Format.defaultDateFormat) : value; }, applyPicker: function(picker, pickerInstance) { if (pickerInstance && pickerInstance.isPicker) { picker = pickerInstance.setConfig(picker); } return picker; }, getPicker: function() { var picker = this._picker, value = this.getValue(); if (picker && !picker.isPicker) { picker = Ext.factory(picker, Ext.ux.picker.DateTime); picker.on({ scope: this, cancel: 'onPickerCancel', change: 'onPickerChange', hide : 'onPickerHide' }); if (value !== null) { picker.setValue(value); } Ext.Viewport.add(picker); this._picker = picker; } return picker; }, /** * @private * Listener to the tap event of the mask element. Shows the internal DatePicker component when the button has been tapped. */ onMaskTap: function(e) { if (this.getDisabled()) { return false; } if (this.getReadOnly()) { return false; } // Make sure to fire the focus event this.fireEvent('focus', this, e); this.getPicker().show(); return false; }, /** * @private * Revert internal date so field won't appear changed */ onPickerCancel: function(picker, options) { if (this.getDestroyPickerOnHide() && picker) { this._picker = this._picker.config; picker.destroy(); } return true; }, /** * Called when the picker changes its value * @param {Ext.ux.picker.DateTime} picker The date picker * @param {Object} value The new value from the date picker * @private */ onPickerChange: function(picker, value) { var me = this; me.setValue(value); me.fireEvent('change', me, me.getValue()); }, /** * Destroys the picker when it is hidden, if * {@link Ext.ux.field.DateTimePicker#destroyPickerOnHide destroyPickerOnHide} is set to true * @private */ onPickerHide: function() { var picker = this.getPicker(); if (this.getDestroyPickerOnHide() && picker) { picker.destroy(); this._picker = true; } }, reset: function() { this.setValue(this.originalValue); }, // @private destroy: function() { var picker = this.getPicker(); if (picker && picker.isPicker) { picker.destroy(); } this.callParent(arguments); } //<deprecated product=touch since=2.0> }, function() { this.override({ getValue: function(format) { if (format) { //<debug warn> Ext.Logger.deprecate("format argument of the getValue method is deprecated, please use getFormattedValue instead", this); //</debug> return this.getFormattedValue(format); } return this.callOverridden(); } }); /** * @method getDatePicker * @inheritdoc Ext.ux.field.DateTimePicker#getPicker * @deprecated 2.0.0 Please use #getPicker instead */ Ext.deprecateMethod(this, 'getDatePicker', 'getPicker'); //</deprecated> });