initial import
[roojs1] / Roo / form / TriggerField.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12 /**
13  * @class Roo.form.TriggerField
14  * @extends Roo.form.TextField
15  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
16  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
17  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
18  * for which you can provide a custom implementation.  For example:
19  * <pre><code>
20 var trigger = new Roo.form.TriggerField();
21 trigger.onTriggerClick = myTriggerFn;
22 trigger.applyTo('my-field');
23 </code></pre>
24  *
25  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
26  * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
27  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
28  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
29  * @constructor
30  * Create a new TriggerField.
31  * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
32  * to the base TextField)
33  */
34 Roo.form.TriggerField = function(config){
35     this.mimicing = false;
36     Roo.form.TriggerField.superclass.constructor.call(this, config);
37 };
38
39 Roo.extend(Roo.form.TriggerField, Roo.form.TextField,  {
40     /**
41      * @cfg {String} triggerClass A CSS class to apply to the trigger
42      */
43     /**
44      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45      * {tag: "input", type: "text", size: "16", autocomplete: "off"})
46      */
47     defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
48     /**
49      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
50      */
51     hideTrigger:false,
52
53     /** @cfg {Boolean} grow @hide */
54     /** @cfg {Number} growMin @hide */
55     /** @cfg {Number} growMax @hide */
56
57     /**
58      * @hide 
59      * @method
60      */
61     autoSize: Roo.emptyFn,
62     // private
63     monitorTab : true,
64     // private
65     deferHeight : true,
66
67     
68     actionMode : 'wrap',
69     // private
70     onResize : function(w, h){
71         Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
72         if(typeof w == 'number'){
73             this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
74         }
75     },
76
77     // private
78     adjustSize : Roo.BoxComponent.prototype.adjustSize,
79
80     // private
81     getResizeEl : function(){
82         return this.wrap;
83     },
84
85     // private
86     getPositionEl : function(){
87         return this.wrap;
88     },
89
90     // private
91     alignErrorIcon : function(){
92         this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
93     },
94
95     // private
96     onRender : function(ct, position){
97         Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
98         this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
99         this.trigger = this.wrap.createChild(this.triggerConfig ||
100                 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
101         if(this.hideTrigger){
102             this.trigger.setDisplayed(false);
103         }
104         this.initTrigger();
105         if(!this.width){
106             this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
107         }
108     },
109
110     // private
111     initTrigger : function(){
112         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
113         this.trigger.addClassOnOver('x-form-trigger-over');
114         this.trigger.addClassOnClick('x-form-trigger-click');
115     },
116
117     // private
118     onDestroy : function(){
119         if(this.trigger){
120             this.trigger.removeAllListeners();
121             this.trigger.remove();
122         }
123         if(this.wrap){
124             this.wrap.remove();
125         }
126         Roo.form.TriggerField.superclass.onDestroy.call(this);
127     },
128
129     // private
130     onFocus : function(){
131         Roo.form.TriggerField.superclass.onFocus.call(this);
132         if(!this.mimicing){
133             this.wrap.addClass('x-trigger-wrap-focus');
134             this.mimicing = true;
135             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
136             if(this.monitorTab){
137                 this.el.on("keydown", this.checkTab, this);
138             }
139         }
140     },
141
142     // private
143     checkTab : function(e){
144         if(e.getKey() == e.TAB){
145             this.triggerBlur();
146         }
147     },
148
149     // private
150     onBlur : function(){
151         // do nothing
152     },
153
154     // private
155     mimicBlur : function(e, t){
156         if(!this.wrap.contains(t) && this.validateBlur()){
157             this.triggerBlur();
158         }
159     },
160
161     // private
162     triggerBlur : function(){
163         this.mimicing = false;
164         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
165         if(this.monitorTab){
166             this.el.un("keydown", this.checkTab, this);
167         }
168         this.wrap.removeClass('x-trigger-wrap-focus');
169         Roo.form.TriggerField.superclass.onBlur.call(this);
170     },
171
172     // private
173     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
174     validateBlur : function(e, t){
175         return true;
176     },
177
178     // private
179     onDisable : function(){
180         Roo.form.TriggerField.superclass.onDisable.call(this);
181         if(this.wrap){
182             this.wrap.addClass('x-item-disabled');
183         }
184     },
185
186     // private
187     onEnable : function(){
188         Roo.form.TriggerField.superclass.onEnable.call(this);
189         if(this.wrap){
190             this.wrap.removeClass('x-item-disabled');
191         }
192     },
193
194     // private
195     onShow : function(){
196         var ae = this.getActionEl();
197         
198         if(ae){
199             ae.dom.style.display = '';
200             ae.dom.style.visibility = 'visible';
201         }
202     },
203
204     // private
205     
206     onHide : function(){
207         var ae = this.getActionEl();
208         ae.dom.style.display = 'none';
209     },
210
211     /**
212      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
213      * by an implementing function.
214      * @method
215      * @param {EventObject} e
216      */
217     onTriggerClick : Roo.emptyFn
218 });
219
220 // TwinTriggerField is not a public class to be used directly.  It is meant as an abstract base class
221 // to be extended by an implementing class.  For an example of implementing this class, see the custom
222 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
223 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
224     initComponent : function(){
225         Roo.form.TwinTriggerField.superclass.initComponent.call(this);
226
227         this.triggerConfig = {
228             tag:'span', cls:'x-form-twin-triggers', cn:[
229             {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
230             {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
231         ]};
232     },
233
234     getTrigger : function(index){
235         return this.triggers[index];
236     },
237
238     initTrigger : function(){
239         var ts = this.trigger.select('.x-form-trigger', true);
240         this.wrap.setStyle('overflow', 'hidden');
241         var triggerField = this;
242         ts.each(function(t, all, index){
243             t.hide = function(){
244                 var w = triggerField.wrap.getWidth();
245                 this.dom.style.display = 'none';
246                 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
247             };
248             t.show = function(){
249                 var w = triggerField.wrap.getWidth();
250                 this.dom.style.display = '';
251                 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
252             };
253             var triggerIndex = 'Trigger'+(index+1);
254
255             if(this['hide'+triggerIndex]){
256                 t.dom.style.display = 'none';
257             }
258             t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
259             t.addClassOnOver('x-form-trigger-over');
260             t.addClassOnClick('x-form-trigger-click');
261         }, this);
262         this.triggers = ts.elements;
263     },
264
265     onTrigger1Click : Roo.emptyFn,
266     onTrigger2Click : Roo.emptyFn
267 });