mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-03-18 21:50:33 +01:00
Navigatable has clearURL, which for Search clears "search" qp, and invites clears "invite" qp. Tab interfaces optionally include "contentObject: AsTab", and show/hide funcs are passed the contentObject of the previously loaded tab if one is available, so that they can call it's clearURL method. This means searches you typed for the accounts tab won't pop up when switching to activity.
109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
import { PageManager } from "./pages";
|
|
|
|
export function isPageEventBindable(object: any): object is PageEventBindable {
|
|
return "bindPageEvents" in object;
|
|
}
|
|
|
|
export function isNavigatable(object: any): object is Navigatable {
|
|
return "isURL" in object && "navigate" in object;
|
|
}
|
|
|
|
export class TabManager implements TabManager {
|
|
private _current: string = "";
|
|
private _baseOffset = -1;
|
|
tabs: Map<string, Tab>;
|
|
pages: Pages;
|
|
|
|
constructor() {
|
|
this.tabs = new Map<string, Tab>();
|
|
this.pages = new PageManager({
|
|
hideOthersOnPageShow: true,
|
|
defaultName: "invites",
|
|
defaultTitle: document.title,
|
|
});
|
|
}
|
|
|
|
addTab = (
|
|
tabID: string,
|
|
url: string,
|
|
contentObject: AsTab | null,
|
|
preFunc: (previous?: AsTab) => void = (_?: AsTab) => void {},
|
|
postFunc: (previous?: AsTab) => void = (_?: AsTab) => void {},
|
|
unloadFunc = () => void {},
|
|
) => {
|
|
let tab: Tab = {
|
|
page: null,
|
|
tabEl: document.getElementById("tab-" + tabID) as HTMLDivElement,
|
|
buttonEl: document.getElementById("button-tab-" + tabID) as HTMLButtonElement,
|
|
contentObject: contentObject,
|
|
preFunc: preFunc,
|
|
postFunc: postFunc,
|
|
};
|
|
if (this._baseOffset == -1) {
|
|
this._baseOffset = tab.buttonEl.offsetLeft;
|
|
}
|
|
const order = Array.from(this.tabs.keys());
|
|
let scrollTo: () => number = (): number => tab.buttonEl.offsetLeft - this._baseOffset;
|
|
if (order.length > 0) {
|
|
scrollTo = (): number =>
|
|
tab.buttonEl.offsetLeft - (tab.buttonEl.parentElement.offsetWidth - tab.buttonEl.offsetWidth) / 2;
|
|
}
|
|
|
|
tab.page = {
|
|
name: tabID,
|
|
title: document.title /*FIXME: Get actual names from translations*/,
|
|
url: url,
|
|
show: () => {
|
|
tab.buttonEl.classList.add("active", "~urge");
|
|
tab.tabEl.classList.remove("unfocused");
|
|
tab.buttonEl.parentElement.scrollTo({
|
|
left: scrollTo(),
|
|
top: 0,
|
|
behavior: "auto",
|
|
});
|
|
document.dispatchEvent(new CustomEvent("tab-change", { detail: tabID }));
|
|
return true;
|
|
},
|
|
hide: () => {
|
|
tab.buttonEl.classList.remove("active");
|
|
tab.buttonEl.classList.remove("~urge");
|
|
tab.tabEl.classList.add("unfocused");
|
|
if (unloadFunc) unloadFunc();
|
|
return true;
|
|
},
|
|
shouldSkip: () => false,
|
|
};
|
|
this.pages.setPage(tab.page);
|
|
tab.buttonEl.onclick = () => {
|
|
this.switch(tabID);
|
|
};
|
|
this.tabs.set(tabID, tab);
|
|
};
|
|
|
|
get current(): string {
|
|
return this._current;
|
|
}
|
|
set current(tabID: string) {
|
|
this.switch(tabID);
|
|
}
|
|
|
|
switch = (tabID: string, noRun: boolean = false) => {
|
|
let t = this.tabs.get(tabID);
|
|
if (t == undefined) {
|
|
[t] = this.tabs.values();
|
|
}
|
|
|
|
const prev = this.tabs.get(this.current);
|
|
|
|
this._current = t.page.name;
|
|
|
|
if (t.preFunc && !noRun) {
|
|
t.preFunc(prev?.contentObject);
|
|
}
|
|
this.pages.load(tabID);
|
|
if (t.postFunc && !noRun) {
|
|
t.postFunc(prev?.contentObject);
|
|
}
|
|
};
|
|
}
|