@matdata/yasgui 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ .yasgui.context-menu {
2
+ position: absolute;
3
+ z-index: 10;
4
+ background: white;
5
+ min-width: 160px;
6
+ font-size: 14px;
7
+ border: 1px solid rgba(0, 0, 0, 0.15);
8
+ border-bottom-right-radius: 4px;
9
+ border-bottom-left-radius: 4px;
10
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
11
+ background-clip: padding-box;
12
+ hr {
13
+ margin: 8px auto;
14
+ border: none;
15
+ border-top: 1px solid #aaaaaa;
16
+ border-bottom: 1px solid #ffffff;
17
+ }
18
+ .context-menu-list {
19
+ padding: 0;
20
+ }
21
+ .context-menu-item {
22
+ display: block;
23
+ padding: 3px 20px;
24
+ clear: both;
25
+ font-weight: 400;
26
+ line-height: 1.42857;
27
+ color: #333;
28
+ white-space: nowrap;
29
+ cursor: pointer;
30
+ &:hover {
31
+ text-decoration: none;
32
+ color: black;
33
+ background-color: #f5f5f5;
34
+ }
35
+ &.disabled {
36
+ text-decoration: none;
37
+ color: gray;
38
+ background-color: #e5e5e5;
39
+ cursor: not-allowed;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,143 @@
1
+ import { addClass } from "@matdata/yasgui-utils";
2
+ import { default as Yasgui, getRandomId } from "./";
3
+ import Tab from "./Tab";
4
+ import { TabListEl } from "./TabElements";
5
+ import { cloneDeep } from "lodash-es";
6
+ require("./TabContextMenu.scss");
7
+ export interface TabContextConfig {
8
+ name: string;
9
+ action: (this: HTMLElement, ev: MouseEvent) => any;
10
+ enabled: boolean;
11
+ }
12
+ export default class TabContextMenu {
13
+ private yasgui: Yasgui;
14
+ private contextEl!: HTMLElement;
15
+ private newTabEl!: HTMLElement;
16
+ private renameTabEl!: HTMLElement;
17
+ private copyTabEl!: HTMLElement;
18
+ private closeTabEl!: HTMLElement;
19
+ private closeOtherTabsEl!: HTMLElement;
20
+ private reOpenOldTab!: HTMLElement;
21
+ private rootEl: HTMLElement;
22
+ private tabRef: TabListEl | undefined; // Need to store it due to scrolling updates
23
+ constructor(yasgui: Yasgui, rootEl: HTMLElement) {
24
+ this.yasgui = yasgui;
25
+ this.rootEl = rootEl;
26
+ document.addEventListener("click", this.handleContextClick);
27
+ document.addEventListener("keyup", this.closeConfigMenu);
28
+ }
29
+ private getMenuItemEl(text?: string) {
30
+ const item = document.createElement("li");
31
+ addClass(item, "context-menu-item");
32
+ // Make sure hitting 'rmb' multiple times doesn't close the menu
33
+ item.addEventListener("contextmenu", (event) => {
34
+ event.stopPropagation();
35
+ });
36
+ if (text !== undefined) item.innerText = text;
37
+ return item;
38
+ }
39
+ private draw(rootEl: HTMLElement) {
40
+ this.contextEl = document.createElement("div");
41
+ const dropDownList = document.createElement("ul");
42
+ addClass(dropDownList, "context-menu-list");
43
+
44
+ this.newTabEl = this.getMenuItemEl("New Tab");
45
+ // We can set the function for addTab here already, as it doesn't need any outside data
46
+ this.newTabEl.onclick = () => this.yasgui.addTab(true);
47
+
48
+ this.renameTabEl = this.getMenuItemEl("Rename Tab");
49
+
50
+ this.copyTabEl = this.getMenuItemEl("Copy Tab");
51
+
52
+ this.closeTabEl = this.getMenuItemEl("Close Tab");
53
+
54
+ this.closeOtherTabsEl = this.getMenuItemEl("Close other tabs");
55
+
56
+ this.reOpenOldTab = this.getMenuItemEl("Undo close Tab");
57
+
58
+ // Add items to list
59
+ dropDownList.appendChild(this.newTabEl);
60
+ dropDownList.appendChild(this.renameTabEl);
61
+ dropDownList.appendChild(this.copyTabEl);
62
+ // Add divider
63
+ dropDownList.appendChild(document.createElement("hr"));
64
+ dropDownList.appendChild(this.closeTabEl);
65
+ dropDownList.appendChild(this.closeOtherTabsEl);
66
+ dropDownList.appendChild(this.reOpenOldTab);
67
+ this.contextEl.appendChild(dropDownList);
68
+ addClass(this.contextEl, "yasgui", "context-menu");
69
+ rootEl.appendChild(this.contextEl);
70
+ }
71
+ public redraw() {
72
+ if (this.contextEl && this.tabRef?.tabEl) {
73
+ const bounding = this.tabRef.tabEl.getBoundingClientRect();
74
+ this.contextEl.style.top = `${window.pageYOffset + bounding.bottom}px`;
75
+ }
76
+ }
77
+ handleContextClick = (event: MouseEvent) => {
78
+ if (event.button !== 2) {
79
+ this.closeConfigMenu();
80
+ } else if (event.target !== this.contextEl) {
81
+ this.closeConfigMenu();
82
+ } else {
83
+ event.stopImmediatePropagation();
84
+ }
85
+ };
86
+
87
+ public openConfigMenu(currentTabId: string, currentTabEl: TabListEl, event: MouseEvent) {
88
+ if (!currentTabEl.tabEl) return;
89
+ this.draw(this.rootEl);
90
+ this.tabRef = currentTabEl;
91
+ const tab = this.yasgui.getTab(currentTabId);
92
+ const bounding = currentTabEl.tabEl.getBoundingClientRect();
93
+ this.contextEl.style.left = `${window.pageXOffset + bounding.left}px`;
94
+ this.contextEl.style.top = `${window.pageYOffset + bounding.bottom}px`;
95
+ event.stopPropagation();
96
+
97
+ // Set rename functionality
98
+ this.renameTabEl.onclick = () => currentTabEl.startRename();
99
+
100
+ // Copy tab functionality`
101
+ this.copyTabEl.onclick = () => {
102
+ if (!tab) return;
103
+ const config = cloneDeep(tab.getPersistedJson());
104
+ config.id = getRandomId();
105
+ this.yasgui.addTab(true, config);
106
+ };
107
+
108
+ // Close tab functionality
109
+ this.closeTabEl.onclick = () => tab?.close();
110
+
111
+ // Close other tab functionality
112
+ if (Object.keys(this.yasgui._tabs).length === 1) {
113
+ addClass(this.closeOtherTabsEl, "disabled");
114
+ } else {
115
+ this.closeOtherTabsEl.onclick = () => {
116
+ for (const tabId of Object.keys(this.yasgui._tabs)) {
117
+ if (tabId !== currentTabId) (this.yasgui.getTab(tabId) as Tab).close();
118
+ }
119
+ };
120
+ }
121
+ if (this.yasgui.persistentConfig && this.yasgui.persistentConfig.hasLastClosedTab()) {
122
+ this.reOpenOldTab.onclick = () => this.yasgui.restoreLastTab();
123
+ } else {
124
+ addClass(this.reOpenOldTab, "disabled");
125
+ }
126
+ }
127
+ public closeConfigMenu = () => {
128
+ this.tabRef = undefined;
129
+ if (this.contextEl) this.contextEl.remove();
130
+ };
131
+
132
+ public static get(yasgui: Yasgui, rootEl: HTMLElement) {
133
+ const instance = new TabContextMenu(yasgui, rootEl);
134
+ return instance;
135
+ }
136
+ public unregisterEventListeners() {
137
+ document.removeEventListener("click", this.handleContextClick);
138
+ document.removeEventListener("keyup", this.closeConfigMenu);
139
+ }
140
+ public destroy() {
141
+ this.unregisterEventListeners();
142
+ }
143
+ }
@@ -0,0 +1,134 @@
1
+ @use "sass:color";
2
+ $minTabHeight: 35px;
3
+ .yasgui {
4
+ .tabsList {
5
+ .sortable-placeholder {
6
+ min-width: 100px;
7
+ min-height: $minTabHeight;
8
+ border: 2px dotted color.adjust(#555, $lightness: 20%);
9
+ }
10
+ display: flex;
11
+ flex-wrap: wrap;
12
+ a {
13
+ cursor: pointer;
14
+ display: flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ min-height: $minTabHeight;
18
+ border-bottom: 2px solid transparent;
19
+ box-sizing: border-box;
20
+ }
21
+ .addTab {
22
+ cursor: pointer;
23
+ height: 100%;
24
+ font-size: 120%;
25
+ font-weight: 800;
26
+ margin-left: 15px;
27
+ padding: 0px 5px 2px 5px;
28
+ background: inherit;
29
+ border: none;
30
+ color: #337ab7;
31
+
32
+ &:hover,
33
+ &:focus-visible {
34
+ transform: scale(1.1);
35
+ }
36
+ &:focus {
37
+ color: #faa857;
38
+ }
39
+ }
40
+ .tab {
41
+ position: relative;
42
+ $activeColor: #337ab7;
43
+ $hoverColor: color.adjust($activeColor, $lightness: 30%);
44
+
45
+ .loader {
46
+ display: none;
47
+ background-color: color.adjust(#555, $lightness: 50%);
48
+ height: 2px;
49
+ position: absolute;
50
+ bottom: 0;
51
+ left: 0;
52
+ right: 100%;
53
+ animation-name: slide;
54
+ animation-duration: 2s;
55
+ animation-timing-function: ease;
56
+ animation-iteration-count: infinite;
57
+ }
58
+ @keyframes slide {
59
+ 0% {
60
+ left: 0;
61
+ right: 100%;
62
+ }
63
+ 70% {
64
+ left: 0;
65
+ right: 0;
66
+ }
67
+ 100% {
68
+ left: 100%;
69
+ right: 0;
70
+ }
71
+ }
72
+ &.active .loader {
73
+ background-color: $hoverColor;
74
+ }
75
+ &:hover .loader {
76
+ background-color: $activeColor;
77
+ }
78
+ &.querying .loader {
79
+ display: block;
80
+ }
81
+ &.active a {
82
+ border-bottom-color: $activeColor;
83
+ color: #555;
84
+ }
85
+ input {
86
+ display: none;
87
+ outline: none;
88
+ border: none;
89
+ }
90
+ &.renaming {
91
+ span {
92
+ display: none;
93
+ }
94
+ .closeTab {
95
+ display: none;
96
+ }
97
+ input {
98
+ display: block;
99
+ }
100
+ }
101
+ a {
102
+ font-weight: 600;
103
+ color: color.adjust(#555, $lightness: 20%);
104
+ font-size: 15px;
105
+ line-height: 1.5rem;
106
+ font-weight: 500;
107
+ min-width: 120px;
108
+ padding: 0px 24px 0px 30px;
109
+ white-space: nowrap;
110
+ overflow: hidden;
111
+ &:hover {
112
+ border-bottom-color: $hoverColor;
113
+ color: #555;
114
+ }
115
+ &:focus {
116
+ border-bottom-color: #faa857;
117
+ color: #555;
118
+ }
119
+ .closeTab {
120
+ color: #000;
121
+ margin-left: 7px;
122
+ font-size: 15px;
123
+ text-shadow: 0 1px 0 #fff;
124
+ opacity: 0.2;
125
+ font-weight: 700;
126
+ padding: 2px;
127
+ &:hover {
128
+ opacity: 0.5;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,336 @@
1
+ import Yasgui from "./";
2
+ import TabContextMenu from "./TabContextMenu";
3
+ import { hasClass, addClass, removeClass } from "@matdata/yasgui-utils";
4
+ const sortablejs = require("sortablejs");
5
+ require("./TabElements.scss");
6
+ export interface TabList {}
7
+ export class TabListEl {
8
+ private tabList: TabList;
9
+ private tabId: string;
10
+ private yasgui: Yasgui;
11
+ private renameEl?: HTMLInputElement;
12
+ private nameEl?: HTMLSpanElement;
13
+ public tabEl?: HTMLDivElement;
14
+ constructor(yasgui: Yasgui, tabList: TabList, tabId: string) {
15
+ this.tabList = tabList;
16
+ this.yasgui = yasgui;
17
+ this.tabId = tabId;
18
+ }
19
+ public delete() {
20
+ if (this.tabEl) {
21
+ this.tabList._tabsListEl?.removeChild(this.tabEl);
22
+ delete this.tabList._tabs[this.tabId];
23
+ }
24
+ }
25
+ public startRename() {
26
+ if (this.renameEl) {
27
+ const tab = this.yasgui.getTab(this.tabId);
28
+ if (tab) {
29
+ this.renameEl.value = tab.name();
30
+ addClass(this.tabEl, "renaming");
31
+ this.renameEl.focus();
32
+ }
33
+ }
34
+ }
35
+ public active(active: boolean) {
36
+ if (!this.tabEl) return;
37
+ if (active) {
38
+ addClass(this.tabEl, "active");
39
+ // add aria-properties
40
+ this.tabEl.children[0].setAttribute("aria-selected", "true");
41
+ this.tabEl.children[0].setAttribute("tabindex", "0");
42
+ } else {
43
+ removeClass(this.tabEl, "active");
44
+ // remove aria-properties
45
+ this.tabEl.children[0].setAttribute("aria-selected", "false");
46
+ this.tabEl.children[0].setAttribute("tabindex", "-1");
47
+ }
48
+ }
49
+ public rename(name: string) {
50
+ if (this.nameEl) {
51
+ this.nameEl.textContent = name;
52
+ }
53
+ }
54
+ public setAsQuerying(querying: boolean) {
55
+ if (querying) {
56
+ addClass(this.tabEl, "querying");
57
+ } else {
58
+ removeClass(this.tabEl, "querying");
59
+ }
60
+ }
61
+ public draw(name: string) {
62
+ this.tabEl = document.createElement("div");
63
+ this.tabEl.setAttribute("role", "presentation");
64
+ this.tabEl.ondblclick = () => {
65
+ this.startRename();
66
+ };
67
+ addClass(this.tabEl, "tab");
68
+ this.tabEl.addEventListener("keydown", (e: KeyboardEvent) => {
69
+ if (e.code === "Delete") handleDeleteTab();
70
+ });
71
+
72
+ const handleDeleteTab = (e?: MouseEvent) => {
73
+ e?.preventDefault();
74
+ this.yasgui.getTab(this.tabId)?.close();
75
+ };
76
+
77
+ const tabLinkEl = document.createElement("a");
78
+ tabLinkEl.setAttribute("role", "tab");
79
+ tabLinkEl.href = "#" + this.tabId;
80
+ tabLinkEl.id = "tab-" + this.tabId; // use the id for the tabpanel which is tabId to set the actual tab id
81
+ tabLinkEl.setAttribute("aria-controls", this.tabId); // respective tabPanel id
82
+ tabLinkEl.addEventListener("blur", () => {
83
+ if (!this.tabEl) return;
84
+ if (this.tabEl.classList.contains("active")) {
85
+ tabLinkEl.setAttribute("tabindex", "0");
86
+ } else {
87
+ tabLinkEl.setAttribute("tabindex", "-1");
88
+ }
89
+ });
90
+ tabLinkEl.addEventListener("focus", () => {
91
+ if (!this.tabEl) return;
92
+ if (this.tabEl.classList.contains("active")) {
93
+ const allTabs = Object.keys(this.tabList._tabs);
94
+ const currentTabIndex = allTabs.indexOf(this.tabId);
95
+ this.tabList.tabEntryIndex = currentTabIndex;
96
+ }
97
+ });
98
+ // if (this.yasgui.persistentConfig.tabIsActive(this.tabId)) {
99
+ // this.yasgui.store.dispatch(selectTab(this.tabId))
100
+ // }
101
+ tabLinkEl.addEventListener("click", (e) => {
102
+ e.preventDefault();
103
+ this.yasgui.selectTabId(this.tabId);
104
+ });
105
+
106
+ //tab name
107
+ this.nameEl = document.createElement("span");
108
+ this.nameEl.textContent = name;
109
+ tabLinkEl.appendChild(this.nameEl);
110
+
111
+ //tab close btn
112
+ const closeBtn = document.createElement("div");
113
+ closeBtn.innerHTML = "✖";
114
+ closeBtn.title = "Close tab";
115
+ closeBtn.setAttribute("tabindex", "-1");
116
+ closeBtn.setAttribute("aria-hidden", "true");
117
+ addClass(closeBtn, "closeTab");
118
+ closeBtn.addEventListener("click", handleDeleteTab);
119
+ tabLinkEl.appendChild(closeBtn);
120
+
121
+ const renameEl = (this.renameEl = document.createElement("input"));
122
+ renameEl.type = "text";
123
+ renameEl.value = name;
124
+ renameEl.onkeyup = (event) => {
125
+ if (event.key === "Enter") {
126
+ this.yasgui.getTab(this.tabId)?.setName(renameEl.value);
127
+ removeClass(this.tabEl, "renaming");
128
+ }
129
+ };
130
+ renameEl.onblur = () => {
131
+ this.yasgui.getTab(this.tabId)?.setName(renameEl.value);
132
+ removeClass(this.tabEl, "renaming");
133
+ };
134
+ tabLinkEl.appendChild(this.renameEl);
135
+ tabLinkEl.oncontextmenu = (ev: MouseEvent) => {
136
+ // Close possible old
137
+ this.tabList.tabContextMenu?.closeConfigMenu();
138
+ this.openTabConfigMenu(ev);
139
+ ev.preventDefault();
140
+ ev.stopPropagation();
141
+ };
142
+ this.tabEl.appendChild(tabLinkEl);
143
+
144
+ //draw loading animation overlay
145
+ const loaderEl = document.createElement("div");
146
+ addClass(loaderEl, "loader");
147
+ this.tabEl.appendChild(loaderEl);
148
+
149
+ return this.tabEl;
150
+ }
151
+ private openTabConfigMenu(event: MouseEvent) {
152
+ this.tabList.tabContextMenu?.openConfigMenu(this.tabId, this, event);
153
+ }
154
+ redrawContextMenu() {
155
+ this.tabList.tabContextMenu?.redraw();
156
+ }
157
+ }
158
+
159
+ export class TabList {
160
+ yasgui: Yasgui;
161
+
162
+ private _selectedTab?: string;
163
+ private addTabEl?: HTMLDivElement;
164
+ public _tabs: { [tabId: string]: TabListEl } = {};
165
+ public _tabsListEl?: HTMLDivElement;
166
+ public tabContextMenu?: TabContextMenu;
167
+ public tabEntryIndex: number | undefined;
168
+
169
+ constructor(yasgui: Yasgui) {
170
+ this.yasgui = yasgui;
171
+ this.registerListeners();
172
+ this.tabEntryIndex = this.getActiveIndex();
173
+ }
174
+ get(tabId: string) {
175
+ return this._tabs[tabId];
176
+ }
177
+
178
+ private registerListeners() {
179
+ this.yasgui.on("query", (_yasgui, tab) => {
180
+ const id = tab.getId();
181
+ if (this._tabs[id]) {
182
+ this._tabs[id].setAsQuerying(true);
183
+ }
184
+ });
185
+ this.yasgui.on("queryResponse", (_yasgui, tab) => {
186
+ const id = tab.getId();
187
+ if (this._tabs[id]) {
188
+ this._tabs[id].setAsQuerying(false);
189
+ }
190
+ });
191
+ this.yasgui.on("queryAbort", (_yasgui, tab) => {
192
+ const id = tab.getId();
193
+ if (this._tabs[id]) {
194
+ this._tabs[id].setAsQuerying(false);
195
+ }
196
+ });
197
+ }
198
+ private getActiveIndex() {
199
+ if (!this._selectedTab) return;
200
+ const allTabs = Object.keys(this._tabs);
201
+ const currentTabIndex = allTabs.indexOf(this._selectedTab);
202
+ return currentTabIndex;
203
+ }
204
+ private handleKeydownArrowKeys = (e: KeyboardEvent) => {
205
+ if (e.code === "ArrowLeft" || e.code === "ArrowRight") {
206
+ if (!this._tabsListEl) return;
207
+ const numOfChildren = this._tabsListEl.childElementCount;
208
+ if (typeof this.tabEntryIndex !== "number") return;
209
+ const tabEntryDiv = this._tabsListEl.children[this.tabEntryIndex];
210
+ // If the current tab does not have active set its tabindex to -1
211
+ if (!tabEntryDiv.classList.contains("active")) {
212
+ tabEntryDiv.children[0].setAttribute("tabindex", "-1"); // cur tab removed from tab index
213
+ }
214
+ if (e.code === "ArrowLeft") {
215
+ this.tabEntryIndex--;
216
+ if (this.tabEntryIndex < 0) {
217
+ this.tabEntryIndex = numOfChildren - 1;
218
+ }
219
+ }
220
+ if (e.code === "ArrowRight") {
221
+ this.tabEntryIndex++;
222
+ if (this.tabEntryIndex >= numOfChildren) {
223
+ this.tabEntryIndex = 0;
224
+ }
225
+ }
226
+ const newTabEntryDiv = this._tabsListEl.children[this.tabEntryIndex];
227
+ newTabEntryDiv.children[0].setAttribute("tabindex", "0");
228
+ (newTabEntryDiv.children[0] as HTMLElement).focus(); // focus on the a tag inside the div for click event
229
+ }
230
+ };
231
+ drawTabsList() {
232
+ this._tabsListEl = document.createElement("div");
233
+ addClass(this._tabsListEl, "tabsList");
234
+ this._tabsListEl.setAttribute("role", "tablist");
235
+ this._tabsListEl.addEventListener("keydown", this.handleKeydownArrowKeys);
236
+
237
+ sortablejs.default.create(this._tabsListEl, {
238
+ group: "tabList",
239
+ animation: 100,
240
+ onUpdate: (_ev: any) => {
241
+ const tabs = this.deriveTabOrderFromEls();
242
+ this.yasgui.emit("tabOrderChanged", this.yasgui, tabs);
243
+ this.yasgui.persistentConfig.setTabOrder(tabs);
244
+ },
245
+ filter: ".addTab",
246
+ onMove: (ev: any, _origEv: any) => {
247
+ return hasClass(ev.related, "tab");
248
+ },
249
+ });
250
+
251
+ this.addTabEl = document.createElement("div");
252
+ this.addTabEl.setAttribute("role", "presentation");
253
+
254
+ const addTabLink = document.createElement("button");
255
+ addTabLink.className = "addTab";
256
+ addTabLink.textContent = "+";
257
+ addTabLink.title = "Add tab";
258
+ addTabLink.setAttribute("aria-label", "Add a new tab");
259
+ addTabLink.addEventListener("click", this.handleAddNewTab);
260
+ addTabLink.addEventListener("focus", () => {
261
+ // sets aria tabEntryIndex to active tab
262
+ // this.tabEntryIndex = this.getActiveIndex();
263
+ if (!this._tabsListEl) return;
264
+ this.tabEntryIndex = this._tabsListEl.childElementCount - 1; // sets tabEntry to add tab, visually makes sense, not sure about accessibility-wise
265
+ });
266
+ addTabLink.addEventListener("blur", () => {
267
+ addTabLink.setAttribute("tabindex", "0"); // maintains tabability
268
+ });
269
+ this.addTabEl.appendChild(addTabLink);
270
+ this._tabsListEl.appendChild(this.addTabEl);
271
+ this.tabContextMenu = TabContextMenu.get(
272
+ this.yasgui,
273
+ this.yasgui.config.contextMenuContainer ? this.yasgui.config.contextMenuContainer : this._tabsListEl,
274
+ );
275
+ return this._tabsListEl;
276
+ }
277
+ handleAddNewTab = (event: Event) => {
278
+ event.preventDefault();
279
+ this.yasgui.addTab(true);
280
+ };
281
+ // drawPanels() {
282
+ // this.tabPanelsEl = document.createElement("div");
283
+ // return this.tabsListEl;
284
+ // }
285
+ public addTab(tabId: string, index?: number) {
286
+ return this.drawTab(tabId, index);
287
+ }
288
+ public deriveTabOrderFromEls() {
289
+ const tabs: string[] = [];
290
+ if (this._tabsListEl) {
291
+ for (let i = 0; i < this._tabsListEl.children.length; i++) {
292
+ const child = this._tabsListEl.children[i]; //this is the tab div
293
+ const anchorTag = child.children[0]; //this one has an href
294
+ if (anchorTag) {
295
+ const href = (<HTMLAnchorElement>anchorTag).href;
296
+ if (href && href.indexOf("#") >= 0) {
297
+ tabs.push(href.substr(href.indexOf("#") + 1));
298
+ }
299
+ }
300
+ }
301
+ }
302
+ return tabs;
303
+ }
304
+
305
+ public selectTab(tabId: string) {
306
+ this._selectedTab = tabId;
307
+ for (const id in this._tabs) {
308
+ this._tabs[id].active(this._selectedTab === id);
309
+ }
310
+ }
311
+
312
+ public drawTab(tabId: string, index?: number) {
313
+ this._tabs[tabId] = new TabListEl(this.yasgui, this, tabId);
314
+ const tabConf = this.yasgui.persistentConfig.getTab(tabId);
315
+ if (index !== undefined && index < this.yasgui.persistentConfig.getTabs().length - 1) {
316
+ this._tabsListEl?.insertBefore(
317
+ this._tabs[tabId].draw(tabConf.name),
318
+ this._tabs[this.yasgui.persistentConfig.getTabs()[index + 1]].tabEl || null,
319
+ );
320
+ } else {
321
+ this._tabsListEl?.insertBefore(this._tabs[tabId].draw(tabConf.name), this.addTabEl || null);
322
+ }
323
+ }
324
+ public destroy() {
325
+ for (const tabId in this._tabs) {
326
+ const tab = this._tabs[tabId];
327
+ tab.delete();
328
+ }
329
+ this._tabs = {};
330
+ this.tabContextMenu?.destroy();
331
+ this._tabsListEl?.remove();
332
+ this._tabsListEl = undefined;
333
+ }
334
+ }
335
+
336
+ export default TabList;