diff --git a/src/web/Manager.mjs b/src/web/Manager.mjs
index 793b61de..730d6e2e 100755
--- a/src/web/Manager.mjs
+++ b/src/web/Manager.mjs
@@ -152,7 +152,6 @@ class Manager {
this.addListeners("#input-wrapper", "dragover", this.input.inputDragover, this.input);
this.addListeners("#input-wrapper", "dragleave", this.input.inputDragleave, this.input);
this.addListeners("#input-wrapper", "drop", this.input.inputDrop, this.input);
- document.querySelector("#input-file .close").addEventListener("click", this.input.clearIoClick.bind(this.input));
document.getElementById("btn-new-tab").addEventListener("click", this.input.addInputClick.bind(this.input));
document.getElementById("btn-previous-input-tab").addEventListener("mousedown", this.input.previousTabClick.bind(this.input));
document.getElementById("btn-next-input-tab").addEventListener("mousedown", this.input.nextTabClick.bind(this.input));
@@ -218,7 +217,6 @@ class Manager {
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
document.getElementById("theme").addEventListener("change", this.options.themeChange.bind(this.options));
document.getElementById("logLevel").addEventListener("change", this.options.logLevelChange.bind(this.options));
- document.getElementById("imagePreview").addEventListener("change", this.input.renderFileThumb.bind(this.input));
// Misc
window.addEventListener("keydown", this.bindings.parseInput.bind(this.bindings));
diff --git a/src/web/html/index.html b/src/web/html/index.html
index 68d69a78..6e2c60a3 100755
--- a/src/web/html/index.html
+++ b/src/web/html/index.html
@@ -265,21 +265,6 @@
diff --git a/src/web/stylesheets/layout/_io.css b/src/web/stylesheets/layout/_io.css
index 185b3bdb..9c64fe85 100755
--- a/src/web/stylesheets/layout/_io.css
+++ b/src/web/stylesheets/layout/_io.css
@@ -220,7 +220,6 @@
transition: all 0.5s ease;
}
-#input-file,
#output-file {
position: absolute;
left: 0;
@@ -450,9 +449,10 @@
font-size: 12px !important;
}
-.ͼ2 .cm-panels {
+.ͼ2 .cm-panels,
+.ͼ2 .cm-side-panels {
background-color: var(--secondary-background-colour);
- border-color: var(--secondary-border-colour);
+ border-color: var(--primary-border-colour);
color: var(--primary-font-colour);
}
@@ -547,4 +547,44 @@
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
-}
\ No newline at end of file
+}
+
+
+/* File details panel */
+
+.cm-file-details {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ overflow-y: auto;
+ padding-bottom: 21px;
+ height: 100%;
+}
+
+.file-details-heading {
+ font-weight: bold;
+ margin: 10px 0 10px 0;
+}
+
+.file-details-data {
+ text-align: left;
+ margin: 10px 2px;
+}
+
+.file-details-data td {
+ padding: 0 3px;
+ max-width: 130px;
+ min-width: 60px;
+ overflow: hidden;
+ vertical-align: top;
+ word-break: break-all;
+}
+
+.file-details-error {
+ color: #f00;
+}
+
+.file-details-thumbnail {
+ max-width: 180px;
+}
diff --git a/src/web/utils/fileDetails.mjs b/src/web/utils/fileDetails.mjs
new file mode 100644
index 00000000..f8e3003b
--- /dev/null
+++ b/src/web/utils/fileDetails.mjs
@@ -0,0 +1,134 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2022
+ * @license Apache-2.0
+ */
+
+import {showSidePanel} from "./sidePanel.mjs";
+import Utils from "../../core/Utils.mjs";
+import {isImage} from "../../core/lib/FileType.mjs";
+
+/**
+ * A File Details extension for CodeMirror
+ */
+class FileDetailsPanel {
+
+ /**
+ * FileDetailsPanel constructor
+ * @param {Object} opts
+ */
+ constructor(opts) {
+ this.fileDetails = opts.fileDetails;
+ this.progress = opts.progress;
+ this.status = opts.status;
+ this.buffer = opts.buffer;
+ this.renderPreview = opts.renderPreview;
+ this.dom = this.buildDOM();
+ this.renderFileThumb();
+ }
+
+ /**
+ * Builds the file details DOM tree
+ * @returns {DOMNode}
+ */
+ buildDOM() {
+ const dom = document.createElement("div");
+
+ dom.className = "cm-file-details";
+ const fileThumb = require("../static/images/file-128x128.png");
+ dom.innerHTML = `
+ File details
+
+
+
+ Name: |
+
+ ${Utils.escapeHtml(this.fileDetails.name)}
+ |
+
+
+ Size: |
+
+ ${Utils.escapeHtml(this.fileDetails.size)} bytes
+ |
+
+
+ Type: |
+
+ ${Utils.escapeHtml(this.fileDetails.type)}
+ |
+
+
+ Loaded: |
+
+ ${this.status === "error" ? "Error" : this.progress + "%"}
+ |
+
+
+ `;
+
+ return dom;
+ }
+
+ /**
+ * Render the file thumbnail
+ */
+ renderFileThumb() {
+ if (!this.renderPreview) {
+ this.resetFileThumb();
+ return;
+ }
+ const fileThumb = this.dom.querySelector(".file-details-thumbnail");
+ const fileType = this.dom.querySelector(".file-details-type");
+ const fileBuffer = new Uint8Array(this.buffer);
+ const type = isImage(fileBuffer);
+
+ if (type && type !== "image/tiff" && fileBuffer.byteLength <= 512000) {
+ // Most browsers don't support displaying TIFFs, so ignore them
+ // Don't render images over 512,000 bytes
+ const blob = new Blob([fileBuffer], {type: type}),
+ url = URL.createObjectURL(blob);
+ fileThumb.src = url;
+ } else {
+ this.resetFileThumb();
+ }
+ fileType.textContent = type;
+ }
+
+ /**
+ * Reset the file thumbnail to the default icon
+ */
+ resetFileThumb() {
+ const fileThumb = this.dom.querySelector(".file-details-thumbnail");
+ fileThumb.src = require("../static/images/file-128x128.png");
+ }
+
+}
+
+/**
+ * A panel constructor factory building a panel that displays file details
+ * @param {Object} opts
+ * @returns {Function}
+ */
+function makePanel(opts) {
+ const fdPanel = new FileDetailsPanel(opts);
+
+ return (view) => {
+ return {
+ dom: fdPanel.dom,
+ width: 200,
+ update(update) {
+ }
+ };
+ };
+}
+
+/**
+ * A function that build the extension that enables the panel in an editor.
+ * @param {Object} opts
+ * @returns {Extension}
+ */
+export function fileDetailsPanel(opts) {
+ const panelMaker = makePanel(opts);
+ return showSidePanel.of(panelMaker);
+}
diff --git a/src/web/utils/sidePanel.mjs b/src/web/utils/sidePanel.mjs
new file mode 100644
index 00000000..a8de0931
--- /dev/null
+++ b/src/web/utils/sidePanel.mjs
@@ -0,0 +1,254 @@
+/**
+ * A modification of the CodeMirror Panel extension to enable panels to the
+ * left and right of the editor.
+ * Based on code here: https://github.com/codemirror/view/blob/main/src/panel.ts
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2022
+ * @license Apache-2.0
+ */
+
+import {EditorView, ViewPlugin} from "@codemirror/view";
+import {Facet} from "@codemirror/state";
+
+const panelConfig = Facet.define({
+ combine(configs) {
+ let leftContainer, rightContainer;
+ for (const c of configs) {
+ leftContainer = leftContainer || c.leftContainer;
+ rightContainer = rightContainer || c.rightContainer;
+ }
+ return {leftContainer, rightContainer};
+ }
+});
+
+/**
+ * Configures the panel-managing extension.
+ * @param {PanelConfig} config
+ * @returns Extension
+ */
+export function panels(config) {
+ return config ? [panelConfig.of(config)] : [];
+}
+
+/**
+ * Get the active panel created by the given constructor, if any.
+ * This can be useful when you need access to your panels' DOM
+ * structure.
+ * @param {EditorView} view
+ * @param {PanelConstructor} panel
+ * @returns {Panel}
+ */
+export function getPanel(view, panel) {
+ const plugin = view.plugin(panelPlugin);
+ const index = plugin ? plugin.specs.indexOf(panel) : -1;
+ return index > -1 ? plugin.panels[index] : null;
+}
+
+const panelPlugin = ViewPlugin.fromClass(class {
+
+ /**
+ * @param {EditorView} view
+ */
+ constructor(view) {
+ this.input = view.state.facet(showSidePanel);
+ this.specs = this.input.filter(s => s);
+ this.panels = this.specs.map(spec => spec(view));
+ const conf = view.state.facet(panelConfig);
+ this.left = new PanelGroup(view, true, conf.leftContainer);
+ this.right = new PanelGroup(view, false, conf.rightContainer);
+ this.left.sync(this.panels.filter(p => p.left));
+ this.right.sync(this.panels.filter(p => !p.left));
+ for (const p of this.panels) {
+ p.dom.classList.add("cm-panel");
+ if (p.mount) p.mount();
+ }
+ }
+
+ /**
+ * @param {ViewUpdate} update
+ */
+ update(update) {
+ const conf = update.state.facet(panelConfig);
+ if (this.left.container !== conf.leftContainer) {
+ this.left.sync([]);
+ this.left = new PanelGroup(update.view, true, conf.leftContainer);
+ }
+ if (this.right.container !== conf.rightContainer) {
+ this.right.sync([]);
+ this.right = new PanelGroup(update.view, false, conf.rightContainer);
+ }
+ this.left.syncClasses();
+ this.right.syncClasses();
+ const input = update.state.facet(showSidePanel);
+ if (input !== this.input) {
+ const specs = input.filter(x => x);
+ const panels = [], left = [], right = [], mount = [];
+ for (const spec of specs) {
+ const known = this.specs.indexOf(spec);
+ let panel;
+ if (known < 0) {
+ panel = spec(update.view);
+ mount.push(panel);
+ } else {
+ panel = this.panels[known];
+ if (panel.update) panel.update(update);
+ }
+ panels.push(panel)
+ ;(panel.left ? left : right).push(panel);
+ }
+ this.specs = specs;
+ this.panels = panels;
+ this.left.sync(left);
+ this.right.sync(right);
+ for (const p of mount) {
+ p.dom.classList.add("cm-panel");
+ if (p.mount) p.mount();
+ }
+ } else {
+ for (const p of this.panels) if (p.update) p.update(update);
+ }
+ }
+
+ /**
+ * Destroy panel
+ */
+ destroy() {
+ this.left.sync([]);
+ this.right.sync([]);
+ }
+}, {
+ // provide: PluginField.scrollMargins.from(value => ({left: value.left.scrollMargin(), right: value.right.scrollMargin()}))
+});
+
+/**
+ * PanelGroup
+ */
+class PanelGroup {
+
+ /**
+ * @param {EditorView} view
+ * @param {boolean} left
+ * @param {HTMLElement} container
+ */
+ constructor(view, left, container) {
+ this.view = view;
+ this.left = left;
+ this.container = container;
+ this.dom = undefined;
+ this.classes = "";
+ this.panels = [];
+ this.bufferWidth = 0;
+ this.syncClasses();
+ }
+
+ /**
+ * @param {Panel[]} panels
+ */
+ sync(panels) {
+ for (const p of this.panels) if (p.destroy && panels.indexOf(p) < 0) p.destroy();
+ this.panels = panels;
+ this.syncDOM();
+ }
+
+ /**
+ * Synchronise the DOM
+ */
+ syncDOM() {
+ if (this.panels.length === 0) {
+ if (this.dom) {
+ this.dom.remove();
+ this.dom = undefined;
+ }
+ return;
+ }
+
+ const parent = this.container || this.view.dom;
+ if (!this.dom) {
+ this.dom = document.createElement("div");
+ this.dom.className = this.left ? "cm-side-panels cm-panels-left" : "cm-side-panels cm-panels-right";
+ parent.insertBefore(this.dom, parent.firstChild);
+ }
+
+ let curDOM = this.dom.firstChild;
+ for (const panel of this.panels) {
+ if (panel.dom.parentNode === this.dom) {
+ while (curDOM !== panel.dom) curDOM = rm(curDOM);
+ curDOM = curDOM.nextSibling;
+ } else {
+ this.dom.insertBefore(panel.dom, curDOM);
+ this.bufferWidth = panel.width;
+ panel.dom.style.width = panel.width + "px";
+ this.dom.style.width = this.bufferWidth + "px";
+ }
+ }
+ while (curDOM) curDOM = rm(curDOM);
+
+ const margin = this.left ? "marginLeft" : "marginRight";
+ parent.querySelector(".cm-scroller").style[margin] = this.bufferWidth + "px";
+ }
+
+ /**
+ *
+ */
+ scrollMargin() {
+ return !this.dom || this.container ? 0 :
+ Math.max(0, this.left ?
+ this.dom.getBoundingClientRect().right - Math.max(0, this.view.scrollDOM.getBoundingClientRect().left) :
+ Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().right) - this.dom.getBoundingClientRect().left);
+ }
+
+ /**
+ *
+ */
+ syncClasses() {
+ if (!this.container || this.classes === this.view.themeClasses) return;
+ for (const cls of this.classes.split(" ")) if (cls) this.container.classList.remove(cls);
+ for (const cls of (this.classes = this.view.themeClasses).split(" ")) if (cls) this.container.classList.add(cls);
+ }
+}
+
+/**
+ * @param {ChildNode} node
+ * @returns HTMLElement
+ */
+function rm(node) {
+ const next = node.nextSibling;
+ node.remove();
+ return next;
+}
+
+const baseTheme = EditorView.baseTheme({
+ ".cm-side-panels": {
+ boxSizing: "border-box",
+ position: "absolute",
+ height: "100%",
+ top: 0,
+ bottom: 0
+ },
+ "&light .cm-side-panels": {
+ backgroundColor: "#f5f5f5",
+ color: "black"
+ },
+ "&light .cm-panels-left": {
+ borderRight: "1px solid #ddd",
+ left: 0
+ },
+ "&light .cm-panels-right": {
+ borderLeft: "1px solid #ddd",
+ right: 0
+ },
+ "&dark .cm-side-panels": {
+ backgroundColor: "#333338",
+ color: "white"
+ }
+});
+
+/**
+ * Opening a panel is done by providing a constructor function for
+ * the panel through this facet. (The panel is closed again when its
+ * constructor is no longer provided.) Values of `null` are ignored.
+ */
+export const showSidePanel = Facet.define({
+ enables: [panelPlugin, baseTheme]
+});
diff --git a/src/web/waiters/InputWaiter.mjs b/src/web/waiters/InputWaiter.mjs
index caa1a098..000940a4 100644
--- a/src/web/waiters/InputWaiter.mjs
+++ b/src/web/waiters/InputWaiter.mjs
@@ -9,7 +9,6 @@ import LoaderWorker from "worker-loader?inline=no-fallback!../workers/LoaderWork
import InputWorker from "worker-loader?inline=no-fallback!../workers/InputWorker.mjs";
import Utils, {debounce} from "../../core/Utils.mjs";
import {toBase64} from "../../core/lib/Base64.mjs";
-import {isImage} from "../../core/lib/FileType.mjs";
import cptable from "codepage";
import {
@@ -21,6 +20,7 @@ import {bracketMatching} from "@codemirror/language";
import {search, searchKeymap, highlightSelectionMatches} from "@codemirror/search";
import {statusBar} from "../utils/statusBar.mjs";
+import {fileDetailsPanel} from "../utils/fileDetails.mjs";
import {renderSpecialChar} from "../utils/editorUtils.mjs";
@@ -65,7 +65,8 @@ class InputWaiter {
initEditor() {
this.inputEditorConf = {
eol: new Compartment,
- lineWrapping: new Compartment
+ lineWrapping: new Compartment,
+ fileDetailsPanel: new Compartment
};
const initialState = EditorState.create({
@@ -92,6 +93,7 @@ class InputWaiter {
}),
// Mutable state
+ this.inputEditorConf.fileDetailsPanel.of([]),
this.inputEditorConf.lineWrapping.of(EditorView.lineWrapping),
this.inputEditorConf.eol.of(EditorState.lineSeparator.of("\n")),
@@ -466,43 +468,32 @@ class InputWaiter {
if (inputNum !== activeTab) return;
if (inputData.file) {
- this.setFile(inputNum, inputData, silent);
+ this.setFile(inputNum, inputData);
} else {
- // TODO Per-tab encodings?
- let inputVal;
- if (this.inputChrEnc > 0) {
- inputVal = cptable.utils.decode(this.inputChrEnc, new Uint8Array(inputData.buffer));
- } else {
- inputVal = Utils.arrayBufferToStr(inputData.buffer);
- }
-
- this.setInput(inputVal);
- 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 = "none";
- fileName.textContent = "";
- fileSize.textContent = "";
- fileType.textContent = "";
- fileLoaded.textContent = "";
-
- this.inputTextEl.classList.remove("blur");
-
- // Set URL to current input
- if (inputVal.length >= 0 && inputVal.length <= 51200) {
- const inputStr = toBase64(inputVal, "A-Za-z0-9+/");
- this.setUrl({
- includeInput: true,
- input: inputStr
- });
- }
-
- if (!silent) window.dispatchEvent(this.manager.statechange);
+ this.clearFile(inputNum);
}
+ // TODO Per-tab encodings?
+ let inputVal;
+ if (this.inputChrEnc > 0) {
+ inputVal = cptable.utils.decode(this.inputChrEnc, new Uint8Array(inputData.buffer));
+ } else {
+ inputVal = Utils.arrayBufferToStr(inputData.buffer);
+ }
+
+ this.setInput(inputVal);
+
+ // Set URL to current input
+ if (inputVal.length >= 0 && inputVal.length <= 51200) {
+ const inputStr = toBase64(inputVal, "A-Za-z0-9+/");
+ this.setUrl({
+ includeInput: true,
+ input: inputStr
+ });
+ }
+
+ if (!silent) window.dispatchEvent(this.manager.statechange);
+
}.bind(this));
}
@@ -520,33 +511,38 @@ class InputWaiter {
* @param {string} file.type
* @param {string} status
* @param {number} progress
- * @param {boolean} [silent=true] - If false, fires the manager statechange event
*/
- setFile(inputNum, inputData, silent=true) {
+ setFile(inputNum, inputData) {
const activeTab = this.manager.tabs.getActiveInputTab();
if (inputNum !== activeTab) return;
- 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");
+ // Create file details panel
+ this.inputEditorView.dispatch({
+ effects: this.inputEditorConf.fileDetailsPanel.reconfigure(
+ fileDetailsPanel({
+ fileDetails: inputData.file,
+ progress: inputData.progress,
+ status: inputData.status,
+ buffer: inputData.buffer,
+ renderPreview: this.app.options.imagePreview
+ })
+ )
+ });
+ }
- fileOverlay.style.display = "block";
- fileName.textContent = inputData.file.name;
- fileSize.textContent = inputData.file.size + " bytes";
- fileType.textContent = inputData.file.type;
- if (inputData.status === "error") {
- fileLoaded.textContent = "Error";
- fileLoaded.style.color = "#FF0000";
- } else {
- fileLoaded.style.color = "";
- fileLoaded.textContent = inputData.progress + "%";
- }
+ /**
+ * Clears the file details panel
+ *
+ * @param {number} inputNum
+ */
+ clearFile(inputNum) {
+ const activeTab = this.manager.tabs.getActiveInputTab();
+ if (inputNum !== activeTab) return;
- this.displayFilePreview(inputNum, inputData);
-
- if (!silent) window.dispatchEvent(this.manager.statechange);
+ // Clear file details panel
+ this.inputEditorView.dispatch({
+ effects: this.inputEditorConf.fileDetailsPanel.reconfigure([])
+ });
}
/**
@@ -571,60 +567,6 @@ class InputWaiter {
this.updateFileProgress(inputNum, 100);
}
- /**
- * Render the input thumbnail
- */
- async renderFileThumb() {
- const activeTab = this.manager.tabs.getActiveInputTab(),
- input = await this.getInputValue(activeTab),
- fileThumb = document.getElementById("input-file-thumbnail");
-
- if (typeof input === "string" ||
- !this.app.options.imagePreview) {
- this.resetFileThumb();
- return;
- }
-
- const inputArr = new Uint8Array(input),
- type = isImage(inputArr);
-
- if (type && type !== "image/tiff" && inputArr.byteLength <= 512000) {
- // Most browsers don't support displaying TIFFs, so ignore them
- // Don't render images over 512000 bytes
- const blob = new Blob([inputArr], {type: type}),
- url = URL.createObjectURL(blob);
- fileThumb.src = url;
- } else {
- this.resetFileThumb();
- }
-
- }
-
- /**
- * Reset the input thumbnail to the default icon
- */
- resetFileThumb() {
- const fileThumb = document.getElementById("input-file-thumbnail");
- fileThumb.src = require("../static/images/file-128x128.png").default;
- }
-
- /**
- * Shows a chunk of the file in the input behind the file overlay
- *
- * @param {number} inputNum - The inputNum of the file being displayed
- * @param {Object} inputData - Object containing the input data
- * @param {string} inputData.stringSample - The first 4096 bytes of input as a string
- */
- displayFilePreview(inputNum, inputData) {
- const activeTab = this.manager.tabs.getActiveInputTab(),
- input = inputData.buffer;
- if (inputNum !== activeTab) return;
- this.inputTextEl.classList.add("blur");
- this.setInput(input.stringSample);
-
- this.renderFileThumb();
- }
-
/**
* Updates the displayed load progress for a file
*
@@ -632,17 +574,19 @@ class InputWaiter {
* @param {number | string} progress - Either a number or "error"
*/
updateFileProgress(inputNum, progress) {
- const activeTab = this.manager.tabs.getActiveInputTab();
- if (inputNum !== activeTab) return;
+ // const activeTab = this.manager.tabs.getActiveInputTab();
+ // if (inputNum !== activeTab) return;
- const fileLoaded = document.getElementById("input-file-loaded");
- if (progress === "error") {
- fileLoaded.textContent = "Error";
- fileLoaded.style.color = "#FF0000";
- } else {
- fileLoaded.textContent = progress + "%";
- fileLoaded.style.color = "";
- }
+ // TODO
+
+ // const fileLoaded = document.getElementById("input-file-loaded");
+ // if (progress === "error") {
+ // fileLoaded.textContent = "Error";
+ // fileLoaded.style.color = "#FF0000";
+ // } else {
+ // fileLoaded.textContent = progress + "%";
+ // fileLoaded.style.color = "";
+ // }
}
/**
@@ -778,10 +722,6 @@ class InputWaiter {
*/
inputChange(e) {
debounce(function(e) {
- // Ignore this function if the input is a file
- const fileOverlay = document.getElementById("input-file");
- if (fileOverlay.style.display === "block") return;
-
const value = this.getInput();
const activeTab = this.manager.tabs.getActiveInputTab();
@@ -806,7 +746,7 @@ class InputWaiter {
e.stopPropagation();
e.preventDefault();
- e.target.closest("#input-text,#input-file").classList.add("dropping-file");
+ e.target.closest("#input-text").classList.add("dropping-file");
}
/**
@@ -821,7 +761,7 @@ class InputWaiter {
// Dragleave often fires when moving between lines in the editor.
// If the target element is within the input-text element, we are still on target.
if (!this.inputTextEl.contains(e.target))
- e.target.closest("#input-text,#input-file").classList.remove("dropping-file");
+ e.target.closest("#input-text").classList.remove("dropping-file");
}
/**
@@ -837,7 +777,7 @@ class InputWaiter {
e.stopPropagation();
e.preventDefault();
- e.target.closest("#input-text,#input-file").classList.remove("dropping-file");
+ e.target.closest("#input-text").classList.remove("dropping-file");
// Dropped text is handled by the editor itself
if (e.dataTransfer.getData("Text")) return;
@@ -1063,23 +1003,6 @@ class InputWaiter {
window.dispatchEvent(this.manager.statechange);
}
- /**
- * Handler for clear IO click event.
- * Resets the input for the current tab
- */
- clearIoClick() {
- const inputNum = this.manager.tabs.getActiveInputTab();
- if (inputNum === -1) return;
-
- this.updateInputValue(inputNum, "", true);
-
- this.set(inputNum, {
- buffer: new ArrayBuffer()
- });
-
- this.manager.tabs.updateInputTabHeader(inputNum, "");
- }
-
/**
* Sets the console log level in the worker.
*