fix button # triggering url change
[roojs1] / Roo / bootstrap / Button.js
1 /*
2  * - LGPL
3  *
4  * button
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.Button
10  * @extends Roo.bootstrap.Component
11  * Bootstrap Button class
12  * @cfg {String} html The button content
13  * @cfg {String} weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default
14  * @cfg {String} badge_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default (same as button)
15  * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
16  * @cfg {String} size (lg|sm|xs)
17  * @cfg {String} tag (a|input|submit)
18  * @cfg {String} href empty or href
19  * @cfg {Boolean} disabled default false;
20  * @cfg {Boolean} isClose default false;
21  * @cfg {String} glyphicon depricated - use fa
22  * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
23  * @cfg {String} badge text for badge
24  * @cfg {String} theme (default|glow)  
25  * @cfg {Boolean} inverse dark themed version
26  * @cfg {Boolean} toggle is it a slidy toggle button
27  * @cfg {Boolean} pressed   default null - if the button ahs active state
28  * @cfg {String} ontext text for on slidy toggle state
29  * @cfg {String} offtext text for off slidy toggle state
30  * @cfg {Boolean} preventDefault  default true (stop click event triggering the URL if it's a link.)
31  * @cfg {Boolean} removeClass remove the standard class..
32  * @cfg {String} target (_self|_blank|_parent|_top|other) target for a href. 
33  * @cfg {Boolean} grpup if parent is a btn group - then it turns it into a toogleGroup.
34  * @cfg {Roo.bootstrap.menu.Menu} menu a Menu 
35
36  * @constructor
37  * Create a new button
38  * @param {Object} config The config object
39  */
40
41
42 Roo.bootstrap.Button = function(config){
43     Roo.bootstrap.Button.superclass.constructor.call(this, config);
44     
45     this.addEvents({
46         // raw events
47         /**
48          * @event click
49          * When a button is pressed
50          * @param {Roo.bootstrap.Button} btn
51          * @param {Roo.EventObject} e
52          */
53         "click" : true,
54         /**
55          * @event dblclick
56          * When a button is double clicked
57          * @param {Roo.bootstrap.Button} btn
58          * @param {Roo.EventObject} e
59          */
60         "dblclick" : true,
61          /**
62          * @event toggle
63          * After the button has been toggles
64          * @param {Roo.bootstrap.Button} btn
65          * @param {Roo.EventObject} e
66          * @param {boolean} pressed (also available as button.pressed)
67          */
68         "toggle" : true
69     });
70 };
71
72 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
73     html: false,
74     active: false,
75     weight: '',
76     badge_weight: '',
77     outline : false,
78     size: '',
79     tag: 'button',
80     href: '',
81     disabled: false,
82     isClose: false,
83     glyphicon: '',
84     fa: '',
85     badge: '',
86     theme: 'default',
87     inverse: false,
88     
89     toggle: false,
90     ontext: 'ON',
91     offtext: 'OFF',
92     defaulton: true,
93     preventDefault: true,
94     removeClass: false,
95     name: false,
96     target: false,
97     group : false,
98      
99     pressed : null,
100      
101     
102     getAutoCreate : function(){
103         
104         var cfg = {
105             tag : 'button',
106             cls : 'roo-button',
107             html: ''
108         };
109         
110         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
111             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
112             this.tag = 'button';
113         } else {
114             cfg.tag = this.tag;
115         }
116         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
117         
118         if (this.toggle == true) {
119             cfg={
120                 tag: 'div',
121                 cls: 'slider-frame roo-button',
122                 cn: [
123                     {
124                         tag: 'span',
125                         'data-on-text':'ON',
126                         'data-off-text':'OFF',
127                         cls: 'slider-button',
128                         html: this.offtext
129                     }
130                 ]
131             };
132             // why are we validating the weights?
133             if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
134                 cfg.cls +=  ' ' + this.weight;
135             }
136             
137             return cfg;
138         }
139         
140         if (this.isClose) {
141             cfg.cls += ' close';
142             
143             cfg["aria-hidden"] = true;
144             
145             cfg.html = "&times;";
146             
147             return cfg;
148         }
149              
150         
151         if (this.theme==='default') {
152             cfg.cls = 'btn roo-button';
153             
154             //if (this.parentType != 'Navbar') {
155             this.weight = this.weight.length ?  this.weight : 'default';
156             //}
157             if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
158                 
159                 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
160                 var weight = this.weight == 'default' ? 'secondary' : this.weight;
161                 cfg.cls += ' btn-' + outline + weight;
162                 if (this.weight == 'default') {
163                     // BC
164                     cfg.cls += ' btn-' + this.weight;
165                 }
166             }
167         } else if (this.theme==='glow') {
168             
169             cfg.tag = 'a';
170             cfg.cls = 'btn-glow roo-button';
171             
172             if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
173                 
174                 cfg.cls += ' ' + this.weight;
175             }
176         }
177    
178         
179         if (this.inverse) {
180             this.cls += ' inverse';
181         }
182         
183         
184         if (this.active || this.pressed === true) {
185             cfg.cls += ' active';
186         }
187         
188         if (this.disabled) {
189             cfg.disabled = 'disabled';
190         }
191         
192         if (this.items) {
193             Roo.log('changing to ul' );
194             cfg.tag = 'ul';
195             this.glyphicon = 'caret';
196             if (Roo.bootstrap.version == 4) {
197                 this.fa = 'caret-down';
198             }
199             
200         }
201         
202         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
203          
204         //gsRoo.log(this.parentType);
205         if (this.parentType === 'Navbar' && !this.parent().bar) {
206             Roo.log('changing to li?');
207             
208             cfg.tag = 'li';
209             
210             cfg.cls = '';
211             cfg.cn =  [{
212                 tag : 'a',
213                 cls : 'roo-button',
214                 html : this.html,
215                 href : this.href || '#'
216             }];
217             if (this.menu) {
218                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
219                 cfg.cls += ' dropdown';
220             }   
221             
222             delete cfg.html;
223             
224         }
225         
226        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
227         
228         if (this.glyphicon) {
229             cfg.html = ' ' + cfg.html;
230             
231             cfg.cn = [
232                 {
233                     tag: 'span',
234                     cls: 'glyphicon glyphicon-' + this.glyphicon
235                 }
236             ];
237         }
238         if (this.fa) {
239             cfg.html = ' ' + cfg.html;
240             
241             cfg.cn = [
242                 {
243                     tag: 'i',
244                     cls: 'fa fas fa-' + this.fa
245                 }
246             ];
247         }
248         
249         if (this.badge) {
250             cfg.html += ' ';
251             
252             cfg.tag = 'a';
253             
254 //            cfg.cls='btn roo-button';
255             
256             cfg.href=this.href;
257             
258             var value = cfg.html;
259             
260             if(this.glyphicon){
261                 value = {
262                     tag: 'span',
263                     cls: 'glyphicon glyphicon-' + this.glyphicon,
264                     html: this.html
265                 };
266             }
267             if(this.fa){
268                 value = {
269                     tag: 'i',
270                     cls: 'fa fas fa-' + this.fa,
271                     html: this.html
272                 };
273             }
274             
275             var bw = this.badge_weight.length ? this.badge_weight :
276                 (this.weight.length ? this.weight : 'secondary');
277             bw = bw == 'default' ? 'secondary' : bw;
278             
279             cfg.cn = [
280                 value,
281                 {
282                     tag: 'span',
283                     cls: 'badge badge-' + bw,
284                     html: this.badge
285                 }
286             ];
287             
288             cfg.html='';
289         }
290         
291         if (this.menu) {
292             cfg.cls += ' dropdown';
293             cfg.html = typeof(cfg.html) != 'undefined' ?
294                     cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
295         }
296         
297         if (cfg.tag !== 'a' && this.href !== '') {
298             throw "Tag must be a to set href.";
299         } else if (this.href.length > 0) {
300             cfg.href = this.href;
301         }
302         
303         if(this.removeClass){
304             cfg.cls = '';
305         }
306         
307         if(this.target){
308             cfg.target = this.target;
309         }
310         
311         return cfg;
312     },
313     initEvents: function() {
314        // Roo.log('init events?');
315 //        Roo.log(this.el.dom);
316         // add the menu...
317         
318         if (typeof (this.menu) != 'undefined') {
319             this.menu.parentType = this.xtype;
320             this.menu.triggerEl = this.el;
321             this.addxtype(Roo.apply({}, this.menu));
322         }
323
324
325         if (this.el.hasClass('roo-button')) {
326              this.el.on('click', this.onClick, this);
327              this.el.on('dblclick', this.onDblClick, this);
328         } else {
329              this.el.select('.roo-button').on('click', this.onClick, this);
330              this.el.select('.roo-button').on('dblclick', this.onDblClick, this);
331              
332         }
333         // why?
334         if(this.removeClass){
335             this.el.on('click', this.onClick, this);
336         }
337         
338         if (this.group === true) {
339              if (this.pressed === false || this.pressed === true) {
340                 // nothing
341             } else {
342                 this.pressed = false;
343                 this.setActive(this.pressed);
344             }
345             
346         }
347         
348         this.el.enableDisplayMode();
349         
350     },
351     onClick : function(e)
352     {
353         if (this.disabled) {
354             return;
355         }
356         
357         Roo.log('button on click ');
358         if(this.href === '' || this.preventDefault){
359             e.preventDefault();
360         }
361         
362         if (this.group) {
363             if (this.pressed) {
364                 // do nothing -
365                 return;
366             }
367             this.setActive(true);
368             var pi = this.parent().items;
369             for (var i = 0;i < pi.length;i++) {
370                 if (this == pi[i]) {
371                     continue;
372                 }
373                 if (pi[i].el.hasClass('roo-button')) {
374                     pi[i].setActive(false);
375                 }
376             }
377             this.fireEvent('click', this, e);            
378             return;
379         }
380         
381         if (this.pressed === true || this.pressed === false) {
382             this.toggleActive(e);
383         }
384         
385         
386         this.fireEvent('click', this, e);
387     },
388     onDblClick: function(e)
389     {
390         if (this.disabled) {
391             return;
392         }
393         if(this.preventDefault){
394             e.preventDefault();
395         }
396         this.fireEvent('dblclick', this, e);
397     },
398     /**
399      * Enables this button
400      */
401     enable : function()
402     {
403         this.disabled = false;
404         this.el.removeClass('disabled');
405         this.el.dom.removeAttribute("disabled");
406     },
407     
408     /**
409      * Disable this button
410      */
411     disable : function()
412     {
413         this.disabled = true;
414         this.el.addClass('disabled');
415         this.el.attr("disabled", "disabled")
416     },
417      /**
418      * sets the active state on/off, 
419      * @param {Boolean} state (optional) Force a particular state
420      */
421     setActive : function(v) {
422         
423         this.el[v ? 'addClass' : 'removeClass']('active');
424         this.pressed = v;
425     },
426      /**
427      * toggles the current active state 
428      */
429     toggleActive : function(e)
430     {
431         this.setActive(!this.pressed); // this modifies pressed...
432         this.fireEvent('toggle', this, e, this.pressed);
433     },
434      /**
435      * get the current active state
436      * @return {boolean} true if it's active
437      */
438     isActive : function()
439     {
440         return this.el.hasClass('active');
441     },
442     /**
443      * set the text of the first selected button
444      */
445     setText : function(str)
446     {
447         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
448     },
449     /**
450      * get the text of the first selected button
451      */
452     getText : function()
453     {
454         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
455     },
456     
457     setWeight : function(str)
458     {
459         this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-' + w; } ) );
460         this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-outline-' + w; } ) );
461         this.weight = str;
462         var outline = this.outline ? 'outline-' : '';
463         if (str == 'default') {
464             this.el.addClass('btn-default btn-outline-secondary');        
465             return;
466         }
467         this.el.addClass('btn-' + outline + str);        
468     }
469     
470     
471 });
472 // fixme - this is probably generic bootstrap - should go in some kind of enum file.. - like sizes.
473
474 Roo.bootstrap.Button.weights = [
475     'default',
476     'secondary' ,
477     'primary',
478     'success',
479     'info',
480     'warning',
481     'danger',
482     'link',
483     'light',
484     'dark'              
485    
486 ];