From c2087f6d5fb1f3e08aede4f6e4925e609d3064d8 Mon Sep 17 00:00:00 2001 From: j433866 Date: Thu, 6 Jun 2019 16:33:35 +0100 Subject: [PATCH] Move tab logic into a new TabWaiter --- src/web/App.mjs | 4 +- src/web/Manager.mjs | 2 + src/web/waiters/BindingsWaiter.mjs | 2 +- src/web/waiters/ControlsWaiter.mjs | 2 +- src/web/waiters/HighlighterWaiter.mjs | 2 +- src/web/waiters/InputWaiter.mjs | 292 ++++-------------- src/web/waiters/OutputWaiter.mjs | 236 +++------------ src/web/waiters/TabWaiter.mjs | 407 ++++++++++++++++++++++++++ src/web/waiters/WorkerWaiter.mjs | 2 +- src/web/workers/InputWorker.mjs | 36 +-- 10 files changed, 523 insertions(+), 462 deletions(-) create mode 100644 src/web/waiters/TabWaiter.mjs diff --git a/src/web/App.mjs b/src/web/App.mjs index 67d36489..2f9e0d84 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -157,7 +157,7 @@ class App { this.manager.input.inputWorker.postMessage({ action: "autobake", data: { - activeTab: this.manager.input.getActiveTab() + activeTab: this.manager.tabs.getActiveInputTab() } }); } else { @@ -194,7 +194,7 @@ class App { setInput(input) { // Get the currently active tab. // If there isn't one, assume there are no inputs so use inputNum of 1 - let inputNum = this.manager.input.getActiveTab(); + let inputNum = this.manager.tabs.getActiveInputTab(); if (inputNum === -1) inputNum = 1; this.manager.input.updateInputValue(inputNum, input); diff --git a/src/web/Manager.mjs b/src/web/Manager.mjs index 0a922b04..c411abf8 100755 --- a/src/web/Manager.mjs +++ b/src/web/Manager.mjs @@ -16,6 +16,7 @@ import HighlighterWaiter from "./waiters/HighlighterWaiter"; import SeasonalWaiter from "./waiters/SeasonalWaiter"; import BindingsWaiter from "./waiters/BindingsWaiter"; import BackgroundWorkerWaiter from "./waiters/BackgroundWorkerWaiter"; +import TabWaiter from "./waiters/TabWaiter"; /** @@ -70,6 +71,7 @@ class Manager { this.seasonal = new SeasonalWaiter(this.app, this); this.bindings = new BindingsWaiter(this.app, this); this.background = new BackgroundWorkerWaiter(this.app, this); + this.tabs = new TabWaiter(this.app, this); // Object to store dynamic handlers to fire on elements that may not exist yet this.dynamicHandlers = {}; diff --git a/src/web/waiters/BindingsWaiter.mjs b/src/web/waiters/BindingsWaiter.mjs index de6207fc..79c2903b 100755 --- a/src/web/waiters/BindingsWaiter.mjs +++ b/src/web/waiters/BindingsWaiter.mjs @@ -126,7 +126,7 @@ class BindingsWaiter { break; case "KeyW": // Close tab e.preventDefault(); - this.manager.input.removeInput(this.manager.input.getActiveTab()); + this.manager.input.removeInput(this.manager.tabs.getActiveInputTab()); break; case "ArrowLeft": // Go to previous tab e.preventDefault(); diff --git a/src/web/waiters/ControlsWaiter.mjs b/src/web/waiters/ControlsWaiter.mjs index 34dc484d..83ebc63b 100755 --- a/src/web/waiters/ControlsWaiter.mjs +++ b/src/web/waiters/ControlsWaiter.mjs @@ -72,7 +72,7 @@ class ControlsWaiter { if (this.app.baking) return; // Reset status using cancelBake this.manager.worker.cancelBake(true, false); - const activeTab = this.manager.input.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); let progress = 0; if (this.manager.output.outputs[activeTab].progress !== false) { progress = this.manager.output.outputs[activeTab].progress; diff --git a/src/web/waiters/HighlighterWaiter.mjs b/src/web/waiters/HighlighterWaiter.mjs index dbe420b0..95050556 100755 --- a/src/web/waiters/HighlighterWaiter.mjs +++ b/src/web/waiters/HighlighterWaiter.mjs @@ -378,7 +378,7 @@ class HighlighterWaiter { displayHighlights(pos, direction) { if (!pos) return; - if (this.manager.input.getActiveTab() !== this.manager.output.getActiveTab()) return; + if (this.manager.tabs.getActiveInputTab() !== this.manager.tabs.getActiveOutputTab()) return; const io = direction === "forward" ? "output" : "input"; diff --git a/src/web/waiters/InputWaiter.mjs b/src/web/waiters/InputWaiter.mjs index d471e8b8..d6cb6636 100644 --- a/src/web/waiters/InputWaiter.mjs +++ b/src/web/waiters/InputWaiter.mjs @@ -48,8 +48,8 @@ class InputWaiter { this.inputWorker = null; this.loaderWorkers = []; this.workerId = 0; - this.maxWorkers = navigator.hardwareConcurrency || 4; this.maxTabs = 4; + this.maxWorkers = navigator.hardwareConcurrency || 4; this.callbacks = {}; this.callbackID = 0; } @@ -58,14 +58,14 @@ class InputWaiter { * Calculates the maximum number of tabs to display */ calcMaxTabs() { - const numTabs = Math.floor((document.getElementById("IO").offsetWidth - 75) / 120); - this.maxTabs = (numTabs > 1) ? numTabs : 2; - if (this.inputWorker) { + const numTabs = this.manager.tabs.calcMaxTabs(); + if (this.inputWorker && this.maxTabs !== numTabs) { + this.maxTabs = numTabs; this.inputWorker.postMessage({ action: "updateMaxTabs", data: { - maxTabs: this.maxTabs, - activeTab: this.getActiveTab() + maxTabs: numTabs, + activeTab: this.manager.tabs.getActiveInputTab() } }); } @@ -94,7 +94,7 @@ class InputWaiter { action: "updateMaxTabs", data: { maxTabs: this.maxTabs, - activeTab: this.getActiveTab() + activeTab: this.manager.tabs.getActiveInputTab() } }); this.inputWorker.postMessage({ @@ -258,7 +258,7 @@ class InputWaiter { this.changeTab(r.data, this.app.options.syncTabs); break; case "updateTabHeader": - this.updateTabHeader(r.data); + this.manager.tabs.updateInputTabHeader(r.data.inputNum, r.data.input); break; case "loadingInfo": this.showLoadingInfo(r.data, true); @@ -327,7 +327,7 @@ class InputWaiter { */ async set(inputData, silent=false) { return new Promise(function(resolve, reject) { - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); if (inputData.inputNum !== activeTab) return; const inputText = document.getElementById("input-text"); @@ -383,7 +383,7 @@ class InputWaiter { * @param {number} inputData.progress - The load progress of the input file */ setFile(inputData) { - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); if (inputData.inputNum !== activeTab) return; const fileOverlay = document.getElementById("input-file"), @@ -425,7 +425,7 @@ class InputWaiter { * @param {ArrayBuffer} inputData.input - The actual input to display */ displayFilePreview(inputData) { - const activeTab = this.getActiveTab(), + const activeTab = this.manager.tabs.getActiveInputTab(), input = inputData.input, inputText = document.getElementById("input-text"), fileThumb = document.getElementById("input-file-thumbnail"); @@ -459,7 +459,7 @@ class InputWaiter { * @param {number | string} progress - Either a number or "error" */ updateFileProgress(inputNum, progress) { - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); if (inputNum !== activeTab) return; const fileLoaded = document.getElementById("input-file-loaded"); @@ -595,11 +595,7 @@ class InputWaiter { async getInputNums() { return await new Promise(resolve => { this.getNums(r => { - resolve({ - inputNums: r.inputNums, - min: r.min, - max: r.max - }); + resolve(r); }); }); } @@ -670,7 +666,7 @@ class InputWaiter { const textArea = document.getElementById("input-text"); const value = (textArea.value !== undefined) ? textArea.value : ""; - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); this.app.progress = 0; @@ -678,7 +674,7 @@ class InputWaiter { (value.count("\n") + 1) : null; this.setInputInfo(value.length, lines); this.updateInputValue(activeTab, value); - this.updateTabHeader({inputNum: activeTab, input: value}); + this.manager.tabs.updateInputTabHeader(activeTab, value); if (e && this.badKeys.indexOf(e.keyCode) < 0) { // Fire the statechange event as the input has been modified @@ -803,7 +799,7 @@ class InputWaiter { */ loadUIFiles(files) { const numFiles = files.length; - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); log.debug(`Loading ${numFiles} files.`); // Display the number of files as pending so the user @@ -938,103 +934,12 @@ class InputWaiter { setTimeout(function() { this.inputWorker.postMessage({ action: "getLoadProgress", - data: this.getActiveTab() + data: this.manager.tabs.getActiveInputTab() }); }.bind(this), 100); } } - /** - * Create a tab element for the input tab bar - * - * @param {number} inputNum - The inputNum of the new tab - * @param {boolean} [active=false] - If true, sets the tab to active - * @returns {Element} - */ - createTabElement(inputNum, active) { - const newTab = document.createElement("li"); - newTab.setAttribute("inputNum", inputNum.toString()); - - if (active) newTab.classList.add("active-input-tab"); - - const newTabContent = document.createElement("div"); - newTabContent.classList.add("input-tab-content"); - newTabContent.innerText = `${inputNum.toString()}: New Tab`; - - const newTabButton = document.createElement("button"); - newTabButton.type = "button"; - newTabButton.className = "btn btn-primary bmd-btn-icon btn-close-tab"; - - const newTabButtonIcon = document.createElement("i"); - newTabButtonIcon.classList.add("material-icons"); - newTabButtonIcon.innerText = "clear"; - - newTabButton.appendChild(newTabButtonIcon); - newTabButton.addEventListener("click", this.removeTabClick.bind(this)); - - newTab.appendChild(newTabContent); - newTab.appendChild(newTabButton); - - return newTab; - } - - /** - * Redraw the tab bar with an updated list of tabs. - * Then changes to the activeTab - * - * @param {number[]} nums - The inputNums of the tab bar to be drawn - * @param {number} activeTab - The inputNum of the active tab - * @param {boolean} tabsLeft - True if there are tabs to the left of the currently displayed tabs - * @param {boolean} tabsRight - True if there are tabs to the right of the currently displayed tabs - */ - refreshTabs(nums, activeTab, tabsLeft, tabsRight) { - const tabsList = document.getElementById("input-tabs"); - - for (let i = tabsList.children.length - 1; i >= 0; i--) { - tabsList.children.item(i).remove(); - } - - for (let i = 0; i < nums.length; i++) { - let active = false; - if (nums[i] === activeTab) active = true; - tabsList.appendChild(this.createTabElement(nums[i], active)); - } - - const firstTabElement = document.getElementById("input-tabs").firstElementChild; - const lastTabElement = document.getElementById("input-tabs").lastElementChild; - - if (firstTabElement) { - if (tabsLeft) { - firstTabElement.style.boxShadow = "15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - firstTabElement.style.boxShadow = ""; - } - } - if (lastTabElement) { - if (tabsRight) { - lastTabElement.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - lastTabElement.style.boxShadow = ""; - } - } - - if (nums.length > 1) { - tabsList.parentElement.style.display = "block"; - - document.getElementById("input-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("input-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("input-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - } else { - tabsList.parentElement.style.display = "none"; - - document.getElementById("input-wrapper").style.height = "calc(100% - var(--title-height))"; - document.getElementById("input-highlighter").style.height = "calc(100% - var(--title-height))"; - document.getElementById("input-file").style.height = "calc(100% - var(--title-height))"; - } - - this.changeTab(activeTab, this.app.options.syncTabs); - } - /** * Change to a different tab. * @@ -1042,26 +947,16 @@ class InputWaiter { * @param {boolean} [changeOutput=false] - If true, also changes the output */ changeTab(inputNum, changeOutput) { - const tabsList = document.getElementById("input-tabs"); - - this.manager.highlighter.removeHighlights(); - getSelection().removeAllRanges(); - - let found = false; - let minNum = Number.MAX_SAFE_INTEGER; - for (let i = 0; i < tabsList.children.length; i++) { - const tabNum = parseInt(tabsList.children.item(i).getAttribute("inputNum"), 10); - if (tabNum === inputNum) { - tabsList.children.item(i).classList.add("active-input-tab"); - found = true; - } else { - tabsList.children.item(i).classList.remove("active-input-tab"); - } - if (tabNum < minNum) { - minNum = tabNum; - } - } - if (!found) { + if (this.manager.tabs.changeInputTab(inputNum)) { + this.inputWorker.postMessage({ + action: "setInput", + data: { + inputNum: inputNum, + silent: true + } + }); + } else { + const minNum = Math.min(...this.manager.tabs.getInputTabList()); let direction = "right"; if (inputNum < minNum) { direction = "left"; @@ -1073,14 +968,6 @@ class InputWaiter { direction: direction } }); - } else { - this.inputWorker.postMessage({ - action: "setInput", - data: { - inputNum: inputNum, - silent: true - } - }); } if (changeOutput) { @@ -1102,70 +989,6 @@ class InputWaiter { } } - - /** - * Updates the tab header to display the new input content - */ - updateTabHeader(headerData) { - const tabsList = document.getElementById("input-tabs"); - const inputNum = headerData.inputNum; - let inputData = "New Tab"; - if (headerData.input.length > 0) { - inputData = headerData.input.slice(0, 100); - } - for (let i = 0; i < tabsList.children.length; i++) { - if (tabsList.children.item(i).getAttribute("inputNum") === inputNum.toString()) { - tabsList.children.item(i).firstElementChild.innerText = `${inputNum}: ${inputData}`; - break; - } - } - } - - /** - * Gets the number of the current active tab - * - * @returns {number} - */ - getActiveTab() { - const activeTabs = document.getElementsByClassName("active-input-tab"); - if (activeTabs.length > 0) { - const activeTab = activeTabs.item(0); - const tabNum = activeTab.getAttribute("inputNum"); - return parseInt(tabNum, 10); - } - return -1; - } - - /** - * Gets the li element for the tab of an input number - * - * @param {number} inputNum - The inputNum of the tab we're trying to find - * @returns {Element} - */ - getTabItem(inputNum) { - const tabs = document.getElementById("input-tabs").children; - for (let i = 0; i < tabs.length; i++) { - if (parseInt(tabs.item(i).getAttribute("inputNum"), 10) === inputNum) { - return tabs.item(i); - } - } - return null; - } - - /** - * Gets a list of tab numbers for the currently open tabs - * - * @returns {number[]} - */ - getTabList() { - const nums = []; - const tabs = document.getElementById("input-tabs").children; - for (let i = 0; i < tabs.length; i++) { - nums.push(parseInt(tabs.item(i).getAttribute("inputNum"), 10)); - } - return nums; - } - /** * Handler for clear all IO events. * Resets the input, output and info areas, and creates a new inputWorker @@ -1206,7 +1029,7 @@ class InputWaiter { * Resets the input for the current tab */ clearIoClick() { - const inputNum = this.getActiveTab(); + const inputNum = this.manager.tabs.getActiveInputTab(); if (inputNum === -1) return; this.manager.highlighter.removeHighlights(); @@ -1219,7 +1042,7 @@ class InputWaiter { input: "" }); - this.updateTabHeader({inputNum: inputNum, input: ""}); + this.manager.tabs.updateInputTabHeader(inputNum, ""); } /** @@ -1283,25 +1106,17 @@ class InputWaiter { * @param {boolean} [changeTab=true] - If true, changes to the new tab once it's been added */ addTab(inputNum, changeTab = true) { - const tabsWrapper = document.getElementById("input-tabs"); - const numTabs = tabsWrapper.children.length; + const tabsWrapper = document.getElementById("input-tabs"), + numTabs = tabsWrapper.children.length; - if (!this.getTabItem(inputNum) && numTabs < this.maxTabs) { - const newTab = this.createTabElement(inputNum, false); + if (!this.manager.tabs.getInputTabItem(inputNum) && numTabs < this.maxTabs) { + const newTab = this.manager.tabs.createInputTabElement(inputNum, changeTab); tabsWrapper.appendChild(newTab); if (numTabs > 0) { - tabsWrapper.parentElement.style.display = "block"; - - document.getElementById("input-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("input-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("input-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + this.manager.tabs.showTabBar(); } else { - tabsWrapper.parentElement.style.display = "none"; - - document.getElementById("input-wrapper").style.height = "calc(100% - var(--title-height))"; - document.getElementById("input-highlighter").style.height = "calc(100% - var(--title-height))"; - document.getElementById("input-file").style.height = "calc(100% - var(--title-height))"; + this.manager.tabs.hideTabBar(); } this.inputWorker.postMessage({ @@ -1313,9 +1128,19 @@ class InputWaiter { document.getElementById("input-tabs").lastElementChild.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; } - if (changeTab) { - this.changeTab(inputNum, true); - } + if (changeTab) this.changeTab(inputNum, false); + } + + /** + * Refreshes the input tabs, and changes to activeTab + * + * @param {number[]} nums - The inputNums to be displayed as tabs + * @param {number} activeTab - The tab to change to + * @param {boolean} tabsLeft - True if there are input tabs to the left of the displayed tabs + * @param {boolean} tabsRight - True if there are input tabs to the right of the displayed tabs + */ + refreshTabs(nums, activeTab, tabsLeft, tabsRight) { + this.manager.tabs.refreshInputTabs(nums, activeTab, tabsLeft, tabsRight); } /** @@ -1326,7 +1151,7 @@ class InputWaiter { */ removeInput(inputNum) { let refresh = false; - if (this.getTabItem(inputNum) !== null) { + if (this.manager.tabs.getInputTabItem(inputNum) !== null) { refresh = true; } this.inputWorker.postMessage({ @@ -1385,7 +1210,7 @@ class InputWaiter { setTimeout(func.bind(this, [newTime]), newTime); } }; - setTimeout(func.bind(this, [time]), time); + this.tabTimeout = setTimeout(func.bind(this, [time]), time); } /** @@ -1402,7 +1227,7 @@ class InputWaiter { setTimeout(func.bind(this, [newTime]), newTime); } }; - setTimeout(func.bind(this, [time]), time); + this.tabTimeout = setTimeout(func.bind(this, [time]), time); } /** @@ -1410,18 +1235,20 @@ class InputWaiter { */ tabMouseUp() { this.mousedown = false; + + clearTimeout(this.tabTimeout); + this.tabTimeout = null; } /** * Changes to the next (right) tab */ changeTabRight() { - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); this.inputWorker.postMessage({ action: "changeTabRight", data: { - activeTab: activeTab, - nums: this.getTabList() + activeTab: activeTab } }); } @@ -1430,12 +1257,11 @@ class InputWaiter { * Changes to the previous (left) tab */ changeTabLeft() { - const activeTab = this.getActiveTab(); + const activeTab = this.manager.tabs.getActiveInputTab(); this.inputWorker.postMessage({ action: "changeTabLeft", data: { - activeTab: activeTab, - nums: this.getTabList() + activeTab: activeTab } }); } @@ -1445,7 +1271,7 @@ class InputWaiter { */ async goToTab() { const inputNums = await this.getInputNums(); - let tabNum = window.prompt(`Enter tab number (${inputNums.min} - ${inputNums.max}):`, this.getActiveTab().toString()); + let tabNum = window.prompt(`Enter tab number (${inputNums.min} - ${inputNums.max}):`, this.manager.tabs.getActiveInputTab().toString()); if (tabNum === null) return; tabNum = parseInt(tabNum, 10); diff --git a/src/web/waiters/OutputWaiter.mjs b/src/web/waiters/OutputWaiter.mjs index 770f82ed..079ce241 100755 --- a/src/web/waiters/OutputWaiter.mjs +++ b/src/web/waiters/OutputWaiter.mjs @@ -25,21 +25,19 @@ class OutputWaiter { this.manager = manager; this.outputs = {}; - this.activeTab = -1; - this.zipWorker = null; - - this.maxTabs = 4; // Calculate this + this.maxTabs = 4; + this.tabTimeout = null; } /** * Calculates the maximum number of tabs to display */ calcMaxTabs() { - const numTabs = Math.floor((document.getElementById("IO").offsetWidth - 75) / 120); + const numTabs = this.manager.tabs.calcMaxTabs(); if (numTabs !== this.maxTabs) { this.maxTabs = numTabs; - this.refreshTabs(this.getActiveTab()); + this.refreshTabs(this.manager.tabs.getActiveOutputTab()); } } @@ -97,7 +95,7 @@ class OutputWaiter { * @returns {string | ArrayBuffer} */ getActive(raw=true) { - return this.getOutput(this.getActiveTab(), raw); + return this.getOutput(this.manager.tabs.getActiveOutputTab(), raw); } /** @@ -249,7 +247,7 @@ class OutputWaiter { if (output === undefined || output === null) return; if (typeof inputNum !== "number") inputNum = parseInt(inputNum, 10); - if (inputNum !== this.getActiveTab()) return; + if (inputNum !== this.manager.tabs.getActiveOutputTab()) return; this.toggleLoader(true); @@ -636,33 +634,10 @@ class OutputWaiter { const tabsWrapper = document.getElementById("output-tabs"); const numTabs = tabsWrapper.children.length; - if (this.getTabItem(inputNum) === undefined && numTabs < this.maxTabs) { + if (!this.manager.tabs.getOutputTabItem(inputNum) && numTabs < this.maxTabs) { // Create a new tab element - const newTab = this.createTabElement(inputNum); - + const newTab = this.manager.tabs.createOutputTabElement(inputNum, changeTab); tabsWrapper.appendChild(newTab); - - if (numTabs > 0) { - tabsWrapper.parentElement.style.display = "block"; - - document.getElementById("output-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-loader").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("show-file-overlay").style.top = "calc(var(--tab-height) + var(--title-height) + 10px)"; - - document.getElementById("save-all-to-file").style.display = "inline-block"; - } else { - tabsWrapper.parentElement.style.display = "none"; - - document.getElementById("output-wrapper").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-highlighter").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-file").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-loader").style.height = "calc(100% - var(--title-height))"; - document.getElementById("show-file-overlay").style.top = "calc(var(--title-height) + 10px)"; - - document.getElementById("save-all-to-file").style.display = "none"; - } } else if (numTabs === this.maxTabs) { // Can't create a new tab document.getElementById("output-tabs").lastElementChild.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; @@ -681,63 +656,24 @@ class OutputWaiter { */ changeTab(inputNum, changeInput = false) { if (!this.outputExists(inputNum)) return; - const currentNum = this.getActiveTab(); + const currentNum = this.manager.tabs.getActiveOutputTab(); this.hideMagicButton(); this.manager.highlighter.removeHighlights(); getSelection().removeAllRanges(); - const tabsWrapper = document.getElementById("output-tabs"); - const tabs = tabsWrapper.children; - - let found = false; - for (let i = 0; i < tabs.length; i++) { - if (tabs.item(i).getAttribute("inputNum") === inputNum.toString()) { - tabs.item(i).classList.add("active-output-tab"); - this.activeTab = inputNum; - found = true; - } else { - tabs.item(i).classList.remove("active-output-tab"); - } - } - if (!found) { + if (!this.manager.tabs.changeOutputTab(inputNum)) { let direction = "right"; if (currentNum > inputNum) { direction = "left"; } - const newOutputs = this.getNearbyNums(inputNum, direction); const tabsLeft = (newOutputs[0] !== this.getSmallestInputNum()); const tabsRight = (newOutputs[newOutputs.length - 1] !== this.getLargestInputNum()); - const firstTabElement = document.getElementById("output-tabs").firstElementChild; - const lastTabElement = document.getElementById("output-tabs").lastElementChild; - - if (firstTabElement) { - if (tabsLeft) { - firstTabElement.style.boxShadow = "15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - firstTabElement.style.boxShadow = ""; - } - } - if (lastTabElement) { - if (tabsRight) { - lastTabElement.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - lastTabElement.style.boxShadow = ""; - } - } - - for (let i = 0; i < newOutputs.length; i++) { - tabs.item(i).setAttribute("inputNum", newOutputs[i].toString()); - this.displayTabInfo(newOutputs[i]); - if (newOutputs[i] === inputNum) { - this.activeTab = inputNum; - tabs.item(i).classList.add("active-output-tab"); - } - } + this.manager.tabs.refreshOutputTabs(newOutputs, inputNum, tabsLeft, tabsRight); } this.app.debounce(this.set, 50, "setOutput", this, [inputNum])(); @@ -792,7 +728,7 @@ class OutputWaiter { setTimeout(func.bind(this, [newTime]), newTime); } }; - setTimeout(func.bind(this, [time]), time); + this.tabTimeout = setTimeout(func.bind(this, [time]), time); } /** @@ -809,7 +745,7 @@ class OutputWaiter { setTimeout(func.bind(this, [newTime]), newTime); } }; - setTimeout(func.bind(this, [time]), time); + this.tabTimeout = setTimeout(func.bind(this, [time]), time); } /** @@ -817,13 +753,16 @@ class OutputWaiter { */ tabMouseUp() { this.mousedown = false; + + clearTimeout(this.tabTimeout); + this.tabTimeout = null; } /** * Handler for changing to the left tab */ changeTabLeft() { - const currentTab = this.getActiveTab(); + const currentTab = this.manager.tabs.getActiveOutputTab(); this.changeTab(this.getPreviousInputNum(currentTab), this.app.options.syncTabs); } @@ -831,7 +770,7 @@ class OutputWaiter { * Handler for changing to the right tab */ changeTabRight() { - const currentTab = this.getActiveTab(); + const currentTab = this.manager.tabs.getActiveOutputTab(); this.changeTab(this.getNextInputNum(currentTab), this.app.options.syncTabs); } @@ -842,7 +781,7 @@ class OutputWaiter { const min = this.getSmallestInputNum(), max = this.getLargestInputNum(); - let tabNum = window.prompt(`Enter tab number (${min} - ${max}):`, this.getActiveTab().toString()); + let tabNum = window.prompt(`Enter tab number (${min} - ${max}):`, this.manager.tabs.getActiveOutputTab().toString()); if (tabNum === null) return; tabNum = parseInt(tabNum, 10); @@ -960,9 +899,9 @@ class OutputWaiter { */ removeTab(inputNum) { if (!this.outputExists(inputNum)) return; - let activeTab = this.getActiveTab(); + let activeTab = this.manager.tabs.getActiveOutputTab(); - const tabElement = this.getTabItem(inputNum); + const tabElement = this.manager.tabs.getOutputTabItem(inputNum); this.removeOutput(inputNum); @@ -970,7 +909,7 @@ class OutputWaiter { // find new tab number? if (inputNum === activeTab) { activeTab = this.getPreviousInputNum(activeTab); - if (activeTab === this.getActiveTab()) { + if (activeTab === this.manager.tabs.getActiveOutputTab()) { activeTab = this.getNextInputNum(activeTab); } } @@ -983,109 +922,15 @@ class OutputWaiter { * @param {number} activeTab */ refreshTabs(activeTab) { - const tabsList = document.getElementById("output-tabs"); - let newInputs = this.getNearbyNums(activeTab, "right"); - if (newInputs.length < this.maxTabs) { - newInputs = this.getNearbyNums(activeTab, "left"); - } - - for (let i = tabsList.children.length - 1; i >= 0; i--) { - tabsList.children.item(i).remove(); - } - - for (let i = 0; i < newInputs.length; i++) { - tabsList.appendChild(this.createTabElement(newInputs[i])); - this.displayTabInfo(newInputs[i]); - } - - const tabsLeft = (newInputs[0] !== this.getSmallestInputNum()); - const tabsRight = (newInputs[newInputs.length - 1] !== this.getLargestInputNum()); - - const firstTabElement = document.getElementById("output-tabs").firstElementChild; - const lastTabElement = document.getElementById("output-tabs").lastElementChild; - - if (firstTabElement) { - if (tabsLeft) { - firstTabElement.style.boxShadow = "15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - firstTabElement.style.boxShadow = ""; - } - } - if (lastTabElement) { - if (tabsRight) { - lastTabElement.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; - } else { - lastTabElement.style.boxShadow = ""; - } - } - - if (newInputs.length > 1) { - tabsList.parentElement.style.display = "block"; - - document.getElementById("output-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("output-loader").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; - document.getElementById("show-file-overlay").style.top = "calc(var(--tab-height) + var(--title-height) + 10px)"; - - document.getElementById("save-all-to-file").style.display = "inline-block"; - - } else { - tabsList.parentElement.style.display = "none"; - - document.getElementById("output-wrapper").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-highlighter").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-file").style.height = "calc(100% - var(--title-height))"; - document.getElementById("output-loader").style.height = "calc(100% - var(--title-height))"; - document.getElementById("show-file-overlay").style.top = "calc(var(--title-height) + 10px)"; - - document.getElementById("save-all-to-file").style.display = "none"; - } - - this.changeTab(activeTab); - - } - - /** - * Creates a new tab element to be added to the tab bar - * - * @param {number} inputNum - */ - createTabElement(inputNum) { - const newTab = document.createElement("li"); - newTab.setAttribute("inputNum", inputNum.toString()); - - const newTabContent = document.createElement("div"); - newTabContent.classList.add("output-tab-content"); - newTabContent.innerText = `Tab ${inputNum.toString()}`; - - // Do we want remove tab button on output? - newTab.appendChild(newTabContent); - - return newTab; - } - - /** - * Gets the number of the current active tab - * - * @returns {number} - */ - getActiveTab() { - return this.activeTab; - } - - /** - * Gets the li element for a tab - * - * @param {number} inputNum - */ - getTabItem(inputNum) { - const tabs = document.getElementById("output-tabs").children; - for (let i = 0; i < tabs.length; i++) { - if (parseInt(tabs.item(i).getAttribute("inputNum"), 10) === inputNum) { - return tabs.item(i); - } + const minNum = Math.min(this.manager.tabs.getOutputTabList()); + let direction = "right"; + if (activeTab < minNum) { + direction = "left"; } + const newNums = this.getNearbyNums(activeTab, direction), + tabsLeft = (newNums[0] !== this.getSmallestInputNum()), + tabsRight = (newNums[newNums.length] !== this.getLargestInputNum()); + this.manager.tabs.refreshOutputTabs(newNums, activeTab, tabsLeft, tabsRight); } /** @@ -1094,7 +939,7 @@ class OutputWaiter { * @param {number} inputNum */ displayTabInfo(inputNum) { - const tabItem = this.getTabItem(inputNum); + const tabItem = this.manager.tabs.getOutputTabItem(inputNum); if (!tabItem) return; @@ -1137,7 +982,7 @@ class OutputWaiter { async backgroundMagic() { this.hideMagicButton(); if (!this.app.options.autoMagic || !this.getActive(true)) return; - const dish = this.outputs[this.getActiveTab()].data.dish; + const dish = this.outputs[this.manager.tabs.getActiveOutputTab()].data.dish; const buffer = await this.getDishBuffer(dish); const sample = buffer.slice(0, 1000) || ""; @@ -1219,7 +1064,7 @@ class OutputWaiter { sliceToEl = document.getElementById("output-file-slice-to"), sliceFrom = parseInt(sliceFromEl.value, 10), sliceTo = parseInt(sliceToEl.value, 10), - output = this.outputs[this.getActiveTab()].data; + output = this.outputs[this.manager.tabs.getActiveOutputTab()].data; let str; if (output.type === "ArrayBuffer") { @@ -1252,7 +1097,7 @@ class OutputWaiter { document.getElementById("output-text").classList.add("blur"); showFileOverlay.style.display = "none"; - this.set(this.getActiveTab()); + this.set(this.manager.tabs.getActiveOutputTab()); } /** @@ -1330,22 +1175,15 @@ class OutputWaiter { */ switchClick() { const active = this.getActive(true); + const transferable = (typeof active === "string" ? undefined : [active]); if (typeof active === "string") { this.manager.input.inputWorker.postMessage({ action: "inputSwitch", data: { - inputNum: this.manager.input.getActiveTab(), + inputNum: this.manager.tabs.getActiveInputTab(), outputData: active } - }); - } else { - this.manager.input.inputWorker.postMessage({ - action: "inputSwitch", - data: { - inputNum: this.manager.input.getActiveTab(), - outputData: active - } - }, [active]); + }, transferable); } } diff --git a/src/web/waiters/TabWaiter.mjs b/src/web/waiters/TabWaiter.mjs new file mode 100644 index 00000000..ad158c74 --- /dev/null +++ b/src/web/waiters/TabWaiter.mjs @@ -0,0 +1,407 @@ +/** + * @author j433866 [j433866@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +/** + * Waiter to handle events related to the input and output tabs + */ +class TabWaiter { + + /** + * TabWaiter constructor. + * + * @param {App} app - The main view object for CyberChef. + * @param {Manager} manager - The CyberChef event manager + */ + constructor(app, manager) { + this.app = app; + this.manager = manager; + } + + /** + * Calculates the maximum number of tabs to display + * + * @returns {number} + */ + calcMaxTabs() { + let numTabs = Math.floor((document.getElementById("IO").offsetWidth - 75) / 120); + numTabs = (numTabs > 1) ? numTabs : 2; + + return numTabs; + } + + /** + * Gets the currently active input or active tab number + * + * @param {string} io - Either "input" or "output" + * @returns {number} - The currently active tab or -1 + */ + getActiveTab(io) { + const activeTabs = document.getElementsByClassName(`active-${io}-tab`); + if (activeTabs.length > 0) { + if (!activeTabs.item(0).hasAttribute("inputNum")) return -1; + const tabNum = activeTabs.item(0).getAttribute("inputNum"); + return parseInt(tabNum, 10); + } + return -1; + } + + /** + * Gets the currently active input tab number + * + * @returns {number} + */ + getActiveInputTab() { + return this.getActiveTab("input"); + } + + /** + * Gets the currently active output tab number + * + * @returns {number} + */ + getActiveOutputTab() { + return this.getActiveTab("output"); + } + + /** + * Gets the li element for the tab of a given input number + * + * @param {number} inputNum - The inputNum of the tab we're trying to get + * @param {string} io - Either "input" or "output" + * @returns {Element} + */ + getTabItem(inputNum, io) { + const tabs = document.getElementById(`${io}-tabs`).children; + for (let i = 0; i < tabs.length; i++) { + if (parseInt(tabs.item(i).getAttribute("inputNum"), 10) === inputNum) { + return tabs.item(i); + } + } + return null; + } + + /** + * Gets the li element for an input tab of the given input number + * + * @param {inputNum} - The inputNum of the tab we're trying to get + * @returns {Element} + */ + getInputTabItem(inputNum) { + return this.getTabItem(inputNum, "input"); + } + + /** + * Gets the li element for an output tab of the given input number + * + * @param {number} inputNum + * @returns {Element} + */ + getOutputTabItem(inputNum) { + return this.getTabItem(inputNum, "output"); + } + + /** + * Gets a list of tab numbers for the currently displayed tabs + * + * @param {string} io - Either "input" or "output" + * @returns {number[]} + */ + getTabList(io) { + const nums = [], + tabs = document.getElementById(`${io}-tabs`).children; + + for (let i = 0; i < tabs.length; i++) { + nums.push(parseInt(tabs.item(i).getAttribute("inputNum"), 10)); + } + + return nums; + } + + /** + * Gets a list of tab numbers for the currently displayed input tabs + * + * @returns {number[]} + */ + getInputTabList() { + return this.getTabList("input"); + } + + /** + * Gets a list of tab numbers for the currently displayed output tabs + * + * @returns {number[]} + */ + getOutputTabList() { + return this.getTabList("output"); + } + + /** + * Creates a new tab element for the tab bar + * + * @param {number} inputNum - The inputNum of the new tab + * @param {boolean} active - If true, sets the tab to active + * @param {string} io - Either "input" or "output" + * @returns {Element} + */ + createTabElement(inputNum, active, io) { + const newTab = document.createElement("li"); + newTab.setAttribute("inputNum", inputNum.toString()); + + if (active) newTab.classList.add(`active-${io}-tab`); + + const newTabContent = document.createElement("div"); + newTabContent.classList.add(`${io}-tab-content`); + + newTabContent.innerText = `Tab ${inputNum.toString()}`; + + newTab.appendChild(newTabContent); + + if (io === "input") { + const newTabButton = document.createElement("button"); + newTabButton.type = "button"; + newTabButton.className = "btn btn-primary bmd-btn-icon btn-close-tab"; + + const newTabButtonIcon = document.createElement("i"); + newTabButtonIcon.classList.add("material-icons"); + newTabButtonIcon.innerText = "clear"; + + newTabButton.appendChild(newTabButtonIcon); + + newTabButton.addEventListener("click", this.manager.input.removeTabClick.bind(this.manager.input)); + + newTab.appendChild(newTabButton); + } + + return newTab; + } + + /** + * Creates a new tab element for the input tab bar + * + * @param {number} inputNum - The inputNum of the new input tab + * @param {boolean} [active=false] - If true, sets the tab to active + * @returns {Element} + */ + createInputTabElement(inputNum, active=false) { + return this.createTabElement(inputNum, active, "input"); + } + + /** + * Creates a new tab element for the output tab bar + * + * @param {number} inputNum - The inputNum of the new output tab + * @param {boolean} [active=false] - If true, sets the tab to active + * @returns {Element} + */ + createOutputTabElement(inputNum, active=false) { + return this.createTabElement(inputNum, active, "output"); + } + + /** + * Displays the tab bar for both the input and output + */ + showTabBar() { + document.getElementById("input-tabs-wrapper").style.display = "block"; + document.getElementById("output-tabs-wrapper").style.display = "block"; + + document.getElementById("input-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("input-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("input-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + + document.getElementById("output-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("output-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("output-file").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("output-loader").style.height = "calc(100% - var(--tab-height) - var(--title-height))"; + document.getElementById("show-file-overlay").style.top = "calc(var(--tab-height) + var(--title-height) + 10px)"; + + document.getElementById("save-all-to-file").style.display = "inline-block"; + } + + /** + * Hides the tab bar for both the input and output + */ + hideTabBar() { + document.getElementById("input-tabs-wrapper").style.display = "none"; + document.getElementById("output-tabs-wrapper").style.display = "none"; + + document.getElementById("input-wrapper").style.height = "calc(100% - var(--title-height))"; + document.getElementById("input-highlighter").style.height = "calc(100% - var(--title-height))"; + document.getElementById("input-file").style.height = "calc(100% - var(--title-height))"; + + document.getElementById("output-wrapper").style.height = "calc(100% - var(--title-height))"; + document.getElementById("output-highlighter").style.height = "calc(100% - var(--title-height))"; + document.getElementById("output-file").style.height = "calc(100% - var(--title-height))"; + document.getElementById("output-loader").style.height = "calc(100% - var(--title-height))"; + document.getElementById("show-file-overlay").style.top = "calc(var(--title-height) + 10px)"; + + document.getElementById("save-all-to-file").style.display = "none"; + } + + /** + * Redraws the tab bar with an updated list of tabs, then changes to activeTab + * + * @param {number[]} nums - The inputNums of the tab bar to be drawn + * @param {number} activeTab - The inputNum of the activeTab + * @param {boolean} tabsLeft - True if there are tabs to the left of the displayed tabs + * @param {boolean} tabsRight - True if there are tabs to the right of the displayed tabs + * @param {string} io - Either "input" or "output" + */ + refreshTabs(nums, activeTab, tabsLeft, tabsRight, io) { + const tabsList = document.getElementById(`${io}-tabs`); + + // Remove existing tab elements + for (let i = tabsList.children.length - 1; i >= 0; i--) { + tabsList.children.item(i).remove(); + } + + // Create and add new tab elements + for (let i = 0; i < nums.length; i++) { + const active = (nums[i] === activeTab); + tabsList.appendChild(this.createTabElement(nums[i], active, io)); + } + + const firstTab = tabsList.firstElementChild, + lastTab = tabsList.lastElementChild; + + // Display shadows if there are tabs left / right of the displayed tabs + if (firstTab) { + if (tabsLeft) { + firstTab.style.boxShadow = "15px 0px 15px -15px var(--primary-border-colour) inset"; + } else { + firstTab.style.boxShadow = ""; + } + } + if (lastTab) { + if (tabsRight) { + lastTab.style.boxShadow = "-15px 0px 15px -15px var(--primary-border-colour) inset"; + } else { + lastTab.style.boxShadow = ""; + } + } + + // Show or hide the tab bar depending on how many tabs we have + if (nums.length > 1) { + this.showTabBar(); + } else { + this.hideTabBar(); + } + + this.changeTab(activeTab, io); + } + + /** + * Refreshes the input tabs, and changes to activeTab + * + * @param {number[]} nums - The inputNums to be displayed as tabs + * @param {number} activeTab - The tab to change to + * @param {boolean} tabsLeft - True if there are input tabs to the left of the displayed tabs + * @param {boolean} tabsRight - True if there are input tabs to the right of the displayed tabs + */ + refreshInputTabs(nums, activeTab, tabsLeft, tabsRight) { + this.refreshTabs(nums, activeTab, tabsLeft, tabsRight, "input"); + } + + /** + * Refreshes the output tabs, and changes to activeTab + * + * @param {number[]} nums - The inputNums to be displayed as tabs + * @param {number} activeTab - The tab to change to + * @param {boolean} tabsLeft - True if there are output tabs to the left of the displayed tabs + * @param {boolean} tabsRight - True if there are output tabs to the right of the displayed tabs + */ + refreshOutputTabs(nums, activeTab, tabsLeft, tabsRight) { + this.refreshTabs(nums, activeTab, tabsLeft, tabsRight, "output"); + } + + /** + * Changes the active tab to a different tab + * + * @param {number} inputNum - The inputNum of the tab to change to + * @param {string} io - Either "input" or "output" + * @return {boolean} - False if the tab is not currently being displayed + */ + changeTab(inputNum, io) { + const tabsList = document.getElementById(`${io}-tabs`); + + this.manager.highlighter.removeHighlights(); + getSelection().removeAllRanges(); + + let found = false; + for (let i = 0; i < tabsList.children.length; i++) { + const tabNum = parseInt(tabsList.children.item(i).getAttribute("inputNum"), 10); + if (tabNum === inputNum) { + tabsList.children.item(i).classList.add(`active-${io}-tab`); + found = true; + } else { + tabsList.children.item(i).classList.remove(`active-${io}-tab`); + } + } + + return found; + } + + /** + * Changes the active input tab to a different tab + * + * @param {number} inputNum + * @returns {boolean} - False if the tab is not currently being displayed + */ + changeInputTab(inputNum) { + return this.changeTab(inputNum, "input"); + } + + /** + * Changes the active output tab to a different tab + * + * @param {number} inputNum + * @returns {boolean} - False if the tab is not currently being displayed + */ + changeOutputTab(inputNum) { + return this.changeTab(inputNum, "output"); + } + + /** + * Updates the tab header to display a preview of the tab contents + * + * @param {number} inputNum - The inputNum of the tab to update the header of + * @param {string} data - The data to display in the tab header + * @param {string} io - Either "input" or "output" + */ + updateTabHeader(inputNum, data, io) { + const tab = this.getTabItem(inputNum, io); + if (tab === null) return; + + let headerData = `Tab ${inputNum}`; + if (data.length > 0) { + headerData = data.slice(0, 100); + headerData = `${inputNum}: ${headerData}`; + } + tab.firstElementChild.innerText = headerData; + } + + /** + * Updates the input tab header to display a preview of the tab contents + * + * @param {number} inputNum - The inputNum of the tab to update the header of + * @param {string} data - The data to display in the tab header + */ + updateInputTabHeader(inputNum, data) { + this.updateTabHeader(inputNum, data, "input"); + } + + /** + * Updates the output tab header to display a preview of the tab contents + * + * @param {number} inputNum - The inputNum of the tab to update the header of + * @param {string} data - The data to display in the tab header + */ + updateOutputTabHeader(inputNum, data) { + this.updateTabHeader(inputNum, data, "output"); + } + +} + +export default TabWaiter; diff --git a/src/web/waiters/WorkerWaiter.mjs b/src/web/waiters/WorkerWaiter.mjs index 989469ea..b5e7d76e 100644 --- a/src/web/waiters/WorkerWaiter.mjs +++ b/src/web/waiters/WorkerWaiter.mjs @@ -325,7 +325,7 @@ class WorkerWaiter { this.inputNums = []; this.totalOutputs = 0; this.loadingOutputs = 0; - if (!silent) this.manager.output.set(this.manager.output.getActiveTab()); + if (!silent) this.manager.output.set(this.manager.tabs.getActiveOutputTab()); } /** diff --git a/src/web/workers/InputWorker.mjs b/src/web/workers/InputWorker.mjs index 64a81a81..30fc41cc 100644 --- a/src/web/workers/InputWorker.mjs +++ b/src/web/workers/InputWorker.mjs @@ -79,10 +79,10 @@ self.addEventListener("message", function(e) { self.removeInput(r.data); break; case "changeTabRight": - self.changeTabRight(r.data.activeTab, r.data.nums); + self.changeTabRight(r.data.activeTab); break; case "changeTabLeft": - self.changeTabLeft(r.data.activeTab, r.data.nums); + self.changeTabLeft(r.data.activeTab); break; case "autobake": self.autoBake(r.data.activeTab, 0, false); @@ -887,38 +887,26 @@ self.removeInput = function(removeInputData) { * Change to the next tab. * * @param {number} inputNum - The inputNum of the tab to change to - * @param {number[]} tabNums - List of the currently displayed tabs */ -self.changeTabRight = function(inputNum, tabNums) { +self.changeTabRight = function(inputNum) { const newInput = self.getNextInputNum(inputNum); - if (tabNums.includes(newInput)) { - self.postMessage({ - action: "changeTab", - data: newInput - }); - } else { - // If the tab is not displayed, refresh the tabs to display it - self.refreshTabs(newInput, "right"); - } + self.postMessage({ + action: "changeTab", + data: newInput + }); }; /** * Change to the previous tab. * * @param {number} inputNum - The inputNum of the tab to change to - * @param {number[]} tabNums - List of the currently displayed tabs */ -self.changeTabLeft = function(inputNum, tabNums) { +self.changeTabLeft = function(inputNum) { const newInput = self.getPreviousInputNum(inputNum); - if (tabNums.includes(newInput)) { - self.postMessage({ - action: "changeTab", - data: newInput - }); - } else { - // If the tab is not displayed, refresh the tabs to display it - self.refreshTabs(newInput, "left"); - } + self.postMessage({ + action: "changeTab", + data: newInput + }); }; /**