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