Hey guys. I had to build a form with lots of on and off switches and I liked the look of the iPhone's on / off switch so I extended the RadioGroup element to make an iPhoneSwitch.
Feel free to use it as you please. If you have any suggestions of how it can be improved let me know. I'm using CSS3 transitions for the animation of the switch.
Here is a picture of how it looks. Sorry, no live demo yet.
iPhoneSwitch.png
Here is the CSS.
Code:
.x-iphone-switch img{background: url(../images/iphone_switch.png) no-repeat 0 0;width:94px;height:27px;cursor:pointer; -webkit-transition: background-position .25s linear;-moz-transition: background-position .25s linear;-o-transition: background-position .25s linear;transition: background-position .25s linear;}
.x-iphone-switch.off img{background-position: -53px 0;}
.x-iphone-switch-label{margin-top:2px;}
Here is the iphone_switch.png and the container image.
iphone_switch.pngiphone_switch_container.gif
Here is the actual plugin. I've only tested this in ExtJS 3.3.1. Should be easily portable to other versions.
Code:
// create namespace for plugins
Ext.namespace('Ext.ux.plugins');
/**
* Ext.ux.plugins.iPhoneSwitch plugin for Ext.form.Radio
*
* @author Chalres Himmer
* @stardate January 25, 2010
*
* @class Ext.ux.plugins.IphoneSwitch
* @extends Ext.form.RadioGroup
*/
Ext.ux.plugins.iPhoneSwitch = Ext.extend(Ext.form.RadioGroup, {
initComponent:function() {
this.addEvents(
'changed'
);
// private hard coded config
var config = {
items:[
{boxLabel: 'On', name: this.name + '-on', inputValue: true, hidden: true},
{boxLabel: 'Off', name: this.name + '-off', inputValue: false, hidden: true, checked: true}
]
};
Ext.apply(this, config);
// call parent initComponent
Ext.ux.plugins.iPhoneSwitch.superclass.initComponent.call(this);
}, // end of function initComponent
onRender: function(ct, position){
Ext.ux.plugins.iPhoneSwitch.superclass.onRender.call(this, ct, position);
var statusClass = (this.getValue().inputValue == 0) ? ' off':'on';
this.switch = new Ext.Element(Ext.DomHelper.append(this.el, {
tag: 'div',
cls: 'x-iphone-switch' + statusClass,
children:[{
tag: 'img',
src: 'static/images/iphone_switch_container.gif'
}]
}));
// add class to label so we can target it using css
this.switch.parent('div.x-form-element').prev('label').addClass('x-iphone-switch-label');
// add listener
this.switch.on('click', this.onClick, this, {delegate:'img'});
},
onClick: function(e, t){
e.stopEvent();
// change the value of the form
this.setValue('toggle');
// fire event
this.fireEvent("afterchange", this, this.value);
},
/**
* @param {string} val
*
* We are overriding the default behavior of the setValue method
* so we can use the form's bulk setValues method and just pass in
* either true, false, on, off, or toggle.
*/
setValue: function(val){
// see if we are toggling the switch's state
if(val === 'toggle'){
val = (this.getValue().inputValue) ? false:true;
}
// if val is 'on', true, or 1 turn this on the switch
else if([1,'true',true,'on'].indexOf(val) !== -1){
val = true;
console.log(this.switch);
}
// then we must be turning the switch off
else if([0,'false',false,'off'].indexOf(val) !== -1){
val = false;
this.switch.removeClass('on').addClass('off');
}
// unrecongized value
else{
console.log('Unknown value for iPhoneSwitch: ' + val);
}
// set the internal radio button's value
this.items.first().setValue(val);
// animate image
this.animateSwitch(val);
},
/**
* @param {string} - Possible values are true or false
*
* This animates the switching of the switch use CSS3 animations
*/
animateSwitch: function(status){
if(status){
this.switch.removeClass('off').addClass('on');
}else{
this.switch.removeClass('on').addClass('off');
}
}
});
// register xtype
Ext.reg('iphoneswitch', Ext.ux.plugins.iPhoneSwitch);
// end of file