Code:
Ext.define('My.form.field.RefField', {
extend: 'Ext.form.field.Trigger',
requires: ['Ext.util.KeyNav', 'Ext.data.StoreManager'],
alias: 'widget.reffield',
editable: true,
triggerCls: Ext.baseCSSPrefix + 'form-search-trigger',
hiddenDataCls: Ext.baseCSSPrefix + 'hide-display ' + Ext.baseCSSPrefix + 'form-data-hidden',
//emptyText:'',
displayField:'',
valueField:'',
refWidth:450,
refHeight:400,
contentPanel:Ext.create('Ext.panel.Panel'),
/**
* @override
*/
fieldSubTpl: [
'<div class="{hiddenDataCls}" role="presentation"></div>',
'<input id="{id}" type="{type}" ',
'<tpl if="size">size="{size}" </tpl>',
'<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
'class="{fieldCls} {typeCls}" autocomplete="off" />',
'<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
'{triggerEl}',
'<div class="{clearCls}" role="presentation"></div>',
'</div>',
{
compiled: true,
disableFormats: true
}
],
getSubTplData: function(){
var me = this;
Ext.applyIf(me.subTplData, {
hiddenDataCls: me.hiddenDataCls
});
return me.callParent(arguments);
},
afterRender: function(){
var me = this;
me.callParent(arguments);
me.setHiddenValue(me.value);
},
initComponent: function() {
var me = this;
Ext.applyIf(me.renderSelectors, {
hiddenDataEl: '.' + me.hiddenDataCls.split(' ').join('.')
});
if (!me.displayTpl) {
me.displayTpl = Ext.create('Ext.XTemplate',
'<tpl for=".">' +
'{[typeof values === "string" ? values : values["' + me.displayField + '"]]}' +
'<tpl if="xindex < xcount">' + me.delimiter + '</tpl>' +
'</tpl>'
);
} else if (Ext.isString(me.displayTpl)) {
me.displayTpl = Ext.create('Ext.XTemplate', me.displayTpl);
}
this.callParent();
this.addEvents('expand','collapse');
if(Ext.isString(me.store)){
me.store = Ext.data.StoreManager.lookup(me.store);
me.store.load();
}
},
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) {
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');
}
},
/**
* Expands this field's picker dropdown.
*/
expand: function() {
var me = this,
bodyEl, picker, collapseIf;
if (me.rendered && !me.isExpanded && !me.isDestroyed) {
bodyEl = me.bodyEl;
picker = me.getPicker();
collapseIf = me.collapseIf;
// show the picker and set isExpanded flag
picker.show();
me.isExpanded = true;
bodyEl.addCls(me.openCls);
//Ext.EventManager.onWindowResize(me.alignPicker, me);
me.fireEvent('expand', me);
me.onExpand();
}
},
onExpand: Ext.emptyFn,
/**
* Collapses this field's picker dropdown.
*/
collapse: function() {
if (this.isExpanded && !this.isDestroyed) {
var me = this,
openCls = me.openCls,
picker = me.picker,
doc = Ext.getDoc(),
collapseIf = me.collapseIf,
aboveSfx = '-above';
// hide the picker and set isExpanded flag
picker.hide();
me.isExpanded = false;
// remove the openCls
me.bodyEl.removeCls([openCls, openCls + aboveSfx]);
picker.el.removeCls(picker.baseCls + aboveSfx);
// remove event listeners
doc.un('mousewheel', collapseIf, me);
doc.un('mousedown', collapseIf, me);
Ext.EventManager.removeResizeListener(me.alignPicker, me);
me.fireEvent('collapse', me);
me.onCollapse();
}
},
onCollapse: Ext.emptyFn,
/**
* @private
* Runs on mousewheel and mousedown of doc to check to see if we should collapse the picker
*/
collapseIf: function(e) {
var me = this;
if (!me.isDestroyed && !e.within(me.bodyEl, false, true) && !e.within(me.picker.el, false, true)) {
me.collapse();
}
},
/**
* Returns a reference to the picker component for this field, creating it if necessary by
* calling {@link #createPicker}.
* @return {Ext.Component} The picker component
*/
getPicker: function() {
var me = this;
return me.picker || (me.picker = me.createPicker());
},
/**
* @method
* Creates and returns the component to be used as this field's picker. Must be implemented by subclasses of Picker.
* The current field should also be passed as a configuration option to the picker component as the pickerField
* property.
*/
createPicker: function(){
var me = this;
var okBtn = new Ext.button.Button({text:'Ok'});
var cancelBtn = new Ext.button.Button({text:'Cancel'});
okBtn.addListener('click',function(){
record = me.contentPanel.getSelectionModel().getLastSelected();
me.onOkButtonClick(record);
});
cancelBtn.addListener('click',function(){
me.refWindow.hide();
});
me.refWindow=Ext.create('Ext.window.Window', {
title:me.refTitle,
height: me.refHeight,
width: me.refWidth,
modal:true,
layout: 'fit',
closeAction:'hide',
buttons:[okBtn,cancelBtn],
items: me.contentPanel,
getSelectionModel:function(){
return me.contentPanel.getSelectionModel();
}
});
return me.refWindow;
},
onOkButtonClick:function(record){
var me = this;
valueField = me.valueField;
if (record) {
me.displayTplData = [record.data];
me.setRawValue(me.getDisplayValue());
me.setValue(record.get(valueField));
me.collapse();
}
},
/**
* Finds the record by searching for a specific field/value combination.
* @param {String} field The name of the field to test.
* @param {Object} value The value to match the field against.
* @return {Ext.data.Model} The matched record or false.
*/
findRecord: function(field, value) {
var ds = this.store,
idx;
idx = ds.findExact(field, value);
return idx !== -1 ? ds.getAt(idx) : false;
},
/**
* Finds the record by searching values in the {@link #valueField}.
* @param {Object} value The value to match the field against.
* @return {Ext.data.Model} The matched record or false.
*/
findRecordByValue: function(value) {
return this.findRecord(this.valueField, value);
},
/**
* Finds the record by searching values in the {@link #displayField}.
* @param {Object} value The value to match the field against.
* @return {Ext.data.Model} The matched record or false.
*/
findRecordByDisplay: function(value) {
return this.findRecord(this.displayField, value);
},
/**
* Handles the trigger click; by default toggles between expanding and collapsing the picker component.
* @protected
*/
onTriggerClick: function() {
var me = this;
if (!me.readOnly && !me.disabled) {
if (me.isExpanded) {
me.collapse();
} else {
me.expand();
}
me.inputEl.focus();
}
},
setValue: function(value, doSelect) {
var me = this,
record;
me.value = value;
if(value){
record = me.findRecordByValue(value);
if(record){
me.setRawValue(record.get(me.displayField));
}
else{
me.setRawValue('');
}
}
me.checkChange();
return me;
},
setHiddenValue: function(value){
var me = this,
name = me.hiddenName,
i,
dom, childNodes, input, valueCount, childrenCount;
if (!me.hiddenDataEl || !name) {
return;
}
values = Ext.Array.from(values);
dom = me.hiddenDataEl.dom;
childNodes = dom.childNodes;
input = childNodes[0];
valueCount = values.length;
childrenCount = childNodes.length;
if (!input && valueCount > 0) {
me.hiddenDataEl.update(Ext.DomHelper.markup({
tag: 'input',
type: 'hidden',
name: name
}));
childrenCount = 1;
input = dom.firstChild;
}
while (childrenCount > valueCount) {
dom.removeChild(childNodes[0]);
-- childrenCount;
}
while (childrenCount < valueCount) {
dom.appendChild(input.cloneNode(true));
++ childrenCount;
}
for (i = 0; i < valueCount; i++) {
childNodes[i].value = values[i];
}
},
getDisplayValue: function() {
return this.displayTpl.apply(this.displayTplData);
},
getValue: function() {
var me = this,
picker = me.picker,
//rawValue = me.getRawValue(), //current value of text field
value = me.value; //stored value from last selection or setValue() call
if (value) {
me.value = me.displayTplData = me.valueModels = null;
if (picker&&picker.isHidden()) {
picker.getSelectionModel().deselectAll();
}
}
return value;
},
getSubmitValue: function() {
return this.getValue();
},
/**
* Clears any value currently set in the ComboBox.
*/
clearValue: function() {
this.setValue([]);
},
reset : function(){
this.callParent();
this.applyEmptyText();
},
applyEmptyText : function(){
var me = this;
me.value = null;
if (me.rendered) {
me.setRawValue('');
}
},
mimicBlur: function(e) {
var me = this,
picker = me.picker;
// ignore mousedown events within the picker element
if (!picker || !e.within(picker.el, false, true)) {
me.callParent(arguments);
}
},
onDestroy : function(){
var me = this,
picker = me.picker;
//Ext.EventManager.removeResizeListener(me.alignPicker, me);
Ext.destroy(me.keyNav);
if (picker) {
delete picker.pickerField;
picker.destroy();
}
me.callParent();
}
});