Combo.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:45k
源码类别:

中间件编程

开发平台:

JavaScript

  1. /*!
  2.  * Ext JS Library 3.0.0
  3.  * Copyright(c) 2006-2009 Ext JS, LLC
  4.  * licensing@extjs.com
  5.  * http://www.extjs.com/license
  6.  */
  7. /**
  8.  * @class Ext.form.ComboBox
  9.  * @extends Ext.form.TriggerField
  10.  * <p>A combobox control with support for autocomplete, remote-loading, paging and many other features.</p>
  11.  * <p>A ComboBox works in a similar manner to a traditional HTML &lt;select> field. The difference is
  12.  * that to submit the {@link #valueField}, you must specify a {@link #hiddenName} to create a hidden input
  13.  * field to hold the value of the valueField. The <i>{@link #displayField}</i> is shown in the text field
  14.  * which is named according to the {@link #name}.</p>
  15.  * <p><b><u>Events</u></b></p>
  16.  * <p>To do something when something in ComboBox is selected, configure the select event:<pre><code>
  17. var cb = new Ext.form.ComboBox({
  18.     // all of your config options
  19.     listeners:{
  20.          scope: yourScope,
  21.          'select': yourFunction
  22.     }
  23. });
  24. // Alternatively, you can assign events after the object is created:
  25. var cb = new Ext.form.ComboBox(yourOptions);
  26. cb.on('select', yourFunction, yourScope);
  27.  * </code></pre></p>
  28.  *
  29.  * <p><b><u>ComboBox in Grid</u></b></p>
  30.  * <p>If using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a {@link Ext.grid.Column#renderer renderer}
  31.  * will be needed to show the displayField when the editor is not active.  Set up the renderer manually, or implement
  32.  * a reusable render, for example:<pre><code>
  33. // create reusable renderer
  34. Ext.util.Format.comboRenderer = function(combo){
  35.     return function(value){
  36.         var record = combo.findRecord(combo.{@link #valueField}, value);
  37.         return record ? record.get(combo.{@link #displayField}) : combo.{@link #valueNotFoundText};
  38.     }
  39. }
  40. // create the combo instance
  41. var combo = new Ext.form.ComboBox({
  42.     {@link #typeAhead}: true,
  43.     {@link #triggerAction}: 'all',
  44.     {@link #lazyRender}:true,
  45.     {@link #mode}: 'local',
  46.     {@link #store}: new Ext.data.ArrayStore({
  47.         id: 0,
  48.         fields: [
  49.             'myId',
  50.             'displayText'
  51.         ],
  52.         data: [[1, 'item1'], [2, 'item2']]
  53.     }),
  54.     {@link #valueField}: 'myId',
  55.     {@link #displayField}: 'displayText'
  56. });
  57. // snippet of column model used within grid
  58. var cm = new Ext.grid.ColumnModel([{
  59.        ...
  60.     },{
  61.        header: "Some Header",
  62.        dataIndex: 'whatever',
  63.        width: 130,
  64.        editor: combo, // specify reference to combo instance
  65.        renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer
  66.     },
  67.     ...
  68. ]);
  69.  * </code></pre></p>
  70.  *
  71.  * <p><b><u>Filtering</u></b></p>
  72.  * <p>A ComboBox {@link #doQuery uses filtering itself}, for information about filtering the ComboBox
  73.  * store manually see <tt>{@link #lastQuery}</tt>.</p>
  74.  * @constructor
  75.  * Create a new ComboBox.
  76.  * @param {Object} config Configuration options
  77.  * @xtype combo
  78.  */
  79. Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {
  80.     /**
  81.      * @cfg {Mixed} transform The id, DOM node or element of an existing HTML SELECT to convert to a ComboBox.
  82.      * Note that if you specify this and the combo is going to be in an {@link Ext.form.BasicForm} or
  83.      * {@link Ext.form.FormPanel}, you must also set <tt>{@link #lazyRender} = true</tt>.
  84.      */
  85.     /**
  86.      * @cfg {Boolean} lazyRender <tt>true</tt> to prevent the ComboBox from rendering until requested
  87.      * (should always be used when rendering into an {@link Ext.Editor} (e.g. {@link Ext.grid.EditorGridPanel Grids}),
  88.      * defaults to <tt>false</tt>).
  89.      */
  90.     /**
  91.      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or <tt>true</tt> for a default
  92.      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
  93.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>
  94.      * <pre><code>{tag: "input", type: "text", size: "24", autocomplete: "off"}</code></pre>
  95.      */
  96.     /**
  97.      * @cfg {Ext.data.Store/Array} store The data source to which this combo is bound (defaults to <tt>undefined</tt>).
  98.      * Acceptable values for this property are:
  99.      * <div class="mdetail-params"><ul>
  100.      * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
  101.      * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.
  102.      * <div class="mdetail-params"><ul>
  103.      * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
  104.      * A 1-dimensional array will automatically be expanded (each array item will be the combo
  105.      * {@link #valueField value} and {@link #displayField text})</div></li>
  106.      * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
  107.      * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
  108.      * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.
  109.      * </div></li></ul></div></li></ul></div>
  110.      * <p>See also <tt>{@link #mode}</tt>.</p>
  111.      */
  112.     /**
  113.      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
  114.      * the dropdown list (defaults to undefined, with no header element)
  115.      */
  116.     // private
  117.     defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
  118.     /**
  119.      * @cfg {Number} listWidth The width (used as a parameter to {@link Ext.Element#setWidth}) of the dropdown
  120.      * list (defaults to the width of the ComboBox field).  See also <tt>{@link #minListWidth}
  121.      */
  122.     /**
  123.      * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this
  124.      * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'text'</tt> if
  125.      * {@link #transform transforming a select} a select).
  126.      * <p>See also <tt>{@link #valueField}</tt>.</p>
  127.      * <p><b>Note</b>: if using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a
  128.      * {@link Ext.grid.Column#renderer renderer} will be needed to show the displayField when the editor is not
  129.      * active.</p>
  130.      */
  131.     /**
  132.      * @cfg {String} valueField The underlying {@link Ext.data.Field#name data value name} to bind to this
  133.      * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'value'</tt> if
  134.      * {@link #transform transforming a select}).
  135.      * <p><b>Note</b>: use of a <tt>valueField</tt> requires the user to make a selection in order for a value to be
  136.      * mapped.  See also <tt>{@link #hiddenName}</tt>, <tt>{@link #hiddenValue}</tt>, and <tt>{@link #displayField}</tt>.</p>
  137.      */
  138.     /**
  139.      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
  140.      * field's data value (defaults to the underlying DOM element's name). Required for the combo's value to automatically
  141.      * post during a form submission.  See also {@link #valueField}.
  142.      * <p><b>Note</b>: the hidden field's id will also default to this name if {@link #hiddenId} is not specified.
  143.      * The ComboBox {@link Ext.Component#id id} and the <tt>{@link #hiddenId}</tt> <b>should be different</b>, since
  144.      * no two DOM nodes should share the same id.  So, if the ComboBox <tt>{@link Ext.form.Field#name name}</tt> and
  145.      * <tt>hiddenName</tt> are the same, you should specify a unique <tt>{@link #hiddenId}</tt>.</p>
  146.      */
  147.     /**
  148.      * @cfg {String} hiddenId If <tt>{@link #hiddenName}</tt> is specified, <tt>hiddenId</tt> can also be provided
  149.      * to give the hidden field a unique id (defaults to the <tt>{@link #hiddenName}</tt>).  The <tt>hiddenId</tt>
  150.      * and combo {@link Ext.Component#id id} should be different, since no two DOM
  151.      * nodes should share the same id.
  152.      */
  153.     /**
  154.      * @cfg {String} hiddenValue Sets the initial value of the hidden field if {@link #hiddenName} is
  155.      * specified to contain the selected {@link #valueField}, from the Store. Defaults to the configured
  156.      * <tt>{@link Ext.form.Field#value value}</tt>.
  157.      */
  158.     /**
  159.      * @cfg {String} listClass The CSS class to add to the predefined <tt>'x-combo-list'</tt> class
  160.      * applied the dropdown list element (defaults to '').
  161.      */
  162.     listClass : '',
  163.     /**
  164.      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list
  165.      * (defaults to <tt>'x-combo-selected'</tt>)
  166.      */
  167.     selectedClass : 'x-combo-selected',
  168.     /**
  169.      * @cfg {String} listEmptyText The empty text to display in the data view if no items are found.
  170.      * (defaults to '')
  171.      */
  172.     listEmptyText: '',
  173.     /**
  174.      * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always
  175.      * get the class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified
  176.      * (defaults to <tt>'x-form-arrow-trigger'</tt> which displays a downward arrow icon).
  177.      */
  178.     triggerClass : 'x-form-arrow-trigger',
  179.     /**
  180.      * @cfg {Boolean/String} shadow <tt>true</tt> or <tt>"sides"</tt> for the default effect, <tt>"frame"</tt> for
  181.      * 4-way shadow, and <tt>"drop"</tt> for bottom-right
  182.      */
  183.     shadow : 'sides',
  184.     /**
  185.      * @cfg {String} listAlign A valid anchor position value. See <tt>{@link Ext.Element#alignTo}</tt> for details
  186.      * on supported anchor positions (defaults to <tt>'tl-bl?'</tt>)
  187.      */
  188.     listAlign : 'tl-bl?',
  189.     /**
  190.      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown
  191.      * (defaults to <tt>300</tt>)
  192.      */
  193.     maxHeight : 300,
  194.     /**
  195.      * @cfg {Number} minHeight The minimum height in pixels of the dropdown list when the list is constrained by its
  196.      * distance to the viewport edges (defaults to <tt>90</tt>)
  197.      */
  198.     minHeight : 90,
  199.     /**
  200.      * @cfg {String} triggerAction The action to execute when the trigger is clicked.
  201.      * <div class="mdetail-params"><ul>
  202.      * <li><b><tt>'query'</tt></b> : <b>Default</b>
  203.      * <p class="sub-desc">{@link #doQuery run the query} using the {@link Ext.form.Field#getRawValue raw value}.</p></li>
  204.      * <li><b><tt>'all'</tt></b> :
  205.      * <p class="sub-desc">{@link #doQuery run the query} specified by the <tt>{@link #allQuery}</tt> config option</p></li>
  206.      * </ul></div>
  207.      * <p>See also <code>{@link #queryParam}</code>.</p>
  208.      */
  209.     triggerAction : 'query',
  210.     /**
  211.      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and
  212.      * {@link #typeAhead} activate (defaults to <tt>4</tt> if <tt>{@link #mode} = 'remote'</tt> or <tt>0</tt> if
  213.      * <tt>{@link #mode} = 'local'</tt>, does not apply if
  214.      * <tt>{@link Ext.form.TriggerField#editable editable} = false</tt>).
  215.      */
  216.     minChars : 4,
  217.     /**
  218.      * @cfg {Boolean} typeAhead <tt>true</tt> to populate and autoselect the remainder of the text being
  219.      * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults
  220.      * to <tt>false</tt>)
  221.      */
  222.     typeAhead : false,
  223.     /**
  224.      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and
  225.      * sending the query to filter the dropdown list (defaults to <tt>500</tt> if <tt>{@link #mode} = 'remote'</tt>
  226.      * or <tt>10</tt> if <tt>{@link #mode} = 'local'</tt>)
  227.      */
  228.     queryDelay : 500,
  229.     /**
  230.      * @cfg {Number} pageSize If greater than <tt>0</tt>, a {@link Ext.PagingToolbar} is displayed in the
  231.      * footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and
  232.      * {@link Ext.PagingToolbar#pageSize limit} parameters. Only applies when <tt>{@link #mode} = 'remote'</tt>
  233.      * (defaults to <tt>0</tt>).
  234.      */
  235.     pageSize : 0,
  236.     /**
  237.      * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.
  238.      * Only applies when <tt>{@link Ext.form.TriggerField#editable editable} = true</tt> (defaults to
  239.      * <tt>false</tt>).
  240.      */
  241.     selectOnFocus : false,
  242.     /**
  243.      * @cfg {String} queryParam Name of the query ({@link Ext.data.Store#baseParam baseParam} name for the store)
  244.      * as it will be passed on the querystring (defaults to <tt>'query'</tt>)
  245.      */
  246.     queryParam : 'query',
  247.     /**
  248.      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
  249.      * when <tt>{@link #mode} = 'remote'</tt> (defaults to <tt>'Loading...'</tt>)
  250.      */
  251.     loadingText : 'Loading...',
  252.     /**
  253.      * @cfg {Boolean} resizable <tt>true</tt> to add a resize handle to the bottom of the dropdown list
  254.      * (creates an {@link Ext.Resizable} with 'se' {@link Ext.Resizable#pinned pinned} handles).
  255.      * Defaults to <tt>false</tt>.
  256.      */
  257.     resizable : false,
  258.     /**
  259.      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if
  260.      * <tt>{@link #resizable} = true</tt> (defaults to <tt>8</tt>)
  261.      */
  262.     handleHeight : 8,
  263.     /**
  264.      * @cfg {String} allQuery The text query to send to the server to return all records for the list
  265.      * with no filtering (defaults to '')
  266.      */
  267.     allQuery: '',
  268.     /**
  269.      * @cfg {String} mode Acceptable values are:
  270.      * <div class="mdetail-params"><ul>
  271.      * <li><b><tt>'remote'</tt></b> : <b>Default</b>
  272.      * <p class="sub-desc">Automatically loads the <tt>{@link #store}</tt> the <b>first</b> time the trigger
  273.      * is clicked. If you do not want the store to be automatically loaded the first time the trigger is
  274.      * clicked, set to <tt>'local'</tt> and manually load the store.  To force a requery of the store
  275.      * <b>every</b> time the trigger is clicked see <tt>{@link #lastQuery}</tt>.</p></li>
  276.      * <li><b><tt>'local'</tt></b> :
  277.      * <p class="sub-desc">ComboBox loads local data</p>
  278.      * <pre><code>
  279. var combo = new Ext.form.ComboBox({
  280.     renderTo: document.body,
  281.     mode: 'local',
  282.     store: new Ext.data.ArrayStore({
  283.         id: 0,
  284.         fields: [
  285.             'myId',  // numeric value is the key
  286.             'displayText'
  287.         ],
  288.         data: [[1, 'item1'], [2, 'item2']]  // data is local
  289.     }),
  290.     valueField: 'myId',
  291.     displayField: 'displayText',
  292.     triggerAction: 'all'
  293. });
  294.      * </code></pre></li>
  295.      * </ul></div>
  296.      */
  297.     mode: 'remote',
  298.     /**
  299.      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to <tt>70</tt>, will
  300.      * be ignored if <tt>{@link #listWidth}</tt> has a higher value)
  301.      */
  302.     minListWidth : 70,
  303.     /**
  304.      * @cfg {Boolean} forceSelection <tt>true</tt> to restrict the selected value to one of the values in the list,
  305.      * <tt>false</tt> to allow the user to set arbitrary text into the field (defaults to <tt>false</tt>)
  306.      */
  307.     forceSelection : false,
  308.     /**
  309.      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
  310.      * if <tt>{@link #typeAhead} = true</tt> (defaults to <tt>250</tt>)
  311.      */
  312.     typeAheadDelay : 250,
  313.     /**
  314.      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
  315.      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined). If this
  316.      * default text is used, it means there is no value set and no validation will occur on this field.
  317.      */
  318.     /**
  319.      * @cfg {Boolean} lazyInit <tt>true</tt> to not initialize the list for this combo until the field is focused
  320.      * (defaults to <tt>true</tt>)
  321.      */
  322.     lazyInit : true,
  323.     /**
  324.      * The value of the match string used to filter the store. Delete this property to force a requery.
  325.      * Example use:
  326.      * <pre><code>
  327. var combo = new Ext.form.ComboBox({
  328.     ...
  329.     mode: 'remote',
  330.     ...
  331.     listeners: {
  332.         // delete the previous query in the beforequery event or set
  333.         // combo.lastQuery = null (this will reload the store the next time it expands)
  334.         beforequery: function(qe){
  335.             delete qe.combo.lastQuery;
  336.         }
  337.     }
  338. });
  339.      * </code></pre>
  340.      * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used
  341.      * configure the combo with <tt>lastQuery=''</tt>. Example use:
  342.      * <pre><code>
  343. var combo = new Ext.form.ComboBox({
  344.     ...
  345.     mode: 'local',
  346.     triggerAction: 'all',
  347.     lastQuery: ''
  348. });
  349.      * </code></pre>
  350.      * @property lastQuery
  351.      * @type String
  352.      */
  353.     // private
  354.     initComponent : function(){
  355.         Ext.form.ComboBox.superclass.initComponent.call(this);
  356.         this.addEvents(
  357.             /**
  358.              * @event expand
  359.              * Fires when the dropdown list is expanded
  360.              * @param {Ext.form.ComboBox} combo This combo box
  361.              */
  362.             'expand',
  363.             /**
  364.              * @event collapse
  365.              * Fires when the dropdown list is collapsed
  366.              * @param {Ext.form.ComboBox} combo This combo box
  367.              */
  368.             'collapse',
  369.             /**
  370.              * @event beforeselect
  371.              * Fires before a list item is selected. Return false to cancel the selection.
  372.              * @param {Ext.form.ComboBox} combo This combo box
  373.              * @param {Ext.data.Record} record The data record returned from the underlying store
  374.              * @param {Number} index The index of the selected item in the dropdown list
  375.              */
  376.             'beforeselect',
  377.             /**
  378.              * @event select
  379.              * Fires when a list item is selected
  380.              * @param {Ext.form.ComboBox} combo This combo box
  381.              * @param {Ext.data.Record} record The data record returned from the underlying store
  382.              * @param {Number} index The index of the selected item in the dropdown list
  383.              */
  384.             'select',
  385.             /**
  386.              * @event beforequery
  387.              * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's
  388.              * cancel property to true.
  389.              * @param {Object} queryEvent An object that has these properties:<ul>
  390.              * <li><code>combo</code> : Ext.form.ComboBox <div class="sub-desc">This combo box</div></li>
  391.              * <li><code>query</code> : String <div class="sub-desc">The query</div></li>
  392.              * <li><code>forceAll</code> : Boolean <div class="sub-desc">True to force "all" query</div></li>
  393.              * <li><code>cancel</code> : Boolean <div class="sub-desc">Set to true to cancel the query</div></li>
  394.              * </ul>
  395.              */
  396.             'beforequery'
  397.         );
  398.         if(this.transform){
  399.             var s = Ext.getDom(this.transform);
  400.             if(!this.hiddenName){
  401.                 this.hiddenName = s.name;
  402.             }
  403.             if(!this.store){
  404.                 this.mode = 'local';
  405.                 var d = [], opts = s.options;
  406.                 for(var i = 0, len = opts.length;i < len; i++){
  407.                     var o = opts[i],
  408.                         value = (o.hasAttribute ? o.hasAttribute('value') : o.getAttributeNode('value').specified) ? o.value : o.text;
  409.                     if(o.selected && Ext.isEmpty(this.value, true)) {
  410.                         this.value = value;
  411.                     }
  412.                     d.push([value, o.text]);
  413.                 }
  414.                 this.store = new Ext.data.ArrayStore({
  415.                     'id': 0,
  416.                     fields: ['value', 'text'],
  417.                     data : d,
  418.                     autoDestroy: true
  419.                 });
  420.                 this.valueField = 'value';
  421.                 this.displayField = 'text';
  422.             }
  423.             s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
  424.             if(!this.lazyRender){
  425.                 this.target = true;
  426.                 this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
  427.                 this.render(this.el.parentNode, s);
  428.                 Ext.removeNode(s); // remove it
  429.             }else{
  430.                 Ext.removeNode(s); // remove it
  431.             }
  432.         }
  433.         //auto-configure store from local array data
  434.         else if(this.store){
  435.             this.store = Ext.StoreMgr.lookup(this.store);
  436.             if(this.store.autoCreated){
  437.                 this.displayField = this.valueField = 'field1';
  438.                 if(!this.store.expandData){
  439.                     this.displayField = 'field2';
  440.                 }
  441.                 this.mode = 'local';
  442.             }
  443.         }
  444.         this.selectedIndex = -1;
  445.         if(this.mode == 'local'){
  446.             if(!Ext.isDefined(this.initialConfig.queryDelay)){
  447.                 this.queryDelay = 10;
  448.             }
  449.             if(!Ext.isDefined(this.initialConfig.minChars)){
  450.                 this.minChars = 0;
  451.             }
  452.         }
  453.     },
  454.     // private
  455.     onRender : function(ct, position){
  456.         Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
  457.         if(this.hiddenName){
  458.             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName,
  459.                     id: (this.hiddenId||this.hiddenName)}, 'before', true);
  460.             // prevent input submission
  461.             this.el.dom.removeAttribute('name');
  462.         }
  463.         if(Ext.isGecko){
  464.             this.el.dom.setAttribute('autocomplete', 'off');
  465.         }
  466.         if(!this.lazyInit){
  467.             this.initList();
  468.         }else{
  469.             this.on('focus', this.initList, this, {single: true});
  470.         }
  471.     },
  472.     // private
  473.     initValue : function(){
  474.         Ext.form.ComboBox.superclass.initValue.call(this);
  475.         if(this.hiddenField){
  476.             this.hiddenField.value =
  477.                 Ext.isDefined(this.hiddenValue) ? this.hiddenValue :
  478.                 Ext.isDefined(this.value) ? this.value : '';
  479.         }
  480.     },
  481.     // private
  482.     initList : function(){
  483.         if(!this.list){
  484.             var cls = 'x-combo-list';
  485.             this.list = new Ext.Layer({
  486.                 parentEl: this.getListParent(),
  487.                 shadow: this.shadow,
  488.                 cls: [cls, this.listClass].join(' '),
  489.                 constrain:false
  490.             });
  491.             var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
  492.             this.list.setSize(lw, 0);
  493.             this.list.swallowEvent('mousewheel');
  494.             this.assetHeight = 0;
  495.             if(this.syncFont !== false){
  496.                 this.list.setStyle('font-size', this.el.getStyle('font-size'));
  497.             }
  498.             if(this.title){
  499.                 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
  500.                 this.assetHeight += this.header.getHeight();
  501.             }
  502.             this.innerList = this.list.createChild({cls:cls+'-inner'});
  503.             this.mon(this.innerList, 'mouseover', this.onViewOver, this);
  504.             this.mon(this.innerList, 'mousemove', this.onViewMove, this);
  505.             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
  506.             if(this.pageSize){
  507.                 this.footer = this.list.createChild({cls:cls+'-ft'});
  508.                 this.pageTb = new Ext.PagingToolbar({
  509.                     store: this.store,
  510.                     pageSize: this.pageSize,
  511.                     renderTo:this.footer
  512.                 });
  513.                 this.assetHeight += this.footer.getHeight();
  514.             }
  515.             if(!this.tpl){
  516.                 /**
  517.                 * @cfg {String/Ext.XTemplate} tpl <p>The template string, or {@link Ext.XTemplate} instance to
  518.                 * use to display each item in the dropdown list. The dropdown list is displayed in a
  519.                 * DataView. See {@link #view}.</p>
  520.                 * <p>The default template string is:</p><pre><code>
  521.                   '&lt;tpl for=".">&lt;div class="x-combo-list-item">{' + this.displayField + '}&lt;/div>&lt;/tpl>'
  522.                 * </code></pre>
  523.                 * <p>Override the default value to create custom UI layouts for items in the list.
  524.                 * For example:</p><pre><code>
  525.                   '&lt;tpl for=".">&lt;div ext:qtip="{state}. {nick}" class="x-combo-list-item">{state}&lt;/div>&lt;/tpl>'
  526.                 * </code></pre>
  527.                 * <p>The template <b>must</b> contain one or more substitution parameters using field
  528.                 * names from the Combo's</b> {@link #store Store}. In the example above an
  529.                 * <pre>ext:qtip</pre> attribute is added to display other fields from the Store.</p>
  530.                 * <p>To preserve the default visual look of list items, add the CSS class name
  531.                 * <pre>x-combo-list-item</pre> to the template's container element.</p>
  532.                 * <p>Also see {@link #itemSelector} for additional details.</p>
  533.                 */
  534.                 this.tpl = '<tpl for="."><div class="'+cls+'-item">{' + this.displayField + '}</div></tpl>';
  535.                 /**
  536.                  * @cfg {String} itemSelector
  537.                  * <p>A simple CSS selector (e.g. div.some-class or span:first-child) that will be
  538.                  * used to determine what nodes the {@link #view Ext.DataView} which handles the dropdown
  539.                  * display will be working with.</p>
  540.                  * <p><b>Note</b>: this setting is <b>required</b> if a custom XTemplate has been
  541.                  * specified in {@link #tpl} which assigns a class other than <pre>'x-combo-list-item'</pre>
  542.                  * to dropdown list items</b>
  543.                  */
  544.             }
  545.             /**
  546.             * The {@link Ext.DataView DataView} used to display the ComboBox's options.
  547.             * @type Ext.DataView
  548.             */
  549.             this.view = new Ext.DataView({
  550.                 applyTo: this.innerList,
  551.                 tpl: this.tpl,
  552.                 singleSelect: true,
  553.                 selectedClass: this.selectedClass,
  554.                 itemSelector: this.itemSelector || '.' + cls + '-item',
  555.                 emptyText: this.listEmptyText
  556.             });
  557.             this.mon(this.view, 'click', this.onViewClick, this);
  558.             this.bindStore(this.store, true);
  559.             if(this.resizable){
  560.                 this.resizer = new Ext.Resizable(this.list,  {
  561.                    pinned:true, handles:'se'
  562.                 });
  563.                 this.mon(this.resizer, 'resize', function(r, w, h){
  564.                     this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
  565.                     this.listWidth = w;
  566.                     this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
  567.                     this.restrictHeight();
  568.                 }, this);
  569.                 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
  570.             }
  571.         }
  572.     },
  573.     /**
  574.      * <p>Returns the element used to house this ComboBox's pop-up list. Defaults to the document body.</p>
  575.      * A custom implementation may be provided as a configuration option if the floating list needs to be rendered
  576.      * to a different Element. An example might be rendering the list inside a Menu so that clicking
  577.      * the list does not hide the Menu:<pre><code>
  578. var store = new Ext.data.ArrayStore({
  579.     autoDestroy: true,
  580.     fields: ['initials', 'fullname'],
  581.     data : [
  582.         ['FF', 'Fred Flintstone'],
  583.         ['BR', 'Barney Rubble']
  584.     ]
  585. });
  586. var combo = new Ext.form.ComboBox({
  587.     store: store,
  588.     displayField: 'fullname',
  589.     emptyText: 'Select a name...',
  590.     forceSelection: true,
  591.     getListParent: function() {
  592.         return this.el.up('.x-menu');
  593.     },
  594.     iconCls: 'no-icon', //use iconCls if placing within menu to shift to right side of menu
  595.     mode: 'local',
  596.     selectOnFocus: true,
  597.     triggerAction: 'all',
  598.     typeAhead: true,
  599.     width: 135
  600. });
  601. var menu = new Ext.menu.Menu({
  602.     id: 'mainMenu',
  603.     items: [
  604.         combo // A Field in a Menu
  605.     ]
  606. });
  607. </code></pre>
  608.      */
  609.     getListParent : function() {
  610.         return document.body;
  611.     },
  612.     /**
  613.      * Returns the store associated with this combo.
  614.      * @return {Ext.data.Store} The store
  615.      */
  616.     getStore : function(){
  617.         return this.store;
  618.     },
  619.     // private
  620.     bindStore : function(store, initial){
  621.         if(this.store && !initial){
  622.             this.store.un('beforeload', this.onBeforeLoad, this);
  623.             this.store.un('load', this.onLoad, this);
  624.             this.store.un('exception', this.collapse, this);
  625.             if(this.store !== store && this.store.autoDestroy){
  626.                 this.store.destroy();
  627.             }
  628.             if(!store){
  629.                 this.store = null;
  630.                 if(this.view){
  631.                     this.view.bindStore(null);
  632.                 }
  633.             }
  634.         }
  635.         if(store){
  636.             if(!initial) {
  637.                 this.lastQuery = null;
  638.                 if(this.pageTb) {
  639.                     this.pageTb.bindStore(store);
  640.                 }
  641.             }
  642.             this.store = Ext.StoreMgr.lookup(store);
  643.             this.store.on({
  644.                 scope: this,
  645.                 beforeload: this.onBeforeLoad,
  646.                 load: this.onLoad,
  647.                 exception: this.collapse
  648.             });
  649.             if(this.view){
  650.                 this.view.bindStore(store);
  651.             }
  652.         }
  653.     },
  654.     // private
  655.     initEvents : function(){
  656.         Ext.form.ComboBox.superclass.initEvents.call(this);
  657.         this.keyNav = new Ext.KeyNav(this.el, {
  658.             "up" : function(e){
  659.                 this.inKeyMode = true;
  660.                 this.selectPrev();
  661.             },
  662.             "down" : function(e){
  663.                 if(!this.isExpanded()){
  664.                     this.onTriggerClick();
  665.                 }else{
  666.                     this.inKeyMode = true;
  667.                     this.selectNext();
  668.                 }
  669.             },
  670.             "enter" : function(e){
  671.                 this.onViewClick();
  672.                 this.delayedCheck = true;
  673.                 this.unsetDelayCheck.defer(10, this);
  674.             },
  675.             "esc" : function(e){
  676.                 this.collapse();
  677.             },
  678.             "tab" : function(e){
  679.                 this.onViewClick(false);
  680.                 return true;
  681.             },
  682.             scope : this,
  683.             doRelay : function(foo, bar, hname){
  684.                 if(hname == 'down' || this.scope.isExpanded()){
  685.                    return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
  686.                 }
  687.                 return true;
  688.             },
  689.             forceKeyDown : true
  690.         });
  691.         this.queryDelay = Math.max(this.queryDelay || 10,
  692.                 this.mode == 'local' ? 10 : 250);
  693.         this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
  694.         if(this.typeAhead){
  695.             this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
  696.         }
  697.         if(this.editable !== false && !this.enableKeyEvents){
  698.             this.mon(this.el, 'keyup', this.onKeyUp, this);
  699.         }
  700.     },
  701.     // private
  702.     onDestroy : function(){
  703.         if (this.dqTask){
  704.             this.dqTask.cancel();
  705.             this.dqTask = null;
  706.         }
  707.         this.bindStore(null);
  708.         Ext.destroy(
  709.             this.resizer,
  710.             this.view,
  711.             this.pageTb,
  712.             this.list
  713.         );
  714.         Ext.form.ComboBox.superclass.onDestroy.call(this);
  715.     },
  716.     // private
  717.     unsetDelayCheck : function(){
  718.         delete this.delayedCheck;
  719.     },
  720.     // private
  721.     fireKey : function(e){
  722.         var fn = function(ev){
  723.             if (ev.isNavKeyPress() && !this.isExpanded() && !this.delayedCheck) {
  724.                 this.fireEvent("specialkey", this, ev);
  725.             }
  726.         };
  727.         //For some reason I can't track down, the events fire in a different order in webkit.
  728.         //Need a slight delay here
  729.         if(this.inEditor && Ext.isWebKit && e.getKey() == e.TAB){
  730.             fn.defer(10, this, [new Ext.EventObjectImpl(e)]);
  731.         }else{
  732.             fn.call(this, e);
  733.         }
  734.     },
  735.     // private
  736.     onResize : function(w, h){
  737.         Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
  738.         if(this.list && !Ext.isDefined(this.listWidth)){
  739.             var lw = Math.max(w, this.minListWidth);
  740.             this.list.setWidth(lw);
  741.             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
  742.         }
  743.     },
  744.     // private
  745.     onEnable : function(){
  746.         Ext.form.ComboBox.superclass.onEnable.apply(this, arguments);
  747.         if(this.hiddenField){
  748.             this.hiddenField.disabled = false;
  749.         }
  750.     },
  751.     // private
  752.     onDisable : function(){
  753.         Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
  754.         if(this.hiddenField){
  755.             this.hiddenField.disabled = true;
  756.         }
  757.     },
  758.     // private
  759.     onBeforeLoad : function(){
  760.         if(!this.hasFocus){
  761.             return;
  762.         }
  763.         this.innerList.update(this.loadingText ?
  764.                '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
  765.         this.restrictHeight();
  766.         this.selectedIndex = -1;
  767.     },
  768.     // private
  769.     onLoad : function(){
  770.         if(!this.hasFocus){
  771.             return;
  772.         }
  773.         if(this.store.getCount() > 0){
  774.             this.expand();
  775.             this.restrictHeight();
  776.             if(this.lastQuery == this.allQuery){
  777.                 if(this.editable){
  778.                     this.el.dom.select();
  779.                 }
  780.                 if(!this.selectByValue(this.value, true)){
  781.                     this.select(0, true);
  782.                 }
  783.             }else{
  784.                 this.selectNext();
  785.                 if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
  786.                     this.taTask.delay(this.typeAheadDelay);
  787.                 }
  788.             }
  789.         }else{
  790.             this.onEmptyResults();
  791.         }
  792.         //this.el.focus();
  793.     },
  794.     // private
  795.     onTypeAhead : function(){
  796.         if(this.store.getCount() > 0){
  797.             var r = this.store.getAt(0);
  798.             var newValue = r.data[this.displayField];
  799.             var len = newValue.length;
  800.             var selStart = this.getRawValue().length;
  801.             if(selStart != len){
  802.                 this.setRawValue(newValue);
  803.                 this.selectText(selStart, newValue.length);
  804.             }
  805.         }
  806.     },
  807.     // private
  808.     onSelect : function(record, index){
  809.         if(this.fireEvent('beforeselect', this, record, index) !== false){
  810.             this.setValue(record.data[this.valueField || this.displayField]);
  811.             this.collapse();
  812.             this.fireEvent('select', this, record, index);
  813.         }
  814.     },
  815.     // inherit docs
  816.     getName: function(){
  817.         var hf = this.hiddenField;
  818.         return hf && hf.name ? hf.name : this.hiddenName || Ext.form.ComboBox.superclass.getName.call(this);
  819.     },
  820.     /**
  821.      * Returns the currently selected field value or empty string if no value is set.
  822.      * @return {String} value The selected value
  823.      */
  824.     getValue : function(){
  825.         if(this.valueField){
  826.             return Ext.isDefined(this.value) ? this.value : '';
  827.         }else{
  828.             return Ext.form.ComboBox.superclass.getValue.call(this);
  829.         }
  830.     },
  831.     /**
  832.      * Clears any text/value currently set in the field
  833.      */
  834.     clearValue : function(){
  835.         if(this.hiddenField){
  836.             this.hiddenField.value = '';
  837.         }
  838.         this.setRawValue('');
  839.         this.lastSelectionText = '';
  840.         this.applyEmptyText();
  841.         this.value = '';
  842.     },
  843.     /**
  844.      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
  845.      * will be displayed in the field.  If the value does not match the data value of an existing item,
  846.      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
  847.      * Otherwise the field will be blank (although the value will still be set).
  848.      * @param {String} value The value to match
  849.      * @return {Ext.form.Field} this
  850.      */
  851.     setValue : function(v){
  852.         var text = v;
  853.         if(this.valueField){
  854.             var r = this.findRecord(this.valueField, v);
  855.             if(r){
  856.                 text = r.data[this.displayField];
  857.             }else if(Ext.isDefined(this.valueNotFoundText)){
  858.                 text = this.valueNotFoundText;
  859.             }
  860.         }
  861.         this.lastSelectionText = text;
  862.         if(this.hiddenField){
  863.             this.hiddenField.value = v;
  864.         }
  865.         Ext.form.ComboBox.superclass.setValue.call(this, text);
  866.         this.value = v;
  867.         return this;
  868.     },
  869.     // private
  870.     findRecord : function(prop, value){
  871.         var record;
  872.         if(this.store.getCount() > 0){
  873.             this.store.each(function(r){
  874.                 if(r.data[prop] == value){
  875.                     record = r;
  876.                     return false;
  877.                 }
  878.             });
  879.         }
  880.         return record;
  881.     },
  882.     // private
  883.     onViewMove : function(e, t){
  884.         this.inKeyMode = false;
  885.     },
  886.     // private
  887.     onViewOver : function(e, t){
  888.         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
  889.             return;
  890.         }
  891.         var item = this.view.findItemFromChild(t);
  892.         if(item){
  893.             var index = this.view.indexOf(item);
  894.             this.select(index, false);
  895.         }
  896.     },
  897.     // private
  898.     onViewClick : function(doFocus){
  899.         var index = this.view.getSelectedIndexes()[0];
  900.         var r = this.store.getAt(index);
  901.         if(r){
  902.             this.onSelect(r, index);
  903.         }
  904.         if(doFocus !== false){
  905.             this.el.focus();
  906.         }
  907.     },
  908.     // private
  909.     restrictHeight : function(){
  910.         this.innerList.dom.style.height = '';
  911.         var inner = this.innerList.dom;
  912.         var pad = this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight;
  913.         var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
  914.         var ha = this.getPosition()[1]-Ext.getBody().getScroll().top;
  915.         var hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height;
  916.         var space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5;
  917.         h = Math.min(h, space, this.maxHeight);
  918.         this.innerList.setHeight(h);
  919.         this.list.beginUpdate();
  920.         this.list.setHeight(h+pad);
  921.         this.list.alignTo(this.wrap, this.listAlign);
  922.         this.list.endUpdate();
  923.     },
  924.     // private
  925.     onEmptyResults : function(){
  926.         this.collapse();
  927.     },
  928.     /**
  929.      * Returns true if the dropdown list is expanded, else false.
  930.      */
  931.     isExpanded : function(){
  932.         return this.list && this.list.isVisible();
  933.     },
  934.     /**
  935.      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
  936.      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
  937.      * @param {String} value The data value of the item to select
  938.      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
  939.      * selected item if it is not currently in view (defaults to true)
  940.      * @return {Boolean} True if the value matched an item in the list, else false
  941.      */
  942.     selectByValue : function(v, scrollIntoView){
  943.         if(!Ext.isEmpty(v, true)){
  944.             var r = this.findRecord(this.valueField || this.displayField, v);
  945.             if(r){
  946.                 this.select(this.store.indexOf(r), scrollIntoView);
  947.                 return true;
  948.             }
  949.         }
  950.         return false;
  951.     },
  952.     /**
  953.      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
  954.      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
  955.      * @param {Number} index The zero-based index of the list item to select
  956.      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
  957.      * selected item if it is not currently in view (defaults to true)
  958.      */
  959.     select : function(index, scrollIntoView){
  960.         this.selectedIndex = index;
  961.         this.view.select(index);
  962.         if(scrollIntoView !== false){
  963.             var el = this.view.getNode(index);
  964.             if(el){
  965.                 this.innerList.scrollChildIntoView(el, false);
  966.             }
  967.         }
  968.     },
  969.     // private
  970.     selectNext : function(){
  971.         var ct = this.store.getCount();
  972.         if(ct > 0){
  973.             if(this.selectedIndex == -1){
  974.                 this.select(0);
  975.             }else if(this.selectedIndex < ct-1){
  976.                 this.select(this.selectedIndex+1);
  977.             }
  978.         }
  979.     },
  980.     // private
  981.     selectPrev : function(){
  982.         var ct = this.store.getCount();
  983.         if(ct > 0){
  984.             if(this.selectedIndex == -1){
  985.                 this.select(0);
  986.             }else if(this.selectedIndex !== 0){
  987.                 this.select(this.selectedIndex-1);
  988.             }
  989.         }
  990.     },
  991.     // private
  992.     onKeyUp : function(e){
  993.         var k = e.getKey();
  994.         if(this.editable !== false && (k == e.BACKSPACE || !e.isSpecialKey())){
  995.             this.lastKey = k;
  996.             this.dqTask.delay(this.queryDelay);
  997.         }
  998.         Ext.form.ComboBox.superclass.onKeyUp.call(this, e);
  999.     },
  1000.     // private
  1001.     validateBlur : function(){
  1002.         return !this.list || !this.list.isVisible();
  1003.     },
  1004.     // private
  1005.     initQuery : function(){
  1006.         this.doQuery(this.getRawValue());
  1007.     },
  1008.     // private
  1009.     beforeBlur : function(){
  1010.         var val = this.getRawValue();
  1011.         if(this.forceSelection){
  1012.             if(val.length > 0 && val != this.emptyText){
  1013.                this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : '';
  1014.                 this.applyEmptyText();
  1015.             }else{
  1016.                 this.clearValue();
  1017.             }
  1018.         }else{
  1019.             var rec = this.findRecord(this.displayField, val);
  1020.             if(rec){
  1021.                 val = rec.get(this.valueField || this.displayField);
  1022.             }
  1023.             this.setValue(val);
  1024.         }
  1025.     },
  1026.     /**
  1027.      * Execute a query to filter the dropdown list.  Fires the {@link #beforequery} event prior to performing the
  1028.      * query allowing the query action to be canceled if needed.
  1029.      * @param {String} query The SQL query to execute
  1030.      * @param {Boolean} forceAll <tt>true</tt> to force the query to execute even if there are currently fewer
  1031.      * characters in the field than the minimum specified by the <tt>{@link #minChars}</tt> config option.  It
  1032.      * also clears any filter previously saved in the current store (defaults to <tt>false</tt>)
  1033.      */
  1034.     doQuery : function(q, forceAll){
  1035.         q = Ext.isEmpty(q) ? '' : q;
  1036.         var qe = {
  1037.             query: q,
  1038.             forceAll: forceAll,
  1039.             combo: this,
  1040.             cancel:false
  1041.         };
  1042.         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
  1043.             return false;
  1044.         }
  1045.         q = qe.query;
  1046.         forceAll = qe.forceAll;
  1047.         if(forceAll === true || (q.length >= this.minChars)){
  1048.             if(this.lastQuery !== q){
  1049.                 this.lastQuery = q;
  1050.                 if(this.mode == 'local'){
  1051.                     this.selectedIndex = -1;
  1052.                     if(forceAll){
  1053.                         this.store.clearFilter();
  1054.                     }else{
  1055.                         this.store.filter(this.displayField, q);
  1056.                     }
  1057.                     this.onLoad();
  1058.                 }else{
  1059.                     this.store.baseParams[this.queryParam] = q;
  1060.                     this.store.load({
  1061.                         params: this.getParams(q)
  1062.                     });
  1063.                     this.expand();
  1064.                 }
  1065.             }else{
  1066.                 this.selectedIndex = -1;
  1067.                 this.onLoad();
  1068.             }
  1069.         }
  1070.     },
  1071.     // private
  1072.     getParams : function(q){
  1073.         var p = {};
  1074.         //p[this.queryParam] = q;
  1075.         if(this.pageSize){
  1076.             p.start = 0;
  1077.             p.limit = this.pageSize;
  1078.         }
  1079.         return p;
  1080.     },
  1081.     /**
  1082.      * Hides the dropdown list if it is currently expanded. Fires the {@link #collapse} event on completion.
  1083.      */
  1084.     collapse : function(){
  1085.         if(!this.isExpanded()){
  1086.             return;
  1087.         }
  1088.         this.list.hide();
  1089.         Ext.getDoc().un('mousewheel', this.collapseIf, this);
  1090.         Ext.getDoc().un('mousedown', this.collapseIf, this);
  1091.         this.fireEvent('collapse', this);
  1092.     },
  1093.     // private
  1094.     collapseIf : function(e){
  1095.         if(!e.within(this.wrap) && !e.within(this.list)){
  1096.             this.collapse();
  1097.         }
  1098.     },
  1099.     /**
  1100.      * Expands the dropdown list if it is currently hidden. Fires the {@link #expand} event on completion.
  1101.      */
  1102.     expand : function(){
  1103.         if(this.isExpanded() || !this.hasFocus){
  1104.             return;
  1105.         }
  1106.         this.list.alignTo(this.wrap, this.listAlign);
  1107.         this.list.show();
  1108.         if(Ext.isGecko2){
  1109.             this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac
  1110.         }
  1111.         Ext.getDoc().on({
  1112.             scope: this,
  1113.             mousewheel: this.collapseIf,
  1114.             mousedown: this.collapseIf
  1115.         });
  1116.         this.fireEvent('expand', this);
  1117.     },
  1118.     /**
  1119.      * @method onTriggerClick
  1120.      * @hide
  1121.      */
  1122.     // private
  1123.     // Implements the default empty TriggerField.onTriggerClick function
  1124.     onTriggerClick : function(){
  1125.         if(this.disabled){
  1126.             return;
  1127.         }
  1128.         if(this.isExpanded()){
  1129.             this.collapse();
  1130.             this.el.focus();
  1131.         }else {
  1132.             this.onFocus({});
  1133.             if(this.triggerAction == 'all') {
  1134.                 this.doQuery(this.allQuery, true);
  1135.             } else {
  1136.                 this.doQuery(this.getRawValue());
  1137.             }
  1138.             this.el.focus();
  1139.         }
  1140.     }
  1141.     /**
  1142.      * @hide
  1143.      * @method autoSize
  1144.      */
  1145.     /**
  1146.      * @cfg {Boolean} grow @hide
  1147.      */
  1148.     /**
  1149.      * @cfg {Number} growMin @hide
  1150.      */
  1151.     /**
  1152.      * @cfg {Number} growMax @hide
  1153.      */
  1154. });
  1155. Ext.reg('combo', Ext.form.ComboBox);