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