Roo/bootstrap/TriggerField.js
[roojs1] / Roo / bootstrap / TriggerField.js
1 /*
2  * - LGPL
3  *
4  * trigger field - base class for combo..
5  * 
6  */
7  
8 /**
9  * @class Roo.bootstrap.TriggerField
10  * @extends Roo.bootstrap.Input
11  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
12  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
13  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
14  * for which you can provide a custom implementation.  For example:
15  * <pre><code>
16 var trigger = new Roo.bootstrap.TriggerField();
17 trigger.onTriggerClick = myTriggerFn;
18 trigger.applyTo('my-field');
19 </code></pre>
20  *
21  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
22  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
23  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
24  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
25  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
26
27  * @constructor
28  * Create a new TriggerField.
29  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
30  * to the base TextField)
31  */
32 Roo.bootstrap.TriggerField = function(config){
33     this.mimicing = false;
34     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
35 };
36
37 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
38     /**
39      * @cfg {String} triggerClass A CSS class to apply to the trigger
40      */
41      /**
42      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
43      */
44     hideTrigger:false,
45
46     /**
47      * @cfg {Boolean} removable (true|false) special filter default false
48      */
49     removable : false,
50     
51     /** @cfg {Boolean} grow @hide */
52     /** @cfg {Number} growMin @hide */
53     /** @cfg {Number} growMax @hide */
54
55     /**
56      * @hide 
57      * @method
58      */
59     autoSize: Roo.emptyFn,
60     // private
61     monitorTab : true,
62     // private
63     deferHeight : true,
64
65     
66     actionMode : 'wrap',
67     
68     caret : false,
69     
70     
71     getAutoCreate : function(){
72        
73         var align = this.labelAlign || this.parentLabelAlign();
74         
75         var id = Roo.id();
76         
77         var cfg = {
78             cls: 'form-group' //input-group
79         };
80         
81         
82         var input =  {
83             tag: 'input',
84             id : id,
85             type : this.inputType,
86             cls : 'form-control',
87             autocomplete: 'new-password',
88             placeholder : this.placeholder || '' 
89             
90         };
91         if (this.name) {
92             input.name = this.name;
93         }
94         if (this.size) {
95             input.cls += ' input-' + this.size;
96         }
97         
98         if (this.disabled) {
99             input.disabled=true;
100         }
101         
102         var inputblock = input;
103         
104         if(this.hasFeedback && !this.allowBlank){
105             
106             var feedback = {
107                 tag: 'span',
108                 cls: 'glyphicon form-control-feedback'
109             };
110             
111             if(this.removable && !this.editable && !this.tickable){
112                 inputblock = {
113                     cls : 'has-feedback',
114                     cn :  [
115                         inputblock,
116                         {
117                             tag: 'button',
118                             html : 'x',
119                             cls : 'roo-combo-removable-btn close'
120                         },
121                         feedback
122                     ] 
123                 };
124             } else {
125                 inputblock = {
126                     cls : 'has-feedback',
127                     cn :  [
128                         inputblock,
129                         feedback
130                     ] 
131                 };
132             }
133
134         } else {
135             if(this.removable && !this.editable && !this.tickable){
136                 inputblock = {
137                     cls : 'roo-removable',
138                     cn :  [
139                         inputblock,
140                         {
141                             tag: 'button',
142                             html : 'x',
143                             cls : 'roo-combo-removable-btn close'
144                         }
145                     ] 
146                 };
147             }
148         }
149         
150         if (this.before || this.after) {
151             
152             inputblock = {
153                 cls : 'input-group',
154                 cn :  [] 
155             };
156             if (this.before) {
157                 inputblock.cn.push({
158                     tag :'span',
159                     cls : 'input-group-addon',
160                     html : this.before
161                 });
162             }
163             
164             inputblock.cn.push(input);
165             
166             if(this.hasFeedback && !this.allowBlank){
167                 inputblock.cls += ' has-feedback';
168                 inputblock.cn.push(feedback);
169             }
170             
171             if (this.after) {
172                 inputblock.cn.push({
173                     tag :'span',
174                     cls : 'input-group-addon',
175                     html : this.after
176                 });
177             }
178             
179         };
180         
181         var box = {
182             tag: 'div',
183             cn: [
184                 {
185                     tag: 'input',
186                     type : 'hidden',
187                     cls: 'form-hidden-field'
188                 },
189                 inputblock
190             ]
191             
192         };
193         
194         if(this.multiple){
195             Roo.log('multiple');
196             
197             box = {
198                 tag: 'div',
199                 cn: [
200                     {
201                         tag: 'input',
202                         type : 'hidden',
203                         cls: 'form-hidden-field'
204                     },
205                     {
206                         tag: 'ul',
207                         cls: 'select2-choices',
208                         cn:[
209                             {
210                                 tag: 'li',
211                                 cls: 'select2-search-field',
212                                 cn: [
213
214                                     inputblock
215                                 ]
216                             }
217                         ]
218                     }
219                 ]
220             }
221         };
222         
223         var combobox = {
224             cls: 'select2-container input-group',
225             cn: [
226                 box
227 //                {
228 //                    tag: 'ul',
229 //                    cls: 'typeahead typeahead-long dropdown-menu',
230 //                    style: 'display:none'
231 //                }
232             ]
233         };
234         
235         if(!this.multiple && this.showToggleBtn){
236             
237             var caret = {
238                         tag: 'span',
239                         cls: 'caret'
240              };
241             if (this.caret != false) {
242                 caret = {
243                      tag: 'i',
244                      cls: 'fa fa-' + this.caret
245                 };
246                 
247             }
248             
249             combobox.cn.push({
250                 tag :'span',
251                 cls : 'input-group-addon btn dropdown-toggle',
252                 cn : [
253                     caret,
254                     {
255                         tag: 'span',
256                         cls: 'combobox-clear',
257                         cn  : [
258                             {
259                                 tag : 'i',
260                                 cls: 'icon-remove'
261                             }
262                         ]
263                     }
264                 ]
265
266             })
267         }
268         
269         if(this.multiple){
270             combobox.cls += ' select2-container-multi';
271         }
272         
273         if (align ==='left' && this.fieldLabel.length) {
274             
275                 Roo.log("left and has label");
276                 cfg.cn = [
277                     
278                     {
279                         tag: 'label',
280                         'for' :  id,
281                         cls : 'control-label col-sm-' + this.labelWidth,
282                         html : this.fieldLabel
283                         
284                     },
285                     {
286                         cls : "col-sm-" + (12 - this.labelWidth), 
287                         cn: [
288                             combobox
289                         ]
290                     }
291                     
292                 ];
293         } else if ( this.fieldLabel.length) {
294                 Roo.log(" label");
295                  cfg.cn = [
296                    
297                     {
298                         tag: 'label',
299                         //cls : 'input-group-addon',
300                         html : this.fieldLabel
301                         
302                     },
303                     
304                     combobox
305                     
306                 ];
307
308         } else {
309             
310                 Roo.log(" no label && no align");
311                 cfg = combobox
312                      
313                 
314         }
315          
316         var settings=this;
317         ['xs','sm','md','lg'].map(function(size){
318             if (settings[size]) {
319                 cfg.cls += ' col-' + size + '-' + settings[size];
320             }
321         });
322         Roo.log(cfg);
323         return cfg;
324         
325     },
326     
327     
328     
329     // private
330     onResize : function(w, h){
331 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
332 //        if(typeof w == 'number'){
333 //            var x = w - this.trigger.getWidth();
334 //            this.inputEl().setWidth(this.adjustWidth('input', x));
335 //            this.trigger.setStyle('left', x+'px');
336 //        }
337     },
338
339     // private
340     adjustSize : Roo.BoxComponent.prototype.adjustSize,
341
342     // private
343     getResizeEl : function(){
344         return this.inputEl();
345     },
346
347     // private
348     getPositionEl : function(){
349         return this.inputEl();
350     },
351
352     // private
353     alignErrorIcon : function(){
354         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
355     },
356
357     // private
358     initEvents : function(){
359         
360         this.createList();
361         
362         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
363         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
364         if(!this.multiple && this.showToggleBtn){
365             this.trigger = this.el.select('span.dropdown-toggle',true).first();
366             if(this.hideTrigger){
367                 this.trigger.setDisplayed(false);
368             }
369             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
370         }
371         
372         if(this.multiple){
373             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
374         }
375         
376         if(this.removable && !this.editable && !this.tickable){
377             var close = this.closeTriggerEl();
378             
379             if(close){
380                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
381                 close.on('click', this.removeBtnClick, this, close);
382             }
383         }
384         
385         //this.trigger.addClassOnOver('x-form-trigger-over');
386         //this.trigger.addClassOnClick('x-form-trigger-click');
387         
388         //if(!this.width){
389         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
390         //}
391     },
392     
393     closeTriggerEl : function()
394     {
395         var close = this.el.select('.roo-combo-removable-btn', true).first();
396         return close ? close : false;
397     },
398     
399     removeBtnClick : function(e, h, el)
400     {
401         e.preventDefault();
402         
403         if(this.fireEvent("remove", this) !== false){
404             this.reset();
405         }
406     },
407     
408     createList : function()
409     {
410         this.list = Roo.get(document.body).createChild({
411             tag: 'ul',
412             cls: 'typeahead typeahead-long dropdown-menu',
413             style: 'display:none'
414         });
415         
416         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
417         
418     },
419
420     // private
421     initTrigger : function(){
422        
423     },
424
425     // private
426     onDestroy : function(){
427         if(this.trigger){
428             this.trigger.removeAllListeners();
429           //  this.trigger.remove();
430         }
431         //if(this.wrap){
432         //    this.wrap.remove();
433         //}
434         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
435     },
436
437     // private
438     onFocus : function(){
439         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
440         /*
441         if(!this.mimicing){
442             this.wrap.addClass('x-trigger-wrap-focus');
443             this.mimicing = true;
444             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
445             if(this.monitorTab){
446                 this.el.on("keydown", this.checkTab, this);
447             }
448         }
449         */
450     },
451
452     // private
453     checkTab : function(e){
454         if(e.getKey() == e.TAB){
455             this.triggerBlur();
456         }
457     },
458
459     // private
460     onBlur : function(){
461         // do nothing
462     },
463
464     // private
465     mimicBlur : function(e, t){
466         /*
467         if(!this.wrap.contains(t) && this.validateBlur()){
468             this.triggerBlur();
469         }
470         */
471     },
472
473     // private
474     triggerBlur : function(){
475         this.mimicing = false;
476         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
477         if(this.monitorTab){
478             this.el.un("keydown", this.checkTab, this);
479         }
480         //this.wrap.removeClass('x-trigger-wrap-focus');
481         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
482     },
483
484     // private
485     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
486     validateBlur : function(e, t){
487         return true;
488     },
489
490     // private
491     onDisable : function(){
492         this.inputEl().dom.disabled = true;
493         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
494         //if(this.wrap){
495         //    this.wrap.addClass('x-item-disabled');
496         //}
497     },
498
499     // private
500     onEnable : function(){
501         this.inputEl().dom.disabled = false;
502         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
503         //if(this.wrap){
504         //    this.el.removeClass('x-item-disabled');
505         //}
506     },
507
508     // private
509     onShow : function(){
510         var ae = this.getActionEl();
511         
512         if(ae){
513             ae.dom.style.display = '';
514             ae.dom.style.visibility = 'visible';
515         }
516     },
517
518     // private
519     
520     onHide : function(){
521         var ae = this.getActionEl();
522         ae.dom.style.display = 'none';
523     },
524
525     /**
526      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
527      * by an implementing function.
528      * @method
529      * @param {EventObject} e
530      */
531     onTriggerClick : Roo.emptyFn
532 });
533