    /**
     * @class Ext.form.field.Trigger
     * @extends Ext.form.field.Text
     * <p>Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
     * The trigger has no default action, so you must assign a function to implement the trigger click handler by
     * overriding {@link #onTriggerClick}. You can create a Trigger field directly, as it renders exactly like a combobox
     * for which you can provide a custom implementation.
     * {@img Ext.form.field.Trigger/Ext.form.field.Trigger.png Ext.form.field.Trigger component}
     * For example:</p>
     * <pre><code>
    Ext.define('Ext.ux.CustomTrigger', {
        extend: 'Ext.form.field.Trigger',
        alias: 'widget.customtrigger',

        // override onTriggerClick
        onTriggerClick: function() {
            Ext.Msg.alert('Status', 'You clicked my trigger!');
        }
    });

    Ext.create('Ext.form.FormPanel', {
        title: 'Form with TriggerField',
        bodyPadding: 5,
        width: 350,
        renderTo: Ext.getBody(),
        items:[{
            xtype: 'customtrigger',
            fieldLabel: 'Sample Trigger',
            emptyText: 'click the trigger',
        }]
    });
    </code></pre>
     *
     * <p>However, in general you will most likely want to use Trigger as the base class for a reusable component.
     * {@link Ext.form.field.Date} and {@link Ext.form.field.ComboBox} are perfect examples of this.</p>
     *
     * @constructor
     * Create a new Trigger field.
     * @param {Object} config Configuration options (valid {@Ext.form.field.Text} config options will also be applied
     * to the base Text field)
     */
    Ext.define('Ext.form.field.Trigger', {
        extend:'Ext.form.field.Text',
        alias: ['widget.triggerfield', 'widget.trigger'],
        requires: ['Ext.core.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
        alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],

        fieldSubTpl: [
            '<input id="{id}" type="{type}" ',
                '<tpl if="name">name="{name}" </tpl>',
                '<tpl if="size">size="{size}" </tpl>',
                '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
                'class="{fieldCls} {typeCls}" autocomplete="off" />',
            '<div class="{triggerWrapCls}" role="presentation">',
                '{triggerEl}',
                '<div class="{clearCls}" role="presentation"></div>',
            '</div>',
            {
                compiled: true,
                disableFormats: true
            }
        ],

        /**
         * @cfg {String} triggerCls
         * An additional CSS class used to style the trigger button.  The trigger will always get the
         * {@link #triggerBaseCls} by default and <tt>triggerCls</tt> will be <b>appended</b> if specified.
         * Defaults to undefined.
         */

        /**
         * @cfg {String} triggerBaseCls
         * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be
         * appended in addition to this class.
         */
        triggerBaseCls: Ext.baseCSSPrefix + 'form-trigger',

        /**
         * @cfg {String} triggerWrapCls
         * The CSS class that is added to the div wrapping the trigger button(s).
         */
        triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',

        /**
         * @cfg {Boolean} hideTrigger <tt>true</tt> to hide the trigger element and display only the base
         * text field (defaults to <tt>false</tt>)
         */
        hideTrigger: false,

        /**
         * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field;
         * the field can only have its value set via an action invoked by the trigger. (defaults to <tt>true</tt>).
         */
        editable: true,

        /**
         * @cfg {Boolean} readOnly <tt>true</tt> to prevent the user from changing the field, and
         * hides the trigger.  Supercedes the editable and hideTrigger options if the value is true.
         * (defaults to <tt>false</tt>)
         */
        readOnly: false,

        /**
         * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.
         * Only applies when <tt>{@link #editable editable} = true</tt> (defaults to <tt>false</tt>).
         */

        /**
         * @cfg {Boolean} repeatTriggerClick <tt>true</tt> to attach a {@link Ext.util.ClickRepeater click repeater}
         * to the trigger. Defaults to <tt>false</tt>.
         */
        repeatTriggerClick: false,

        /**
         * @hide
         * @method autoSize
         */
        autoSize: Ext.emptyFn,
        // private
        monitorTab: true,
        // private
        mimicing: false,
        // private
        triggerIndexRe: /trigger-index-(\d+)/,

        componentLayout: 'triggerfield',

        initComponent: function() {
            this.wrapFocusCls = this.triggerWrapCls + '-focus';
            this.callParent(arguments);
        },

        // private
        onRender: function(ct, position) {
            var me = this,
                triggerCls,
                triggerBaseCls = me.triggerBaseCls,
                triggerWrapCls = me.triggerWrapCls,
                triggerConfigs = [],
                i;

            // triggerCls is a synonym for trigger1Cls, so copy it.
            // TODO this trigger<n>Cls API design doesn't feel clean, especially where it butts up against the
            // single triggerCls config. Should rethink this, perhaps something more structured like a list of
            // trigger config objects that hold cls, handler, etc.
            if (!me.trigger1Cls) {
                me.trigger1Cls = me.triggerCls;
            }

            // Create as many trigger elements as we have trigger<n>Cls configs, but always at least one
            for (i = 0; (triggerCls = me['trigger' + (i + 1) + 'Cls']) || i < 1; i++) {
                triggerConfigs.push({
                    cls: [Ext.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
                    role: 'button'
                });
            }
            triggerConfigs[i - 1].cls += ' ' + triggerBaseCls + '-last';

            Ext.applyIf(me.renderSelectors, {
                /**
                 * @property triggerWrap
                 * @type Ext.core.Element
                 * A reference to the div element wrapping the trigger button(s). Only set after the field has been rendered.
                 */
                triggerWrap: '.' + triggerWrapCls
            });
            Ext.applyIf(me.subTplData, {
                triggerWrapCls: triggerWrapCls,
                triggerEl: Ext.core.DomHelper.markup(triggerConfigs),
                clearCls: me.clearCls
            });

            me.callParent(arguments);

            /**
             * @property triggerEl
             * @type Ext.CompositeElement
             * A composite of all the trigger button elements. Only set after the field has been rendered.
             */
            me.triggerEl = Ext.select('.' + triggerBaseCls, true, me.triggerWrap.dom);

            me.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc();
            me.initTrigger();
        },

        onEnable: function() {
            this.callParent();
            this.triggerWrap.unmask();
        },

        onDisable: function() {
            this.callParent();
            this.triggerWrap.mask();
        },

        afterRender: function() {
            this.callParent();
            this.updateEditState();
        },

        updateEditState: function() {
            var me = this,
                inputEl = me.inputEl,
                triggerWrap = me.triggerWrap,
                noeditCls = Ext.baseCSSPrefix + 'trigger-noedit',
                displayed,
                readOnly;

            if (me.rendered) {
                if (me.readOnly) {
                    inputEl.addCls(noeditCls);
                    readOnly = true;
                    displayed = false;
                } else {
                    if (me.editable) {
                        inputEl.removeCls(noeditCls);
                        readOnly = false;
                    } else {
                        inputEl.addCls(noeditCls);
                        readOnly = true;
                    }
                    displayed = !me.hideTrigger;
                }

                triggerWrap.setDisplayed(displayed);
                inputEl.dom.readOnly = readOnly;
                me.doComponentLayout();
            }
        },

        /**
         * Get the total width of the trigger button area. Only useful after the field has been rendered.
         * @return {Number} The trigger width
         */
        getTriggerWidth: function() {
            var me = this,
                triggerWrap = me.triggerWrap,
                totalTriggerWidth = 0;
            if (triggerWrap && !me.hideTrigger && !me.readOnly) {
                me.triggerEl.each(function(trigger) {
                    totalTriggerWidth += trigger.getWidth();
                });
                totalTriggerWidth += me.triggerWrap.getFrameWidth('lr');
            }
            return totalTriggerWidth;
        },

        setHideTrigger: function(hideTrigger) {
            if (hideTrigger != this.hideTrigger) {
                this.hideTrigger = hideTrigger;
                this.updateEditState();
            }
        },

        /**
         * @param {Boolean} editable True to allow the user to directly edit the field text
         * Allow or prevent the user from directly editing the field text.  If false is passed,
         * the user will only be able to modify the field using the trigger.  Will also add
         * a click event to the text field which will call the trigger. This method
         * is the runtime equivalent of setting the 'editable' config option at config time.
         */
        setEditable: function(editable) {
            if (editable != this.editable) {
                this.editable = editable;
                this.updateEditState();
            }
        },

        /**
         * @param {Boolean} readOnly True to prevent the user changing the field and explicitly
         * hide the trigger.
         * Setting this to true will superceed settings editable and hideTrigger.
         * Setting this to false will defer back to editable and hideTrigger. This method
         * is the runtime equivalent of setting the 'readOnly' config option at config time.
         */
        setReadOnly: function(readOnly) {
            if (readOnly != this.readOnly) {
                this.readOnly = readOnly;
                this.updateEditState();
            }
        },

        // private
        initTrigger: function() {
            var me = this,
                triggerWrap = me.triggerWrap,
                triggerEl = me.triggerEl;

            if (me.repeatTriggerClick) {
                me.triggerRepeater = Ext.create('Ext.util.ClickRepeater', triggerWrap, {
                    preventDefault: true,
                    handler: function(cr, e) {
                        me.onTriggerWrapClick(e);
                    }
                });
            } else {
                me.mon(me.triggerWrap, 'click', me.onTriggerWrapClick, me);
            }

            triggerEl.addClsOnOver(me.triggerBaseCls + '-over');
            triggerEl.each(function(el, c, i) {
                el.addClsOnOver(me['trigger' + (i + 1) + 'Cls'] + '-over');
            });
            triggerEl.addClsOnClick(me.triggerBaseCls + '-click');
            triggerEl.each(function(el, c, i) {
                el.addClsOnClick(me['trigger' + (i + 1) + 'Cls'] + '-click');
            });
        },

        // private
        onDestroy: function() {
            var me = this;
            Ext.destroyMembers(me, 'triggerRepeater', 'triggerWrap', 'triggerEl');
            delete me.doc;
            me.callParent();
        },

        // private
        onFocus: function() {
            var me = this;
            this.callParent();
            if (!me.mimicing) {
                me.bodyEl.addCls(me.wrapFocusCls);
                me.mimicing = true;
                me.mon(me.doc, 'mousedown', me.mimicBlur, me, {
                    delay: 10
                });
                if (me.monitorTab) {
                    me.on('specialkey', me.checkTab, me);
                }
            }
        },

        // private
        checkTab: function(me, e) {
            if (!this.ignoreMonitorTab && e.getKey() == e.TAB) {
                this.triggerBlur();
            }
        },

        // private
        onBlur: Ext.emptyFn,

        // private
        mimicBlur: function(e) {
            if (!this.isDestroyed && !this.bodyEl.contains(e.target) && this.validateBlur(e)) {
                this.triggerBlur();
            }
        },

        // private
        triggerBlur: function() {
            var me = this;
            me.mimicing = false;
            me.mun(me.doc, 'mousedown', me.mimicBlur, me);
            if (me.monitorTab && me.inputEl) {
                me.un('specialkey', me.checkTab, me);
            }
            Ext.form.field.Trigger.superclass.onBlur.call(me);
            if (me.bodyEl) {
                me.bodyEl.removeCls(me.wrapFocusCls);
            }
        },

        beforeBlur: Ext.emptyFn,

        // private
        // This should be overridden by any subclass that needs to check whether or not the field can be blurred.
        validateBlur: function(e) {
            return true;
        },

        // private
        // process clicks upon triggers.
        // determine which trigger index, and dispatch to the appropriate click handler
        onTriggerWrapClick: function(e) {
            var me = this,
                t = e && e.getTarget('.' + Ext.baseCSSPrefix + 'form-trigger', null),
                match = t && t.className.match(me.triggerIndexRe),
                idx,
                triggerClickMethod;

            if (match && !me.readOnly) {
                idx = parseInt(match[1], 10);
                triggerClickMethod = me['onTrigger' + (idx + 1) + 'Click'] || me.onTriggerClick;
                if (triggerClickMethod) {
                    triggerClickMethod.call(me, e);
                }
            }
        },

        /**
         * The function that should handle the trigger's click event.  This method does nothing by default
         * until overridden by an implementing function.  See Ext.form.field.ComboBox and Ext.form.field.Date for
         * sample implementations.
         * @method
         * @param {Ext.EventObject} e
         */
        onTriggerClick: Ext.emptyFn

        /**
         * @cfg {Boolean} grow @hide
         */
        /**
         * @cfg {Number} growMin @hide
         */
        /**
         * @cfg {Number} growMax @hide
         */
    });