33598f486500ec030c3b6f98d58a066117489277
[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 input-group-prepend input-group-text',
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 input-group-append input-group-text',
175                     html : this.after
176                 });
177             }
178             
179         };
180         
181       
182         
183         var ibwrap = inputblock;
184         
185         if(this.multiple){
186             ibwrap = {
187                 tag: 'ul',
188                 cls: 'roo-select2-choices',
189                 cn:[
190                     {
191                         tag: 'li',
192                         cls: 'roo-select2-search-field',
193                         cn: [
194
195                             inputblock
196                         ]
197                     }
198                 ]
199             };
200                 
201         }
202         
203         var combobox = {
204             cls: 'roo-select2-container input-group',
205             cn: [
206                  {
207                     tag: 'input',
208                     type : 'hidden',
209                     cls: 'form-hidden-field'
210                 },
211                 ibwrap
212             ]
213         };
214         
215         if(!this.multiple && this.showToggleBtn){
216             
217             var caret = {
218                         tag: 'span',
219                         cls: 'caret'
220              };
221             if (this.caret != false) {
222                 caret = {
223                      tag: 'i',
224                      cls: 'fa fa-' + this.caret
225                 };
226                 
227             }
228             
229             combobox.cn.push({
230                 tag :'span',
231                 cls : 'input-group-addon input-group-append input-group-text btn'  +
232                     (Roo.bootstrap.version == 3 ? ' dropdown-toggle' : ''),
233                 cn : [
234                     caret,
235                     {
236                         tag: 'span',
237                         cls: 'combobox-clear',
238                         cn  : [
239                             {
240                                 tag : 'i',
241                                 cls: 'icon-remove'
242                             }
243                         ]
244                     }
245                 ]
246
247             })
248         }
249         
250         if(this.multiple){
251             combobox.cls += ' roo-select2-container-multi';
252         }
253          var indicator = {
254             tag : 'i',
255             cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
256             tooltip : 'This field is required'
257         };
258         if (Roo.bootstrap.version == 4) {
259             indicator = {
260                 tag : 'i',
261                 style : 'display:none'
262             };
263         }
264         
265         
266         if (align ==='left' && this.fieldLabel.length) {
267             
268             cfg.cls += ' roo-form-group-label-left'  + (Roo.bootstrap.version == 4 ? ' row' : '');
269
270             cfg.cn = [
271                 indicator,
272                 {
273                     tag: 'label',
274                     'for' :  id,
275                     cls : 'control-label',
276                     html : this.fieldLabel
277
278                 },
279                 {
280                     cls : "", 
281                     cn: [
282                         combobox
283                     ]
284                 }
285
286             ];
287             
288             var labelCfg = cfg.cn[1];
289             var contentCfg = cfg.cn[2];
290             
291             if(this.indicatorpos == 'right'){
292                 cfg.cn = [
293                     {
294                         tag: 'label',
295                         'for' :  id,
296                         cls : 'control-label',
297                         cn : [
298                             {
299                                 tag : 'span',
300                                 html : this.fieldLabel
301                             },
302                             indicator
303                         ]
304                     },
305                     {
306                         cls : "", 
307                         cn: [
308                             combobox
309                         ]
310                     }
311
312                 ];
313                 
314                 labelCfg = cfg.cn[0];
315                 contentCfg = cfg.cn[1];
316             }
317             
318             if(this.labelWidth > 12){
319                 labelCfg.style = "width: " + this.labelWidth + 'px';
320             }
321             
322             if(this.labelWidth < 13 && this.labelmd == 0){
323                 this.labelmd = this.labelWidth;
324             }
325             
326             if(this.labellg > 0){
327                 labelCfg.cls += ' col-lg-' + this.labellg;
328                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
329             }
330             
331             if(this.labelmd > 0){
332                 labelCfg.cls += ' col-md-' + this.labelmd;
333                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
334             }
335             
336             if(this.labelsm > 0){
337                 labelCfg.cls += ' col-sm-' + this.labelsm;
338                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
339             }
340             
341             if(this.labelxs > 0){
342                 labelCfg.cls += ' col-xs-' + this.labelxs;
343                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
344             }
345             
346         } else if ( this.fieldLabel.length) {
347 //                Roo.log(" label");
348             cfg.cn = [
349                 indicator,
350                {
351                    tag: 'label',
352                    //cls : 'input-group-addon',
353                    html : this.fieldLabel
354
355                },
356
357                combobox
358
359             ];
360             
361             if(this.indicatorpos == 'right'){
362                 
363                 cfg.cn = [
364                     {
365                        tag: 'label',
366                        cn : [
367                            {
368                                tag : 'span',
369                                html : this.fieldLabel
370                            },
371                            indicator
372                        ]
373
374                     },
375                     combobox
376
377                 ];
378
379             }
380
381         } else {
382             
383 //                Roo.log(" no label && no align");
384                 cfg = combobox
385                      
386                 
387         }
388         
389         var settings=this;
390         ['xs','sm','md','lg'].map(function(size){
391             if (settings[size]) {
392                 cfg.cls += ' col-' + size + '-' + settings[size];
393             }
394         });
395         
396         return cfg;
397         
398     },
399     
400     
401     
402     // private
403     onResize : function(w, h){
404 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
405 //        if(typeof w == 'number'){
406 //            var x = w - this.trigger.getWidth();
407 //            this.inputEl().setWidth(this.adjustWidth('input', x));
408 //            this.trigger.setStyle('left', x+'px');
409 //        }
410     },
411
412     // private
413     adjustSize : Roo.BoxComponent.prototype.adjustSize,
414
415     // private
416     getResizeEl : function(){
417         return this.inputEl();
418     },
419
420     // private
421     getPositionEl : function(){
422         return this.inputEl();
423     },
424
425     // private
426     alignErrorIcon : function(){
427         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
428     },
429
430     // private
431     initEvents : function(){
432         
433         this.createList();
434         
435         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
436         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
437         if(!this.multiple && this.showToggleBtn){
438             this.trigger = this.el.select('span.input-group-append',true).first();
439             if(this.hideTrigger){
440                 this.trigger.setDisplayed(false);
441             }
442             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
443         }
444         
445         if(this.multiple){
446             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
447         }
448         
449         if(this.removable && !this.editable && !this.tickable){
450             var close = this.closeTriggerEl();
451             
452             if(close){
453                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
454                 close.on('click', this.removeBtnClick, this, close);
455             }
456         }
457         
458         //this.trigger.addClassOnOver('x-form-trigger-over');
459         //this.trigger.addClassOnClick('x-form-trigger-click');
460         
461         //if(!this.width){
462         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
463         //}
464     },
465     
466     closeTriggerEl : function()
467     {
468         var close = this.el.select('.roo-combo-removable-btn', true).first();
469         return close ? close : false;
470     },
471     
472     removeBtnClick : function(e, h, el)
473     {
474         e.preventDefault();
475         
476         if(this.fireEvent("remove", this) !== false){
477             this.reset();
478             this.fireEvent("afterremove", this)
479         }
480     },
481     
482     createList : function()
483     {
484         this.list = Roo.get(document.body).createChild({
485             tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
486             cls: 'typeahead typeahead-long dropdown-menu',
487             style: 'display:none'
488         });
489         
490         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
491         
492     },
493
494     // private
495     initTrigger : function(){
496        
497     },
498
499     // private
500     onDestroy : function(){
501         if(this.trigger){
502             this.trigger.removeAllListeners();
503           //  this.trigger.remove();
504         }
505         //if(this.wrap){
506         //    this.wrap.remove();
507         //}
508         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
509     },
510
511     // private
512     onFocus : function(){
513         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
514         /*
515         if(!this.mimicing){
516             this.wrap.addClass('x-trigger-wrap-focus');
517             this.mimicing = true;
518             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
519             if(this.monitorTab){
520                 this.el.on("keydown", this.checkTab, this);
521             }
522         }
523         */
524     },
525
526     // private
527     checkTab : function(e){
528         if(e.getKey() == e.TAB){
529             this.triggerBlur();
530         }
531     },
532
533     // private
534     onBlur : function(){
535         // do nothing
536     },
537
538     // private
539     mimicBlur : function(e, t){
540         /*
541         if(!this.wrap.contains(t) && this.validateBlur()){
542             this.triggerBlur();
543         }
544         */
545     },
546
547     // private
548     triggerBlur : function(){
549         this.mimicing = false;
550         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
551         if(this.monitorTab){
552             this.el.un("keydown", this.checkTab, this);
553         }
554         //this.wrap.removeClass('x-trigger-wrap-focus');
555         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
556     },
557
558     // private
559     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
560     validateBlur : function(e, t){
561         return true;
562     },
563
564     // private
565     onDisable : function(){
566         this.inputEl().dom.disabled = true;
567         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
568         //if(this.wrap){
569         //    this.wrap.addClass('x-item-disabled');
570         //}
571     },
572
573     // private
574     onEnable : function(){
575         this.inputEl().dom.disabled = false;
576         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
577         //if(this.wrap){
578         //    this.el.removeClass('x-item-disabled');
579         //}
580     },
581
582     // private
583     onShow : function(){
584         var ae = this.getActionEl();
585         
586         if(ae){
587             ae.dom.style.display = '';
588             ae.dom.style.visibility = 'visible';
589         }
590     },
591
592     // private
593     
594     onHide : function(){
595         var ae = this.getActionEl();
596         ae.dom.style.display = 'none';
597     },
598
599     /**
600      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
601      * by an implementing function.
602      * @method
603      * @param {EventObject} e
604      */
605     onTriggerClick : Roo.emptyFn
606 });
607