Add UI for input tabs.

Can add, remove and switch tabs
This commit is contained in:
j433866 2019-03-21 12:31:01 +00:00
parent 328c0ade22
commit 37218c1e81
5 changed files with 304 additions and 34 deletions

View File

@ -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 = "&times;";
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;

View File

@ -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));

View File

@ -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">&times;</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">&times;</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>

View File

@ -8,6 +8,7 @@
:root {
--title-height: 48px;
--tab-height: 40px;
}
.title {

View File

@ -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;
}