NeonMonk
3 Dec 2008, 11:57 PM
Hey guys,
I have quickly thrown together a radiotextfield & checkboxtextfield extensions (by shamelessly piggy backing off jsakalos's fantastic work with the DateTimeField extension (https://extjs.com/forum/showthread.php?t=22661))
It works and may help people searching for something like this. I make no guarantees however, consider it not properly tested & fundamentally unfinished!
Any bugs/fixes/improvements please post back to this thread. :)
Ext.ns('Ext.ux.form');
Ext.ux.form.CheckTextfield = Ext.extend(Ext.form.Field, {
value: false,
checkType: 'checkbox',
checked: false,
defaultAutoCreate: {
tag: 'input',
type: 'hidden'
},
initComponent: function() {
Ext.ux.form.CheckTextfield.superclass.initComponent.call(this);
var checkConfig = Ext.apply({},{
id: this.id + '-' + this.checkType,
checked: this.checked,
ownerCt: this,
listeners: {
blur: {
scope: this,
fn: this.onBlur
},
focus: {
scope: this,
fn: this.onFocus
}
}
},this.checkConfig);
this.cf = (this.checkType == 'checkbox' ? new Ext.form.Checkbox(checkConfig) : new Ext.form.Radio(checkConfig));
delete(this.checkConfig);
var textfieldConfig = Ext.apply({},{
id: this.id + '-textfield',
disabled: true,
style: 'width: 100%;',
ownerCt: this,
enable: function() {
this.disabled = false;
this.el.removeClass('x-item-disabled');
this.focus();
},
disable: function(check) {
this.ownerCt.cf.setValue(false);
this.disabled = true;
this.el.addClass('x-item-disabled');
if (this.hasFocus) {
this.ownerCt.cf.focus();
}
// else {
// var field = (this.checkType == "checkbox" ? Ext.form.Checkbox : Ext.form.Radio);
// field.prototype.disable.apply(this, arguments);
// }
},
listeners: {
blur: {
scope: this,
fn: this.onBlur
},
focus: {
scope: this,
fn: this.onFocus
}
}
},this.textfieldConfig);
this.tf = new Ext.form.TextField(textfieldConfig);
delete(this.textfieldConfig);
},
onRender: function(ct, position) {
if (this.isRendered) {
return null;
}
Ext.ux.form.CheckTextfield.superclass.onRender.call(this, ct, position);
var t;
t = Ext.DomHelper.append(ct, {
tag: 'table',
style: 'border-collapse:collapse;',
children: [{
tag: 'tr',
children: [{
tag: 'td',
style: 'padding-right:4px; width: 10px;',
cls: 'ux-checktextfield-cf'
},
{
tag: 'td',
cls: 'ux-checktextfield-tf'
}]
}]
},true);
this.tableEl = t;
this.wrap = t.wrap();
this.cf.render(t.child('td.ux-checktextfield-cf'));
this.cf.on('check',this.onCheck, this);
this.tf.render(t.child('td.ux-checktextfield-tf'));
this.tf.el.on('click',this.onClick, this);
if (Ext.isIE && Ext.isStrict) {
t.select('input').applyStyles({
top: 0
});
}
this.on('specialkey', this.onSpecialKey, this);
this.cf.el.swallowEvent(['keydown', 'keypress']);
this.tf.el.swallowEvent(['keydown', 'keypress']);
if ('side' === this.msgTarget) {
var elp = this.el.findParent('.x-form-element', 10, true);
this.errorIcon = elp.createChild({
cls: 'x-form-invalid-icon'
});
this.cf.errorIcon = this.errorIcon;
this.tf.errorIcon = this.errorIcon;
}
this.hiddenName = this.name || this.id;
this.hiddenName = this.hiddenName + '-hidden';
this.el.dom.name = this.name || this.id;
if (this.checkType == 'radio') {
this.cf.el.dom.name = this.name || this.id;
this.cf.name = this.name || this.id;
} else {
this.cf.el.dom.removeAttribute("name");
}
this.tf.el.dom.removeAttribute("name");
this.isRendered = true;
this.cf.setValue(this.checked || false);
},
onCheck: function(cb,checked) {
if (checked) {
this.enable();
} else {
this.disable('textfield');
}
},
onClick: function(e,el) {
if (this.tf.disabled) {
this.tf.enable();
this.tf.focus(true);
}
this.setValue(true);
},
adjustSize: Ext.BoxComponent.prototype.adjustSize,
alignErrorIcon: function() {
this.errorIcon.alignTo(this.tableEl, 'tl-tr', [2, 0]);
},
clearInvalid: function() {
this.tf.clearInvalid();
},
disable: function(e) {
if (e) {
this.cf.setValue(false);
this.tf.disable(true);
return this;
}
if (this.isRendered) {
this.cf.disabled = this.disabled;
this.cf.onDisable();
this.tf.onDisable();
}
this.disabled = true;
this.cf.disabled = true;
this.tf.disabled = true;
this.fireEvent("disable", this);
return this;
},
enable: function() {
if (this.rendered) {
this.cf.onEnable();
this.tf.onEnable();
}
this.disabled = false;
this.cf.disabled = false;
this.tf.disabled = false;
this.fireEvent("enable", this);
return this;
},
focus: function() {
this.cf.focus();
},
getPositionEl: function() {
return this.wrap;
},
getResizeEl: function() {
return this.wrap;
},
setSize: function(w, h) {
if (!w) {
return null;
}
this.tf.el.up('td').setWidth(w - 24);
},
getValue: function() {
return (this.cf.getValue() ? this.tf.getValue() : false);
},
isValid: function() {
if (this.cf.getValue()) {
return this.tf.isValid();
}
return this.cf.getValue();
},
isVisible: function() {
return this.cf.rendered && this.cf.getActionEl().isVisible();
},
onBlur: function(f) {
if (this.wrapClick) {
f.focus();
this.wrapClick = false;
}
(function() {
if (!this.cf.hasFocus && !this.tf.hasFocus) {
var v = this.getValue();
if (String(v) !== String(this.startValue)) {
this.fireEvent("change", this, v, this.startValue);
}
this.hasFocus = false;
this.fireEvent('blur', this);
}
}).defer(100, this);
},
onFocus: function() {
if (!this.hasFocus) {
this.hasFocus = true;
this.startValue = this.getValue();
this.fireEvent("focus", this);
}
},
onMouseDown: function(e) {
if (!this.disabled) {
this.wrapClick = 'td' === e.target.nodeName.toLowerCase();
}
},
onSpecialKey: function(t, e) {
var key = e.getKey();
if (key === e.TAB) {
if (t === this.df && !e.shiftKey) {
e.stopEvent();
this.tf.focus();
}
if (t === this.tf && e.shiftKey) {
e.stopEvent();
this.cf.focus();
}
}
if (key === e.ENTER) {
this.updateValue();
}
},
toggleValue : function() {
if(this.cf.checked){
var els = this.cf.getParent().select('input[name='+this.el.dom.name+']');
els.each(function(el){
if(el.dom.id != this.id && el.dom.id != this.id + '-radio'){
Ext.getCmp(el.dom.id).setValue(false);
}
}, this);
}
},
initValue : function(){
if(this.value !== undefined){
this.setValue(this.value,true);
}else if(this.el.dom.value.length > 0 && this.el.dom.value != this.emptyText){
this.setValue(this.el.dom.value,true);
}
// reference to original value for reset
this.originalValue = this.getValue();
},
setValue: function(val,init) {
if (!init) {
this.cf.setValue(val);
if (val !== true && val !== false) {
this.tf.setValue(this.value);
}
this.cf.setValue(val);
if (val === true && this.checkType == 'radio') {
this.toggleValue();
}
} else {
if (this.checkType == "radio" && val !== true && val !== false) {
this.tf.setValue(this.value);
}
this.cf.setValue(this.checked || false);
}
},
setVisible: function(visible) {
if (visible) {
this.cf.show();
this.tf.show();
} else {
this.cf.hide();
this.tf.hide();
}
return this;
},
show: function() {
return this.setVisible(true);
},
hide: function() {
return this.setVisible(false);
},
updateHidden: function() {
if (this.isRendered) {
this.el.dom.value = this.tf.getValue();
}
},
updateValue: function() {
this.updateHidden();
return null;
},
validate: function() {
return this.tf.validate();
}
});
Ext.ux.form.RadioTextfield = Ext.extend(Ext.ux.form.CheckTextfield,{
checkType: 'radio'
});
Ext.ux.form.CheckboxTextfield = Ext.extend(Ext.ux.form.CheckTextfield,{
checkType: 'checkbox',
valueInField: false
});
Ext.reg('radiotext', Ext.ux.form.RadioTextfield);
Ext.reg('checktext', Ext.ux.form.CheckboxTextfield);
Usage:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>CheckboxTextfield</title>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css"/>
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript" src="Ext.ux.form.CheckboxTextfield.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
Ext.QuickTips.init();
// turn on validation errors beside the field globally
Ext.form.Field.prototype.msgTarget = 'side';
var bd = Ext.getBody();
/*
* ================ Simple form =======================
*/
bd.createChild({tag: 'h2', html: 'Form 1 - Very Simple'});
var simple = new Ext.FormPanel({
labelWidth: 75, // label settings here cascade unless overridden
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {width: 230},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false
},{
fieldLabel: 'Last Name',
name: 'last'
},{
fieldLabel: 'Got Milk? (what brand)',
id: 'checktext',
xtype: 'checktext',
name: 'got milk'
},{
fieldLabel: 'one',
id: 'one',
xtype: 'radiotext',
name: 'gotmilk'
},{
fieldLabel: 'two',
id: 'two',
xtype: 'radiotext',
name: 'gotmilk'
},{
fieldLabel: 'three',
id: 'three',
xtype: 'radiotext',
name: 'gotmilk'
}
],
buttons: [{
text: 'Save'
},{
text: 'Cancel'
}]
});
simple.render(document.body);
});
</script>
</head>
<body>
</body>
</html>
I have quickly thrown together a radiotextfield & checkboxtextfield extensions (by shamelessly piggy backing off jsakalos's fantastic work with the DateTimeField extension (https://extjs.com/forum/showthread.php?t=22661))
It works and may help people searching for something like this. I make no guarantees however, consider it not properly tested & fundamentally unfinished!
Any bugs/fixes/improvements please post back to this thread. :)
Ext.ns('Ext.ux.form');
Ext.ux.form.CheckTextfield = Ext.extend(Ext.form.Field, {
value: false,
checkType: 'checkbox',
checked: false,
defaultAutoCreate: {
tag: 'input',
type: 'hidden'
},
initComponent: function() {
Ext.ux.form.CheckTextfield.superclass.initComponent.call(this);
var checkConfig = Ext.apply({},{
id: this.id + '-' + this.checkType,
checked: this.checked,
ownerCt: this,
listeners: {
blur: {
scope: this,
fn: this.onBlur
},
focus: {
scope: this,
fn: this.onFocus
}
}
},this.checkConfig);
this.cf = (this.checkType == 'checkbox' ? new Ext.form.Checkbox(checkConfig) : new Ext.form.Radio(checkConfig));
delete(this.checkConfig);
var textfieldConfig = Ext.apply({},{
id: this.id + '-textfield',
disabled: true,
style: 'width: 100%;',
ownerCt: this,
enable: function() {
this.disabled = false;
this.el.removeClass('x-item-disabled');
this.focus();
},
disable: function(check) {
this.ownerCt.cf.setValue(false);
this.disabled = true;
this.el.addClass('x-item-disabled');
if (this.hasFocus) {
this.ownerCt.cf.focus();
}
// else {
// var field = (this.checkType == "checkbox" ? Ext.form.Checkbox : Ext.form.Radio);
// field.prototype.disable.apply(this, arguments);
// }
},
listeners: {
blur: {
scope: this,
fn: this.onBlur
},
focus: {
scope: this,
fn: this.onFocus
}
}
},this.textfieldConfig);
this.tf = new Ext.form.TextField(textfieldConfig);
delete(this.textfieldConfig);
},
onRender: function(ct, position) {
if (this.isRendered) {
return null;
}
Ext.ux.form.CheckTextfield.superclass.onRender.call(this, ct, position);
var t;
t = Ext.DomHelper.append(ct, {
tag: 'table',
style: 'border-collapse:collapse;',
children: [{
tag: 'tr',
children: [{
tag: 'td',
style: 'padding-right:4px; width: 10px;',
cls: 'ux-checktextfield-cf'
},
{
tag: 'td',
cls: 'ux-checktextfield-tf'
}]
}]
},true);
this.tableEl = t;
this.wrap = t.wrap();
this.cf.render(t.child('td.ux-checktextfield-cf'));
this.cf.on('check',this.onCheck, this);
this.tf.render(t.child('td.ux-checktextfield-tf'));
this.tf.el.on('click',this.onClick, this);
if (Ext.isIE && Ext.isStrict) {
t.select('input').applyStyles({
top: 0
});
}
this.on('specialkey', this.onSpecialKey, this);
this.cf.el.swallowEvent(['keydown', 'keypress']);
this.tf.el.swallowEvent(['keydown', 'keypress']);
if ('side' === this.msgTarget) {
var elp = this.el.findParent('.x-form-element', 10, true);
this.errorIcon = elp.createChild({
cls: 'x-form-invalid-icon'
});
this.cf.errorIcon = this.errorIcon;
this.tf.errorIcon = this.errorIcon;
}
this.hiddenName = this.name || this.id;
this.hiddenName = this.hiddenName + '-hidden';
this.el.dom.name = this.name || this.id;
if (this.checkType == 'radio') {
this.cf.el.dom.name = this.name || this.id;
this.cf.name = this.name || this.id;
} else {
this.cf.el.dom.removeAttribute("name");
}
this.tf.el.dom.removeAttribute("name");
this.isRendered = true;
this.cf.setValue(this.checked || false);
},
onCheck: function(cb,checked) {
if (checked) {
this.enable();
} else {
this.disable('textfield');
}
},
onClick: function(e,el) {
if (this.tf.disabled) {
this.tf.enable();
this.tf.focus(true);
}
this.setValue(true);
},
adjustSize: Ext.BoxComponent.prototype.adjustSize,
alignErrorIcon: function() {
this.errorIcon.alignTo(this.tableEl, 'tl-tr', [2, 0]);
},
clearInvalid: function() {
this.tf.clearInvalid();
},
disable: function(e) {
if (e) {
this.cf.setValue(false);
this.tf.disable(true);
return this;
}
if (this.isRendered) {
this.cf.disabled = this.disabled;
this.cf.onDisable();
this.tf.onDisable();
}
this.disabled = true;
this.cf.disabled = true;
this.tf.disabled = true;
this.fireEvent("disable", this);
return this;
},
enable: function() {
if (this.rendered) {
this.cf.onEnable();
this.tf.onEnable();
}
this.disabled = false;
this.cf.disabled = false;
this.tf.disabled = false;
this.fireEvent("enable", this);
return this;
},
focus: function() {
this.cf.focus();
},
getPositionEl: function() {
return this.wrap;
},
getResizeEl: function() {
return this.wrap;
},
setSize: function(w, h) {
if (!w) {
return null;
}
this.tf.el.up('td').setWidth(w - 24);
},
getValue: function() {
return (this.cf.getValue() ? this.tf.getValue() : false);
},
isValid: function() {
if (this.cf.getValue()) {
return this.tf.isValid();
}
return this.cf.getValue();
},
isVisible: function() {
return this.cf.rendered && this.cf.getActionEl().isVisible();
},
onBlur: function(f) {
if (this.wrapClick) {
f.focus();
this.wrapClick = false;
}
(function() {
if (!this.cf.hasFocus && !this.tf.hasFocus) {
var v = this.getValue();
if (String(v) !== String(this.startValue)) {
this.fireEvent("change", this, v, this.startValue);
}
this.hasFocus = false;
this.fireEvent('blur', this);
}
}).defer(100, this);
},
onFocus: function() {
if (!this.hasFocus) {
this.hasFocus = true;
this.startValue = this.getValue();
this.fireEvent("focus", this);
}
},
onMouseDown: function(e) {
if (!this.disabled) {
this.wrapClick = 'td' === e.target.nodeName.toLowerCase();
}
},
onSpecialKey: function(t, e) {
var key = e.getKey();
if (key === e.TAB) {
if (t === this.df && !e.shiftKey) {
e.stopEvent();
this.tf.focus();
}
if (t === this.tf && e.shiftKey) {
e.stopEvent();
this.cf.focus();
}
}
if (key === e.ENTER) {
this.updateValue();
}
},
toggleValue : function() {
if(this.cf.checked){
var els = this.cf.getParent().select('input[name='+this.el.dom.name+']');
els.each(function(el){
if(el.dom.id != this.id && el.dom.id != this.id + '-radio'){
Ext.getCmp(el.dom.id).setValue(false);
}
}, this);
}
},
initValue : function(){
if(this.value !== undefined){
this.setValue(this.value,true);
}else if(this.el.dom.value.length > 0 && this.el.dom.value != this.emptyText){
this.setValue(this.el.dom.value,true);
}
// reference to original value for reset
this.originalValue = this.getValue();
},
setValue: function(val,init) {
if (!init) {
this.cf.setValue(val);
if (val !== true && val !== false) {
this.tf.setValue(this.value);
}
this.cf.setValue(val);
if (val === true && this.checkType == 'radio') {
this.toggleValue();
}
} else {
if (this.checkType == "radio" && val !== true && val !== false) {
this.tf.setValue(this.value);
}
this.cf.setValue(this.checked || false);
}
},
setVisible: function(visible) {
if (visible) {
this.cf.show();
this.tf.show();
} else {
this.cf.hide();
this.tf.hide();
}
return this;
},
show: function() {
return this.setVisible(true);
},
hide: function() {
return this.setVisible(false);
},
updateHidden: function() {
if (this.isRendered) {
this.el.dom.value = this.tf.getValue();
}
},
updateValue: function() {
this.updateHidden();
return null;
},
validate: function() {
return this.tf.validate();
}
});
Ext.ux.form.RadioTextfield = Ext.extend(Ext.ux.form.CheckTextfield,{
checkType: 'radio'
});
Ext.ux.form.CheckboxTextfield = Ext.extend(Ext.ux.form.CheckTextfield,{
checkType: 'checkbox',
valueInField: false
});
Ext.reg('radiotext', Ext.ux.form.RadioTextfield);
Ext.reg('checktext', Ext.ux.form.CheckboxTextfield);
Usage:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>CheckboxTextfield</title>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css"/>
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript" src="Ext.ux.form.CheckboxTextfield.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
Ext.QuickTips.init();
// turn on validation errors beside the field globally
Ext.form.Field.prototype.msgTarget = 'side';
var bd = Ext.getBody();
/*
* ================ Simple form =======================
*/
bd.createChild({tag: 'h2', html: 'Form 1 - Very Simple'});
var simple = new Ext.FormPanel({
labelWidth: 75, // label settings here cascade unless overridden
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {width: 230},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false
},{
fieldLabel: 'Last Name',
name: 'last'
},{
fieldLabel: 'Got Milk? (what brand)',
id: 'checktext',
xtype: 'checktext',
name: 'got milk'
},{
fieldLabel: 'one',
id: 'one',
xtype: 'radiotext',
name: 'gotmilk'
},{
fieldLabel: 'two',
id: 'two',
xtype: 'radiotext',
name: 'gotmilk'
},{
fieldLabel: 'three',
id: 'three',
xtype: 'radiotext',
name: 'gotmilk'
}
],
buttons: [{
text: 'Save'
},{
text: 'Cancel'
}]
});
simple.render(document.body);
});
</script>
</head>
<body>
</body>
</html>