[turbolizer] Keep tabs and info tab between loads

This is a first step towards support for opening more than one
turbolizer json file at once.

Change-Id: Id51ce47c59492ba63de03eceb0163fa1701ea500
Notry: true
Bug: v8:7327
Reviewed-on: https://chromium-review.googlesource.com/c/1407057
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58790}
This commit is contained in:
Sigurd Schneider 2019-01-12 17:12:32 +01:00 committed by Commit Bot
parent 5b490eb2ee
commit d7a989e3b8
2 changed files with 114 additions and 102 deletions

View File

@ -1,104 +1,114 @@
export class Tabs {
container: HTMLElement;
tabBar: HTMLElement;
nextTabId: number;
private container: HTMLElement;
private tabBar: HTMLElement;
private nextTabId: number;
mkTabBar(container: HTMLElement) {
container.classList.add("nav-tabs-container");
this.tabBar = document.createElement("ul");
this.tabBar.id = `tab-bar-${container.id}`;
this.tabBar.className = "nav-tabs";
this.tabBar.ondrop = this.tabBarOnDrop.bind(this);
this.tabBar.ondragover = this.tabBarOnDragover.bind(this);
this.tabBar.onclick = this.tabBarOnClick.bind(this);
private mkTabBar(container: HTMLElement) {
container.classList.add("nav-tabs-container");
this.tabBar = document.createElement("ul");
this.tabBar.id = `tab-bar-${container.id}`;
this.tabBar.className = "nav-tabs";
this.tabBar.ondrop = this.tabBarOnDrop.bind(this);
this.tabBar.ondragover = this.tabBarOnDragover.bind(this);
this.tabBar.onclick = this.tabBarOnClick.bind(this);
const defaultDiv = document.createElement("div");
defaultDiv.className = "tab-content tab-default";
defaultDiv.id = `tab-content-${container.id}-default`;
container.insertBefore(defaultDiv, container.firstChild);
container.insertBefore(this.tabBar, container.firstChild);
const defaultDiv = document.createElement("div");
defaultDiv.className = "tab-content tab-default";
defaultDiv.id = `tab-content-${container.id}-default`;
container.insertBefore(defaultDiv, container.firstChild);
container.insertBefore(this.tabBar, container.firstChild);
}
constructor(container: HTMLElement) {
this.container = container;
this.nextTabId = 0;
this.mkTabBar(container);
}
activateTab(tab: HTMLLIElement) {
if (typeof tab.dataset.divid !== "string") return;
for (const li of this.tabBar.querySelectorAll<HTMLLIElement>("li.active")) {
li.classList.remove("active");
this.showTab(li, false);
}
tab.classList.add("active");
this.showTab(tab, true);
}
constructor(container: HTMLElement) {
this.container = container;
this.nextTabId = 0;
this.mkTabBar(container);
}
showTab(li: HTMLElement, show: boolean = true) {
const tabDiv = document.getElementById(li.dataset.divid);
tabDiv.style.display = show ? "block" : "none";
}
activateTab(tab: HTMLLIElement) {
if (typeof tab.dataset.divid !== "string") return;
for (const li of this.tabBar.querySelectorAll<HTMLLIElement>("li.active")) {
li.classList.remove("active");
this.showTab(li, false);
}
tab.classList.add("active");
this.showTab(tab, true);
}
addTab(caption: string): HTMLLIElement {
const newTab = document.createElement("li");
newTab.innerHTML = caption;
newTab.id = `tab-header-${this.container.id}-${this.nextTabId++}`;
const lastTab = this.tabBar.querySelector("li.open-tab");
this.tabBar.insertBefore(newTab, lastTab);
return newTab;
}
addTabAndContent(caption: string): [HTMLLIElement, HTMLDivElement] {
const contentDiv = document.createElement("div");
contentDiv.className = "tab-content tab-default";
contentDiv.id = `tab-content-${this.container.id}-${this.nextTabId++}`;
contentDiv.style.display = "none";
this.container.appendChild(contentDiv);
const newTab = this.addTab(caption);
newTab.dataset.divid = contentDiv.id;
newTab.draggable = true;
newTab.ondragstart = this.tabOnDragStart.bind(this);
const lastTab = this.tabBar.querySelector("li.open-tab");
this.tabBar.insertBefore(newTab, lastTab);
return [newTab, contentDiv];
}
moveTabDiv(tab: HTMLLIElement) {
clearTabsAndContent() {
for (const tab of this.tabBar.querySelectorAll(".nav-tabs > li")) {
if (!(tab instanceof HTMLLIElement)) continue;
if (tab.classList.contains("persistent-tab")) continue;
const tabDiv = document.getElementById(tab.dataset.divid);
tabDiv.style.display = "none";
tab.classList.remove("active");
this.tabBar.parentNode.appendChild(tabDiv);
tabDiv.parentNode.removeChild(tabDiv);
tab.parentNode.removeChild(tab);
}
}
tabBarOnDrop(e: DragEvent) {
if (!(e.target instanceof HTMLElement)) return;
e.preventDefault();
const tabId = e.dataTransfer.getData("text");
const tab = document.getElementById(tabId) as HTMLLIElement;
if (tab.parentNode != this.tabBar) {
this.moveTabDiv(tab);
}
const dropTab =
e.target.parentNode == this.tabBar
? e.target : this.tabBar.querySelector("li.open-tab");
this.tabBar.insertBefore(tab, dropTab);
this.activateTab(tab);
}
private showTab(li: HTMLElement, show: boolean = true) {
const tabDiv = document.getElementById(li.dataset.divid);
tabDiv.style.display = show ? "block" : "none";
}
tabBarOnDragover(e) {
e.preventDefault();
}
public addTab(caption: string): HTMLLIElement {
const newTab = document.createElement("li");
newTab.innerHTML = caption;
newTab.id = `tab-header-${this.container.id}-${this.nextTabId++}`;
const lastTab = this.tabBar.querySelector("li.last-tab");
this.tabBar.insertBefore(newTab, lastTab);
return newTab;
}
tabOnDragStart(e: DragEvent) {
if (!(e.target instanceof HTMLElement)) return;
e.dataTransfer.setData("text", e.target.id);
}
public addTabAndContent(caption: string): [HTMLLIElement, HTMLDivElement] {
const contentDiv = document.createElement("div");
contentDiv.className = "tab-content tab-default";
contentDiv.id = `tab-content-${this.container.id}-${this.nextTabId++}`;
contentDiv.style.display = "none";
this.container.appendChild(contentDiv);
tabBarOnClick(e: MouseEvent) {
const li = e.target as HTMLLIElement;
this.activateTab(li);
const newTab = this.addTab(caption);
newTab.dataset.divid = contentDiv.id;
newTab.draggable = true;
newTab.ondragstart = this.tabOnDragStart.bind(this);
const lastTab = this.tabBar.querySelector("li.last-tab");
this.tabBar.insertBefore(newTab, lastTab);
return [newTab, contentDiv];
}
private moveTabDiv(tab: HTMLLIElement) {
const tabDiv = document.getElementById(tab.dataset.divid);
tabDiv.style.display = "none";
tab.classList.remove("active");
this.tabBar.parentNode.appendChild(tabDiv);
}
private tabBarOnDrop(e: DragEvent) {
if (!(e.target instanceof HTMLElement)) return;
e.preventDefault();
const tabId = e.dataTransfer.getData("text");
const tab = document.getElementById(tabId) as HTMLLIElement;
if (tab.parentNode != this.tabBar) {
this.moveTabDiv(tab);
}
const dropTab =
e.target.parentNode == this.tabBar
? e.target : this.tabBar.querySelector("li.last-tab");
this.tabBar.insertBefore(tab, dropTab);
this.activateTab(tab);
}
private tabBarOnDragover(e) {
e.preventDefault();
}
private tabOnDragStart(e: DragEvent) {
if (!(e.target instanceof HTMLElement)) return;
e.dataTransfer.setData("text", e.target.id);
}
private tabBarOnClick(e: MouseEvent) {
const li = e.target as HTMLLIElement;
this.activateTab(li);
}
}

View File

@ -16,16 +16,29 @@ window.onload = function () {
let multiview = null;
let disassemblyView = null;
let sourceViews = [];
let infoView = null;
let selectionBroker = null;
let sourceResolver = null;
const resizer = new Resizer(panesUpdatedCallback, 100);
const sourceTabsContainer = document.getElementById(C.SOURCE_PANE_ID);
const sourceTabs = new Tabs(sourceTabsContainer);
sourceTabs.addTab("&#x2b;").classList.add("last-tab", "persistent-tab");
const disassemblyTabsContainer = document.getElementById(C.GENERATED_PANE_ID);
const disassemblyTabs = new Tabs(disassemblyTabsContainer);
disassemblyTabs.addTab("&#x2b;").classList.add("last-tab", "persistent-tab");
const [infoTab, infoContainer] = sourceTabs.addTabAndContent("Info");
infoTab.classList.add("persistent-tab");
infoContainer.classList.add("viewpane", "scrollable");
const infoView = new InfoView(infoContainer);
infoView.show(null, null);
sourceTabs.activateTab(infoTab);
function panesUpdatedCallback() {
if (multiview) multiview.onresize();
}
function loadFile(txtRes: string) {
sourceTabs.clearTabsAndContent();
disassemblyTabs.clearTabsAndContent();
// If the JSON isn't properly terminated, assume compiler crashed and
// add best-guess empty termination
if (txtRes[txtRes.length - 2] == ',') {
@ -63,33 +76,22 @@ window.onload = function () {
sourceResolver.setNodePositionMap(jsonObj.nodePositions);
sourceResolver.parsePhases(jsonObj.phases);
const sourceTabsContainer = document.getElementById(C.SOURCE_PANE_ID);
const sourceTabs = new Tabs(sourceTabsContainer);
const [sourceTab, sourceContainer] = sourceTabs.addTabAndContent("Source");
sourceContainer.classList.add("viewpane", "scrollable");
sourceTabs.activateTab(sourceTab);
sourceTabs.addTab("&#x2b;").classList.add("open-tab");
const sourceView = new CodeView(sourceContainer, selectionBroker, sourceResolver, fnc, CodeMode.MAIN_SOURCE);
sourceView.show(null, null);
sourceViews.push(sourceView);
const [, infoContainer] = sourceTabs.addTabAndContent("Info");
infoContainer.classList.add("viewpane", "scrollable");
infoView = new InfoView(infoContainer);
infoView.show(null, null);
sourceResolver.forEachSource(source => {
const sourceView = new CodeView(sourceContainer, selectionBroker, sourceResolver, source, CodeMode.INLINED_SOURCE);
sourceView.show(null, null);
sourceViews.push(sourceView);
});
const disassemblyTabsContainer = document.getElementById(C.GENERATED_PANE_ID);
const disassemblyTabs = new Tabs(disassemblyTabsContainer);
const [disassemblyTab, disassemblyContainer] = disassemblyTabs.addTabAndContent("Disassembly");
disassemblyContainer.classList.add("viewpane", "scrollable");
disassemblyTabs.activateTab(disassemblyTab);
disassemblyTabs.addTab("&#x2b;").classList.add("open-tab");
disassemblyView = new DisassemblyView(disassemblyContainer, selectionBroker);
disassemblyView.initializeCode(fnc.sourceText);
if (sourceResolver.disassemblyPhase) {