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        Roo.log('testingggggg');
74        
75         var align = this.labelAlign || this.parentLabelAlign();
76         
77         var id = Roo.id();
78         
79         var cfg = {
80             cls: 'form-group' //input-group
81         };
82         
83         
84         var input =  {
85             tag: 'input',
86             id : id,
87             type : this.inputType,
88             cls : 'form-control',
89             autocomplete: 'new-password',
90             placeholder : this.placeholder || '' 
91             
92         };
93         if (this.name) {
94             input.name = this.name;
95         }
96         if (this.size) {
97             input.cls += ' input-' + this.size;
98         }
99         
100         if (this.disabled) {
101             input.disabled=true;
102         }
103         
104         var inputblock = input;
105         
106         if(this.hasFeedback && !this.allowBlank){
107             
108             var feedback = {
109                 tag: 'span',
110                 cls: 'glyphicon form-control-feedback'
111             };
112             
113             if(this.removable && !this.editable && !this.tickable){
114                 inputblock = {
115                     cls : 'has-feedback',
116                     cn :  [
117                         inputblock,
118                         {
119                             tag: 'button',
120                             html : 'x',
121                             cls : 'roo-combo-removable-btn close'
122                         },
123                         feedback
124                     ] 
125                 };
126             } else {
127                 inputblock = {
128                     cls : 'has-feedback',
129                     cn :  [
130                         inputblock,
131                         feedback
132                     ] 
133                 };
134             }
135
136         } else {
137             if(this.removable && !this.editable && !this.tickable){
138                 inputblock = {
139                     cls : 'roo-removable',
140                     cn :  [
141                         inputblock,
142                         {
143                             tag: 'button',
144                             html : 'x',
145                             cls : 'roo-combo-removable-btn close'
146                         }
147                     ] 
148                 };
149             }
150         }
151         
152         if (this.before || this.after) {
153             
154             inputblock = {
155                 cls : 'input-group',
156                 cn :  [] 
157             };
158             if (this.before) {
159                 inputblock.cn.push({
160                     tag :'span',
161                     cls : 'input-group-addon',
162                     html : this.before
163                 });
164             }
165             
166             inputblock.cn.push(input);
167             
168             if(this.hasFeedback && !this.allowBlank){
169                 inputblock.cls += ' has-feedback';
170                 inputblock.cn.push(feedback);
171             }
172             
173             if (this.after) {
174                 inputblock.cn.push({
175                     tag :'span',
176                     cls : 'input-group-addon',
177                     html : this.after
178                 });
179             }
180             
181         };
182         
183         var box = {
184             tag: 'div',
185             cn: [
186                 {
187                     tag: 'input',
188                     type : 'hidden',
189                     cls: 'form-hidden-field'
190                 },
191                 inputblock
192             ]
193             
194         };
195         
196         if(this.multiple){
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: 'roo-select2-choices',
208                         cn:[
209                             {
210                                 tag: 'li',
211                                 cls: 'roo-select2-search-field',
212                                 cn: [
213
214                                     inputblock
215                                 ]
216                             }
217                         ]
218                     }
219                 ]
220             }
221         };
222         
223         var combobox = {
224             cls: 'roo-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 += ' roo-select2-container-multi';
271         }
272         
273         if (align ==='left' && this.fieldLabel.length) {
274             
275             cfg.cls += ' roo-form-group-label-left';
276
277             cfg.cn = [
278                 {
279                     tag : 'i',
280                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
281                     tooltip : 'This field is required'
282                 },
283                 {
284                     tag: 'label',
285                     'for' :  id,
286                     cls : 'control-label',
287                     html : this.fieldLabel
288
289                 },
290                 {
291                     cls : "", 
292                     cn: [
293                         combobox
294                     ]
295                 }
296
297             ];
298             
299             var labelCfg = cfg.cn[1];
300             var contentCfg = cfg.cn[2];
301             
302             if(this.indicatorpos == 'right'){
303                 cfg.cn = [
304                     {
305                         tag: 'label',
306                         'for' :  id,
307                         cls : 'control-label',
308                         cn : [
309                             {
310                                 tag : 'span',
311                                 html : this.fieldLabel
312                             },
313                             {
314                                 tag : 'i',
315                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
316                                 tooltip : 'This field is required'
317                             }
318                         ]
319                     },
320                     {
321                         cls : "", 
322                         cn: [
323                             combobox
324                         ]
325                     }
326
327                 ];
328                 
329                 labelCfg = cfg.cn[0];
330                 contentCfg = cfg.cn[1];
331             }
332             
333             if(this.labelWidth > 12){
334                 labelCfg.style = "width: " + this.labelWidth + 'px';
335             }
336             
337             if(this.labelWidth < 13 && this.labelmd == 0){
338                 this.labelmd = this.labelWidth;
339             }
340             
341             if(this.labellg > 0){
342                 labelCfg.cls += ' col-lg-' + this.labellg;
343                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
344             }
345             
346             if(this.labelmd > 0){
347                 labelCfg.cls += ' col-md-' + this.labelmd;
348                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
349             }
350             
351             if(this.labelsm > 0){
352                 labelCfg.cls += ' col-sm-' + this.labelsm;
353                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
354             }
355             
356             if(this.labelxs > 0){
357                 labelCfg.cls += ' col-xs-' + this.labelxs;
358                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
359             }
360             
361         } else if ( this.fieldLabel.length) {
362 //                Roo.log(" label");
363             cfg.cn = [
364                 {
365                    tag : 'i',
366                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
367                    tooltip : 'This field is required'
368                },
369                {
370                    tag: 'label',
371                    //cls : 'input-group-addon',
372                    html : this.fieldLabel
373
374                },
375
376                combobox
377
378             ];
379             
380             if(this.indicatorpos == 'right'){
381                 
382                 cfg.cn = [
383                     {
384                        tag: 'label',
385                        cn : [
386                            {
387                                tag : 'span',
388                                html : this.fieldLabel
389                            },
390                            {
391                               tag : 'i',
392                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
393                               tooltip : 'This field is required'
394                            }
395                        ]
396
397                     },
398                     combobox
399
400                 ];
401
402             }
403
404         } else {
405             
406 //                Roo.log(" no label && no align");
407                 cfg = combobox
408                      
409                 
410         }
411         
412         var settings=this;
413         ['xs','sm','md','lg'].map(function(size){
414             if (settings[size]) {
415                 cfg.cls += ' col-' + size + '-' + settings[size];
416             }
417         });
418         
419         return cfg;
420         
421     },
422     
423     
424     
425     // private
426     onResize : function(w, h){
427 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
428 //        if(typeof w == 'number'){
429 //            var x = w - this.trigger.getWidth();
430 //            this.inputEl().setWidth(this.adjustWidth('input', x));
431 //            this.trigger.setStyle('left', x+'px');
432 //        }
433     },
434
435     // private
436     adjustSize : Roo.BoxComponent.prototype.adjustSize,
437
438     // private
439     getResizeEl : function(){
440         return this.inputEl();
441     },
442
443     // private
444     getPositionEl : function(){
445         return this.inputEl();
446     },
447
448     // private
449     alignErrorIcon : function(){
450         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
451     },
452
453     // private
454     initEvents : function(){
455         
456         this.createList();
457         
458         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
459         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
460         if(!this.multiple && this.showToggleBtn){
461             this.trigger = this.el.select('span.dropdown-toggle',true).first();
462             if(this.hideTrigger){
463                 this.trigger.setDisplayed(false);
464             }
465             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
466         }
467         
468         if(this.multiple){
469             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
470         }
471         
472         if(this.removable && !this.editable && !this.tickable){
473             var close = this.closeTriggerEl();
474             
475             if(close){
476                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
477                 close.on('click', this.removeBtnClick, this, close);
478             }
479         }
480         
481         //this.trigger.addClassOnOver('x-form-trigger-over');
482         //this.trigger.addClassOnClick('x-form-trigger-click');
483         
484         //if(!this.width){
485         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
486         //}
487     },
488     
489     closeTriggerEl : function()
490     {
491         var close = this.el.select('.roo-combo-removable-btn', true).first();
492         return close ? close : false;
493     },
494     
495     removeBtnClick : function(e, h, el)
496     {
497         e.preventDefault();
498         
499         if(this.fireEvent("remove", this) !== false){
500             this.reset();
501             this.fireEvent("afterremove", this)
502         }
503     },
504     
505     createList : function()
506     {
507         this.list = Roo.get(document.body).createChild({
508             tag: 'ul',
509             cls: 'typeahead typeahead-long dropdown-menu',
510             style: 'display:none'
511         });
512         
513         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
514         
515     },
516
517     // private
518     initTrigger : function(){
519        
520     },
521
522     // private
523     onDestroy : function(){
524         if(this.trigger){
525             this.trigger.removeAllListeners();
526           //  this.trigger.remove();
527         }
528         //if(this.wrap){
529         //    this.wrap.remove();
530         //}
531         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
532     },
533
534     // private
535     onFocus : function(){
536         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
537         /*
538         if(!this.mimicing){
539             this.wrap.addClass('x-trigger-wrap-focus');
540             this.mimicing = true;
541             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
542             if(this.monitorTab){
543                 this.el.on("keydown", this.checkTab, this);
544             }
545         }
546         */
547     },
548
549     // private
550     checkTab : function(e){
551         if(e.getKey() == e.TAB){
552             this.triggerBlur();
553         }
554     },
555
556     // private
557     onBlur : function(){
558         // do nothing
559     },
560
561     // private
562     mimicBlur : function(e, t){
563         /*
564         if(!this.wrap.contains(t) && this.validateBlur()){
565             this.triggerBlur();
566         }
567         */
568     },
569
570     // private
571     triggerBlur : function(){
572         this.mimicing = false;
573         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
574         if(this.monitorTab){
575             this.el.un("keydown", this.checkTab, this);
576         }
577         //this.wrap.removeClass('x-trigger-wrap-focus');
578         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
579     },
580
581     // private
582     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
583     validateBlur : function(e, t){
584         return true;
585     },
586
587     // private
588     onDisable : function(){
589         this.inputEl().dom.disabled = true;
590         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
591         //if(this.wrap){
592         //    this.wrap.addClass('x-item-disabled');
593         //}
594     },
595
596     // private
597     onEnable : function(){
598         this.inputEl().dom.disabled = false;
599         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
600         //if(this.wrap){
601         //    this.el.removeClass('x-item-disabled');
602         //}
603     },
604
605     // private
606     onShow : function(){
607         var ae = this.getActionEl();
608         
609         if(ae){
610             ae.dom.style.display = '';
611             ae.dom.style.visibility = 'visible';
612         }
613     },
614
615     // private
616     
617     onHide : function(){
618         var ae = this.getActionEl();
619         ae.dom.style.display = 'none';
620     },
621
622     /**
623      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
624      * by an implementing function.
625      * @method
626      * @param {EventObject} e
627      */
628     onTriggerClick : Roo.emptyFn
629 });
630