sync
[roojs1] / Roo / bootstrap / NavItem.js
1 /*
2  * - LGPL
3  *
4  * row
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.NavItem
10  * @extends Roo.bootstrap.Component
11  * Bootstrap Navbar.NavItem class
12  * @cfg {String} href  link to
13  * @cfg {String} button_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default none
14  * @cfg {Boolean} button_outline show and outlined button
15  * @cfg {String} html content of button
16  * @cfg {String} badge text inside badge
17  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
18  * @cfg {String} glyphicon DEPRICATED - use fa
19  * @cfg {String} icon DEPRICATED - use fa
20  * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
21  * @cfg {Boolean} active Is item active
22  * @cfg {Boolean} disabled Is item disabled
23  * @cfg {String} linkcls  Link Class
24  * @cfg {Boolean} preventDefault (true | false) default false
25  * @cfg {String} tabId the tab that this item activates.
26  * @cfg {String} tagtype (a|span) render as a href or span?
27  * @cfg {Boolean} animateRef (true|false) link to element default false  
28  * @cfg {Roo.bootstrap.Menu} menu a Menu 
29   
30  * @constructor
31  * Create a new Navbar Item
32  * @param {Object} config The config object
33  */
34 Roo.bootstrap.NavItem = function(config){
35     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
36     this.addEvents({
37         // raw events
38         /**
39          * @event click
40          * The raw click event for the entire grid.
41          * @param {Roo.EventObject} e
42          */
43         "click" : true,
44          /**
45             * @event changed
46             * Fires when the active item active state changes
47             * @param {Roo.bootstrap.NavItem} this
48             * @param {boolean} state the new state
49              
50          */
51         'changed': true,
52         /**
53             * @event scrollto
54             * Fires when scroll to element
55             * @param {Roo.bootstrap.NavItem} this
56             * @param {Object} options
57             * @param {Roo.EventObject} e
58              
59          */
60         'scrollto': true
61     });
62    
63 };
64
65 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
66     
67     href: false,
68     html: '',
69     badge: '',
70     icon: false,
71     fa : false,
72     glyphicon: false,
73     active: false,
74     preventDefault : false,
75     tabId : false,
76     tagtype : 'a',
77     tag: 'li',
78     disabled : false,
79     animateRef : false,
80     was_active : false,
81     button_weight : '',
82     button_outline : false,
83     linkcls : '',
84     navLink: false,
85     
86     getAutoCreate : function(){
87          
88         var cfg = {
89             tag: this.tag,
90             cls: 'nav-item'
91         };
92         
93         cfg.cls =  typeof(cfg.cls) == 'undefined'  ? '' : cfg.cls;
94         
95         if (this.active) {
96             cfg.cls +=  ' active' ;
97         }
98         if (this.disabled) {
99             cfg.cls += ' disabled';
100         }
101         
102         // BS4 only?
103         if (this.button_weight.length) {
104             cfg.tag = this.href ? 'a' : 'button';
105             cfg.html = this.html || '';
106             cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
107             if (this.href) {
108                 cfg.href = this.href;
109             }
110             if (this.fa) {
111                 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span class="nav-html">' + this.html + '</span>';
112             } else {
113                 cfg.cls += " nav-html";
114             }
115             
116             // menu .. should add dropdown-menu class - so no need for carat..
117             
118             if (this.badge !== '') {
119                  
120                 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
121             }
122             return cfg;
123         }
124         
125         if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
126             cfg.cn = [
127                 {
128                     tag: this.tagtype,
129                     href : this.href || "#",
130                     html: this.html || '',
131                     cls : ''
132                 }
133             ];
134             if (this.tagtype == 'a') {
135                 cfg.cn[0].cls = 'nav-link' +  (this.active ?  ' active'  : '') + ' ' + this.linkcls;
136         
137             }
138             if (this.icon) {
139                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
140             } else  if (this.fa) {
141                 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
142             } else if(this.glyphicon) {
143                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
144             } else {
145                 cfg.cn[0].cls += " nav-html";
146             }
147             
148             if (this.menu) {
149                 cfg.cn[0].html += " <span class='caret'></span>";
150              
151             }
152             
153             if (this.badge !== '') {
154                 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
155             }
156         }
157         
158         
159         
160         return cfg;
161     },
162     onRender : function(ct, position)
163     {
164        // Roo.log("Call onRender: " + this.xtype);
165         if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
166             this.tag = 'div';
167         }
168         
169         var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
170         this.navLink = this.el.select('.nav-link',true).first();
171         this.htmlEl = this.el.hasClass('nav-html') ? this.el : this.el.select('.nav-html',true).first();
172         return ret;
173     },
174       
175     
176     initEvents: function() 
177     {
178         if (typeof (this.menu) != 'undefined') {
179             this.menu.parentType = this.xtype;
180             this.menu.triggerEl = this.el;
181             this.menu = this.addxtype(Roo.apply({}, this.menu));
182         }
183         
184         this.el.on('click', this.onClick, this);
185         
186         //if(this.tagtype == 'span'){
187         //    this.el.select('span',true).on('click', this.onClick, this);
188         //}
189        
190         // at this point parent should be available..
191         this.parent().register(this);
192     },
193     
194     onClick : function(e)
195     {
196         if (e.getTarget('.dropdown-menu-item')) {
197             // did you click on a menu itemm.... - then don't trigger onclick..
198             return;
199         }
200         
201         if(
202                 this.preventDefault || 
203                 this.href == '#' 
204         ){
205             Roo.log("NavItem - prevent Default?");
206             e.preventDefault();
207         }
208         
209         if (this.disabled) {
210             return;
211         }
212         
213         var tg = Roo.bootstrap.TabGroup.get(this.navId);
214         if (tg && tg.transition) {
215             Roo.log("waiting for the transitionend");
216             return;
217         }
218         
219         
220         
221         //Roo.log("fire event clicked");
222         if(this.fireEvent('click', this, e) === false){
223             return;
224         };
225         
226         if(this.tagtype == 'span'){
227             return;
228         }
229         
230         //Roo.log(this.href);
231         var ael = this.el.select('a',true).first();
232         //Roo.log(ael);
233         
234         if(ael && this.animateRef && this.href.indexOf('#') > -1){
235             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
236             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
237                 return; // ignore... - it's a 'hash' to another page.
238             }
239             Roo.log("NavItem - prevent Default?");
240             e.preventDefault();
241             this.scrollToElement(e);
242         }
243         
244         
245         var p =  this.parent();
246    
247         if (['tabs','pills'].indexOf(p.type)!==-1 && p.pilltype) {
248             if (typeof(p.setActiveItem) !== 'undefined') {
249                 p.setActiveItem(this);
250             }
251         }
252         
253         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
254         if (p.parentType == 'NavHeaderbar' && !this.menu) {
255             // remove the collapsed menu expand...
256             p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');  
257         }
258     },
259     
260     isActive: function () {
261         return this.active
262     },
263     setActive : function(state, fire, is_was_active)
264     {
265         if (this.active && !state && this.navId) {
266             this.was_active = true;
267             var nv = Roo.bootstrap.NavGroup.get(this.navId);
268             if (nv) {
269                 nv.clearWasActive(this);
270             }
271             
272         }
273         this.active = state;
274         
275         if (!state ) {
276             this.el.removeClass('active');
277             this.navLink ? this.navLink.removeClass('active') : false;
278         } else if (!this.el.hasClass('active')) {
279             
280             this.el.addClass('active');
281             if (Roo.bootstrap.version == 4 && this.navLink ) {
282                 this.navLink.addClass('active');
283             }
284             
285         }
286         if (fire) {
287             this.fireEvent('changed', this, state);
288         }
289         
290         // show a panel if it's registered and related..
291         
292         if (!this.navId || !this.tabId || !state || is_was_active) {
293             return;
294         }
295         
296         var tg = Roo.bootstrap.TabGroup.get(this.navId);
297         if (!tg) {
298             return;
299         }
300         var pan = tg.getPanelByName(this.tabId);
301         if (!pan) {
302             return;
303         }
304         // if we can not flip to new panel - go back to old nav highlight..
305         if (false == tg.showPanel(pan)) {
306             var nv = Roo.bootstrap.NavGroup.get(this.navId);
307             if (nv) {
308                 var onav = nv.getWasActive();
309                 if (onav) {
310                     onav.setActive(true, false, true);
311                 }
312             }
313             
314         }
315         
316         
317         
318     },
319      // this should not be here...
320     setDisabled : function(state)
321     {
322         this.disabled = state;
323         if (!state ) {
324             this.el.removeClass('disabled');
325         } else if (!this.el.hasClass('disabled')) {
326             this.el.addClass('disabled');
327         }
328         
329     },
330     
331     /**
332      * Fetch the element to display the tooltip on.
333      * @return {Roo.Element} defaults to this.el
334      */
335     tooltipEl : function()
336     {
337         return this.el; //this.tagtype  == 'a' ? this.el  : this.el.select('' + this.tagtype + '', true).first();
338     },
339     
340     scrollToElement : function(e)
341     {
342         var c = document.body;
343         
344         /*
345          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
346          */
347         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
348             c = document.documentElement;
349         }
350         
351         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
352         
353         if(!target){
354             return;
355         }
356
357         var o = target.calcOffsetsTo(c);
358         
359         var options = {
360             target : target,
361             value : o[1]
362         };
363         
364         this.fireEvent('scrollto', this, options, e);
365         
366         Roo.get(c).scrollTo('top', options.value, true);
367         
368         return;
369     },
370     /**
371      * Set the HTML (text content) of the item
372      * @param {string} html  content for the nav item
373      */
374     setHtml : function(html)
375     {
376         this.html = html;
377         this.htmlEl.dom.innerHTML = html;
378         
379     } 
380 });
381  
382
383