12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046 |
- /*
- * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
- *
- * http://extjs.com/license
- */
- /**
- * @class Ext.form.ComboBox
- * @extends Ext.form.TriggerField A combobox control with support for
- * autocomplete, remote-loading, paging and many other features.
- * @constructor Create a new ComboBox.
- * @param {Object}
- * config Configuration options
- */
- Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {
- /**
- * @cfg {Mixed} transform The id, DOM node or element of an existing select
- * to convert to a ComboBox
- */
- /**
- * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering
- * until requested (should always be used when rendering into an
- * Ext.Editor, defaults to false)
- */
- /**
- * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a
- * default element spec (defaults to: {tag: "input", type: "text",
- * size: "24", autocomplete: "off"})
- */
- /**
- * @cfg {Ext.data.Store} store The data store to which this combo is bound
- * (defaults to undefined)
- */
- /**
- * @cfg {String} title If supplied, a header element is created containing
- * this text and added into the top of the dropdown list (defaults to
- * undefined, with no header element)
- */
- // private
- defaultAutoCreate : {
- tag : "input",
- type : "text",
- size : "24",
- autocomplete : "off"
- },
- /**
- * @cfg {Number} listWidth The width in pixels of the dropdown list
- * (defaults to the width of the ComboBox field)
- */
- /**
- * @cfg {String} displayField The underlying data field name to bind to this
- * ComboBox (defaults to undefined if mode = 'remote' or 'text' if
- * transforming a select)
- */
- /**
- * @cfg {String} valueField The underlying data value name to bind to this
- * ComboBox (defaults to undefined if mode = 'remote' or 'value' if
- * transforming a select) Note: use of a valueField requires the user
- * to make a selection in order for a value to be mapped.
- */
- /**
- * @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.
- */
- /**
- * @cfg {String} listClass CSS class to apply to the dropdown list element
- * (defaults to '')
- */
- listClass : '',
- /**
- * @cfg {String} selectedClass CSS class to apply to the selected item in
- * the dropdown list (defaults to 'x-combo-selected')
- */
- selectedClass : 'x-combo-selected',
- /**
- * @cfg {String} triggerClass An additional CSS class used to style the
- * trigger button. The trigger will always get the class
- * 'x-form-trigger' and triggerClass will be <b>appended</b> if
- * specified (defaults to 'x-form-arrow-trigger' which displays a
- * downward arrow icon).
- */
- triggerClass : 'x-form-arrow-trigger',
- /**
- * @cfg {Boolean/String} shadow True or "sides" for the default effect,
- * "frame" for 4-way shadow, and "drop" for bottom-right
- */
- 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')
- */
- listAlign : 'tl-bl?',
- /**
- * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list
- * before scrollbars are shown (defaults to 300)
- */
- maxHeight : 300,
- /**
- * @cfg {String} triggerAction The action to execute when the trigger field
- * is activated. Use 'all' to run the query specified by the allQuery
- * config option (defaults to 'query')
- */
- triggerAction : 'query',
- /**
- * @cfg {Number} minChars The minimum number of characters the user must
- * type before autocomplete and typeahead activate (defaults to 4 if
- * remote or 0 if local, does not apply if editable = false)
- */
- minChars : 4,
- /**
- * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of
- * the text being typed after a configurable delay (typeAheadDelay) if
- * it matches a known value (defaults to false)
- */
- typeAhead : false,
- /**
- * @cfg {Number} queryDelay The length of time in milliseconds to delay
- * between the start of typing and sending the query to filter the
- * dropdown list (defaults to 500 if mode = 'remote' or 10 if mode =
- * 'local')
- */
- queryDelay : 500,
- /**
- * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed
- * in the footer of the dropdown list and the filter queries will
- * execute with page start and limit parameters. Only applies when mode =
- * 'remote' (defaults to 0)
- */
- pageSize : 0,
- /**
- * @cfg {Boolean} selectOnFocus True to select any existing text in the
- * field immediately on focus. Only applies when editable = true
- * (defaults to false)
- */
- selectOnFocus : false,
- /**
- * @cfg {String} queryParam Name of the query as it will be passed on the
- * querystring (defaults to 'query')
- */
- queryParam : 'query',
- /**
- * @cfg {String} loadingText The text to display in the dropdown list while
- * data is loading. Only applies when mode = 'remote' (defaults to
- * 'Loading...')
- */
- loadingText : 'Loading...',
- /**
- * @cfg {Boolean} resizable True to add a resize handle to the bottom of the
- * dropdown list (defaults to false)
- */
- resizable : false,
- /**
- * @cfg {Number} handleHeight The height in pixels of the dropdown list
- * resize handle if resizable = true (defaults to 8)
- */
- handleHeight : 8,
- /**
- * @cfg {Boolean} editable False to prevent the user from typing text
- * directly into the field, just like a traditional select (defaults to
- * true)
- */
- editable : true,
- /**
- * @cfg {String} allQuery The text query to send to the server to return all
- * records for the list with no filtering (defaults to '')
- */
- allQuery : '',
- /**
- * @cfg {String} mode Set to 'local' if the ComboBox loads local data
- * (defaults to 'remote' which loads from the server)
- */
- mode : 'remote',
- /**
- * @cfg {Number} minListWidth The minimum width of the dropdown list in
- * pixels (defaults to 70, will be ignored if listWidth has a higher
- * value)
- */
- minListWidth : 70,
- /**
- * @cfg {Boolean} forceSelection True to restrict the selected value to one
- * of the values in the list, false to allow the user to set arbitrary
- * text into the field (defaults to false)
- */
- forceSelection : false,
- /**
- * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait
- * until the typeahead text is displayed if typeAhead = true (defaults
- * to 250)
- */
- typeAheadDelay : 250,
- /**
- * @cfg {String} valueNotFoundText When using a name/value combo, if the
- * value passed to setValue is not found in the store,
- * valueNotFoundText will be displayed as the field text if defined
- * (defaults to undefined)
- */
- /**
- * @cfg {Boolean} lazyInit True to not initialize the list for this combo
- * until the field is focused. (defaults to true)
- */
- lazyInit : true,
- initComponent : function() {
- Ext.form.ComboBox.superclass.initComponent.call(this);
- this.addEvents(
- /**
- * @event expand Fires when the dropdown list is expanded
- * @param {Ext.form.ComboBox}
- * combo This combo box
- */
- 'expand',
- /**
- * @event collapse Fires when the dropdown list is collapsed
- * @param {Ext.form.ComboBox}
- * combo This combo box
- */
- 'collapse',
- /**
- * @event beforeselect Fires before a list item is selected.
- * Return false to cancel the selection.
- * @param {Ext.form.ComboBox}
- * combo This combo box
- * @param {Ext.data.Record}
- * record The data record returned from the
- * underlying store
- * @param {Number}
- * index The index of the selected item in the
- * dropdown list
- */
- 'beforeselect',
- /**
- * @event select Fires when a list item is selected
- * @param {Ext.form.ComboBox}
- * combo This combo box
- * @param {Ext.data.Record}
- * record The data record returned from the
- * underlying store
- * @param {Number}
- * index The index of the selected item in the
- * dropdown list
- */
- 'select',
- /**
- * @event beforequery Fires before all queries are processed.
- * Return false to cancel the query or set the
- * queryEvent's cancel property to true.
- * @param {Object}
- * queryEvent An object that has these properties:
- * <ul>
- * <li><code>combo</code> : Ext.form.ComboBox <div
- * class="sub-desc">This combo box</div></li>
- * <li><code>query</code> : String <div
- * class="sub-desc">The query</div></li>
- * <li><code>forceAll</code> : Boolean <div
- * class="sub-desc">True to force "all" query</div></li>
- * <li><code>cancel</code> : Boolean <div
- * class="sub-desc">Set to true to cancel the query</div></li>
- * </ul>
- */
- 'beforequery');
- if (this.transform) {
- this.allowDomMove = false;
- var s = Ext.getDom(this.transform);
- if (!this.hiddenName) {
- this.hiddenName = s.name;
- }
- if (!this.store) {
- this.mode = 'local';
- var d = [], opts = s.options;
- for (var i = 0, len = opts.length; i < len; i++) {
- var o = opts[i];
- var value = (Ext.isIE
- ? o.getAttributeNode('value').specified
- : o.hasAttribute('value')) ? o.value : o.text;
- if (o.selected) {
- this.value = value;
- }
- d.push([value, o.text]);
- }
- this.store = new Ext.data.SimpleStore({
- 'id' : 0,
- fields : ['value', 'text'],
- data : d
- });
- this.valueField = 'value';
- this.displayField = 'text';
- }
- s.name = Ext.id(); // wipe out the name in case somewhere else they
- // have a reference
- if (!this.lazyRender) {
- this.target = true;
- this.el = Ext.DomHelper.insertBefore(s, this.autoCreate
- || this.defaultAutoCreate);
- Ext.removeNode(s); // remove it
- this.render(this.el.parentNode);
- } else {
- Ext.removeNode(s); // remove it
- }
- }
- this.selectedIndex = -1;
- if (this.mode == 'local') {
- if (this.initialConfig.queryDelay === undefined) {
- this.queryDelay = 10;
- }
- if (this.initialConfig.minChars === undefined) {
- this.minChars = 0;
- }
- }
- },
- // private
- onRender : function(ct, position) {
- 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);
- this.hiddenField.value = this.hiddenValue !== undefined
- ? this.hiddenValue
- : this.value !== undefined ? this.value : '';
- // prevent input submission
- this.el.dom.removeAttribute('name');
- }
- if (Ext.isGecko) {
- this.el.dom.setAttribute('autocomplete', 'off');
- }
- if (!this.lazyInit) {
- this.initList();
- } else {
- this.on('focus', this.initList, this, {
- single : true
- });
- }
- if (!this.editable) {
- this.editable = true;
- this.setEditable(false);
- }
- },
- initList : function() {
- if (!this.list) {
- var cls = 'x-combo-list';
- this.list = new Ext.Layer({
- shadow : this.shadow,
- cls : [cls, this.listClass].join(' '),
- constrain : false
- });
- var lw = this.listWidth
- || Math.max(this.wrap.getWidth(), this.minListWidth);
- this.list.setWidth(lw);
- this.list.swallowEvent('mousewheel');
- this.assetHeight = 0;
- if (this.title) {
- this.header = this.list.createChild({
- cls : cls + '-hd',
- html : this.title
- });
- this.assetHeight += this.header.getHeight();
- }
- this.innerList = this.list.createChild({
- cls : cls + '-inner'
- });
- this.innerList.on('mouseover', this.onViewOver, this);
- this.innerList.on('mousemove', this.onViewMove, this);
- this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
- if (this.pageSize) {
- this.footer = this.list.createChild({
- cls : cls + '-ft'
- });
- this.pageTb = new Ext.PagingToolbar({
- store : this.store,
- pageSize : this.pageSize,
- renderTo : this.footer
- });
- this.assetHeight += this.footer.getHeight();
- }
- if (!this.tpl) {
- /**
- * @cfg {String/Ext.XTemplate} tpl The template string, or
- * {@link Ext.XTemplate} instance to use to display each
- * item in the dropdown list. Use this to create custom UI
- * layouts for items in the list.
- * <p>
- * If you wish to preserve the default visual look of list
- * items, add the CSS class name
- *
- * <pre>
- * x - combo - list - item
- * </pre>
- *
- * to the template's container element.
- * <p>
- * <b>The template must contain one or more substitution
- * parameters using field names from the Combo's</b>
- * {@link #store Store}. An example of a custom template
- * would be adding an
- *
- * <pre>
- * ext : qtip
- * </pre>
- *
- * attribute which might display other fields from the
- * Store.
- * <p>
- * The dropdown list is displayed in a DataView. See
- * {@link Ext.DataView} for details.
- */
- this.tpl = '<tpl for="."><div class="' + cls + '-item">{'
- + this.displayField + '}</div></tpl>';
- }
- /**
- * The {@link Ext.DataView DataView} used to display the ComboBox's
- * options.
- *
- * @type Ext.DataView
- */
- this.view = new Ext.DataView({
- applyTo : this.innerList,
- tpl : this.tpl,
- singleSelect : true,
- selectedClass : this.selectedClass,
- itemSelector : this.itemSelector || '.' + cls + '-item'
- });
- this.view.on('click', this.onViewClick, this);
- this.bindStore(this.store, true);
- if (this.resizable) {
- this.resizer = new Ext.Resizable(this.list, {
- pinned : true,
- handles : 'se'
- });
- this.resizer.on('resize', function(r, w, h) {
- this.maxHeight = h - this.handleHeight
- - this.list.getFrameWidth('tb')
- - this.assetHeight;
- this.listWidth = w;
- this.innerList.setWidth(w
- - this.list.getFrameWidth('lr'));
- this.restrictHeight();
- }, this);
- this[this.pageSize ? 'footer' : 'innerList'].setStyle(
- 'margin-bottom', this.handleHeight + 'px');
- }
- }
- },
- // 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('loadexception', this.collapse, this);
- if (!store) {
- this.store = null;
- if (this.view) {
- this.view.setStore(null);
- }
- }
- }
- if (store) {
- this.store = Ext.StoreMgr.lookup(store);
- this.store.on('beforeload', this.onBeforeLoad, this);
- this.store.on('load', this.onLoad, this);
- this.store.on('loadexception', this.collapse, this);
- if (this.view) {
- this.view.setStore(store);
- }
- }
- },
- // private
- initEvents : function() {
- Ext.form.ComboBox.superclass.initEvents.call(this);
- this.keyNav = new Ext.KeyNav(this.el, {
- "up" : function(e) {
- this.inKeyMode = true;
- this.selectPrev();
- },
- "down" : function(e) {
- if (!this.isExpanded()) {
- this.onTriggerClick();
- } else {
- this.inKeyMode = true;
- this.selectNext();
- }
- },
- "enter" : function(e) {
- this.onViewClick();
- // return true;
- },
- "esc" : function(e) {
- this.collapse();
- },
- "tab" : function(e) {
- this.onViewClick(false);
- return true;
- },
- scope : this,
- doRelay : function(foo, bar, hname) {
- if (hname == 'down' || this.scope.isExpanded()) {
- return Ext.KeyNav.prototype.doRelay.apply(this,
- arguments);
- }
- return true;
- },
- forceKeyDown : true
- });
- this.queryDelay = Math.max(this.queryDelay || 10, this.mode == 'local'
- ? 10
- : 250);
- this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
- if (this.typeAhead) {
- this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
- }
- if (this.editable !== false) {
- this.el.on("keyup", this.onKeyUp, this);
- }
- if (this.forceSelection) {
- this.on('blur', this.doForce, this);
- }
- },
- onDestroy : function() {
- if (this.view) {
- this.view.el.removeAllListeners();
- this.view.el.remove();
- this.view.purgeListeners();
- }
- if (this.list) {
- this.list.destroy();
- }
- this.bindStore(null);
- Ext.form.ComboBox.superclass.onDestroy.call(this);
- },
- // private
- fireKey : function(e) {
- if (e.isNavKeyPress() && !this.list.isVisible()) {
- this.fireEvent("specialkey", this, e);
- }
- },
- // private
- onResize : function(w, h) {
- Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
- if (this.list && this.listWidth === undefined) {
- var lw = Math.max(w, this.minListWidth);
- this.list.setWidth(lw);
- this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
- }
- },
- // private
- onDisable : function() {
- Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
- if (this.hiddenField) {
- this.hiddenField.disabled = this.disabled;
- }
- },
- /**
- * Allow or prevent the user from directly editing the field text. If false
- * is passed, the user will only be able to select from the items defined in
- * the dropdown list. This method is the runtime equivalent of setting the
- * 'editable' config option at config time.
- *
- * @param {Boolean}
- * value True to allow the user to directly edit the field text
- */
- setEditable : function(value) {
- if (value == this.editable) {
- return;
- }
- this.editable = value;
- if (!value) {
- this.el.dom.setAttribute('readOnly', true);
- this.el.on('mousedown', this.onTriggerClick, this);
- this.el.addClass('x-combo-noedit');
- } else {
- this.el.dom.setAttribute('readOnly', false);
- this.el.un('mousedown', this.onTriggerClick, this);
- this.el.removeClass('x-combo-noedit');
- }
- },
- // private
- onBeforeLoad : function() {
- if (!this.hasFocus) {
- return;
- }
- this.innerList.update(this.loadingText
- ? '<div class="loading-indicator">' + this.loadingText
- + '</div>'
- : '');
- this.restrictHeight();
- this.selectedIndex = -1;
- },
- // private
- onLoad : function() {
- if (!this.hasFocus) {
- return;
- }
- if (this.store.getCount() > 0) {
- this.expand();
- this.restrictHeight();
- if (this.lastQuery == this.allQuery) {
- if (this.editable) {
- this.el.dom.select();
- }
- if (!this.selectByValue(this.value, true)) {
- this.select(0, true);
- }
- } else {
- this.selectNext();
- if (this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE
- && this.lastKey != Ext.EventObject.DELETE) {
- this.taTask.delay(this.typeAheadDelay);
- }
- }
- } else {
- this.onEmptyResults();
- }
- // this.el.focus();
- },
- // private
- onTypeAhead : function() {
- if (this.store.getCount() > 0) {
- var r = this.store.getAt(0);
- var newValue = r.data[this.displayField];
- var len = newValue.length;
- var selStart = this.getRawValue().length;
- if (selStart != len) {
- this.setRawValue(newValue);
- this.selectText(selStart, newValue.length);
- }
- }
- },
- // private
- onSelect : function(record, index) {
- if (this.fireEvent('beforeselect', this, record, index) !== false) {
- this.setValue(record.data[this.valueField || this.displayField]);
- this.collapse();
- this.fireEvent('select', this, record, index);
- }
- },
- /**
- * Returns the currently selected field value or empty string if no value is
- * set.
- *
- * @return {String} value The selected value
- */
- getValue : function() {
- if (this.valueField) {
- return typeof this.value != 'undefined' ? this.value : '';
- } else {
- return Ext.form.ComboBox.superclass.getValue.call(this);
- }
- },
- /**
- * Clears any text/value currently set in the field
- */
- clearValue : function() {
- if (this.hiddenField) {
- this.hiddenField.value = '';
- }
- this.setRawValue('');
- this.lastSelectionText = '';
- this.applyEmptyText();
- },
- /**
- * Sets the specified value into the field. If the value finds a match, the
- * corresponding record text will be displayed in the field. If the value
- * does not match the data value of an existing item, and the
- * valueNotFoundText config option is defined, it will be displayed as the
- * default field text. Otherwise the field will be blank (although the value
- * will still be set).
- *
- * @param {String}
- * value The value to match
- */
- setValue : function(v) {
- var text = v;
- if (this.valueField) {
- var r = this.findRecord(this.valueField, v);
- if (r) {
- text = r.data[this.displayField];
- } else if (this.valueNotFoundText !== undefined) {
- text = this.valueNotFoundText;
- }
- }
- this.lastSelectionText = text;
- if (this.hiddenField) {
- this.hiddenField.value = v;
- }
- Ext.form.ComboBox.superclass.setValue.call(this, text);
- this.value = v;
- },
- // private
- findRecord : function(prop, value) {
- var record;
- if (this.store.getCount() > 0) {
- this.store.each(function(r) {
- if (r.data[prop] == value) {
- record = r;
- return false;
- }
- });
- }
- return record;
- },
- // private
- onViewMove : function(e, t) {
- this.inKeyMode = false;
- },
- // private
- onViewOver : function(e, t) {
- if (this.inKeyMode) { // prevent key nav and mouse over conflicts
- return;
- }
- var item = this.view.findItemFromChild(t);
- if (item) {
- var index = this.view.indexOf(item);
- this.select(index, false);
- }
- },
- // private
- onViewClick : function(doFocus) {
- var index = this.view.getSelectedIndexes()[0];
- var r = this.store.getAt(index);
- if (r) {
- this.onSelect(r, index);
- }
- if (doFocus !== false) {
- this.el.focus();
- }
- },
- // private
- restrictHeight : function() {
- this.innerList.dom.style.height = '';
- var inner = this.innerList.dom;
- var fw = this.list.getFrameWidth('tb');
- var h = Math.max(inner.clientHeight, inner.offsetHeight,
- inner.scrollHeight);
- this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
- this.list.beginUpdate();
- this.list.setHeight(this.innerList.getHeight() + fw
- + (this.resizable ? this.handleHeight : 0) + this.assetHeight);
- this.list.alignTo(this.el, this.listAlign);
- this.list.endUpdate();
- },
- // private
- onEmptyResults : function() {
- this.collapse();
- },
- /**
- * Returns true if the dropdown list is expanded, else false.
- */
- isExpanded : function() {
- return this.list && this.list.isVisible();
- },
- /**
- * Select an item in the dropdown list by its data value. This function does
- * NOT cause the select event to fire. The store must be loaded and the list
- * expanded for this function to work, otherwise use setValue.
- *
- * @param {String}
- * value The data value of the item to select
- * @param {Boolean}
- * scrollIntoView False to prevent the dropdown list from
- * autoscrolling to display the selected item if it is not
- * currently in view (defaults to true)
- * @return {Boolean} True if the value matched an item in the list, else
- * false
- */
- selectByValue : function(v, scrollIntoView) {
- if (v !== undefined && v !== null) {
- var r = this.findRecord(this.valueField || this.displayField, v);
- if (r) {
- this.select(this.store.indexOf(r), scrollIntoView);
- return true;
- }
- }
- return false;
- },
- /**
- * Select an item in the dropdown list by its numeric index in the list.
- * This function does NOT cause the select event to fire. The store must be
- * loaded and the list expanded for this function to work, otherwise use
- * setValue.
- *
- * @param {Number}
- * index The zero-based index of the list item to select
- * @param {Boolean}
- * scrollIntoView False to prevent the dropdown list from
- * autoscrolling to display the selected item if it is not
- * currently in view (defaults to true)
- */
- select : function(index, scrollIntoView) {
- this.selectedIndex = index;
- this.view.select(index);
- if (scrollIntoView !== false) {
- var el = this.view.getNode(index);
- if (el) {
- this.innerList.scrollChildIntoView(el, false);
- }
- }
- },
- // private
- selectNext : function() {
- var ct = this.store.getCount();
- if (ct > 0) {
- if (this.selectedIndex == -1) {
- this.select(0);
- } else if (this.selectedIndex < ct - 1) {
- this.select(this.selectedIndex + 1);
- }
- }
- },
- // private
- selectPrev : function() {
- var ct = this.store.getCount();
- if (ct > 0) {
- if (this.selectedIndex == -1) {
- this.select(0);
- } else if (this.selectedIndex != 0) {
- this.select(this.selectedIndex - 1);
- }
- }
- },
- // private
- onKeyUp : function(e) {
- if (this.editable !== false && !e.isSpecialKey()) {
- this.lastKey = e.getKey();
- this.dqTask.delay(this.queryDelay);
- }
- },
- // private
- validateBlur : function() {
- return !this.list || !this.list.isVisible();
- },
- // private
- initQuery : function() {
- this.doQuery(this.getRawValue());
- },
- // private
- doForce : function() {
- if (this.el.dom.value.length > 0) {
- this.el.dom.value = this.lastSelectionText === undefined
- ? ''
- : this.lastSelectionText;
- this.applyEmptyText();
- }
- },
- /**
- * Execute a query to filter the dropdown list. Fires the beforequery event
- * prior to performing the query allowing the query action to be canceled if
- * needed.
- *
- * @param {String}
- * query The SQL query to execute
- * @param {Boolean}
- * forceAll True to force the query to execute even if there are
- * currently fewer characters in the field than the minimum
- * specified by the minChars config option. It also clears any
- * filter previously saved in the current store (defaults to
- * false)
- */
- doQuery : function(q, forceAll) {
- if (q === undefined || q === null) {
- q = '';
- }
- var qe = {
- query : q,
- forceAll : forceAll,
- combo : this,
- cancel : false
- };
- if (this.fireEvent('beforequery', qe) === false || qe.cancel) {
- return false;
- }
- q = qe.query;
- forceAll = qe.forceAll;
- if (forceAll === true || (q.length >= this.minChars)) {
- if (this.lastQuery !== q) {
- this.lastQuery = q;
- if (this.mode == 'local') {
- this.selectedIndex = -1;
- if (forceAll) {
- this.store.clearFilter();
- } else {
- this.store.filter(this.displayField, q);
- }
- this.onLoad();
- } else {
- this.store.baseParams[this.queryParam] = q;
- this.store.load({
- params : this.getParams(q)
- });
- this.expand();
- }
- } else {
- this.selectedIndex = -1;
- this.onLoad();
- }
- }
- },
- // private
- getParams : function(q) {
- var p = {};
- // p[this.queryParam] = q;
- if (this.pageSize) {
- p.start = 0;
- p.limit = this.pageSize;
- }
- return p;
- },
- /**
- * Hides the dropdown list if it is currently expanded. Fires the 'collapse'
- * event on completion.
- */
- collapse : function() {
- if (!this.isExpanded()) {
- return;
- }
- this.list.hide();
- Ext.getDoc().un('mousewheel', this.collapseIf, this);
- Ext.getDoc().un('mousedown', this.collapseIf, this);
- this.fireEvent('collapse', this);
- },
- // private
- collapseIf : function(e) {
- if (!e.within(this.wrap) && !e.within(this.list)) {
- this.collapse();
- }
- },
- /**
- * Expands the dropdown list if it is currently hidden. Fires the 'expand'
- * event on completion.
- */
- expand : function() {
- if (this.isExpanded() || !this.hasFocus) {
- return;
- }
- this.list.alignTo(this.wrap, this.listAlign);
- this.list.show();
- Ext.getDoc().on('mousewheel', this.collapseIf, this);
- Ext.getDoc().on('mousedown', this.collapseIf, this);
- this.fireEvent('expand', this);
- },
- // private
- // Implements the default empty TriggerField.onTriggerClick function
- onTriggerClick : function() {
- if (this.disabled) {
- return;
- }
- if (this.isExpanded()) {
- this.collapse();
- this.el.focus();
- } else {
- this.onFocus({});
- if (this.triggerAction == 'all') {
- this.doQuery(this.allQuery, true);
- } else {
- this.doQuery(this.getRawValue());
- }
- this.el.focus();
- }
- }
- /**
- * @hide
- * @method autoSize
- */
- /**
- * @cfg {Boolean} grow
- * @hide
- */
- /**
- * @cfg {Number} growMin
- * @hide
- */
- /**
- * @cfg {Number} growMax
- * @hide
- */
- });
- Ext.reg('combo', Ext.form.ComboBox);
|