Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Trigger.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-form.field.Trigger-method-constructor'><span id='Ext-form.field.Trigger'>/**
2 </span></span> * @class Ext.form.field.Trigger
3  * @extends Ext.form.field.Text
4  * &lt;p&gt;Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6  * overriding {@link #onTriggerClick}. You can create a Trigger field directly, as it renders exactly like a combobox
7  * for which you can provide a custom implementation. 
8  * {@img Ext.form.field.Trigger/Ext.form.field.Trigger.png Ext.form.field.Trigger component}
9  * For example:&lt;/p&gt;
10  * &lt;pre&gt;&lt;code&gt;
11 Ext.define('Ext.ux.CustomTrigger', {
12     extend: 'Ext.form.field.Trigger',
13     alias: 'widget.customtrigger',
14     
15     // override onTriggerClick
16     onTriggerClick: function() {
17         Ext.Msg.alert('Status', 'You clicked my trigger!');
18     }
19 });
20
21 Ext.create('Ext.form.FormPanel', {
22     title: 'Form with TriggerField',
23     bodyPadding: 5,
24     width: 350,
25     renderTo: Ext.getBody(),
26     items:[{
27         xtype: 'customtrigger',
28         fieldLabel: 'Sample Trigger',
29         emptyText: 'click the trigger',
30     }]
31 });
32 &lt;/code&gt;&lt;/pre&gt;
33  *
34  * &lt;p&gt;However, in general you will most likely want to use Trigger as the base class for a reusable component.
35  * {@link Ext.form.field.Date} and {@link Ext.form.field.ComboBox} are perfect examples of this.&lt;/p&gt;
36  *
37  * @constructor
38  * Create a new Trigger field.
39  * @param {Object} config Configuration options (valid {@Ext.form.field.Text} config options will also be applied
40  * to the base Text field)
41  * @xtype triggerfield
42  */
43 Ext.define('Ext.form.field.Trigger', {
44     extend:'Ext.form.field.Text',
45     alias: ['widget.triggerfield', 'widget.trigger'],
46     requires: ['Ext.core.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
47     alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],
48
49     fieldSubTpl: [
50         '&lt;input id=&quot;{id}&quot; type=&quot;{type}&quot; ',
51             '&lt;tpl if=&quot;name&quot;&gt;name=&quot;{name}&quot; &lt;/tpl&gt;',
52             '&lt;tpl if=&quot;size&quot;&gt;size=&quot;{size}&quot; &lt;/tpl&gt;',
53             '&lt;tpl if=&quot;tabIdx&quot;&gt;tabIndex=&quot;{tabIdx}&quot; &lt;/tpl&gt;',
54             'class=&quot;{fieldCls} {typeCls}&quot; autocomplete=&quot;off&quot; /&gt;',
55         '&lt;div class=&quot;{triggerWrapCls}&quot; role=&quot;presentation&quot;&gt;',
56             '{triggerEl}',
57             '&lt;div class=&quot;{clearCls}&quot; role=&quot;presentation&quot;&gt;&lt;/div&gt;',
58         '&lt;/div&gt;',
59         {
60             compiled: true,
61             disableFormats: true
62         }
63     ],
64
65 <span id='Ext-form.field.Trigger-cfg-triggerCls'>    /**
66 </span>     * @cfg {String} triggerCls
67      * An additional CSS class used to style the trigger button.  The trigger will always get the
68      * {@link #triggerBaseCls} by default and &lt;tt&gt;triggerCls&lt;/tt&gt; will be &lt;b&gt;appended&lt;/b&gt; if specified.
69      * Defaults to undefined.
70      */
71
72 <span id='Ext-form.field.Trigger-cfg-triggerBaseCls'>    /**
73 </span>     * @cfg {String} triggerBaseCls
74      * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be
75      * appended in addition to this class.
76      */
77     triggerBaseCls: Ext.baseCSSPrefix + 'form-trigger',
78
79 <span id='Ext-form.field.Trigger-cfg-triggerWrapCls'>    /**
80 </span>     * @cfg {String} triggerWrapCls
81      * The CSS class that is added to the div wrapping the trigger button(s).
82      */
83     triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',
84
85 <span id='Ext-form.field.Trigger-cfg-hideTrigger'>    /**
86 </span>     * @cfg {Boolean} hideTrigger &lt;tt&gt;true&lt;/tt&gt; to hide the trigger element and display only the base
87      * text field (defaults to &lt;tt&gt;false&lt;/tt&gt;)
88      */
89     hideTrigger: false,
90
91 <span id='Ext-form.field.Trigger-cfg-editable'>    /**
92 </span>     * @cfg {Boolean} editable &lt;tt&gt;false&lt;/tt&gt; to prevent the user from typing text directly into the field;
93      * the field can only have its value set via an action invoked by the trigger. (defaults to &lt;tt&gt;true&lt;/tt&gt;).
94      */
95     editable: true,
96
97 <span id='Ext-form.field.Trigger-cfg-readOnly'>    /**
98 </span>     * @cfg {Boolean} readOnly &lt;tt&gt;true&lt;/tt&gt; to prevent the user from changing the field, and
99      * hides the trigger.  Supercedes the editable and hideTrigger options if the value is true.
100      * (defaults to &lt;tt&gt;false&lt;/tt&gt;)
101      */
102     readOnly: false,
103
104 <span id='Ext-form.field.Trigger-cfg-selectOnFocus'>    /**
105 </span>     * @cfg {Boolean} selectOnFocus &lt;tt&gt;true&lt;/tt&gt; to select any existing text in the field immediately on focus.
106      * Only applies when &lt;tt&gt;{@link #editable editable} = true&lt;/tt&gt; (defaults to &lt;tt&gt;false&lt;/tt&gt;).
107      */
108
109 <span id='Ext-form.field.Trigger-cfg-repeatTriggerClick'>    /**
110 </span>     * @cfg {Boolean} repeatTriggerClick &lt;tt&gt;true&lt;/tt&gt; to attach a {@link Ext.util.ClickRepeater click repeater}
111      * to the trigger. Defaults to &lt;tt&gt;false&lt;/tt&gt;.
112      */
113     repeatTriggerClick: false,
114
115
116 <span id='Ext-form.field.Trigger-method-autoSize'>    /**
117 </span>     * @hide
118      * @method autoSize
119      */
120     autoSize: Ext.emptyFn,
121     // private
122     monitorTab: true,
123     // private
124     mimicing: false,
125     // private
126     triggerIndexRe: /trigger-index-(\d+)/,
127
128     componentLayout: 'triggerfield',
129
130     initComponent: function() {
131         this.wrapFocusCls = this.triggerWrapCls + '-focus';
132         this.callParent(arguments);
133     },
134
135     // private
136     onRender: function(ct, position) {
137         var me = this,
138             triggerCls,
139             triggerBaseCls = me.triggerBaseCls,
140             triggerWrapCls = me.triggerWrapCls,
141             triggerConfigs = [],
142             i;
143
144         // triggerCls is a synonym for trigger1Cls, so copy it.
145         // TODO this trigger&lt;n&gt;Cls API design doesn't feel clean, especially where it butts up against the
146         // single triggerCls config. Should rethink this, perhaps something more structured like a list of
147         // trigger config objects that hold cls, handler, etc.
148         if (!me.trigger1Cls) {
149             me.trigger1Cls = me.triggerCls;
150         }
151
152         // Create as many trigger elements as we have trigger&lt;n&gt;Cls configs, but always at least one
153         for (i = 0; (triggerCls = me['trigger' + (i + 1) + 'Cls']) || i &lt; 1; i++) {
154             triggerConfigs.push({
155                 cls: [Ext.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
156                 role: 'button'
157             });
158         }
159         triggerConfigs[i - 1].cls += ' ' + triggerBaseCls + '-last';
160
161         Ext.applyIf(me.renderSelectors, {
162 <span id='Ext-form.field.Trigger-property-triggerWrap'>            /**
163 </span>             * @property triggerWrap
164              * @type Ext.core.Element
165              * A reference to the div element wrapping the trigger button(s). Only set after the field has been rendered.
166              */
167             triggerWrap: '.' + triggerWrapCls
168         });
169         Ext.applyIf(me.subTplData, {
170             triggerWrapCls: triggerWrapCls,
171             triggerEl: Ext.core.DomHelper.markup(triggerConfigs),
172             clearCls: me.clearCls
173         });
174
175         me.callParent(arguments);
176
177 <span id='Ext-form.field.Trigger-property-triggerEl'>        /**
178 </span>         * @property triggerEl
179          * @type Ext.CompositeElement
180          * A composite of all the trigger button elements. Only set after the field has been rendered.
181          */
182         me.triggerEl = Ext.select('.' + triggerBaseCls, true, me.triggerWrap.dom);
183
184         me.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc();
185         me.initTrigger();
186     },
187
188     onEnable: function() {
189         this.callParent();
190         this.triggerWrap.unmask();
191     },
192     
193     onDisable: function() {
194         this.callParent();
195         this.triggerWrap.mask();
196     },
197     
198     afterRender: function() {
199         this.callParent();
200         this.updateEditState();
201     },
202
203     updateEditState: function() {
204         var me = this,
205             inputEl = me.inputEl,
206             triggerWrap = me.triggerWrap,
207             noeditCls = Ext.baseCSSPrefix + 'trigger-noedit',
208             displayed,
209             readOnly;
210
211         if (me.rendered) {
212             if (me.readOnly) {
213                 inputEl.addCls(noeditCls);
214                 readOnly = true;
215                 displayed = false;
216             } else {
217                 if (me.editable) {
218                     inputEl.removeCls(noeditCls);
219                     readOnly = false;
220                 } else {
221                     inputEl.addCls(noeditCls);
222                     readOnly = true;
223                 }
224                 displayed = !me.hideTrigger;
225             }
226
227             triggerWrap.setDisplayed(displayed);
228             inputEl.dom.readOnly = readOnly;
229             me.doComponentLayout();
230         }
231     },
232
233 <span id='Ext-form.field.Trigger-method-getTriggerWidth'>    /**
234 </span>     * Get the total width of the trigger button area. Only useful after the field has been rendered.
235      * @return {Number} The trigger width
236      */
237     getTriggerWidth: function() {
238         var me = this,
239             triggerWrap = me.triggerWrap,
240             totalTriggerWidth = 0;
241         if (triggerWrap &amp;&amp; !me.hideTrigger &amp;&amp; !me.readOnly) {
242             me.triggerEl.each(function(trigger) {
243                 totalTriggerWidth += trigger.getWidth();
244             });
245             totalTriggerWidth += me.triggerWrap.getFrameWidth('lr');
246         }
247         return totalTriggerWidth;
248     },
249
250     setHideTrigger: function(hideTrigger) {
251         if (hideTrigger != this.hideTrigger) {
252             this.hideTrigger = hideTrigger;
253             this.updateEditState();
254         }
255     },
256
257 <span id='Ext-form.field.Trigger-method-setEditable'>    /**
258 </span>     * @param {Boolean} editable True to allow the user to directly edit the field text
259      * Allow or prevent the user from directly editing the field text.  If false is passed,
260      * the user will only be able to modify the field using the trigger.  Will also add
261      * a click event to the text field which will call the trigger. This method
262      * is the runtime equivalent of setting the 'editable' config option at config time.
263      */
264     setEditable: function(editable) {
265         if (editable != this.editable) {
266             this.editable = editable;
267             this.updateEditState();
268         }
269     },
270
271 <span id='Ext-form.field.Trigger-method-setReadOnly'>    /**
272 </span>     * @param {Boolean} readOnly True to prevent the user changing the field and explicitly
273      * hide the trigger.
274      * Setting this to true will superceed settings editable and hideTrigger.
275      * Setting this to false will defer back to editable and hideTrigger. This method
276      * is the runtime equivalent of setting the 'readOnly' config option at config time.
277      */
278     setReadOnly: function(readOnly) {
279         if (readOnly != this.readOnly) {
280             this.readOnly = readOnly;
281             this.updateEditState();
282         }
283     },
284
285     // private
286     initTrigger: function() {
287         var me = this,
288             triggerWrap = me.triggerWrap,
289             triggerEl = me.triggerEl;
290
291         if (me.repeatTriggerClick) {
292             me.triggerRepeater = Ext.create('Ext.util.ClickRepeater', triggerWrap, {
293                 preventDefault: true,
294                 handler: function(cr, e) {
295                     me.onTriggerWrapClick(e);
296                 }
297             });
298         } else {
299             me.mon(me.triggerWrap, 'click', me.onTriggerWrapClick, me);
300         }
301
302         triggerEl.addClsOnOver(me.triggerBaseCls + '-over');
303         triggerEl.each(function(el, c, i) {
304             el.addClsOnOver(me['trigger' + (i + 1) + 'Cls'] + '-over');
305         });
306         triggerEl.addClsOnClick(me.triggerBaseCls + '-click');
307         triggerEl.each(function(el, c, i) {
308             el.addClsOnClick(me['trigger' + (i + 1) + 'Cls'] + '-click');
309         });
310     },
311
312     // private
313     onDestroy: function() {
314         var me = this;
315         Ext.destroyMembers(me, 'triggerRepeater', 'triggerWrap', 'triggerEl');
316         delete me.doc;
317         me.callParent();
318     },
319
320     // private
321     onFocus: function() {
322         var me = this;
323         this.callParent();
324         if (!me.mimicing) {
325             me.bodyEl.addCls(me.wrapFocusCls);
326             me.mimicing = true;
327             me.mon(me.doc, 'mousedown', me.mimicBlur, me, {
328                 delay: 10
329             });
330             if (me.monitorTab) {
331                 me.on('specialkey', me.checkTab, me);
332             }
333         }
334     },
335
336     // private
337     checkTab: function(me, e) {
338         if (!this.ignoreMonitorTab &amp;&amp; e.getKey() == e.TAB) {
339             this.triggerBlur();
340         }
341     },
342
343     // private
344     onBlur: Ext.emptyFn,
345
346     // private
347     mimicBlur: function(e) {
348         if (!this.isDestroyed &amp;&amp; !this.bodyEl.contains(e.target) &amp;&amp; this.validateBlur(e)) {
349             this.triggerBlur();
350         }
351     },
352
353     // private
354     triggerBlur: function() {
355         var me = this;
356         me.mimicing = false;
357         me.mun(me.doc, 'mousedown', me.mimicBlur, me);
358         if (me.monitorTab &amp;&amp; me.inputEl) {
359             me.un('specialkey', me.checkTab, me);
360         }
361         Ext.form.field.Trigger.superclass.onBlur.call(me);
362         if (me.bodyEl) {
363             me.bodyEl.removeCls(me.wrapFocusCls);
364         }
365     },
366
367     beforeBlur: Ext.emptyFn,
368
369     // private
370     // This should be overridden by any subclass that needs to check whether or not the field can be blurred.
371     validateBlur: function(e) {
372         return true;
373     },
374
375     // private
376     // process clicks upon triggers.
377     // determine which trigger index, and dispatch to the appropriate click handler
378     onTriggerWrapClick: function(e) {
379         var me = this,
380             t = e &amp;&amp; e.getTarget('.' + Ext.baseCSSPrefix + 'form-trigger', null),
381             match = t &amp;&amp; t.className.match(me.triggerIndexRe),
382             idx,
383             triggerClickMethod;
384
385         if (match &amp;&amp; !me.readOnly) {
386             idx = parseInt(match[1], 10);
387             triggerClickMethod = me['onTrigger' + (idx + 1) + 'Click'] || me.onTriggerClick;
388             if (triggerClickMethod) {
389                 triggerClickMethod.call(me, e);
390             }
391         }
392     },
393
394 <span id='Ext-form.field.Trigger-method-onTriggerClick'>    /**
395 </span>     * The function that should handle the trigger's click event.  This method does nothing by default
396      * until overridden by an implementing function.  See Ext.form.field.ComboBox and Ext.form.field.Date for
397      * sample implementations.
398      * @method
399      * @param {Ext.EventObject} e
400      */
401     onTriggerClick: Ext.emptyFn
402
403 <span id='Ext-form.field.Trigger-cfg-grow'>    /**
404 </span>     * @cfg {Boolean} grow @hide
405      */
406 <span id='Ext-form.field.Trigger-cfg-growMin'>    /**
407 </span>     * @cfg {Number} growMin @hide
408      */
409 <span id='Ext-form.field.Trigger-cfg-growMax'>    /**
410 </span>     * @cfg {Number} growMax @hide
411      */
412 });
413 </pre></pre></body></html>