mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-22 07:46:16 -04:00
Add UI for input tabs.
Can add, remove and switch tabs
This commit is contained in:
parent
328c0ade22
commit
37218c1e81
5 changed files with 304 additions and 34 deletions
|
@ -349,6 +349,189 @@ class InputWaiter {
|
|||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for adding a new input tab.
|
||||
*
|
||||
*/
|
||||
addTab() {
|
||||
const tabWrapper = document.getElementById("input-tabs");
|
||||
const tabsList = tabWrapper.children[0];
|
||||
const lastTabNum = tabsList.lastElementChild.id.replace("input-tab-", "");
|
||||
const newTabNum = parseInt(lastTabNum, 10) + 1;
|
||||
|
||||
tabWrapper.style.display = "block";
|
||||
|
||||
// Resize highlighter
|
||||
// document.getElementById("input-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))";
|
||||
|
||||
const activeTabElements = document.getElementsByClassName("active-input-tab");
|
||||
for (let i = 0; i < activeTabElements.length; i++) {
|
||||
activeTabElements.item(i).classList.remove("active-input-tab");
|
||||
}
|
||||
|
||||
const newTab = document.createElement("li");
|
||||
newTab.id = `input-tab-${newTabNum}`;
|
||||
newTab.classList.add("active-input-tab");
|
||||
|
||||
const newTabContent = document.createElement("div");
|
||||
newTabContent.classList.add("input-tab-content");
|
||||
newTabContent.innerText = `Tab ${newTabNum}`;
|
||||
|
||||
const newTabCloseBtn = document.createElement("button");
|
||||
newTabCloseBtn.className = "btn btn-primary bmd-btn-icon btn-close-tab";
|
||||
newTabCloseBtn.id = `btn-close-tab-${newTabNum}`;
|
||||
|
||||
const newTabCloseBtnIcon = document.createElement("i");
|
||||
newTabCloseBtnIcon.classList.add("material-icons");
|
||||
newTabCloseBtnIcon.innerText = "clear";
|
||||
|
||||
newTabCloseBtn.appendChild(newTabCloseBtnIcon);
|
||||
newTab.appendChild(newTabContent);
|
||||
newTab.appendChild(newTabCloseBtn);
|
||||
|
||||
tabsList.appendChild(newTab);
|
||||
|
||||
const multiWrapper = document.getElementById("multi-input-wrapper");
|
||||
|
||||
const activeAreaElements = document.getElementsByClassName("active-input-area");
|
||||
for (let i = 0; i < activeAreaElements.length; i++) {
|
||||
activeAreaElements.item(i).classList.remove("active-input-area");
|
||||
}
|
||||
|
||||
const newTextAreaWrapper = document.createElement("div");
|
||||
newTextAreaWrapper.className = "textarea-wrapper no-select input-wrapper active-input-area";
|
||||
newTextAreaWrapper.id = `tab-input-area-${newTabNum}`;
|
||||
|
||||
const newTextArea = document.createElement("textarea");
|
||||
newTextArea.id = `input-text-${newTabNum}`;
|
||||
newTextArea.spellcheck = "false";
|
||||
newTextArea.classList.add("input-text");
|
||||
|
||||
const newFileArea = document.createElement("div");
|
||||
newFileArea.id = `input-file-${newTabNum}`;
|
||||
newFileArea.classList.add("input-file");
|
||||
|
||||
const newFileOverlay = document.createElement("div");
|
||||
newFileOverlay.classList.add("file-overlay");
|
||||
|
||||
const newFileWrapper = document.createElement("div");
|
||||
newFileWrapper.style.position = "relative";
|
||||
newFileWrapper.style.height = "100%";
|
||||
|
||||
const newFileCard = document.createElement("div");
|
||||
newFileCard.className = "io-card card";
|
||||
|
||||
const newFileThumb = document.createElement("img");
|
||||
newFileThumb["aria-hidden"] = "true";
|
||||
newFileThumb.src = require("./static/images/file-128x128.png");
|
||||
newFileThumb.alt = "File icon";
|
||||
newFileThumb.id = `input-file-thumbnail-${newTabNum}`;
|
||||
|
||||
const newFileCardBody = document.createElement("div");
|
||||
newFileCardBody.class = "card-body";
|
||||
|
||||
const newFileCloseButton = document.createElement("button");
|
||||
newFileCloseButton.type = "button";
|
||||
newFileCloseButton.class = "close";
|
||||
newFileCloseButton.id = `input-file-close-${newTabNum}`;
|
||||
newFileCloseButton.innerHTML = "×";
|
||||
|
||||
newFileCardBody.appendChild(newFileCloseButton);
|
||||
|
||||
const cardInfo = `
|
||||
Name: <span id="input-file-name-${newTabNum}"></span><br>
|
||||
Size: <span id="input-file-size-${newTabNum}"></span><br>
|
||||
Type: <span id="input-file-type-${newTabNum}"></span><br>
|
||||
Loaded: <span id="input-file-loaded-${newTabNum}"></span>`;
|
||||
|
||||
newFileCardBody.innerHTML = newFileCardBody.innerHTML + cardInfo;
|
||||
|
||||
newFileCard.appendChild(newFileThumb);
|
||||
newFileCard.appendChild(newFileCardBody);
|
||||
newFileWrapper.appendChild(newFileCard);
|
||||
newFileArea.appendChild(newFileOverlay);
|
||||
newFileArea.appendChild(newFileWrapper);
|
||||
|
||||
newTextAreaWrapper.appendChild(newTextArea);
|
||||
newTextAreaWrapper.appendChild(newFileArea);
|
||||
multiWrapper.appendChild(newTextAreaWrapper);
|
||||
|
||||
// file inputs!
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for removing an input tab
|
||||
*
|
||||
* @param {event} mouseEvent
|
||||
*/
|
||||
removeTab(mouseEvent) {
|
||||
if (!mouseEvent.path) {
|
||||
return;
|
||||
}
|
||||
const closeBtn = mouseEvent.path[1];
|
||||
const liItem = closeBtn.parentElement;
|
||||
const tabList = liItem.parentElement;
|
||||
if (tabList.children.length > 1) {
|
||||
if (liItem.classList.contains("active-input-tab")) {
|
||||
// If current tab is active, change the active tab and input to another tab
|
||||
let newActiveAreaId;
|
||||
if (liItem.previousElementSibling) {
|
||||
liItem.previousElementSibling.classList.add("active-input-tab");
|
||||
const newActiveTabNum = liItem.previousElementSibling.id.replace("input-tab-", "");
|
||||
newActiveAreaId = `tab-input-area-${newActiveTabNum}`;
|
||||
} else if (liItem.nextElementSibling) {
|
||||
liItem.nextElementSibling.classList.add("active-input-tab");
|
||||
const newActiveTabNum = liItem.nextElementSibling.id.replace("input-tab-", "");
|
||||
newActiveAreaId = `tab-input-area-${newActiveTabNum}`;
|
||||
}
|
||||
|
||||
if (newActiveAreaId) {
|
||||
document.getElementById(newActiveAreaId).classList.add("active-input-area");
|
||||
}
|
||||
}
|
||||
const tabNum = liItem.id.replace("input-tab-", "");
|
||||
const multiInputArea = document.getElementById("multi-input-wrapper");
|
||||
const inputAreaId = `tab-input-area-${tabNum}`;
|
||||
const inputArea = document.getElementById(inputAreaId);
|
||||
|
||||
tabList.removeChild(liItem);
|
||||
multiInputArea.removeChild(inputArea);
|
||||
}
|
||||
if (tabList.children.length === 1) {
|
||||
document.getElementById("input-tabs").style.display = "none";
|
||||
// document.getElementById("input-highlighter").style.height = "calc(100% - var(--title-height))";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for changing tabs
|
||||
*
|
||||
* @param {event} mouseEvent
|
||||
*/
|
||||
changeTab(mouseEvent) {
|
||||
if (!mouseEvent.path) {
|
||||
return;
|
||||
}
|
||||
const tabContent = mouseEvent.path[0];
|
||||
const liItem = tabContent.parentElement;
|
||||
const tabNum = liItem.id.replace("input-tab-", "");
|
||||
|
||||
const activeTabsList = document.getElementsByClassName("active-input-tab");
|
||||
for (let i = 0; i < activeTabsList.length; i++) {
|
||||
activeTabsList.item(i).classList.remove("active-input-tab");
|
||||
}
|
||||
|
||||
const activeAreaList = document.getElementsByClassName("active-input-area");
|
||||
for (let i = 0; i < activeAreaList.length; i++) {
|
||||
activeAreaList.item(i).classList.remove("active-input-area");
|
||||
}
|
||||
liItem.classList.add("active-input-tab");
|
||||
|
||||
const newActiveAreaId = `tab-input-area-${tabNum}`;
|
||||
document.getElementById(newActiveAreaId).classList.add("active-input-area");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default InputWaiter;
|
||||
|
|
|
@ -142,19 +142,22 @@ class Manager {
|
|||
this.addDynamicListener("textarea.arg", "drop", this.recipe.textArgDrop, this.recipe);
|
||||
|
||||
// Input
|
||||
this.addMultiEventListener("#input-text", "keyup", this.input.inputChange, this.input);
|
||||
this.addMultiEventListener("#input-text", "paste", this.input.inputPaste, this.input);
|
||||
// this.addMultiEventListener("#input-text", "keyup", this.input.inputChange, this.input);
|
||||
// this.addMultiEventListener("#input-text", "paste", this.input.inputPaste, this.input);
|
||||
document.getElementById("reset-layout").addEventListener("click", this.app.resetLayout.bind(this.app));
|
||||
document.getElementById("clr-io").addEventListener("click", this.input.clearIoClick.bind(this.input));
|
||||
this.addListeners("#open-file", "change", this.input.inputOpen, this.input);
|
||||
this.addListeners("#input-text,#input-file", "dragover", this.input.inputDragover, this.input);
|
||||
this.addListeners("#input-text,#input-file", "dragleave", this.input.inputDragleave, this.input);
|
||||
this.addListeners("#input-text,#input-file", "drop", this.input.inputDrop, this.input);
|
||||
document.getElementById("input-text").addEventListener("scroll", this.highlighter.inputScroll.bind(this.highlighter));
|
||||
document.getElementById("input-text").addEventListener("mouseup", this.highlighter.inputMouseup.bind(this.highlighter));
|
||||
document.getElementById("input-text").addEventListener("mousemove", this.highlighter.inputMousemove.bind(this.highlighter));
|
||||
this.addMultiEventListener("#input-text", "mousedown dblclick select", this.highlighter.inputMousedown, this.highlighter);
|
||||
document.querySelector("#input-file .close").addEventListener("click", this.input.clearIoClick.bind(this.input));
|
||||
// this.addListeners("#input-text,#input-file", "dragover", this.input.inputDragover, this.input);
|
||||
// this.addListeners("#input-text,#input-file", "dragleave", this.input.inputDragleave, this.input);
|
||||
// this.addListeners("#input-text,#input-file", "drop", this.input.inputDrop, this.input);
|
||||
// document.getElementById("input-text").addEventListener("scroll", this.highlighter.inputScroll.bind(this.highlighter));
|
||||
// document.getElementById("input-text").addEventListener("mouseup", this.highlighter.inputMouseup.bind(this.highlighter));
|
||||
// document.getElementById("input-text").addEventListener("mousemove", this.highlighter.inputMousemove.bind(this.highlighter));
|
||||
// this.addMultiEventListener("#input-text", "mousedown dblclick select", this.highlighter.inputMousedown, this.highlighter);
|
||||
// document.querySelector("#input-file .close").addEventListener("click", this.input.clearIoClick.bind(this.input));
|
||||
document.getElementById("btn-new-tab").addEventListener("click", this.input.addTab);
|
||||
this.addDynamicListener("#input-tabs ul li .btn-close-tab i", "click", this.input.removeTab, this.input);
|
||||
this.addDynamicListener("#input-tabs ul li .input-tab-content", "click", this.input.changeTab, this.input);
|
||||
|
||||
// Output
|
||||
document.getElementById("save-to-file").addEventListener("click", this.output.saveClick.bind(this.output));
|
||||
|
|
|
@ -229,6 +229,9 @@
|
|||
<div class="title no-select">
|
||||
<label for="input-text">Input</label>
|
||||
<span class="float-right">
|
||||
<button type="button" class="btn btn-primary bmd-btn-icon" id="btn-new-tab" data-toggle="tooltip" title="Add a new input tab">
|
||||
<i class="material-icons">add</i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary bmd-btn-icon" id="btn-open-file" data-toggle="tooltip" title="Open file as input" onclick="document.getElementById('open-file').click();">
|
||||
<i class="material-icons">input</i>
|
||||
<input type="file" id="open-file" style="display: none">
|
||||
|
@ -243,20 +246,34 @@
|
|||
<div class="io-info" id="input-info"></div>
|
||||
<div class="io-info" id="input-selection-info"></div>
|
||||
</div>
|
||||
<div class="textarea-wrapper no-select">
|
||||
<div id="input-highlighter" class="no-select"></div>
|
||||
<textarea id="input-text" spellcheck="false"></textarea>
|
||||
<div id="input-file">
|
||||
<div class="file-overlay"></div>
|
||||
<div style="position: relative; height: 100%;">
|
||||
<div class="io-card card">
|
||||
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
|
||||
<div class="card-body">
|
||||
<button type="button" class="close" id="input-file-close">×</button>
|
||||
Name: <span id="input-file-name"></span><br>
|
||||
Size: <span id="input-file-size"></span><br>
|
||||
Type: <span id="input-file-type"></span><br>
|
||||
Loaded: <span id="input-file-loaded"></span>
|
||||
<div id="multi-input-wrapper">
|
||||
<div id="input-tabs" style="display: none;">
|
||||
<ul>
|
||||
<li id="input-tab-1" class="active-input-tab">
|
||||
<div class="input-tab-content">
|
||||
Tab 1
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary bmd-btn-icon btn-close-tab" id="btn-close-tab-1">
|
||||
<i class="material-icons">clear</i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="textarea-wrapper no-select input-wrapper active-input-area" id="tab-input-area-1">
|
||||
<div id="input-highlighter" class="no-select"></div>
|
||||
<textarea id="input-text-1" class="input-text" spellcheck="false"></textarea>
|
||||
<div class="input-file" id="input-file-1">
|
||||
<div class="file-overlay"></div>
|
||||
<div style="position: relative; height: 100%;">
|
||||
<div class="io-card card">
|
||||
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon" id="input-file-thumbnail-1"/>
|
||||
<div class="card-body">
|
||||
<button type="button" class="close" id="input-file-close">×</button>
|
||||
Name: <span id="input-file-name-1"></span><br>
|
||||
Size: <span id="input-file-size-1"></span><br>
|
||||
Type: <span id="input-file-type-1"></span><br>
|
||||
Loaded: <span id="input-file-loaded-1"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
:root {
|
||||
--title-height: 48px;
|
||||
--tab-height: 40px;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
#input-text,
|
||||
.input-text,
|
||||
#output-text,
|
||||
#output-html {
|
||||
position: relative;
|
||||
|
@ -30,12 +30,69 @@
|
|||
-moz-padding-start: 1px; /* Fixes bug in Firefox */
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
position: absolute;
|
||||
top: var(--title-height);
|
||||
bottom: 0;
|
||||
#multi-input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - var(--title-height));
|
||||
}
|
||||
|
||||
#input-tabs ul {
|
||||
list-style: none;
|
||||
background-color: var(--title-background-colour);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid var(--primary-border-colour);
|
||||
height: var(--tab-height);
|
||||
}
|
||||
|
||||
#input-tabs ul li {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
min-width: 120px;
|
||||
float: left;
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
border-right: 1px solid var(--primary-border-colour);
|
||||
height: var(--tab-height);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#input-tabs ul li:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--primary-background-colour);
|
||||
}
|
||||
|
||||
.active-input-tab {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.input-tab-content {
|
||||
width: 100%;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
height: var(--tab-height);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.btn-close-tab {
|
||||
height: var(--tab-height);
|
||||
vertical-align: middle;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.textarea-wrapper textarea,
|
||||
|
@ -45,13 +102,21 @@
|
|||
color: var(--fixed-width-font-colour);
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.active-input-area {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#input-highlighter,
|
||||
#output-highlighter {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100% - var(--title-height));
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
|
@ -61,6 +126,7 @@
|
|||
color: #fff;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#output-loader {
|
||||
|
@ -101,13 +167,13 @@
|
|||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#input-file,
|
||||
.input-file,
|
||||
#output-file {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100% - var(--tab-height) - var(--title-height));
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue