mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-09 15:55:01 -04:00
Added Header Aliases
This commit is contained in:
parent
037590f831
commit
da7cd1668a
3 changed files with 175 additions and 21 deletions
|
@ -167,6 +167,8 @@ class Manager {
|
|||
document.getElementById("btn-go-to-input-tab").addEventListener("click", this.input.goToTab.bind(this.input));
|
||||
document.getElementById("btn-find-input-tab").addEventListener("click", this.input.findTab.bind(this.input));
|
||||
this.addDynamicListener("#input-tabs li .input-tab-content", "click", this.input.changeTabClick, this.input);
|
||||
this.addDynamicListener("#input-tabs-wrapper #input-tabs .input-tab-content", "dblclick", this.input.renameTabClick, this.input);
|
||||
this.addDynamicListener("#input-tabs-wrapper #input-tabs .input-tab-content span input", "focusout", this.input.confirmTabRename, this.input);
|
||||
document.getElementById("input-show-pending").addEventListener("change", this.input.filterTabSearch.bind(this.input));
|
||||
document.getElementById("input-show-loading").addEventListener("change", this.input.filterTabSearch.bind(this.input));
|
||||
document.getElementById("input-show-loaded").addEventListener("change", this.input.filterTabSearch.bind(this.input));
|
||||
|
|
|
@ -1001,6 +1001,11 @@ class InputWaiter {
|
|||
*/
|
||||
changeTab(inputNum, changeOutput) {
|
||||
if (this.manager.tabs.getInputTabItem(inputNum) !== null) {
|
||||
if (this.manager.tabs.getActiveTab("input") === inputNum) {
|
||||
if (changeOutput && this.manager.tabs.getActiveTab("output") !== inputNum)
|
||||
this.manager.output.changeTab(inputNum, false);
|
||||
return;
|
||||
}
|
||||
this.manager.tabs.changeInputTab(inputNum);
|
||||
this.inputWorker.postMessage({
|
||||
action: "setInput",
|
||||
|
@ -1090,6 +1095,7 @@ class InputWaiter {
|
|||
const inputNum = this.manager.tabs.getActiveInputTab();
|
||||
if (inputNum === -1) return;
|
||||
|
||||
this.manager.tabs.removeTabHeaderAlias(inputNum);
|
||||
this.manager.highlighter.removeHighlights();
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
|
@ -1228,6 +1234,7 @@ class InputWaiter {
|
|||
removeChefWorker: true
|
||||
}
|
||||
});
|
||||
this.manager.tabs.removeTabHeaderAlias(inputNum);
|
||||
|
||||
this.manager.output.removeTab(inputNum);
|
||||
}
|
||||
|
@ -1241,9 +1248,10 @@ class InputWaiter {
|
|||
if (!mouseEvent.target) {
|
||||
return;
|
||||
}
|
||||
const tabNum = mouseEvent.target.closest("button").parentElement.getAttribute("inputNum");
|
||||
if (tabNum) {
|
||||
this.removeInput(parseInt(tabNum, 10));
|
||||
const tabNumStr = mouseEvent.target.closest("button").parentElement.getAttribute("inputNum");
|
||||
if (tabNumStr) {
|
||||
const tabNum = parseInt(tabNumStr, 10);
|
||||
this.removeInput(tabNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1438,6 +1446,74 @@ class InputWaiter {
|
|||
this.app.updateTitle(urlData.includeInput, urlData.input, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for renaming tabs.
|
||||
* Opens the tab-renaming dialogue.
|
||||
*
|
||||
* @param {event} mouseEvent - The mouse event that this call was triggered by
|
||||
*/
|
||||
async renameTabClick(mouseEvent) {
|
||||
const targetElement = mouseEvent.target;
|
||||
if (!targetElement) return;
|
||||
|
||||
const editingElement = document.createElement("input");
|
||||
editingElement.classList.add("form-control");
|
||||
let renameContents = targetElement.textContent;
|
||||
const renameContentsColon = renameContents.indexOf(":");
|
||||
|
||||
// Calling 'getInputValue()' might take a long time for large datasets,
|
||||
// it could be beneficial to modify the API to allow for querying whether
|
||||
// there is any input rather than getting the full string just to access its length.
|
||||
const inputLength = (await this.getInputValue(this.manager.tabs.getActiveInputTab())).length;
|
||||
|
||||
// Remove the data from the renaming section
|
||||
if (renameContentsColon !== -1 && inputLength !== 0) {
|
||||
renameContents = renameContents.substring(0, renameContentsColon);
|
||||
}
|
||||
|
||||
// Remove the single quotation marks from the renaming section
|
||||
renameContents = renameContents.replaceAll("'", "");
|
||||
|
||||
if (renameContents.length < 3 && !isNaN(parseInt(renameContents, 10))) {
|
||||
renameContents = `Tab ${renameContents.toString()}`;
|
||||
}
|
||||
|
||||
editingElement.setAttribute("value", renameContents);
|
||||
editingElement.setAttribute("minlength", "3"); // Delimiting between shortened tab headers and custom ones.
|
||||
targetElement.textContent = "";
|
||||
editingElement.style.height = "1.5em";
|
||||
editingElement.style.textAlign = "center";
|
||||
targetElement.appendChild(editingElement);
|
||||
// A delay is required between appending and focusing.
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
editingElement.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the current user-entered text to
|
||||
* the tab's new name.
|
||||
* Resets the DOM of the tab to the default non-editable state.
|
||||
*/
|
||||
async confirmTabRename() {
|
||||
const activeInputTabNum = this.manager.tabs.getActiveInputTab();
|
||||
if (activeInputTabNum === -1) {
|
||||
return;
|
||||
}
|
||||
const activeInputTabElement = this.manager.tabs.getTabItem(activeInputTabNum, "input");
|
||||
if (activeInputTabElement == null || activeInputTabElement.children.size < 1) {
|
||||
return;
|
||||
}
|
||||
const tabContent = activeInputTabElement.children[0];
|
||||
const tabHeader = tabContent.children[0].children[0].value;
|
||||
const inputContents = await this.getInputValue(activeInputTabNum);
|
||||
|
||||
if (tabHeader.length === 0)
|
||||
this.manager.tabs.removeTabHeaderAlias(activeInputTabNum, false);
|
||||
else
|
||||
this.manager.tabs.addTabHeaderAlias(activeInputTabNum, tabHeader);
|
||||
this.manager.tabs.updateInputTabHeader(activeInputTabNum, inputContents);
|
||||
this.manager.tabs.updateOutputTabHeader(activeInputTabNum, inputContents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ class TabWaiter {
|
|||
constructor(app, manager) {
|
||||
this.app = app;
|
||||
this.manager = manager;
|
||||
this.tabHeaderAliases = []; // Mapping custom tab headers to indexes/numbers.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,6 +252,9 @@ class TabWaiter {
|
|||
tabsList.appendChild(this.createTabElement(nums[i], active, io));
|
||||
}
|
||||
|
||||
// Show or hide the tab bar depending on how many tabs we have
|
||||
if (nums.length > 1) {
|
||||
this.showTabBar();
|
||||
// Display shadows if there are tabs left / right of the displayed tabs
|
||||
if (tabsLeft) {
|
||||
tabsList.classList.add("tabs-left");
|
||||
|
@ -262,10 +266,6 @@ class TabWaiter {
|
|||
} else {
|
||||
tabsList.classList.remove("tabs-right");
|
||||
}
|
||||
|
||||
// Show or hide the tab bar depending on how many tabs we have
|
||||
if (nums.length > 1) {
|
||||
this.showTabBar();
|
||||
} else {
|
||||
this.hideTabBar();
|
||||
}
|
||||
|
@ -349,16 +349,35 @@ class TabWaiter {
|
|||
* @param {string} data - The data to display in the tab header
|
||||
* @param {string} io - Either "input" or "output"
|
||||
*/
|
||||
updateTabHeader(inputNum, data, io) {
|
||||
async updateTabHeader(inputNum, data, io) {
|
||||
const tab = this.getTabItem(inputNum, io);
|
||||
if (tab === null) return;
|
||||
if (tab == null) return;
|
||||
|
||||
let headerData = `Tab ${inputNum}`;
|
||||
if (data.length > 0) {
|
||||
headerData = data.slice(0, 100);
|
||||
headerData = `${inputNum}: ${headerData}`;
|
||||
const customHeaderData = this.getTabHeaderAlias(inputNum);
|
||||
|
||||
// When 'customHeaderData === `Tab ${inputNum}`' is true, it's usually due to
|
||||
// a user having opened the rename textbox but then closing it without change.
|
||||
const isStandardHeader = customHeaderData === null || customHeaderData === `Tab ${inputNum}`;
|
||||
|
||||
let headerData = isStandardHeader ? `Tab ${inputNum}` : customHeaderData;
|
||||
const dataIsFile = data instanceof ArrayBuffer;
|
||||
const includeData = data.length > 0 || dataIsFile;
|
||||
|
||||
if (includeData) {
|
||||
const inputObj = await this.manager.input.getInputObj(inputNum);
|
||||
|
||||
const dataPreview = dataIsFile ? inputObj.data.name : data.slice(0, 100);
|
||||
|
||||
if (isStandardHeader)
|
||||
headerData = inputNum.toString();
|
||||
else
|
||||
headerData = `'${customHeaderData}'`;
|
||||
|
||||
headerData += `: ${dataPreview}`;
|
||||
}
|
||||
tab.firstElementChild.innerText = headerData;
|
||||
if (!isStandardHeader && !includeData)
|
||||
tab.firstElementChild.innerText = `'${headerData}'`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -423,6 +442,63 @@ class TabWaiter {
|
|||
this.updateTabProgress(inputNum, progress, total, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an alias between a custom tab header and a tab number so that
|
||||
* mapping between the two is possible if DOM element is removed.
|
||||
*
|
||||
* @param {number} tabNum - The index of the tab being aliased
|
||||
* @param {string} tabHeader - The custom tab header
|
||||
*/
|
||||
addTabHeaderAlias(tabNum, tabHeader) {
|
||||
// First, we try to overwrite an existing alias.
|
||||
for (let i = 0; i < this.tabHeaderAliases.length; i++) {
|
||||
if (this.tabHeaderAliases.at(i).tabNumber === tabNum) {
|
||||
this.tabHeaderAliases.at(i).customHeader = tabHeader;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.tabHeaderAliases.push({tabNumber: tabNum, customHeader: tabHeader});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a previously-assigned header alias.
|
||||
*
|
||||
* @param {number} tabNum - The index of the tab that should be removed.
|
||||
* @param {boolean} shouldThrow - A boolean representing whether the function should throw an exception or return silently if it cannot locate the tab header.
|
||||
*/
|
||||
removeTabHeaderAlias(tabNum, shouldThrow) {
|
||||
for (let i = 0; i < this.tabHeaderAliases.length; i++) {
|
||||
|
||||
if (this.tabHeaderAliases.at(i).tabNumber === tabNum) {
|
||||
this.tabHeaderAliases.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (shouldThrow)
|
||||
throw `Unable to locate header alias at tab index ${tabNum.toString()}.`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the custom header for a given tab.
|
||||
*
|
||||
* @param {number} tabNum - The index of the tab whose alias should be retrieved.
|
||||
* @param {boolean} shouldThrow - Whether the function should throw an exception (instead of returning null) in the event of it being unable to locate the tab.
|
||||
* @returns {string} customHeader - The custom header for the requested tab.
|
||||
*/
|
||||
getTabHeaderAlias(tabNum, shouldThrow) {
|
||||
for (let i = 0; i < this.tabHeaderAliases.length; i++) {
|
||||
|
||||
if (this.tabHeaderAliases.at(i).tabNumber === tabNum)
|
||||
return this.tabHeaderAliases.at(i).customHeader;
|
||||
|
||||
}
|
||||
if (shouldThrow)
|
||||
throw `Unable to locate header alias at tab index ${tabNum.toString()}.`;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TabWaiter;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue