cables_dev/cables_ui/src/ui/elements/tabpanel/tabpanel.js
import { Events, Logger } from "cables-shared-client";
import userSettings from "../../components/usersettings.js";
import { getHandleBarHtml } from "../../utils/handlebars.js";
import { notify, notifyError } from "../notification.js";
/**
* a tab panel, that can contain tabs
*
* @export
* @class TabPanel
* @extends {Events}
*/
export default class TabPanel extends Events
{
constructor(eleId)
{
super();
this._log = new Logger("TabPanel " + eleId);
this.id = CABLES.uuid();
this._eleId = eleId;
this._tabs = [];
this._eleContentContainer = null;
this._eleTabPanel = null;
this.showTabListButton = false;
this._dynCmds = [];
if (!this._eleTabPanel)
{
this._eleTabPanel = document.createElement("div");
this._eleTabPanel.classList.add("tabpanel");
this._eleTabPanel.innerHTML = "";
const el = ele.byId(this._eleId);
if (!el)
{
console.error("could not find ele " + this._eleId);
return;
}
el.appendChild(this._eleTabPanel);
this._eleContentContainer = document.createElement("div");
this._eleContentContainer.classList.add("contentcontainer");
this._eleContentContainer.innerHTML = "";
el.appendChild(this._eleContentContainer);
}
this.on("resize", () =>
{
for (let i = 0; i < this._tabs.length; i++) this._tabs[i].emitEvent("resize");
});
}
getUniqueTitle(title)
{
const existingTab = this.getTabByTitle(title);
let count = 0;
while (existingTab)
{
count++;
if (!this.getTabByTitle(title + " (" + count + ")")) break;
}
if (count > 0)
title = title + " (" + count + ")";
return title;
}
updateHtml()
{
let html = "";
html += getHandleBarHtml("tabpanel_bar", { "id": this.id, "tabs": this._tabs });
this._eleTabPanel.innerHTML = html;
const editortabList = document.getElementById("editortabList" + this.id);
if (!editortabList)
{
console.warn("no editortabList?!?");
return;
}
if (!this.showTabListButton)
{
editortabList.style.display = "none";
editortabList.parentElement.style["padding-left"] = "0";
}
else
{
editortabList.parentElement.style["padding-left"] = "34px";
editortabList.style.display = "block";
editortabList.addEventListener(
"mousedown",
(e) =>
{
const items = [];
for (let i = 0; i < this._tabs.length; i++)
{
const tab = this._tabs[i];
items.push({
"title": tab.options.name,
"func": () => { this.activateTab(tab.id); }
});
}
CABLES.contextMenu.show(
{
"items": items
}, e.target);
},
);
}
for (let i = 0; i < this._dynCmds.length; i++) gui.cmdPallet.removeDynamic(this._dynCmds[i]);
for (let i = 0; i < this._tabs.length; i++)
{
if (window.gui && this._eleId == "maintabs")
{
const t = this._tabs[i];
const cmd = gui.cmdPallet.addDynamic("tab", "Tab " + t.title, () =>
{
gui.maintabPanel.show(true);
this.activateTab(t.id, true);
}, t.icon || "edit");
this._dynCmds.push(cmd);
}
// ----------------
document.getElementById("editortab" + this._tabs[i].id).addEventListener(
"mousedown",
function (e)
{
if (e.target.dataset.id) this.activateTab(e.target.dataset.id, true);
}.bind(this),
);
if (this._tabs[i].options.closable)
{
document.getElementById("editortab" + this._tabs[i].id).addEventListener(
"mousedown",
function (e)
{
if (e.button == 1) if (e.target.dataset.id) this.closeTab(e.target.dataset.id);
}.bind(this),
);
}
if (document.getElementById("closetab" + this._tabs[i].id))
{
document.getElementById("closetab" + this._tabs[i].id).addEventListener(
"mousedown",
function (e)
{
this.closeTab(e.target.dataset.id);
}.bind(this),
);
}
}
this.scrollToActiveTab();
}
activateTabByName(name)
{
name = name || "";
let found = false;
let tab = null;
for (let i = 0; i < this._tabs.length; i++)
{
if (this._tabs[i].title.toLowerCase() === name.toLowerCase() ||
(this._tabs[i].options.name || "").toLowerCase() === name.toLowerCase())
{
tab = this._tabs[i];
this.activateTab(tab.id);
found = true;
}
else this._tabs[i].deactivate();
}
if (!found) console.log("[activateTabByName] could not find tab", name);
this.updateHtml();
return tab;
}
scrollToActiveTab()
{
const tab = this.getActiveTab();
const w = this._eleTabPanel.clientWidth;
if (!tab) return;
let left = document.getElementById("editortab" + tab.id).offsetLeft;
left += document.getElementById("editortab" + tab.id).clientWidth;
left += 25;
const tabContainer = document.querySelector("#maintabs .tabs");
if (tabContainer && left > w) tabContainer.scrollLeft = left;
}
activateTab(id)
{
let found = false;
for (let i = 0; i < this._tabs.length; i++)
{
if (this._tabs[i].id === id)
{
found = true;
this.emitEvent("onTabActivated", this._tabs[i]);
this._tabs[i].activate();
}
}
if (found)
for (let i = 0; i < this._tabs.length; i++)
if (this._tabs[i].id != id)
this._tabs[i].deactivate();
this.updateHtml();
if (!found)
{
// console.log("could not find tab", id);
}
if (CABLES.editorSession && CABLES.editorSession.loaded() && CABLES.UI.loaded) this.saveCurrentTabUsersettings();
}
loadCurrentTabUsersettings()
{
let found = false;
for (let i = 0; i < this._tabs.length; i++)
{
if (userSettings.get("tabsLastTitle_" + this._eleId) == this._tabs[i].title)
{
this.activateTab(this._tabs[i].id);
found = true;
break;
}
}
}
saveCurrentTabUsersettings()
{
const activeTab = this.getActiveTab();
if (!activeTab) return;
userSettings.set("tabsLastTitle_" + this._eleId, activeTab.title);
}
getTabByDataId(dataId)
{
for (let i = 0; i < this._tabs.length; i++) if (this._tabs[i].dataId == dataId) return this._tabs[i];
}
getTabByTitle(title)
{
for (let i = 0; i < this._tabs.length; i++) if (this._tabs[i].title == title) return this._tabs[i];
}
getTabById(id)
{
for (let i = 0; i < this._tabs.length; i++) if (this._tabs[i].id == id) return this._tabs[i];
}
closeAllTabs()
{
while (this._tabs.length) this.closeTab(this._tabs[0].id);
}
closeTab(id)
{
let tab = null;
let idx = 0;
for (let i = 0; i < this._tabs.length; i++)
{
if (this._tabs[i].id == id)
{
tab = this._tabs[i];
// tab.emitEvent("close");
this._tabs.splice(i, 1);
idx = i;
break;
}
}
if (!tab) return;
this.emitEvent("onTabRemoved", tab);
tab.remove();
if (idx > this._tabs.length - 1) idx = this._tabs.length - 1;
if (this._tabs[idx]) this.activateTab(this._tabs[idx].id);
this.updateHtml();
}
setChanged(id, changed)
{
if (this.getTabById(id)) this.getTabById(id).options.wasChanged = changed;
this.updateHtml();
}
setTabNum(num)
{
const tab = this._tabs[Math.min(this._tabs.length, num)];
this.activateTab(tab.id);
}
getNumTabs()
{
return this._tabs.length;
}
cycleActiveTab()
{
if (this._tabs.length <= 1) return;
for (let i = 1; i < this._tabs.length; i++)
if (this._tabs[i - 1].active)
return this.activateTab(this._tabs[i].id);
return this.activateTab(this._tabs[0].id);
}
getActiveTab()
{
for (let i = 0; i < this._tabs.length; i++) if (this._tabs[i].active) return this._tabs[i];
}
updateSize()
{
for (let i = 0; i < this._tabs.length; i++) this._tabs[i].updateSize();
}
getSaveButton()
{
const t = this.getActiveTab();
if (!t) return;
const b = t.getSaveButton();
if (b) return b;
}
addTab(tab, activate)
{
if (tab.options.singleton)
{
const t = this.getTabByTitle(tab.title);
if (t)
{
this.activateTab(t.id);
this.emitEvent("onTabAdded", t, true);
if (activate) this.activateTab(t.id);
return t;
}
}
tab.initHtml(this._eleContentContainer);
this._tabs.push(tab);
if (activate) this.activateTab(tab.id);
// var tabEl=document.getElementById("editortab"+tab.id)
this.updateHtml();
this.emitEvent("onTabAdded", tab, false);
// setTimeout(() => { this.updateSize(); console.log("update size of tab"); }, 200);
return tab;
}
addIframeTab(title, url, options, userInteraction)
{
const iframeTab = this.addTab(new CABLES.UI.Tab(title, options));
const id = CABLES.uuid();
const html = "<div class=\"loading\" id=\"loading" + id + "\" style=\"position:absolute;left:45%;top:34%\"></div><iframe id=\"iframe" + id + "\" allow=\"clipboard-write\" style=\"border:none;width:100%;height:100%\" src=\"" + url + "\" onload=\"document.getElementById('loading" + id + "').style.display='none';\"></iframe";
iframeTab.contentEle.innerHTML = html;
iframeTab.contentEle.style.padding = "0px";
if (options.gotoUrl)
{
iframeTab.toolbarEle.innerHTML = "<a class=\"button-small\" href=\"" + options.gotoUrl + "\" target=\"_blank\">Open in new tab</a>";
}
else
{
iframeTab.toolbarEle.innerHTML = "<a class=\"button-small\" href=\"" + url + "\" target=\"_blank\">Open in new tab</a>";
}
const frame = document.getElementById("iframe" + id);
const talkerAPI = new CABLESUILOADER.TalkerAPI(frame.contentWindow);
talkerAPI.addEventListener("manualScreenshot", (opts, next) =>
{
CABLES.platform.setManualScreenshot(opts.manualScreenshot);
if (opts.manualScreenshot)
{
gui.patchView.store.saveScreenshot(true, () =>
{
talkerAPI.send("screenshotSaved");
});
}
});
talkerAPI.addEventListener("notify", (opts, next) =>
{
notify(opts.msg, opts.text, opts.options);
});
talkerAPI.addEventListener("notifyError", (opts, next) =>
{
notifyError(opts.msg, opts.text, opts.options);
});
talkerAPI.addEventListener("updatePatchName", (opts, next) =>
{
gui.setProjectName(opts.name);
CABLESUILOADER.talkerAPI.send("updatePatchName", opts, (err, r) => {});
});
talkerAPI.addEventListener("updatePatchSummary", (opts, next) =>
{
gui.project().summary = opts;
gui.patchParamPanel.show(true);
});
talkerAPI.addEventListener("opsDeleted", (opts, next) =>
{
const opdocs = gui.opDocs.getAll();
const deletedOps = opts.ops || [];
for (let i = 0; i < deletedOps.length; i++)
{
const deletedOp = deletedOps[i];
const opDocToDelete = opdocs.findIndex((opDoc) => { return opDoc.id === deletedOp.id; });
if (opDocToDelete) opdocs.splice(opDocToDelete, 1);
gui.opSelect().reload();
}
let plural = deletedOps.length > 1 ? "s" : "";
if (deletedOps.length > 0) notify("deleted " + deletedOps.length + " op" + plural);
this.closeTab(iframeTab.id);
});
this.activateTab(iframeTab.id);
gui.maintabPanel.show(userInteraction);
return iframeTab;
}
}