Code:
/**
* Ext.ux.Box
* Ext.ux.BoxSelect
*
* http://extjs.com/forum/showthread.php?t=33794
*/
Ext.namespace('Ext.ux');
Ext.ux.Box = Ext.extend(Ext.Component, {
initComponent : function(){
Ext.ux.Box.superclass.initComponent.call(this);
},
onRender: function(ct, position){
Ext.ux.Box.superclass.onRender.call(this, ct, this.maininput);
this.addEvents('remove');
this.addClass('bit-box');
this.el = ct.createChild({ tag: "li" }, this.maininput);
this.el.addClassOnOver('bit-hover');
Ext.apply(this.el, {
'focus': function(){ this.down('a.closebutton').focus(); },
'dispose': function(){ this.dispose() }.createDelegate(this)
});
this.el.on('click', function(e){
this.focus()
}, this, {stopEvent:true});
this.el.update(this.caption);
this.lnk = this.el.createChild({
'tag': 'a',
'class': 'closebutton',
'href':'#'
});
this.lnk.on({
'click': function(e){
e.stopEvent();
this.fireEvent('remove', this);
this.dispose();
},
'focus': function(){
this.el.addClass("bit-box-focus");
},
'blur': function(){
this.el.removeClass("bit-box-focus");
},
scope: this
});
new Ext.KeyMap(this.lnk, [
{
key: [Ext.EventObject.BACKSPACE, Ext.EventObject.DELETE],
fn: function(){
this.dispose();
}.createDelegate(this)
},
{
key: Ext.EventObject.RIGHT,
fn: function(){
this.move('right');
}.createDelegate(this)
},
{
key: Ext.EventObject.LEFT,
fn: function(){
this.move('left');
}.createDelegate(this)
},
{
key: Ext.EventObject.TAB,
fn: function(){
}.createDelegate(this)
}
]).stopEvent = true;
},
move: function(direction) {
if(direction == 'left')
el = this.el.prev();
else
el = this.el.next();
if(el)
el.focus();
},
dispose: function() {
Ext.fly(this.hidden).remove();
this.el.hide({
duration: .1,
callback: function(){
this.move('right');
this.destroy()
}.createDelegate(this)
});
return this;
}
});
Ext.ux.BoxSelect = Ext.extend(Ext.form.ComboBox, {
/**
* @cfg {Array} value default value(s). Should be an array of objects
*/
/**
* @cfg {String} valueField value attribute of the value objects
*/
/**
* @cfg {String} displayField display attribute of the value objects
*/
/**
* @cfg {String} displayFieldTpl
*/
initComponent:function() {
Ext.apply(this, {
selectedValues: {},
boxElements: {},
current: false,
options: {
className: 'bit',
separator: ','
},
hideTrigger: true,
grow: false
});
Ext.ux.BoxSelect.superclass.initComponent.call(this);
},
onRender:function(ct, position) {
Ext.ux.BoxSelect.superclass.onRender.call(this, ct, position);
this.el.removeClass('x-form-text');
this.el.className = 'maininput';
this.el.dom.name = '';
this.el.setWidth(20);
this.el.dom.value = ''
this.holder = this.el.wrap({
'tag': 'ul',
'class':'holder x-form-text'
});
this.holder.on('click', function(e){
e.stopEvent();
if(this.maininput != this.current) this.focus(this.maininput);
}, this);
this.maininput = this.el.wrap({
'tag': 'li', 'class':'bit-input'
});
Ext.apply(this.maininput, {
'focus': function(){
this.focus();
}.createDelegate(this)
});
},
// private
initValue : function() {
if(typeof this.displayFieldTpl === 'string') {
this.displayFieldTpl = new Ext.XTemplate(this.displayFieldTpl)
}
if(typeof this.value !== 'undefined') {
Ext.each(this.value, function(item){
if(this.displayFieldTpl) {
caption = this.displayFieldTpl.apply(item);
} else {
caption = item[this.displayField]
}
this.addBox(item[this.valueField], caption);
}, this);
}
},
onResize : function( w, h, rw, rh ){
this._width = w;
Ext.ux.BoxSelect.superclass.onResize.call(this, w, h, rw, rh);
this.autoSize();
},
onKeyUp : function(e) {
if(this.editable !== false && !e.isSpecialKey()){
this.lastKey = e.getKey();
if(e.getKey() == e.BACKSPACE && this.el.dom.value.length == 0){
e.stopEvent();
this.collapse();
var el = this.maininput.prev();
if(el) el.focus();
return;
}
this.dqTask.delay(this.queryDelay);
}
this.autoSize();
Ext.ux.BoxSelect.superclass.onKeyUp.call(this, e);
},
onSelect: function(record, index) {
var val = record.data[this.valueField];
this.selectedValues[val] = val;
if(typeof this.displayFieldTpl === 'string') {
this.displayFieldTpl = new Ext.XTemplate(this.displayFieldTpl)
}
if(!this.boxElements[val]) {
var caption;
if(this.displayFieldTpl)
caption = this.displayFieldTpl.apply(record.data)
else if(this.displayField)
caption = record.data[this.displayField];
this.addBox(record.data[this.valueField], caption)
}
this.collapse();
this.setRawValue('');
this.lastSelectionText = '';
this.applyEmptyText();
this.autoSize();
},
addBox: function(id, caption){
var box = new Ext.ux.Box({
id: 'Box_' + id,
maininput: this.maininput,
renderTo: this.holder,
className: this.options['className'],
caption: caption,
'value': id,
listeners: {
'remove': function(box){
this.selectedValues[box.value] = null;
},
scope: this
}
});
box.render();
box.hidden = this.el.insertSibling({
'tag':'input',
'type':'hidden',
'value': id,
'name': (this.hiddenName || this.name)
},'before', true);
},
autoSize : function(){
if(!this.rendered){ return; }
if(!this.metrics){
this.metrics = Ext.util.TextMetrics.createInstance(this.el);
}
var el = this.el;
var v = el.dom.value;
var d = document.createElement('div');
d.appendChild(document.createTextNode(v));
v = d.innerHTML;
d = null;
v += "*";
var w = Math.min(this._width, Math.max(this.metrics.getWidth(v) + 10, 10));
this.el.setWidth(w);
},
getValues: function(){
var ret = [];
for(var k in this.selectedValues){
if(this.selectedValues[k]) {
ret.push(this.selectedValues[k]);
}
}
return ret.join(this.options['separator']);
}
});
Ext.reg('boxselect', Ext.ux.BoxSelect);