| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-form-field-Trigger'>/**</span> * 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. * * For example: * *     @example *     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' *         }] *     }); * * 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. */Ext.define('Ext.form.field.Trigger', {    extend:'Ext.form.field.Text',    alias: ['widget.triggerfield', 'widget.trigger'],    requires: ['Ext.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],    alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],    childEls: [<span id='Ext-form-field-Trigger-property-triggerEl'>        /**</span>         * @property {Ext.CompositeElement} triggerEl         * A composite of all the trigger button elements. Only set after the field has been rendered.         */        { name: 'triggerCell', select: '.' + Ext.baseCSSPrefix + 'trigger-cell' },        { name: 'triggerEl', select: '.' + Ext.baseCSSPrefix + 'form-trigger' },<span id='Ext-form-field-Trigger-property-triggerWrap'>        /**</span>         * @property {Ext.Element} triggerWrap         * A reference to the `TABLE` element which encapsulates the input field and all trigger button(s). Only set after the field has been rendered.         */        'triggerWrap',<span id='Ext-form-field-Trigger-property-inputCell'>        /**</span>         * @property {Ext.Element} inputCell         * A reference to the `TD` element wrapping the input element. Only set after the field has been rendered.         */        'inputCell'    ],<span id='Ext-form-field-Trigger-cfg-triggerCls'>    /**</span>     * @cfg {String} triggerCls     * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}     * by default and triggerCls will be **appended** if specified.     */<span id='Ext-form-field-Trigger-cfg-triggerBaseCls'>    /**</span>     * @cfg     * 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',<span id='Ext-form-field-Trigger-cfg-triggerWrapCls'>    /**</span>     * @cfg     * The CSS class that is added to the div wrapping the trigger button(s).     */    triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',<span id='Ext-form-field-Trigger-cfg-triggerNoEditCls'>    /**</span>     * @cfg     * The CSS class that is added to the text field when component is read-only or not editable.     */    triggerNoEditCls: Ext.baseCSSPrefix + 'trigger-noedit',<span id='Ext-form-field-Trigger-cfg-hideTrigger'>    /**</span>     * @cfg {Boolean} hideTrigger     * true to hide the trigger element and display only the base text field     */    hideTrigger: false,<span id='Ext-form-field-Trigger-cfg-editable'>    /**</span>     * @cfg {Boolean} editable     * false 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.     */    editable: true,<span id='Ext-form-field-Trigger-cfg-readOnly'>    /**</span>     * @cfg {Boolean} readOnly     * true to prevent the user from changing the field, and hides the trigger. Supercedes the editable and hideTrigger     * options if the value is true.     */    readOnly: false,<span id='Ext-form-field-Trigger-cfg-selectOnFocus'>    /**</span>     * @cfg {Boolean} [selectOnFocus=false]     * true to select any existing text in the field immediately on focus. Only applies when     * {@link #editable editable} = true     */<span id='Ext-form-field-Trigger-cfg-repeatTriggerClick'>    /**</span>     * @cfg {Boolean} repeatTriggerClick     * true to attach a {@link Ext.util.ClickRepeater click repeater} to the trigger.     */    repeatTriggerClick: false,<span id='Ext-form-field-Trigger-method-autoSize'>    /**</span>     * @method autoSize     * @private     */    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);    },    getSubTplMarkup: function() {        var me = this,            field = me.callParent(arguments);        return '<table id="' + me.id + '-triggerWrap" class="' + Ext.baseCSSPrefix + 'form-trigger-wrap" cellpadding="0" cellspacing="0"><tbody><tr>' +            '<td id="' + me.id + '-inputCell" class="' + Ext.baseCSSPrefix + 'form-trigger-input-cell">' + field + '</td>' +            me.getTriggerMarkup() +            '</tr></tbody></table>';    },        getSubTplData: function(){        var me = this,            data = me.callParent(),            readOnly = me.readOnly === true,            editable = me.editable !== false;                return Ext.apply(data, {            editableCls: (readOnly || !editable) ? ' ' + me.triggerNoEditCls : '',            readOnly: !editable || readOnly        });      },    getLabelableRenderData: function() {        var me = this,            triggerWrapCls = me.triggerWrapCls,            result = me.callParent(arguments);        return Ext.applyIf(result, {            triggerWrapCls: triggerWrapCls,            triggerMarkup: me.getTriggerMarkup()        });    },    getTriggerMarkup: function() {        var me = this,            i = 0,            hideTrigger = (me.readOnly || me.hideTrigger),            triggerCls,            triggerBaseCls = me.triggerBaseCls,            triggerConfigs = [];        // 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.        // triggerCls is a synonym for trigger1Cls, so copy it.        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({                tag: 'td',                valign: 'top',                cls: Ext.baseCSSPrefix + 'trigger-cell',                style: 'width:' + me.triggerWidth + (hideTrigger ? 'px;display:none' : 'px'),                cn: {                    cls: [Ext.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),                    role: 'button'                }            });        }        triggerConfigs[i - 1].cn.cls += ' ' + triggerBaseCls + '-last';        return Ext.DomHelper.markup(triggerConfigs);    },        disableCheck: function() {        return !this.disabled;        },    // private    beforeRender: function() {        var me = this,            triggerBaseCls = me.triggerBaseCls,            tempEl;            <span id='Ext-form-field-Trigger-property-triggerWidth'>        /**</span>         * @property {Number} triggerWidth         * Width of the trigger element. Unless set explicitly, it will be         * automatically calculated through creating a temporary element         * on page. (That will be done just once per app run.)         * @private         */        if (!me.triggerWidth) {            tempEl = Ext.resetElement.createChild({                style: 'position: absolute;',                 cls: Ext.baseCSSPrefix + 'form-trigger'            });            Ext.form.field.Trigger.prototype.triggerWidth = tempEl.getWidth();            tempEl.remove();        }        me.callParent();        if (triggerBaseCls != Ext.baseCSSPrefix + 'form-trigger') {            // we may need to change the selectors by which we extract trigger elements if is triggerBaseCls isn't the value we            // stuck in childEls            me.addChildEls({ name: 'triggerEl', select: '.' + triggerBaseCls });        }        // these start correct in the fieldSubTpl:        me.lastTriggerStateFlags = me.getTriggerStateFlags();    },    onRender: function() {        var me = this;        me.callParent(arguments);        me.doc = Ext.getDoc();        me.initTrigger();        me.triggerEl.unselectable();    },<span id='Ext-form-field-Trigger-method-getTriggerWidth'>    /**</span>     * Get the total width of the trigger button area.     * @return {Number} The total trigger width     */    getTriggerWidth: function() {        var me = this,            totalTriggerWidth = 0;        if (me.triggerWrap && !me.hideTrigger && !me.readOnly) {            totalTriggerWidth = me.triggerEl.getCount() * me.triggerWidth;        }        return totalTriggerWidth;    },    setHideTrigger: function(hideTrigger) {        if (hideTrigger != this.hideTrigger) {            this.hideTrigger = hideTrigger;            this.updateLayout();        }    },<span id='Ext-form-field-Trigger-method-setEditable'>    /**</span>     * Sets the editable state of this field. This method is the runtime equivalent of setting the 'editable' config     * option at config time.     * @param {Boolean} editable True to allow the user to directly edit 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.      */    setEditable: function(editable) {        if (editable != this.editable) {            this.editable = editable;            this.updateLayout();        }    },<span id='Ext-form-field-Trigger-method-setReadOnly'>    /**</span>     * Sets the read-only state of this field. This method is the runtime equivalent of setting the 'readOnly' config     * option at config time.     * @param {Boolean} readOnly True to prevent the user changing the field and explicitly hide the trigger. Setting     * this to true will supercede settings editable and hideTrigger. Setting this to false will defer back to editable     * and hideTrigger.     */    setReadOnly: function(readOnly) {        if (readOnly != this.readOnly) {            this.readOnly = readOnly;            this.updateLayout();        }    },    // private    initTrigger: function() {        var me = this,            triggerWrap = me.triggerWrap,            triggerEl = me.triggerEl,            disableCheck = me.disableCheck,            els, eLen, el, e, idx;        if (me.repeatTriggerClick) {            me.triggerRepeater = new Ext.util.ClickRepeater(triggerWrap, {                preventDefault: true,                handler: me.onTriggerWrapClick,                listeners: {                    mouseup: me.onTriggerWrapMouseup,                    scope: me                },                scope: me            });        } else {            me.mon(triggerWrap, {                click: me.onTriggerWrapClick,                mouseup: me.onTriggerWrapMouseup,                scope: me            });        }        triggerEl.setVisibilityMode(Ext.Element.DISPLAY);        triggerEl.addClsOnOver(me.triggerBaseCls + '-over', disableCheck, me);        els  = triggerEl.elements;        eLen = els.length;        for (e = 0; e < eLen; e++) {            el = els[e];            idx = e+1;            el.addClsOnOver(me['trigger' + (idx) + 'Cls'] + '-over', disableCheck, me);            el.addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);        }        triggerEl.addClsOnClick(me.triggerBaseCls + '-click', disableCheck, me);    },    // private    onDestroy: function() {        var me = this;        Ext.destroyMembers(me, 'triggerRepeater', 'triggerWrap', 'triggerEl');        delete me.doc;        me.callParent();    },    // private    onFocus: function() {        var me = this;        me.callParent(arguments);        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();        }    },<span id='Ext-form-field-Trigger-method-getTriggerStateFlags'>    /**</span>     * Returns a set of flags that describe the trigger state. These are just used to easily     * determine if the DOM is out-of-sync with the component's properties.     * @private     */    getTriggerStateFlags: function () {        var me = this,            state = 0;        if (me.readOnly) {            state += 1;        }        if (me.editable) {            state += 2;        }        if (me.hideTrigger) {            state += 4;        }        return state;    },<span id='Ext-form-field-Trigger-method-onBlur'>    /**</span>     * @private     * The default blur handling must not occur for a TriggerField, implementing this template method as emptyFn disables that.     * Instead the tab key is monitored, and the superclass's onBlur is called when tab is detected     */    onBlur: Ext.emptyFn,    // private    mimicBlur: function(e) {        if (!this.isDestroyed && !this.bodyEl.contains(e.target) && this.validateBlur(e)) {            this.triggerBlur(e);        }    },    // private    triggerBlur: function(e) {        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, e);        if (me.bodyEl) {            me.bodyEl.removeCls(me.wrapFocusCls);        }    },    // 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() {        var me = this,            targetEl, match,            triggerClickMethod,            event;        event = arguments[me.triggerRepeater ? 1 : 0];        if (event && !me.readOnly && !me.disabled) {                targetEl = event.getTarget('.' + me.triggerBaseCls, null);                match = targetEl && targetEl.className.match(me.triggerIndexRe);            if (match) {                triggerClickMethod = me['onTrigger' + (parseInt(match[1], 10) + 1) + 'Click'] || me.onTriggerClick;                if (triggerClickMethod) {                    triggerClickMethod.call(me, event);                }            }        }    },    // private    // Handle trigger mouse up gesture. To be implemented in subclasses.    // Currently the Spinner subclass refocuses the input element upon end of spin.    onTriggerWrapMouseup: Ext.emptyFn,<span id='Ext-form-field-Trigger-method-onTriggerClick'>    /**</span>     * @method onTriggerClick     * @protected     * 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.     * @param {Ext.EventObject} e     */    onTriggerClick: Ext.emptyFn<span id='Ext-form-field-Trigger-cfg-grow'>    /**</span>     * @cfg {Boolean} grow     * @private     */<span id='Ext-form-field-Trigger-cfg-growMin'>    /**</span>     * @cfg {Number} growMin     * @private     */<span id='Ext-form-field-Trigger-cfg-growMax'>    /**</span>     * @cfg {Number} growMax     * @private     */});</pre></body></html>
 |