X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..6b044c28b5f26fb99c86c237ffad19741c0f7f3d:/docs/source/Combo.html?ds=inline diff --git a/docs/source/Combo.html b/docs/source/Combo.html index 1c162801..8288c937 100644 --- a/docs/source/Combo.html +++ b/docs/source/Combo.html @@ -1,11 +1,18 @@ - -
-/** + + + ++ \ No newline at end of fileThe source code + + + + +/*! + * Ext JS Library 3.3.1 + * Copyright(c) 2006-2010 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** * @class Ext.form.ComboBox * @extends Ext.form.TriggerField *- +Ext.reg('combo', Ext.form.ComboBox); +A combobox control with support for autocomplete, remote-loading, paging and many other features.
@@ -102,14 +109,15 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { * Acceptable values for this property are: ***
- any {@link Ext.data.Store Store} subclass
- *- an Array : Arrays will be converted to a {@link Ext.data.ArrayStore} internally. + *
- an Array : Arrays will be converted to a {@link Ext.data.ArrayStore} internally, + * automatically generating {@link Ext.data.Field#name field names} to work with all data components. *
**
- 1-dimensional array : (e.g., ['Foo','Bar'])
+ * A 1-dimensional array will automatically be expanded (each array item will be used for both the combo + * {@link #valueField} and {@link #displayField})- * A 1-dimensional array will automatically be expanded (each array item will be the combo - * {@link #valueField value} and {@link #displayField text})- 2-dimensional array : (e.g., [['f','Foo'],['b','Bar']])
* For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo - * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}. + * {@link #valueField}, while the value at index 1 is assumed to be the combo {@link #displayField}. *See also {@link #mode}.
*/ @@ -126,8 +134,9 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { */ /** * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this - * ComboBox (defaults to undefined if {@link #mode} = 'remote' or 'text' if - * {@link #transform transforming a select} a select). + * ComboBox (defaults to undefined if {@link #mode} = 'remote' or 'field1' if + * {@link #transform transforming a select} or if the {@link #store field name is autogenerated based on + * the store configuration}). *See also {@link #valueField}.
*Note: if using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a * {@link Ext.grid.Column#renderer renderer} will be needed to show the displayField when the editor is not @@ -135,8 +144,9 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { */
/** * @cfg {String} valueField The underlying {@link Ext.data.Field#name data value name} to bind to this - * ComboBox (defaults to undefined if {@link #mode} = 'remote' or 'value' if - * {@link #transform transforming a select}). + * ComboBox (defaults to undefined if {@link #mode} = 'remote' or 'field2' if + * {@link #transform transforming a select} or if the {@link #store field name is autogenerated based on + * the store configuration}). *Note: use of a valueField requires the user to make a selection in order for a value to be * mapped. See also {@link #hiddenName}, {@link #hiddenValue}, and {@link #displayField}.
*/ @@ -144,16 +154,11 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the * field's data value (defaults to the underlying DOM element's name). Required for the combo's value to automatically * post during a form submission. See also {@link #valueField}. - *Note: the hidden field's id will also default to this name if {@link #hiddenId} is not specified. - * The ComboBox {@link Ext.Component#id id} and the {@link #hiddenId} should be different, since - * no two DOM nodes should share the same id. So, if the ComboBox {@link Ext.form.Field#name name} and - * hiddenName are the same, you should specify a unique {@link #hiddenId}.
*/ /** * @cfg {String} hiddenId If {@link #hiddenName} is specified, hiddenId can also be provided - * to give the hidden field a unique id (defaults to the {@link #hiddenName}). The hiddenId - * and combo {@link Ext.Component#id id} should be different, since no two DOM - * nodes should share the same id. + * to give the hidden field a unique id. The hiddenId and combo {@link Ext.Component#id id} should be + * different, since no two DOM nodes should share the same id. */ /** * @cfg {String} hiddenValue Sets the initial value of the hidden field if {@link #hiddenName} is @@ -187,8 +192,10 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { */ shadow : 'sides', /** - * @cfg {String} listAlign A valid anchor position value. See {@link Ext.Element#alignTo} for details - * on supported anchor positions (defaults to 'tl-bl?') + * @cfg {String/Array} listAlign A valid anchor position value. See {@link Ext.Element#alignTo} for details + * on supported anchor positions and offsets. To specify x/y offsets as well, this value + * may be specified as an Array of {@link Ext.Element#alignTo} method arguments. + *(defaults to 'tl-bl?') */ listAlign : 'tl-bl?', /** @@ -219,6 +226,12 @@ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, { * {@link Ext.form.TriggerField#editable editable} = false). */ minChars : 4, + /** + * @cfg {Boolean} autoSelect true to select the first result gathered by the data store (defaults + * to true). A false value would require a manual selection from the dropdown list to set the components value + * unless the value of ({@link #typeAheadDelay}) were true. + */ + autoSelect : true, /** * @cfg {Boolean} typeAhead true to populate and autoselect the remainder of the text being * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults @@ -327,6 +340,19 @@ var combo = new Ext.form.ComboBox({ */ lazyInit : true, + /** + * @cfg {Boolean} clearFilterOnReset true to clear any filters on the store (when in local mode) when reset is called + * (defaults to true) + */ + clearFilterOnReset : true, + + /** + * @cfg {Boolean} submitValue False to clear the name attribute on the field so that it is not submitted during a form post. + * If a hiddenName is specified, setting this to true will cause both the hidden field and the element to be submitted. + * Defaults to undefined. + */ + submitValue: undefined, + /** * The value of the match string used to filter the store. Delete this property to force a requery. * Example use: @@ -374,6 +400,7 @@ var combo = new Ext.form.ComboBox({ * @param {Ext.form.ComboBox} combo This combo box */ 'collapse', + /** * @event beforeselect * Fires before a list item is selected. Return false to cancel the selection. @@ -420,7 +447,7 @@ var combo = new Ext.form.ComboBox({ d.push([value, o.text]); } this.store = new Ext.data.ArrayStore({ - 'id': 0, + idIndex: 0, fields: ['value', 'text'], data : d, autoDestroy: true @@ -433,10 +460,8 @@ var combo = new Ext.form.ComboBox({ this.target = true; this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate); this.render(this.el.parentNode, s); - Ext.removeNode(s); // remove it - }else{ - Ext.removeNode(s); // remove it } + Ext.removeNode(s); } //auto-configure store from local array data else if(this.store){ @@ -463,13 +488,14 @@ var combo = new Ext.form.ComboBox({ // private onRender : function(ct, position){ + if(this.hiddenName && !Ext.isDefined(this.submitValue)){ + this.submitValue = false; + } Ext.form.ComboBox.superclass.onRender.call(this, ct, position); if(this.hiddenName){ this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, - id: (this.hiddenId||this.hiddenName)}, 'before', true); + id: (this.hiddenId || Ext.id())}, 'before', true); - // prevent input submission - this.el.dom.removeAttribute('name'); } if(Ext.isGecko){ this.el.dom.setAttribute('autocomplete', 'off'); @@ -487,21 +513,42 @@ var combo = new Ext.form.ComboBox({ Ext.form.ComboBox.superclass.initValue.call(this); if(this.hiddenField){ this.hiddenField.value = - Ext.isDefined(this.hiddenValue) ? this.hiddenValue : - Ext.isDefined(this.value) ? this.value : ''; + Ext.value(Ext.isDefined(this.hiddenValue) ? this.hiddenValue : this.value, ''); + } + }, + + getParentZIndex : function(){ + var zindex; + if (this.ownerCt){ + this.findParentBy(function(ct){ + zindex = parseInt(ct.getPositionEl().getStyle('z-index'), 10); + return !!zindex; + }); + } + return zindex; + }, + + getZIndex : function(listParent){ + listParent = listParent || Ext.getDom(this.getListParent() || Ext.getBody()); + var zindex = parseInt(Ext.fly(listParent).getStyle('z-index'), 10); + if(!zindex){ + zindex = this.getParentZIndex(); } + return (zindex || 12000) + 5; }, // private initList : function(){ if(!this.list){ - var cls = 'x-combo-list'; + var cls = 'x-combo-list', + listParent = Ext.getDom(this.getListParent() || Ext.getBody()); this.list = new Ext.Layer({ - parentEl: this.getListParent(), + parentEl: listParent, shadow: this.shadow, cls: [cls, this.listClass].join(' '), - constrain:false + constrain:false, + zindex: this.getZIndex(listParent) }); var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth); @@ -572,10 +619,15 @@ var combo = new Ext.form.ComboBox({ singleSelect: true, selectedClass: this.selectedClass, itemSelector: this.itemSelector || '.' + cls + '-item', - emptyText: this.listEmptyText + emptyText: this.listEmptyText, + deferEmptyText: false }); - this.mon(this.view, 'click', this.onViewClick, this); + this.mon(this.view, { + containerclick : this.onViewClick, + click : this.onViewClick, + scope :this + }); this.bindStore(this.store, true); @@ -648,17 +700,21 @@ var menu = new Ext.menu.Menu({ // private bindStore : function(store, initial){ if(this.store && !initial){ - this.store.un('beforeload', this.onBeforeLoad, this); - this.store.un('load', this.onLoad, this); - this.store.un('exception', this.collapse, this); if(this.store !== store && this.store.autoDestroy){ this.store.destroy(); + }else{ + this.store.un('beforeload', this.onBeforeLoad, this); + this.store.un('load', this.onLoad, this); + this.store.un('exception', this.collapse, this); } if(!store){ this.store = null; if(this.view){ this.view.bindStore(null); } + if(this.pageTb){ + this.pageTb.bindStore(null); + } } } if(store){ @@ -683,10 +739,34 @@ var menu = new Ext.menu.Menu({ } }, + reset : function(){ + if(this.clearFilterOnReset && this.mode == 'local'){ + this.store.clearFilter(); + } + Ext.form.ComboBox.superclass.reset.call(this); + }, + // private initEvents : function(){ Ext.form.ComboBox.superclass.initEvents.call(this); + /** + * @property keyNav + * @type Ext.KeyNav + *[ 'tl-bl?', [6,0] ]
A {@link Ext.KeyNav KeyNav} object which handles navigation keys for this ComboBox. This performs actions + * based on keystrokes typed when the input field is focused.
+ *After the ComboBox has been rendered, you may override existing navigation key functionality, + * or add your own based upon key names as specified in the {@link Ext.KeyNav KeyNav} class.
+ *The function is executed in the scope (
this
reference of the ComboBox. Example:+ */ this.keyNav = new Ext.KeyNav(this.el, { "up" : function(e){ this.inKeyMode = true; @@ -704,8 +784,6 @@ var menu = new Ext.menu.Menu({ "enter" : function(e){ this.onViewClick(); - this.delayedCheck = true; - this.unsetDelayCheck.defer(10, this); }, "esc" : function(e){ @@ -713,20 +791,31 @@ var menu = new Ext.menu.Menu({ }, "tab" : function(e){ - this.onViewClick(false); + if (this.forceSelection === true) { + this.collapse(); + } else { + this.onViewClick(false); + } return true; }, scope : this, - doRelay : function(foo, bar, hname){ + doRelay : function(e, h, hname){ if(hname == 'down' || this.scope.isExpanded()){ - return Ext.KeyNav.prototype.doRelay.apply(this, arguments); + // this MUST be called before ComboBox#fireKey() + var relay = Ext.KeyNav.prototype.doRelay.apply(this, arguments); + if(!Ext.isIE && Ext.EventManager.useKeydown){ + // call Combo#fireKey() for browsers which use keydown event (except IE) + this.scope.fireKey(e); + } + return relay; } return true; }, - forceKeyDown : true + forceKeyDown : true, + defaultEventAction: 'stopEvent' }); this.queryDelay = Math.max(this.queryDelay || 10, this.mode == 'local' ? 10 : 250); @@ -734,11 +823,12 @@ var menu = new Ext.menu.Menu({ if(this.typeAhead){ this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this); } - if(this.editable !== false && !this.enableKeyEvents){ + if(!this.enableKeyEvents){ this.mon(this.el, 'keyup', this.onKeyUp, this); } }, + // private onDestroy : function(){ if (this.dqTask){ @@ -752,34 +842,29 @@ var menu = new Ext.menu.Menu({ this.pageTb, this.list ); + Ext.destroyMembers(this, 'hiddenField'); Ext.form.ComboBox.superclass.onDestroy.call(this); }, - // private - unsetDelayCheck : function(){ - delete this.delayedCheck; - }, - // private fireKey : function(e){ - var fn = function(ev){ - if (ev.isNavKeyPress() && !this.isExpanded() && !this.delayedCheck) { - this.fireEvent("specialkey", this, ev); - } - }; - //For some reason I can't track down, the events fire in a different order in webkit. - //Need a slight delay here - if(this.inEditor && Ext.isWebKit && e.getKey() == e.TAB){ - fn.defer(10, this, [new Ext.EventObjectImpl(e)]); - }else{ - fn.call(this, e); + if (!this.isExpanded()) { + Ext.form.ComboBox.superclass.fireKey.call(this, e); } }, // private onResize : function(w, h){ Ext.form.ComboBox.superclass.onResize.apply(this, arguments); - if(this.list && !Ext.isDefined(this.listWidth)){ + if(!isNaN(w) && this.isVisible() && this.list){ + this.doResize(w); + }else{ + this.bufferSize = w; + } + }, + + doResize: function(w){ + if(!Ext.isDefined(this.listWidth)){ var lw = Math.max(w, this.minListWidth); this.list.setWidth(lw); this.innerList.setWidth(lw - this.list.getFrameWidth('lr')); @@ -818,26 +903,29 @@ var menu = new Ext.menu.Menu({ if(!this.hasFocus){ return; } - if(this.store.getCount() > 0){ + if(this.store.getCount() > 0 || this.listEmptyText){ this.expand(); this.restrictHeight(); if(this.lastQuery == this.allQuery){ if(this.editable){ this.el.dom.select(); } - if(!this.selectByValue(this.value, true)){ + + if(this.autoSelect !== false && !this.selectByValue(this.value, true)){ this.select(0, true); } }else{ - this.selectNext(); + if(this.autoSelect !== false){ + this.selectNext(); + } if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){ this.taTask.delay(this.typeAheadDelay); } } }else{ - this.onEmptyResults(); + this.collapse(); } - //this.el.focus(); + }, // private @@ -854,6 +942,38 @@ var menu = new Ext.menu.Menu({ } }, + // private + assertValue : function(){ + var val = this.getRawValue(), + rec; + + if(this.valueField && Ext.isDefined(this.value)){ + rec = this.findRecord(this.valueField, this.value); + } + if(!rec || rec.get(this.displayField) != val){ + rec = this.findRecord(this.displayField, val); + } + if(!rec && this.forceSelection){ + if(val.length > 0 && val != this.emptyText){ + this.el.dom.value = Ext.value(this.lastSelectionText, ''); + this.applyEmptyText(); + }else{ + this.clearValue(); + } + }else{ + if(rec && this.valueField){ + // onSelect may have already set the value and by doing so + // set the display field properly. Let's not wipe out the + // valueField here by just sending the displayField. + if (this.value == val){ + return; + } + val = rec.get(this.valueField || this.displayField); + } + this.setValue(val); + } + }, + // private onSelect : function(record, index){ if(this.fireEvent('beforeselect', this, record, index) !== false){ @@ -914,7 +1034,7 @@ var menu = new Ext.menu.Menu({ } this.lastSelectionText = text; if(this.hiddenField){ - this.hiddenField.value = v; + this.hiddenField.value = Ext.value(v, ''); } Ext.form.ComboBox.superclass.setValue.call(this, text); this.value = v; @@ -954,39 +1074,39 @@ var menu = new Ext.menu.Menu({ // private onViewClick : function(doFocus){ - var index = this.view.getSelectedIndexes()[0]; - var r = this.store.getAt(index); + var index = this.view.getSelectedIndexes()[0], + s = this.store, + r = s.getAt(index); if(r){ this.onSelect(r, index); + }else { + this.collapse(); } if(doFocus !== false){ this.el.focus(); } }, + // private restrictHeight : function(){ this.innerList.dom.style.height = ''; - var inner = this.innerList.dom; - var pad = this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight; - var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight); - var ha = this.getPosition()[1]-Ext.getBody().getScroll().top; - var hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height; - var space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5; + var inner = this.innerList.dom, + pad = this.list.getFrameWidth('tb') + (this.resizable ? this.handleHeight : 0) + this.assetHeight, + h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight), + ha = this.getPosition()[1]-Ext.getBody().getScroll().top, + hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height, + space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5; + h = Math.min(h, space, this.maxHeight); this.innerList.setHeight(h); this.list.beginUpdate(); this.list.setHeight(h+pad); - this.list.alignTo(this.wrap, this.listAlign); + this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign)); this.list.endUpdate(); }, - // private - onEmptyResults : function(){ - this.collapse(); - }, - /** * Returns true if the dropdown list is expanded, else false. */ @@ -1029,6 +1149,7 @@ var menu = new Ext.menu.Menu({ this.innerList.scrollChildIntoView(el, false); } } + }, // private @@ -1058,7 +1179,8 @@ var menu = new Ext.menu.Menu({ // private onKeyUp : function(e){ var k = e.getKey(); - if(this.editable !== false && (k == e.BACKSPACE || !e.isSpecialKey())){ + if(this.editable !== false && this.readOnly !== true && (k == e.BACKSPACE || !e.isSpecialKey())){ + this.lastKey = k; this.dqTask.delay(this.queryDelay); } @@ -1077,21 +1199,14 @@ var menu = new Ext.menu.Menu({ // private beforeBlur : function(){ - var val = this.getRawValue(); - if(this.forceSelection){ - if(val.length > 0 && val != this.emptyText){ - this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : ''; - this.applyEmptyText(); - }else{ - this.clearValue(); - } - }else{ - var rec = this.findRecord(this.displayField, val); - if(rec){ - val = rec.get(this.valueField || this.displayField); - } - this.setValue(val); - } + this.assertValue(); + }, + + // private + postBlur : function(){ + Ext.form.ComboBox.superclass.postBlur.call(this); + this.collapse(); + this.inKeyMode = false; }, /** @@ -1142,13 +1257,13 @@ var menu = new Ext.menu.Menu({ // private getParams : function(q){ - var p = {}; - //p[this.queryParam] = q; + var params = {}, + paramNames = this.store.paramNames; if(this.pageSize){ - p.start = 0; - p.limit = this.pageSize; + params[paramNames.start] = 0; + params[paramNames.limit] = this.pageSize; } - return p; + return params; }, /** @@ -1166,7 +1281,7 @@ var menu = new Ext.menu.Menu({ // private collapseIf : function(e){ - if(!e.within(this.wrap) && !e.within(this.list)){ + if(!this.isDestroyed && !e.within(this.wrap) && !e.within(this.list)){ this.collapse(); } }, @@ -1178,12 +1293,30 @@ var menu = new Ext.menu.Menu({ if(this.isExpanded() || !this.hasFocus){ return; } - this.list.alignTo(this.wrap, this.listAlign); + + if(this.title || this.pageSize){ + this.assetHeight = 0; + if(this.title){ + this.assetHeight += this.header.getHeight(); + } + if(this.pageSize){ + this.assetHeight += this.footer.getHeight(); + } + } + + if(this.bufferSize){ + this.doResize(this.bufferSize); + delete this.bufferSize; + } + this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign)); + + // zindex can change, re-check it and set it if necessary + this.list.setZIndex(this.getZIndex()); this.list.show(); if(Ext.isGecko2){ this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac } - Ext.getDoc().on({ + this.mon(Ext.getDoc(), { scope: this, mousewheel: this.collapseIf, mousedown: this.collapseIf @@ -1198,7 +1331,7 @@ var menu = new Ext.menu.Menu({ // private // Implements the default empty TriggerField.onTriggerClick function onTriggerClick : function(){ - if(this.disabled){ + if(this.readOnly || this.disabled){ return; } if(this.isExpanded()){ @@ -1230,6 +1363,7 @@ var menu = new Ext.menu.Menu({ */ }); -Ext.reg('combo', Ext.form.ComboBox);+myCombo.keyNav.esc = function(e) { // Override ESC handling function + this.collapse(); // Standard behaviour of Ext's ComboBox. + this.setValue(this.startValue); // We reset to starting value on ESC +}; +myCombo.keyNav.tab = function() { // Override TAB handling function + this.onViewClick(false); // Select the currently highlighted row +}; +