需求的变态是没有极限的
某RIA以前使用Silverlight开发,今年3月开始使用ExtJS4写JavaScript版本
两种完全不同的语言,写出来的界面任你再一致,很多特性还是很难移植的
比如Silverlight的timefield控件,支持用键盘的上下方向键调整时间,光标在小时数字的位置时,上下键的作用是增减一小时,光标在分钟数字的位置时,上下键的作用是增减一分钟
于是某测试人员说,既然Silverlight能做到,JS版本也希望实现这个功能
(余抽乃大爷100遍,这种要求何等无理啊,这是和控件自身相关的特性,JS要实现就非得hack ExtJS的代码不可,Silverlight能做到是控件它自身就已经实现,又不是代码写出来的,#$*%^&_+
花了一晚时间,还是把它给实现了,就是下面的定制timefield控件
由于光标位置没法判断,因此键盘操作只能增减一分钟
先是拦截timefield的keypress事件,不起作用,再试着拦截specialkey事件,UP键和DOWN键都成功捕捉到了
UP键的事件能停止,DOWN键的事件死活不能停止
仔细想一下,timefield控件的DOWN键是用来展开下拉列表的,看来默认是不给停止的了,没办法,读源代码
timefield是Ext.form.field.Time的别名
Ext.form.field.Time依次继承自Ext.form.field.Picker,Ext.form.field.Trigger,Ext.form.field.Text
在Ext.form.field.Picker中发现initEvents方法:
initEvents: function() {
var me = this;
me.callParent();
// Add handlers for keys to expand/collapse the picker
me.keyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
down: function() {
if (!me.isExpanded) {
// Don't call expand() directly as there may be additional processing involved before
// expanding, e.g. in the case of a ComboBox query.
me.onTriggerClick();
}
},
esc: me.collapse,
scope: me,
forceKeyDown: true
});
// Non-editable allows opening the picker by clicking the field
if (!me.editable) {
me.mon(me.inputEl, 'click', me.onTriggerClick, me);
}
// Disable native browser autocomplete
if (Ext.isGecko) {
me.inputEl.dom.setAttribute('autocomplete', 'off');
}
},
很显然,Down键的事件在这里就被写死了
试着从Ext.form.field.Time派生一个新类MyProject.ui.UpDownTimeField,覆盖initEvents,绕过基类的事件处理
initEvents: function() {
var me = this;
me.callParent();
me.keyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
down: function() {
me.decreaseTime();
},
up: function(e) {
me.increaseTime();
},
esc: me.collapse,
scope: me,
forceKeyDown: true
});
if (!me.editable) {
me.mon(me.inputEl, 'click', me.onTriggerClick, me);
}
if (Ext.isGecko) {
me.inputEl.dom.setAttribute('autocomplete', 'off');
}
},
还是失败了
细心一想,UpDownTimeField的initEvents方法中,me.callParent()调用基类方法,也即是Ext.form.field.Picker的initEvents,根本就还没绕过去嘛
于是用Ext.form.field.Text.prototype.initEvents.call(me)代替,成功用自己的事件处理取代了原来的事件处理
最后的UpDownTimeField:
Ext.define('MyProject.ui.UpDownTimeField', {
extend: 'Ext.form.field.Time',
alias: 'widget.updowntimefield',
format: 'H:i',
increment: 30,
minValue: '00:00',
maxValue: '23:59',
initEvents: function() {
var me = this;
Ext.form.field.Text.prototype.initEvents.call(me);
me.keyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
pageDown: function() {
if (!me.isExpanded) {
me.onTriggerClick();
}
},
down: function() {
me.decreaseTime();
},
up: function(e) {
me.increaseTime();
},
esc: me.collapse,
scope: me,
forceKeyDown: true
});
if (!me.editable) {
me.mon(me.inputEl, 'click', me.onTriggerClick, me);
}
if (Ext.isGecko) {
me.inputEl.dom.setAttribute('autocomplete', 'off');
}
},
increaseTime: function() {
var me = this;
if (me.isExpanded || !me.isValid()) {
return;
}
var timeString = me.getRawValue();
if (timeString) {
var arr = timeString.split(':');
var h = parseInt(arr[0], 10);
var m = parseInt(arr[1], 10);
m++;
if (m > 59) {
m = 0;
h++;
if (h > 23) {
h = 0;
}
}
h = h>=10 ? h.toString() : '0'+h;
m = m>=10 ? m.toString() : '0'+m;
me.setRawValue(h + ':' + m);
}
},
decreaseTime: function() {
var me = this;
if (me.isExpanded || !me.isValid()) {
return;
}
var timeString = me.getRawValue();
if (timeString) {
var arr = timeString.split(':');
var h = parseInt(arr[0], 10);
var m = parseInt(arr[1], 10);
m--;
if (m < 0) {
m = 59;
h--;
if (h < 0) {
h = 23;
}
}
h = h>=10 ? h.toString() : '0'+h;
m = m>=10 ? m.toString() : '0'+m;
me.setRawValue(h + ':' + m);
}
}
});
使用:
{
xtype: 'updowntimefield',
itemId: 'form-xxx-pickTimeField',
name: 'LaunchTime',
fieldLabel: message.YourLable,
labelWidth: 150,
labelClsExtra: 'your-css',
regex: /^\d\d:[0-5]\d$/,
regexText: message.YourMessage
}
事实上timefield的合法性验证不是特别严密,可以自己指定regex属性
评论