gd-bs
Version:
Bootstrap JavaScript, TypeScript and Web Components library.
177 lines (147 loc) • 6.09 kB
text/typescript
import { INav, INavLink, INavProps } from "./types";
import { Base } from "../base";
import { NavLink } from "./link";
import { HTML, HTMLTabs, HTMLVerticalTabs } from "./templates";
/**
* Navigation
* @param props - The navigation properties.
*/
class _Nav extends Base<INavProps> implements INav {
private _links: Array<NavLink> = null;
// Constructor
constructor(props: INavProps, template: string = props.menuOnly ? HTML : (props.isVertical ? HTMLVerticalTabs : HTMLTabs), itemTemplate?: string) {
super(template, props);
// Configure the collapse
this.configure(itemTemplate);
// Configure the events
this.configureEvents();
// Configure the parent
this.configureParent();
}
// Configure the card group
private configure(itemTemplate: string) {
// Update the navigation
let nav = this.el.classList.contains("nav") ? this.el : this.el.querySelector(".nav");
if (nav) {
this.props.id ? nav.id = this.props.id : null;
this.props.enableFill ? nav.classList.add("nav-fill") : null;
this.props.isJustified ? nav.classList.add("nav-justified") : null;
this.props.isVertical ? nav.classList.add("flex-column") : null;
// Set the class name based on the properties
if (this.props.isTabs) { nav.classList.add("nav-tabs"); }
else if (this.props.isPills) { nav.classList.add("nav-pills"); }
else if (this.props.isTabs) { nav.classList.add("nav-tabs"); }
}
// Render the nav links
this.renderItems(itemTemplate);
}
// Configure the events
private configureEvents() {
// Execute the event(s)
this.props.onRendered ? this.props.onRendered(this.el) : null;
}
// Configures the tab link event
private configureLinkEvents(link: NavLink) {
// Add a click event
link.el.addEventListener("click", () => {
let prevTab: INavLink = null;
let newTab: INavLink = link;
// See if this link is disabled
if (link.isDisabled) {
// Do nothing
return;
}
// Parse the links
for (let i = 0; i < this._links.length; i++) {
let link = this._links[i];
// See if it's active
if (link.isActive) {
// Set the old tab
prevTab = link;
// Toggle it
link.toggle(this.props.fadeTabs);
}
}
// Toggle the link
link.toggle(this.props.fadeTabs);
// Call the click event
this.props.onClick ? this.props.onClick(newTab, prevTab) : null;
});
}
// Renders the links
private renderItems(itemTemplate: string) {
// Clear the links
this._links = [];
// Get the nav and tab elements
let nav = this.el.classList.contains("nav") ? this.el : this.el.querySelector(".nav");
if (nav) {
let tabs = this.el.querySelector(".tab-content");
// Parse the navigation items
let links = this.props.items || [];
for (let i = 0; i < links.length; i++) {
// Create the link
let link = new NavLink(links[i], tabs ? true : false, itemTemplate);
nav.appendChild(link.el);
this._links.push(link);
// Configure the link event
this.configureLinkEvents(link);
// See if we are rendering tabs
if (tabs) {
// Add the tab content
tabs.appendChild(link.elTabContent);
// See if the fade option is enabled
if (this.props.fadeTabs) {
// Set the class name
link.elTabContent.classList.add("fade");
// See if the tab is active
if (link.props.isActive) {
// Set the class name
link.elTabContent.classList.add("show");
}
}
}
// Call the render events
this.props.onLinkRendered ? this.props.onLinkRendered(link.elTab, links[i]) : null;
this.props.onTabRendered ? this.props.onTabRendered(link.elTabContent, links[i]) : null;
}
}
}
/**
* Public Interface
*/
// The active tab
get activeTab(): INavLink {
// Parse the links
for (let i = 0; i < this._links.length; i++) {
let link = this._links[i];
// See if it's active
if (link.isActive) {
// Return the link
return link;
}
}
// Active tab not found
return null;
}
// Shows a tab
showTab(tabId?: string | number) {
// Ensure tabs exist
if (this.props.isTabs) {
// Parse the tabs
for (let i = 0; i < this._links.length; i++) {
let link = this._links[i];
// See if this is the target tab
if (tabId === i + 1 || link.elTabContent.getAttribute("data-title") == tabId) {
// Toggle it if it's not active
link.isActive ? null : link.toggle(this.props.fadeTabs);
}
// Else, see if it's active
else if (link.isActive) {
// Toggle it
link.toggle(this.props.fadeTabs);
}
}
}
}
}
export const Nav = (props: INavProps, template?: string, itemTemplate?: string): INav => { return new _Nav(props, template, itemTemplate); }