• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2export class Tabs {
3  private container: HTMLElement;
4  private tabBar: HTMLElement;
5  private nextTabId: number;
6
7  private mkTabBar(container: HTMLElement) {
8    container.classList.add("nav-tabs-container");
9    this.tabBar = document.createElement("ul");
10    this.tabBar.id = `tab-bar-${container.id}`;
11    this.tabBar.className = "nav-tabs";
12    this.tabBar.ondrop = this.tabBarOnDrop.bind(this);
13    this.tabBar.ondragover = this.tabBarOnDragover.bind(this);
14    this.tabBar.onclick = this.tabBarOnClick.bind(this);
15
16    const defaultDiv = document.createElement("div");
17    defaultDiv.className = "tab-content tab-default";
18    defaultDiv.id = `tab-content-${container.id}-default`;
19    container.insertBefore(defaultDiv, container.firstChild);
20    container.insertBefore(this.tabBar, container.firstChild);
21  }
22
23  constructor(container: HTMLElement) {
24    this.container = container;
25    this.nextTabId = 0;
26    this.mkTabBar(container);
27  }
28
29  activateTab(tab: HTMLLIElement) {
30    if (typeof tab.dataset.divid !== "string") return;
31    for (const li of this.tabBar.querySelectorAll<HTMLLIElement>("li.active")) {
32      li.classList.remove("active");
33      this.showTab(li, false);
34    }
35    tab.classList.add("active");
36    this.showTab(tab, true);
37  }
38
39  clearTabsAndContent() {
40    for (const tab of this.tabBar.querySelectorAll(".nav-tabs > li")) {
41        if (!(tab instanceof HTMLLIElement)) continue;
42        if (tab.classList.contains("persistent-tab")) continue;
43        const tabDiv = document.getElementById(tab.dataset.divid);
44        tabDiv.parentNode.removeChild(tabDiv);
45        tab.parentNode.removeChild(tab);
46    }
47  }
48
49  private showTab(li: HTMLElement, show: boolean = true) {
50    const tabDiv = document.getElementById(li.dataset.divid);
51    tabDiv.style.display = show ? "block" : "none";
52  }
53
54  public addTab(caption: string): HTMLLIElement {
55    const newTab = document.createElement("li");
56    newTab.innerHTML = caption;
57    newTab.id = `tab-header-${this.container.id}-${this.nextTabId++}`;
58    const lastTab = this.tabBar.querySelector("li.last-tab");
59    this.tabBar.insertBefore(newTab, lastTab);
60    return newTab;
61  }
62
63  public addTabAndContent(caption: string): [HTMLLIElement, HTMLDivElement] {
64    const contentDiv = document.createElement("div");
65    contentDiv.className = "tab-content tab-default";
66    contentDiv.id = `tab-content-${this.container.id}-${this.nextTabId++}`;
67    contentDiv.style.display = "none";
68    this.container.appendChild(contentDiv);
69
70    const newTab = this.addTab(caption);
71    newTab.dataset.divid = contentDiv.id;
72    newTab.draggable = true;
73    newTab.ondragstart = this.tabOnDragStart.bind(this);
74    const lastTab = this.tabBar.querySelector("li.last-tab");
75    this.tabBar.insertBefore(newTab, lastTab);
76    return [newTab, contentDiv];
77  }
78
79  private moveTabDiv(tab: HTMLLIElement) {
80    const tabDiv = document.getElementById(tab.dataset.divid);
81    tabDiv.style.display = "none";
82    tab.classList.remove("active");
83    this.tabBar.parentNode.appendChild(tabDiv);
84  }
85
86  private tabBarOnDrop(e: DragEvent) {
87    if (!(e.target instanceof HTMLElement)) return;
88    e.preventDefault();
89    const tabId = e.dataTransfer.getData("text");
90    const tab = document.getElementById(tabId) as HTMLLIElement;
91    if (tab.parentNode != this.tabBar) {
92      this.moveTabDiv(tab);
93    }
94    const dropTab =
95      e.target.parentNode == this.tabBar
96        ? e.target : this.tabBar.querySelector("li.last-tab");
97    this.tabBar.insertBefore(tab, dropTab);
98    this.activateTab(tab);
99  }
100
101  private tabBarOnDragover(e) {
102    e.preventDefault();
103  }
104
105  private tabOnDragStart(e: DragEvent) {
106    if (!(e.target instanceof HTMLElement)) return;
107    e.dataTransfer.setData("text", e.target.id);
108  }
109
110  private tabBarOnClick(e: MouseEvent) {
111    const li = e.target as HTMLLIElement;
112    this.activateTab(li);
113  }
114}
115