Stores inputs in memory instead of in textareas.

Allow selecting multiple files.
Allow drag and dropping multiple files.
Clear all IO button will close all tabs.
Will now spawn multiple loaderworkers simultaneously.
Improve tab logic to break less and work in Firefox.
This commit is contained in:
j433866 2019-03-22 15:10:19 +00:00
parent 37218c1e81
commit c0c83c5cdc
5 changed files with 300 additions and 230 deletions

View File

@ -41,18 +41,25 @@ class InputWaiter {
145, //Scroll
];
this.loaderWorker = null;
this.fileBuffer = null;
this.loaderWorkers = {};
this.fileBuffers = {};
this.inputs = {};
}
/**
* Gets the user's input from the input textarea.
* Gets the user's input from the active input textarea.
*
* @returns {string}
*/
get() {
return this.fileBuffer || document.getElementById("input-text").value;
const textArea = document.getElementById("input-text");
const value = textArea.value;
const inputNum = this.getActiveTab();
if (this.fileBuffers[inputNum] && this.fileBuffers[inputNum].fileBuffer) {
return this.fileBuffers[inputNum].fileBuffer;
}
return value;
}
@ -66,17 +73,21 @@ class InputWaiter {
*/
set(input, silent=false) {
const inputText = document.getElementById("input-text");
const inputNum = this.getActiveTab();
if (input instanceof File) {
this.setFile(input);
inputText.value = "";
this.setInputInfo(input.size, null);
this.displayTabInfo(input);
} else {
inputText.value = input;
this.closeFile();
this.inputs[inputNum] = input;
this.closeFile(inputNum);
if (!silent) window.dispatchEvent(this.manager.statechange);
const lines = input.length < (this.app.options.ioDisplayThreshold * 1024) ?
input.count("\n") + 1 : null;
this.setInputInfo(input.length, lines);
this.displayTabInfo(input);
}
}
@ -88,18 +99,17 @@ class InputWaiter {
*/
setFile(file) {
// Display file overlay in input area with details
const fileOverlay = document.getElementById("input-file"),
fileName = document.getElementById("input-file-name"),
fileSize = document.getElementById("input-file-size"),
fileType = document.getElementById("input-file-type"),
fileLoaded = document.getElementById("input-file-loaded");
const inputNum = this.getActiveTab();
this.fileBuffer = new ArrayBuffer();
fileOverlay.style.display = "block";
fileName.textContent = file.name;
fileSize.textContent = file.size.toLocaleString() + " bytes";
fileType.textContent = file.type || "unknown";
fileLoaded.textContent = "0%";
this.fileBuffers[inputNum] = {
fileBuffer: new ArrayBuffer(),
name: file.name,
size: file.size.toLocaleString(),
type: file.type || "unknown",
loaded: "0%"
};
this.setFileInfo(this.fileBuffers[inputNum]);
}
@ -122,6 +132,26 @@ class InputWaiter {
}
document.getElementById("input-info").innerHTML = msg;
}
/**
* Displays information about the input file.
*
* @param fileObj
*/
setFileInfo(fileObj) {
const fileOverlay = document.getElementById("input-file"),
fileName = document.getElementById("input-file-name"),
fileSize = document.getElementById("input-file-size"),
fileType = document.getElementById("input-file-type"),
fileLoaded = document.getElementById("input-file-loaded");
fileOverlay.style.display = "block";
fileName.textContent = fileObj.name;
fileSize.textContent = fileObj.size + " bytes";
fileType.textContent = fileObj.type;
fileLoaded.textContent = fileObj.loaded;
}
@ -134,20 +164,23 @@ class InputWaiter {
*/
inputChange(e) {
// Ignore this function if the input is a File
if (this.fileBuffer) return;
const inputNum = this.getActiveTab();
if (this.fileBuffers[inputNum]) return;
// Remove highlighting from input and output panes as the offsets might be different now
this.manager.highlighter.removeHighlights();
// this.manager.highlighter.removeHighlights();
// Reset recipe progress as any previous processing will be redundant now
this.app.progress = 0;
// Update the input metadata info
const inputText = this.get();
this.inputs[inputNum] = inputText;
const lines = inputText.length < (this.app.options.ioDisplayThreshold * 1024) ?
inputText.count("\n") + 1 : null;
this.setInputInfo(inputText.length, lines);
this.displayTabInfo(inputText);
if (e && this.badKeys.indexOf(e.keyCode) < 0) {
// Fire the statechange event as the input has been modified
@ -178,7 +211,7 @@ class InputWaiter {
this.loaderWorker = new LoaderWorker();
this.loaderWorker.addEventListener("message", this.handleLoaderMessage.bind(this));
this.loaderWorker.postMessage({"file": file});
this.loaderWorker.postMessage({"file": file, "inputNum": this.getActiveTab()});
this.set(file);
return false;
}
@ -211,8 +244,7 @@ class InputWaiter {
inputDragleave(e) {
e.stopPropagation();
e.preventDefault();
document.getElementById("input-text").classList.remove("dropping-file");
document.getElementById("input-file").classList.remove("dropping-file");
e.target.closest("#input-text,#input-file").classList.remove("dropping-file");
}
@ -230,20 +262,24 @@ class InputWaiter {
e.stopPropagation();
e.preventDefault();
const file = e.dataTransfer.files[0];
const text = e.dataTransfer.getData("Text");
document.getElementById("input-text").classList.remove("dropping-file");
document.getElementById("input-file").classList.remove("dropping-file");
e.target.closest("#input-text,#input-file").classList.remove("dropping-file");
if (text) {
this.closeFile();
this.closeFile(this.getActiveTab());
this.set(text);
return;
}
if (file) {
this.loadFile(file);
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
for (let i = 0; i < e.dataTransfer.files.length; i++) {
const file = e.dataTransfer.files[i];
if (i !== 0) {
this.addTab();
}
this.loadFile(file, this.getActiveTab());
}
}
}
@ -255,8 +291,15 @@ class InputWaiter {
*/
inputOpen(e) {
e.preventDefault();
const file = e.srcElement.files[0];
this.loadFile(file);
// TODO : CHANGE THIS TO HANDLE MULTIPLE FILES
for (let i = 0; i < e.srcElement.files.length; i++) {
const file = e.srcElement.files[i];
if (i !== 0) {
this.addTab();
}
this.loadFile(file, this.getActiveTab());
}
}
@ -267,9 +310,17 @@ class InputWaiter {
*/
handleLoaderMessage(e) {
const r = e.data;
let inputNum;
const tabNum = this.getActiveTab();
if (r.hasOwnProperty("inputNum")) {
inputNum = r.inputNum;
}
if (r.hasOwnProperty("progress")) {
const fileLoaded = document.getElementById("input-file-loaded");
fileLoaded.textContent = r.progress + "%";
this.fileBuffers[inputNum].loaded = r.progress + "%";
if (tabNum === inputNum) {
const fileLoaded = document.getElementById("input-file-loaded");
fileLoaded.textContent = r.progress + "%";
}
}
if (r.hasOwnProperty("error")) {
@ -278,7 +329,7 @@ class InputWaiter {
if (r.hasOwnProperty("fileBuffer")) {
log.debug("Input file loaded");
this.fileBuffer = r.fileBuffer;
this.fileBuffers[inputNum].fileBuffer = r.fileBuffer;
this.displayFilePreview();
window.dispatchEvent(this.manager.statechange);
}
@ -289,13 +340,14 @@ class InputWaiter {
* Shows a chunk of the file in the input behind the file overlay.
*/
displayFilePreview() {
const inputNum = this.getActiveTab();
const inputText = document.getElementById("input-text"),
fileSlice = this.fileBuffer.slice(0, 4096);
fileSlice = this.fileBuffers[inputNum].fileBuffer.slice(0, 4096);
inputText.style.overflow = "hidden";
inputText.classList.add("blur");
inputText.value = Utils.printable(Utils.arrayBufferToStr(fileSlice));
if (this.fileBuffer.byteLength > 4096) {
if (this.fileBuffers[inputNum].fileBuffer.byteLength > 4096) {
inputText.value += "[truncated]...";
}
}
@ -304,9 +356,9 @@ class InputWaiter {
/**
* Handler for file close events.
*/
closeFile() {
if (this.loaderWorker) this.loaderWorker.terminate();
this.fileBuffer = null;
closeFile(inputNum) {
if (this.loaderWorkers[inputNum]) this.loaderWorkers[inputNum].terminate();
delete this.fileBuffers[inputNum];
document.getElementById("input-file").style.display = "none";
const inputText = document.getElementById("input-text");
inputText.style.overflow = "auto";
@ -318,18 +370,18 @@ class InputWaiter {
* Loads a file into the input.
*
* @param {File} file
* @param {string} inputNum
*/
loadFile(file) {
if (file) {
this.closeFile();
this.loaderWorker = new LoaderWorker();
this.loaderWorker.addEventListener("message", this.handleLoaderMessage.bind(this));
this.loaderWorker.postMessage({"file": file});
loadFile(file, inputNum) {
if (file && inputNum) {
this.closeFile(inputNum);
this.loaderWorkers[inputNum] = new LoaderWorker();
this.loaderWorkers[inputNum].addEventListener("message", this.handleLoaderMessage.bind(this));
this.loaderWorkers[inputNum].postMessage({"file": file, "inputNum": inputNum});
this.set(file);
}
}
/**
* Handler for clear IO events.
* Resets the input, output and info areas.
@ -337,7 +389,7 @@ class InputWaiter {
* @fires Manager#statechange
*/
clearIoClick() {
this.closeFile();
this.closeFile(this.getActiveTab());
this.manager.output.closeFile();
this.manager.highlighter.removeHighlights();
document.getElementById("input-text").value = "";
@ -350,10 +402,38 @@ class InputWaiter {
}
/**
* Handler for adding a new input tab.
* Handler for clear all IO events.
* Resets the input, output and info areas.
*
* @fires Manager#statechange
*/
addTab() {
clearAllIoClick() {
// TODO: Close all tabs here
const tabs = document.getElementById("input-tabs").getElementsByTagName("li");
for (let i = tabs.length - 1; i >= 0; i--) {
const tabItem = tabs.item(i);
this.closeFile(this.getActiveTab(tabItem.id.replace("input-tab-", "")));
this.removeTab(tabItem);
}
this.manager.output.closeFile();
// this.manager.highlighter.removeHighlights();
const inputNum = this.getActiveTab();
document.getElementById(`input-tab-${inputNum}`).firstElementChild.innerText = "New Tab";
document.getElementById("input-text").value = "";
document.getElementById("output-text").value = "";
document.getElementById("input-info").innerHTML = "";
document.getElementById("output-info").innerHTML = "";
document.getElementById("input-selection-info").innerHTML = "";
document.getElementById("output-selection-info").innerHTML = "";
window.dispatchEvent(this.manager.statechange);
}
/**
* Function to create a new tab
*
* @param {boolean} changeTab
*/
addTab(changeTab = true) {
const tabWrapper = document.getElementById("input-tabs");
const tabsList = tabWrapper.children[0];
const lastTabNum = tabsList.lastElementChild.id.replace("input-tab-", "");
@ -361,21 +441,17 @@ class InputWaiter {
tabWrapper.style.display = "block";
// Resize highlighter
// document.getElementById("input-highlighter").style.height = "calc(100% - var(--tab-height) - var(--title-height))";
document.getElementById("input-wrapper").style.height = "calc(100% - var(--tab-height) - var(--title-height))";
document.getElementById("input-file").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");
}
this.inputs[newTabNum.toString()] = "";
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}`;
newTabContent.innerText = "New Tab";
const newTabCloseBtn = document.createElement("button");
newTabCloseBtn.className = "btn btn-primary bmd-btn-icon btn-close-tab";
@ -391,72 +467,50 @@ class InputWaiter {
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");
if (changeTab) {
this.changeTab(newTabContent);
}
}
const newTextAreaWrapper = document.createElement("div");
newTextAreaWrapper.className = "textarea-wrapper no-select input-wrapper active-input-area";
newTextAreaWrapper.id = `tab-input-area-${newTabNum}`;
/**
* Function to remove a tab
*
* @param {Element} tabLiItem
*/
removeTab(tabLiItem) {
const tabList= tabLiItem.parentElement;
if (tabList.children.length > 1) {
if (tabLiItem.classList.contains("active-input-tab")) {
if (tabLiItem.previousElementSibling) {
this.changeTab(tabLiItem.previousElementSibling.firstElementChild);
const newTextArea = document.createElement("textarea");
newTextArea.id = `input-text-${newTabNum}`;
newTextArea.spellcheck = "false";
newTextArea.classList.add("input-text");
window.dispatchEvent(this.manager.statechange);
} else if (tabLiItem.nextElementSibling) {
this.changeTab(tabLiItem.nextElementSibling.firstElementChild);
const newFileArea = document.createElement("div");
newFileArea.id = `input-file-${newTabNum}`;
newFileArea.classList.add("input-file");
window.dispatchEvent(this.manager.statechange);
}
}
const tabNum = tabLiItem.id.replace("input-tab-", "");
const newFileOverlay = document.createElement("div");
newFileOverlay.classList.add("file-overlay");
delete this.fileBuffers[tabNum];
delete this.inputs[tabNum];
const newFileWrapper = document.createElement("div");
newFileWrapper.style.position = "relative";
newFileWrapper.style.height = "100%";
tabList.removeChild(tabLiItem);
} else {
const tabNum = tabLiItem.id.replace("input-tab-", "");
delete this.fileBuffers[tabNum];
this.inputs[tabNum] = "";
document.getElementById("input-text").value = "";
tabLiItem.firstElementChild.innerText = "New Tab";
}
if (tabList.children.length === 1) {
document.getElementById("input-tabs").style.display = "none";
const newFileCard = document.createElement("div");
newFileCard.className = "io-card card";
document.getElementById("input-wrapper").style.height = "calc(100% - var(--title-height))";
document.getElementById("input-file").style.height = "calc(100% - var(--title-height))";
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!
}
}
/**
@ -464,72 +518,97 @@ class InputWaiter {
*
* @param {event} mouseEvent
*/
removeTab(mouseEvent) {
if (!mouseEvent.path) {
removeTabClick(mouseEvent) {
if (!mouseEvent.srcElement) {
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}`;
}
this.removeTab(mouseEvent.srcElement.parentElement.parentElement);
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
* Change the active tab to tabElement
*
* @param {Element} tabElement The tab element to change to
*/
changeTab(tabElement) {
const liItem = tabElement.parentElement;
const newTabNum = liItem.id.replace("input-tab-", "");
const currentTabNum = this.getActiveTab();
const inputText = document.getElementById("input-text");
document.getElementById(`input-tab-${currentTabNum}`).classList.remove("active-input-tab");
liItem.classList.add("active-input-tab");
this.inputs[currentTabNum] = inputText.value;
if (this.fileBuffers[newTabNum]) {
const fileObj = this.fileBuffers[newTabNum];
this.setInputInfo(fileObj.size, 1);
this.setFileInfo(fileObj);
this.displayFilePreview();
} else {
inputText.value = this.inputs[newTabNum];
inputText.style.overflow = "auto";
inputText.classList.remove("blur");
this.inputChange(null);
document.getElementById("input-file").style.display = "none";
}
window.dispatchEvent(this.manager.statechange);
}
/**
* Handler for changing tabs event
*
* @param {event} mouseEvent
*/
changeTab(mouseEvent) {
if (!mouseEvent.path) {
changeTabClick(mouseEvent) {
if (!mouseEvent.srcElement) {
return;
}
const tabContent = mouseEvent.path[0];
const liItem = tabContent.parentElement;
const tabNum = liItem.id.replace("input-tab-", "");
this.changeTab(mouseEvent.srcElement);
const activeTabsList = document.getElementsByClassName("active-input-tab");
for (let i = 0; i < activeTabsList.length; i++) {
activeTabsList.item(i).classList.remove("active-input-tab");
}
/**
* Display input information in the tab header
*
* @param {string|File} input
*/
displayTabInfo(input) {
const activeTabs = document.getElementsByClassName("active-input-tab");
if (activeTabs.length > 0) {
const activeTabContent = activeTabs.item(0).getElementsByClassName("input-tab-content")[0];
if (input instanceof File) {
activeTabContent.innerText = input.name;
} else {
if (input.length > 0) {
activeTabContent.innerText = input.slice(0, 100);
} else {
activeTabContent.innerText = "New Tab";
}
}
}
const activeAreaList = document.getElementsByClassName("active-input-area");
for (let i = 0; i < activeAreaList.length; i++) {
activeAreaList.item(i).classList.remove("active-input-area");
}
/**
* Gets the number of the current active tab
*
* @returns {string}
*/
getActiveTab() {
const activeTabs = document.getElementsByClassName("active-input-tab");
if (activeTabs.length > 0) {
const activeTab = activeTabs.item(0);
const activeTabNum = activeTab.id.replace("input-tab-", "");
return activeTabNum;
} else {
throw "Could not find an active tab";
}
liItem.classList.add("active-input-tab");
const newActiveAreaId = `tab-input-area-${tabNum}`;
document.getElementById(newActiveAreaId).classList.add("active-input-area");
}
}

View File

@ -12,8 +12,10 @@
*/
self.addEventListener("message", function(e) {
const r = e.data;
if (r.hasOwnProperty("file")) {
self.loadFile(r.file);
if (r.hasOwnProperty("file") && (r.hasOwnProperty("inputNum"))) {
self.loadFile(r.file, r.inputNum);
} else if (r.hasOwnProperty("file")) {
self.loadFile(r.file, "");
}
});
@ -22,8 +24,9 @@ self.addEventListener("message", function(e) {
* Loads a file object into an ArrayBuffer, then transfers it back to the parent thread.
*
* @param {File} file
* @param {string} inputNum
*/
self.loadFile = function(file) {
self.loadFile = function(file, inputNum) {
const reader = new FileReader();
const data = new Uint8Array(file.size);
let offset = 0;
@ -31,11 +34,11 @@ self.loadFile = function(file) {
const seek = function() {
if (offset >= file.size) {
self.postMessage({"progress": 100});
self.postMessage({"fileBuffer": data.buffer}, [data.buffer]);
self.postMessage({"progress": 100, "inputNum": inputNum});
self.postMessage({"fileBuffer": data.buffer, "inputNum": inputNum}, [data.buffer]);
return;
}
self.postMessage({"progress": Math.round(offset / file.size * 100)});
self.postMessage({"progress": Math.round(offset / file.size * 100), "inputNum": inputNum});
const slice = file.slice(offset, offset + CHUNK_SIZE);
reader.readAsArrayBuffer(slice);
};

View File

@ -142,22 +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));
document.getElementById("clr-io").addEventListener("click", this.input.clearAllIoClick.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);
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);
document.querySelector("#input-file .close").addEventListener("click", this.input.clearIoClick.bind(this.input));
document.getElementById("btn-new-tab").addEventListener("click", this.input.addTab.bind(this.input));
this.addDynamicListener("#input-tabs ul li .btn-close-tab i", "click", this.input.removeTabClick, this.input);
this.addDynamicListener("#input-tabs ul li .input-tab-content", "click", this.input.changeTabClick, this.input);
// Output
document.getElementById("save-to-file").addEventListener("click", this.output.saveClick.bind(this.output));

View File

@ -234,7 +234,7 @@
</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">
<input type="file" id="open-file" style="display: none" multiple>
</button>
<button type="button" class="btn btn-primary bmd-btn-icon" id="clr-io" data-toggle="tooltip" title="Clear input and output">
<i class="material-icons">delete</i>
@ -246,34 +246,32 @@
<div class="io-info" id="input-info"></div>
<div class="io-info" id="input-selection-info"></div>
</div>
<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 id="input-tabs" style="display: none;">
<ul>
<li id="input-tab-1" class="active-input-tab">
<div class="input-tab-content">
New Tab
</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" id="input-wrapper">
<div id="input-highlighter" class="no-select"></div>
<textarea id="input-text" class="input-text" spellcheck="false"></textarea>
<div class="input-file" id="input-file">
<div class="file-overlay" id="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"/>
<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>
</div>
</div>

View File

@ -6,7 +6,7 @@
* @license Apache-2.0
*/
.input-text,
#input-text,
#output-text,
#output-html {
position: relative;
@ -30,12 +30,6 @@
-moz-padding-start: 1px; /* Fixes bug in Firefox */
}
#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);
@ -69,16 +63,21 @@
.active-input-tab {
font-weight: bold;
background-color: var(--primary-background-colour);
}
.input-tab-content {
width: 100%;
max-width: 100%;
padding-left: 5px;
padding-right: 5px;
padding-top: 10px;
padding-bottom: 10px;
height: var(--tab-height);
vertical-align: middle;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.btn-close-tab {
@ -89,7 +88,7 @@
.textarea-wrapper {
width: 100%;
height: 100%;
height: calc(100% - var(--title-height));
box-sizing: border-box;
overflow: hidden;
pointer-events: auto;
@ -102,21 +101,13 @@
color: var(--fixed-width-font-colour);
}
.input-wrapper {
display: none;
}
.active-input-area {
display: inline-block;
}
#input-highlighter,
#output-highlighter {
position: absolute;
left: 0;
bottom: 0;
top: 0;
width: 100%;
height: calc(100% - var(--title-height));
height: 100%;
padding: 3px;
margin: 0;
overflow: hidden;
@ -167,13 +158,13 @@
transition: all 0.5s ease;
}
.input-file,
#input-file,
#output-file {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: calc(100% - var(--tab-height) - var(--title-height));
height: calc(100% - var(--title-height));
display: none;
}
@ -213,7 +204,6 @@
.dropping-file {
border: 5px dashed var(--drop-file-border-colour) !important;
margin: -5px;
}
#stale-indicator {