/*!
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
/**
* @class Ext.form.TwoDateField
* @extends Ext.form.TriggerField
* Provides a date input field with a {@link Ext.DatePicker} dropdown and automatic date validation.
* @constructor
* Create a new DateField
* @param {Object} config
* @xtype datefield
*/
Ext.form.TwoDateField = Ext.extend(Ext.form.TriggerField, {
format : "Y-m-d",
/**
* @cfg {String} altFormats
* Multiple date formats separated by "|" to try when parsing a user input value and it
* does not match the defined format (defaults to
* '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').
*/
altFormats : "",
/**
* @cfg {String} disabledDaysText
* The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
*/
disabledDaysText : "Disabled",
/**
* @cfg {String} disabledDatesText
* The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
*/
disabledDatesText : "Disabled",
/**
* @cfg {String} minText
* The error text to display when the date in the cell is before {@link #minValue} (defaults to
* 'The date in this field must be after {minValue}').
*/
minText : "The date in this field must be equal to or after {0}",
/**
* @cfg {String} maxText
* The error text to display when the date in the cell is after {@link #maxValue} (defaults to
* 'The date in this field must be before {maxValue}').
*/
maxText : "The date in this field must be equal to or before {0}",
/**
* @cfg {String} invalidText
* The error text to display when the date in the field is invalid (defaults to
* '{value} is not a valid date - it must be in the format {format}').
*/
invalidText : "{0} 无效数据,格式必须是 Y-m-d -- Y-m-d",
/**
* @cfg {String} triggerClass
* An additional CSS class used to style the trigger button. The trigger will always get the
* class 'x-form-trigger' and triggerClass will be appended if specified
* (defaults to 'x-form-date-trigger' which displays a calendar icon).
*/
triggerClass : 'x-form-date-trigger',
/**
* @cfg {Boolean} showToday
* false to hide the footer area of the DatePicker containing the Today button and disable
* the keyboard handler for spacebar that selects the current date (defaults to true).
*/
showToday : false,
/**
* @cfg {Number} startDay
* Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
*/
startDay : 0,
// private
defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
// in the absence of a time value, a default value of 12 noon will be used
// (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
initTime: '12', // 24 hour format
initTimeFormat: 'H',
// start date value: {String}
startDate: null,
// end date value: {String}
endDate: null,
// select start date value: {Date}
selectStartDate: null,
// select end date value: {Date}
selectEndDate: null,
// Separator
separator: ' -- ',
initComponent : function(){
Ext.form.TwoDateField.superclass.initComponent.call(this);
this.addEvents(
/**
* @event select
* Fires when a date is selected via the date picker.
* @param {Ext.form.TwoDateField} this
* @param {Date} date The date that was selected
*/
'select'
);
this.disabledDatesRE = null;
this.initDisabledDays();
},
initEvents: function() {
Ext.form.TwoDateField.superclass.initEvents.call(this);
this.keyNav = new Ext.KeyNav(this.el, {
"down": function(e) {
this.onTriggerClick();
},
scope: this,
forceKeyDown: true
});
},
// private
initDisabledDays : function(){
if(this.disabledDates){
var dd = this.disabledDates,
len = dd.length - 1,
re = "(?:";
Ext.each(dd, function(d, i){
re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
if(i != len){
re += '|';
}
}, this);
this.disabledDatesRE = new RegExp(re + ')');
}
},
/**
* Replaces any existing disabled dates with new values and refreshes the DatePicker.
* @param {Array} disabledDates An array of date strings (see the {@link #disabledDates} config
* for details on supported values) used to disable a pattern of dates.
*/
setDisabledDates : function(dd){
this.disabledDates = dd;
this.initDisabledDays();
if(this.menu){
this.menu.picker.setDisabledDates(this.disabledDatesRE);
}
},
/**
* Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
* @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays}
* config for details on supported values.
*/
setDisabledDays : function(dd){
this.disabledDays = dd;
if(this.menu){
this.menu.picker.setDisabledDays(dd);
}
},
getErrors: function(value) {
var errors = Ext.form.TwoDateField.superclass.getErrors.apply(this, arguments);
if (value.length == 0) {
return errors;
}
if (!this.validTwoDate(value)) {
errors.push(String.format(this.invalidText, value));
return errors;
}
return errors;
},
// private
// Provides logic to override the default TriggerField.validateBlur which just returns true
validateBlur : function(){
return !this.menu || !this.menu.isVisible();
},
getValue : function(){
var start = this.formatDate(this.getStartValue());
var end = this.formatDate(this.getEndValue());
this.value = start + this.separator + end;
if (start.length == 0 && end.length == 0) {
this.value = '';
}
return this.value;//--需要改造
},
setValue : function(text){
//清空开始、结束日期值
if (!text || text.length == 0) {
this.startDate = null;
this.endDate = null;
}
//校验数据格式合法性 [Y-m-d] -- [Y-m-d]
this.originalValue = text;
return Ext.form.TwoDateField.superclass.setValue.call(this, text);//--需要改造
},
getStartValue: function(){
return this.parseDate(this.startDate);
},
getEndValue: function(){
return this.parseDate(this.endDate);
},
// private
parseDate : function(value) {
if(!value || Ext.isDate(value)){
return value;
}
var v = this.safeParse(value, this.format),
af = this.altFormats,
afa = this.altFormatsArray;
if (!v && af) {
afa = afa || af.split("|");
for (var i = 0, len = afa.length; i < len && !v; i++) {
v = this.safeParse(value, afa[i]);
}
}
return v;
},
safeParse : function(value, format) {
if (/[gGhH]/.test(format.replace(/(\\.)/g, ''))) {
// if parse format contains hour information, no DST adjustment is necessary
return Date.parseDate(value, format);
} else {
// set time to 12 noon, then clear the time
var parsedDate = Date.parseDate(value + ' ' + this.initTime, format + ' ' + this.initTimeFormat);
if (parsedDate) {
return parsedDate.clearTime();
}
}
},
// private
onDestroy : function(){
Ext.destroy(this.menu, this.keyNav);
Ext.form.TwoDateField.superclass.onDestroy.call(this);
},
// private
formatDate : function(date){
if (!date) return '';
return Ext.isDate(date) ? date.dateFormat(this.format) : date;
},
/**
* @method onTriggerClick
* @hide
*/
onTriggerClick : function(){
if(this.disabled){
return;
}
if(this.menu == null){
this.menu = new Ext.menu.TwoDateMenu({
hideOnClick: false,
focusOnSelect: false
});
}
this.onFocus();
Ext.apply(this.menu.picker, {
minDate : this.minValue,
maxDate : this.maxValue,
disabledDatesRE : this.disabledDatesRE,
disabledDatesText : this.disabledDatesText,
disabledDays : this.disabledDays,
disabledDaysText : this.disabledDaysText,
format : this.format,
showToday : this.showToday,
startDay: this.startDay,
minText : String.format(this.minText, this.formatDate(this.minValue)),
maxText : String.format(this.maxText, this.formatDate(this.maxValue))
});
Ext.apply(this.menu.two_picker, {
minDate : this.minValue,
maxDate : this.maxValue,
disabledDatesRE : this.disabledDatesRE,
disabledDatesText : this.disabledDatesText,
disabledDays : this.disabledDays,
disabledDaysText : this.disabledDaysText,
format : this.format,
showToday : this.showToday,
startDay: this.startDay,
minText : String.format(this.minText, this.formatDate(this.minValue)),
maxText : String.format(this.maxText, this.formatDate(this.maxValue))
});
//每次打开选择区时,都清空选择日期值
this.selectStartDate = null;
this.selectEndDate = null;
//给开始控件与结束控件赋值
this.initTwoDate();
//给日期范围设置背景色
this.styleTwoDate();
this.menu.show(this.el, "tl-bl?");
this.menuEvents('on');
},
//private 初始化2个日期控件的值
// 如果两个日期是同一个月,则都显示在第一个日期控件;否则分开显示
initTwoDate: function() {
var startDate = this.getStartValue();
if (!startDate) startDate = new Date();
var endDate = this.getEndValue();
//如果是同月,就显示在一个日期控件中
if (endDate && startDate.format('Y-m') == endDate.format('Y-m')) {
this.menu.picker.setValue(startDate);
this.menu.picker.setTwoValue(endDate);
//清空选择日期标记
this.menu.two_picker.cells.removeClass('x-date-selected');
} else {
if (startDate) this.menu.picker.setValue(startDate);
if (!endDate) {
endDate = (new Date()).add(Date.MONTH, 1);
this.menu.two_picker.setValue(endDate);//设定为第二个月,但不显示标记
JxUtil.delay(20, function(){this.menu.two_picker.cells.removeClass('x-date-selected');}, this);
} else {
this.menu.two_picker.setValue(endDate);
}
}
},
//private
menuEvents: function(method){
this.menu[method]('select', this.onSelect, this);
this.menu[method]('hide', this.onMenuHide, this);
this.menu[method]('show', this.onFocus, this);
},
//private 给日期范围设置背景色
styleTwoDate: function(){
if (this.menu.picker.cells) this.menu.picker.cells.removeClass('x-date-seltwo');
if (this.menu.two_picker.cells) this.menu.two_picker.cells.removeClass('x-date-seltwo');
var startDate = this.getStartValue();
var endDate = this.getEndValue();
if (!startDate || !endDate) return;
//给一个日期添加背景色
var addcss = function(cells, t){
cells.each(function(c){
if(c.dom.firstChild.dateValue == t){
c.addClass('x-date-seltwo');
return false;
}
});
};
if (startDate.format('Y-m') == endDate.format('Y-m')) {
//第一个日期控件添加背景色
var sd = startDate.add(Date.DAY, 1);
while (sd.getTime() < endDate.getTime()) {
addcss(this.menu.picker.cells, sd.getTime());
sd = sd.add(Date.DAY, 1);
}
} else {
//显示第一个日期控件的背景色
var next = JxUtil.getNextMonth(startDate.format('Y-m'), 1);
var ed = this.parseDate(next + '-01');
var sd = startDate.add(Date.DAY, 1);
while (sd.getTime() < ed.getTime()) {
addcss(this.menu.picker.cells, sd.getTime());
sd = sd.add(Date.DAY, 1);
}
//显示第二个日期控件的背景色
sd = this.parseDate(endDate.format('Y-m') + '-01');
while (sd.getTime() < endDate.getTime()) {
addcss(this.menu.two_picker.cells, sd.getTime());
sd = sd.add(Date.DAY, 1);
}
}
},
//private 点击范围按钮时,自动设置开始、结束日期
setTwoDate: function(btntype){
if (btntype == 'week') {//本周
var wd = JxUtil.getWeekDates();
this.startDate = wd[0];
this.endDate = wd[1];
} else if (btntype == 'month') {//本月
var md = JxUtil.getMonthDates();
this.startDate = md[0];
this.endDate = md[1];
} else if (btntype == 'quarter') {//3个月
var smonth = JxUtil.getMonth();
var sd = JxUtil.getNextMonth(smonth, -2) + '-01';
this.startDate = sd;
this.endDate = JxUtil.getToday();
} else if (btntype == 'year') {//本年
var y = (new Date()).format('Y');
this.startDate = y+'-01'+'-01';
this.endDate = JxUtil.getToday();
} else if (btntype == 'preweek') {//上周
var md = JxUtil.getPreWeekDates();
this.startDate = md[0];
this.endDate = md[1];
} else if (btntype == 'premonth') {//上月
var md = JxUtil.getPreMonthDates();
this.startDate = md[0];
this.endDate = md[1];
}
var text = this.startDate + this.separator + this.endDate;
this.setValue(text);
this.menu.hide();
},
onSelect: function(m, d){
//点击按钮选择日期范围
if (m.getXType() == 'button') {
var btntype = m.getItemId();
this.setTwoDate(btntype);
return;
}
if (this.menu.picker.cells) this.menu.picker.cells.removeClass('x-date-seltwo');
if (this.menu.two_picker.cells) this.menu.two_picker.cells.removeClass('x-date-seltwo');
if (!this.selectStartDate) {
this.selectStartDate = d;
//第1次点选时,要清空另一个选择日期标记
if (m.id == this.menu.picker.id) {
this.menu.two_picker.cells.removeClass('x-date-selected');
} else {
this.menu.picker.cells.removeClass('x-date-selected');
}
} else {
//第二次选择日期时,则赋值并隐藏选择块
//小的日期值放在start,大的日期值放在end
if (d.getTime() < this.selectStartDate.getTime()) {
this.selectEndDate = this.selectStartDate;
this.selectStartDate = d;
} else {
this.selectEndDate = d;
}
this.startDate = this.formatDate(this.selectStartDate);
this.endDate = this.formatDate(this.selectEndDate);
var text = this.startDate + this.separator + this.endDate;
this.setValue(text);
this.fireEvent('select', this, d);
this.menu.hide();
}
},
onMenuHide: function(){
this.focus(false, 60);
this.menuEvents('un');
},
// private 格式化2个日期值,格式不对清空
validTwoDate: function(value){
if (value == null || value.length == 0) return true;
if (value && value.length > 0) {
var values = value.split(this.separator);
if (values && values.length == 2) {
this.startDate = this.formatDate(this.parseDate(values[0].trim()));
this.endDate = this.formatDate(this.parseDate(values[1].trim()));
if (this.startDate.length > 0 && this.endDate.length > 0) {
return true;
}
}
}
return false;
},
// private
beforeBlur : function(){
var value = this.getRawValue();
if (this.validTwoDate(value)) {
this.setValue(value);
} else {
this.setValue(this.originalValue);
}
}
});
Ext.reg('twodatefield', Ext.form.TwoDateField);