mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-25 01:06:16 -04:00
Output now uses CodeMirror editor
This commit is contained in:
parent
bc949b47d9
commit
68733c74cc
14 changed files with 665 additions and 495 deletions
|
@ -176,34 +176,16 @@ class HighlighterWaiter {
|
|||
this.mouseTarget = OUTPUT;
|
||||
this.removeHighlights();
|
||||
|
||||
const el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
|
||||
this.highlightInput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output HTML mousedown events.
|
||||
* Calculates the current selection info.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputHtmlMousedown(e) {
|
||||
this.mouseButtonDown = true;
|
||||
this.mouseTarget = OUTPUT;
|
||||
|
||||
const sel = this._getOutputHtmlSelectionOffsets();
|
||||
if (sel.start !== 0 || sel.end !== 0) {
|
||||
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input mouseup events.
|
||||
*
|
||||
|
@ -224,16 +206,6 @@ class HighlighterWaiter {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output HTML mouseup events.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputHtmlMouseup(e) {
|
||||
this.mouseButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input mousemove events.
|
||||
* Calculates the current selection info, and highlights the corresponding data in the output.
|
||||
|
@ -270,37 +242,16 @@ class HighlighterWaiter {
|
|||
this.mouseTarget !== OUTPUT)
|
||||
return;
|
||||
|
||||
const el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
|
||||
this.highlightInput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output HTML mousemove events.
|
||||
* Calculates the current selection info.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputHtmlMousemove(e) {
|
||||
// Check that the left mouse button is pressed
|
||||
if (!this.mouseButtonDown ||
|
||||
e.which !== 1 ||
|
||||
this.mouseTarget !== OUTPUT)
|
||||
return;
|
||||
|
||||
const sel = this._getOutputHtmlSelectionOffsets();
|
||||
if (sel.start !== 0 || sel.end !== 0) {
|
||||
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given start and end offsets, writes the HTML for the selection info element with the correct
|
||||
* padding.
|
||||
|
@ -326,7 +277,6 @@ class HighlighterWaiter {
|
|||
removeHighlights() {
|
||||
document.getElementById("input-highlighter").innerHTML = "";
|
||||
document.getElementById("output-highlighter").innerHTML = "";
|
||||
document.getElementById("output-selection-info").innerHTML = "";
|
||||
}
|
||||
|
||||
|
||||
|
@ -379,7 +329,8 @@ class HighlighterWaiter {
|
|||
|
||||
const io = direction === "forward" ? "output" : "input";
|
||||
|
||||
document.getElementById(io + "-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
|
||||
// TODO
|
||||
// document.getElementById(io + "-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
|
||||
this.highlight(
|
||||
document.getElementById(io + "-text"),
|
||||
document.getElementById(io + "-highlighter"),
|
||||
|
@ -398,67 +349,67 @@ class HighlighterWaiter {
|
|||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
async highlight(textarea, highlighter, pos) {
|
||||
if (!this.app.options.showHighlighter) return false;
|
||||
if (!this.app.options.attemptHighlight) return false;
|
||||
// if (!this.app.options.showHighlighter) return false;
|
||||
// if (!this.app.options.attemptHighlight) return false;
|
||||
|
||||
// Check if there is a carriage return in the output dish as this will not
|
||||
// be displayed by the HTML textarea and will mess up highlighting offsets.
|
||||
if (await this.manager.output.containsCR()) return false;
|
||||
// // Check if there is a carriage return in the output dish as this will not
|
||||
// // be displayed by the HTML textarea and will mess up highlighting offsets.
|
||||
// if (await this.manager.output.containsCR()) return false;
|
||||
|
||||
const startPlaceholder = "[startHighlight]";
|
||||
const startPlaceholderRegex = /\[startHighlight\]/g;
|
||||
const endPlaceholder = "[endHighlight]";
|
||||
const endPlaceholderRegex = /\[endHighlight\]/g;
|
||||
let text = textarea.value;
|
||||
// const startPlaceholder = "[startHighlight]";
|
||||
// const startPlaceholderRegex = /\[startHighlight\]/g;
|
||||
// const endPlaceholder = "[endHighlight]";
|
||||
// const endPlaceholderRegex = /\[endHighlight\]/g;
|
||||
// // let text = textarea.value; // TODO
|
||||
|
||||
// Put placeholders in position
|
||||
// If there's only one value, select that
|
||||
// If there are multiple, ignore the first one and select all others
|
||||
if (pos.length === 1) {
|
||||
if (pos[0].end < pos[0].start) return;
|
||||
text = text.slice(0, pos[0].start) +
|
||||
startPlaceholder + text.slice(pos[0].start, pos[0].end) + endPlaceholder +
|
||||
text.slice(pos[0].end, text.length);
|
||||
} else {
|
||||
// O(n^2) - Can anyone improve this without overwriting placeholders?
|
||||
let result = "",
|
||||
endPlaced = true;
|
||||
// // Put placeholders in position
|
||||
// // If there's only one value, select that
|
||||
// // If there are multiple, ignore the first one and select all others
|
||||
// if (pos.length === 1) {
|
||||
// if (pos[0].end < pos[0].start) return;
|
||||
// text = text.slice(0, pos[0].start) +
|
||||
// startPlaceholder + text.slice(pos[0].start, pos[0].end) + endPlaceholder +
|
||||
// text.slice(pos[0].end, text.length);
|
||||
// } else {
|
||||
// // O(n^2) - Can anyone improve this without overwriting placeholders?
|
||||
// let result = "",
|
||||
// endPlaced = true;
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
for (let j = 1; j < pos.length; j++) {
|
||||
if (pos[j].end < pos[j].start) continue;
|
||||
if (pos[j].start === i) {
|
||||
result += startPlaceholder;
|
||||
endPlaced = false;
|
||||
}
|
||||
if (pos[j].end === i) {
|
||||
result += endPlaceholder;
|
||||
endPlaced = true;
|
||||
}
|
||||
}
|
||||
result += text[i];
|
||||
}
|
||||
if (!endPlaced) result += endPlaceholder;
|
||||
text = result;
|
||||
}
|
||||
// for (let i = 0; i < text.length; i++) {
|
||||
// for (let j = 1; j < pos.length; j++) {
|
||||
// if (pos[j].end < pos[j].start) continue;
|
||||
// if (pos[j].start === i) {
|
||||
// result += startPlaceholder;
|
||||
// endPlaced = false;
|
||||
// }
|
||||
// if (pos[j].end === i) {
|
||||
// result += endPlaceholder;
|
||||
// endPlaced = true;
|
||||
// }
|
||||
// }
|
||||
// result += text[i];
|
||||
// }
|
||||
// if (!endPlaced) result += endPlaceholder;
|
||||
// text = result;
|
||||
// }
|
||||
|
||||
const cssClass = "hl1";
|
||||
// const cssClass = "hl1";
|
||||
|
||||
// Remove HTML tags
|
||||
text = text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/\n/g, " ")
|
||||
// Convert placeholders to tags
|
||||
.replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
|
||||
.replace(endPlaceholderRegex, "</span>") + " ";
|
||||
// // Remove HTML tags
|
||||
// text = text
|
||||
// .replace(/&/g, "&")
|
||||
// .replace(/</g, "<")
|
||||
// .replace(/>/g, ">")
|
||||
// .replace(/\n/g, " ")
|
||||
// // Convert placeholders to tags
|
||||
// .replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
|
||||
// .replace(endPlaceholderRegex, "</span>") + " ";
|
||||
|
||||
// Adjust width to allow for scrollbars
|
||||
highlighter.style.width = textarea.clientWidth + "px";
|
||||
highlighter.innerHTML = text;
|
||||
highlighter.scrollTop = textarea.scrollTop;
|
||||
highlighter.scrollLeft = textarea.scrollLeft;
|
||||
// // Adjust width to allow for scrollbars
|
||||
// highlighter.style.width = textarea.clientWidth + "px";
|
||||
// highlighter.innerHTML = text;
|
||||
// highlighter.scrollTop = textarea.scrollTop;
|
||||
// highlighter.scrollLeft = textarea.scrollLeft;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ import {defaultKeymap, insertTab, insertNewline, history, historyKeymap} from "@
|
|||
import {bracketMatching} from "@codemirror/language";
|
||||
import {search, searchKeymap, highlightSelectionMatches} from "@codemirror/search";
|
||||
|
||||
import {statusBar} from "../extensions/statusBar.mjs";
|
||||
import {statusBar} from "../utils/statusBar.mjs";
|
||||
import {renderSpecialChar} from "../utils/editorUtils.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -87,14 +88,17 @@ class InputWaiter {
|
|||
doc: null,
|
||||
extensions: [
|
||||
history(),
|
||||
highlightSpecialChars({render: this.renderSpecialChar}),
|
||||
highlightSpecialChars({render: renderSpecialChar}),
|
||||
drawSelection(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
bracketMatching(),
|
||||
highlightSelectionMatches(),
|
||||
search({top: true}),
|
||||
statusBar(this.inputEditorConf),
|
||||
statusBar({
|
||||
label: "Input",
|
||||
eolHandler: this.eolChange.bind(this)
|
||||
}),
|
||||
this.inputEditorConf.lineWrapping.of(EditorView.lineWrapping),
|
||||
this.inputEditorConf.eol.of(EditorState.lineSeparator.of("\n")),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
@ -118,44 +122,10 @@ class InputWaiter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Override for rendering special characters.
|
||||
* Should mirror the toDOM function in
|
||||
* https://github.com/codemirror/view/blob/main/src/special-chars.ts#L150
|
||||
* But reverts the replacement of line feeds with newline control pictures.
|
||||
* @param {number} code
|
||||
* @param {string} desc
|
||||
* @param {string} placeholder
|
||||
* @returns {element}
|
||||
*/
|
||||
renderSpecialChar(code, desc, placeholder) {
|
||||
const s = document.createElement("span");
|
||||
// CodeMirror changes 0x0a to "NL" instead of "LF". We change it back.
|
||||
s.textContent = code === 0x0a ? "\u240a" : placeholder;
|
||||
s.title = desc;
|
||||
s.setAttribute("aria-label", desc);
|
||||
s.className = "cm-specialChar";
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for EOL Select clicks
|
||||
* Handler for EOL change events
|
||||
* Sets the line separator
|
||||
* @param {Event} e
|
||||
*/
|
||||
eolSelectClick(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const eolLookup = {
|
||||
"LF": "\u000a",
|
||||
"VT": "\u000b",
|
||||
"FF": "\u000c",
|
||||
"CR": "\u000d",
|
||||
"CRLF": "\u000d\u000a",
|
||||
"NEL": "\u0085",
|
||||
"LS": "\u2028",
|
||||
"PS": "\u2029"
|
||||
};
|
||||
const eolval = eolLookup[e.target.getAttribute("data-val")];
|
||||
eolChange(eolval) {
|
||||
const oldInputVal = this.getInput();
|
||||
|
||||
// Update the EOL value
|
||||
|
|
|
@ -140,14 +140,11 @@ class OptionsWaiter {
|
|||
*/
|
||||
setWordWrap() {
|
||||
this.manager.input.setWordWrap(this.app.options.wordWrap);
|
||||
document.getElementById("output-text").classList.remove("word-wrap");
|
||||
document.getElementById("output-html").classList.remove("word-wrap");
|
||||
this.manager.output.setWordWrap(this.app.options.wordWrap);
|
||||
document.getElementById("input-highlighter").classList.remove("word-wrap");
|
||||
document.getElementById("output-highlighter").classList.remove("word-wrap");
|
||||
|
||||
if (!this.app.options.wordWrap) {
|
||||
document.getElementById("output-text").classList.add("word-wrap");
|
||||
document.getElementById("output-html").classList.add("word-wrap");
|
||||
document.getElementById("input-highlighter").classList.add("word-wrap");
|
||||
document.getElementById("output-highlighter").classList.add("word-wrap");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,18 @@ import Dish from "../../core/Dish.mjs";
|
|||
import FileSaver from "file-saver";
|
||||
import ZipWorker from "worker-loader?inline=no-fallback!../workers/ZipWorker.mjs";
|
||||
|
||||
import {
|
||||
EditorView, keymap, highlightSpecialChars, drawSelection, rectangularSelection, crosshairCursor
|
||||
} from "@codemirror/view";
|
||||
import {EditorState, Compartment} from "@codemirror/state";
|
||||
import {defaultKeymap} from "@codemirror/commands";
|
||||
import {bracketMatching} from "@codemirror/language";
|
||||
import {search, searchKeymap, highlightSelectionMatches} from "@codemirror/search";
|
||||
|
||||
import {statusBar} from "../utils/statusBar.mjs";
|
||||
import {renderSpecialChar} from "../utils/editorUtils.mjs";
|
||||
import {htmlPlugin} from "../utils/htmlWidget.mjs";
|
||||
|
||||
/**
|
||||
* Waiter to handle events related to the output
|
||||
*/
|
||||
|
@ -25,12 +37,155 @@ class OutputWaiter {
|
|||
this.app = app;
|
||||
this.manager = manager;
|
||||
|
||||
this.outputTextEl = document.getElementById("output-text");
|
||||
// Object to contain bake statistics - used by statusBar extension
|
||||
this.bakeStats = {
|
||||
duration: 0
|
||||
};
|
||||
// Object to handle output HTML state - used by htmlWidget extension
|
||||
this.htmlOutput = {
|
||||
html: "",
|
||||
changed: false
|
||||
};
|
||||
this.initEditor();
|
||||
|
||||
this.outputs = {};
|
||||
this.zipWorker = null;
|
||||
this.maxTabs = this.manager.tabs.calcMaxTabs();
|
||||
this.tabTimeout = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the CodeMirror Editor and returns the view
|
||||
*/
|
||||
initEditor() {
|
||||
this.outputEditorConf = {
|
||||
eol: new Compartment,
|
||||
lineWrapping: new Compartment
|
||||
};
|
||||
|
||||
const initialState = EditorState.create({
|
||||
doc: null,
|
||||
extensions: [
|
||||
EditorState.readOnly.of(true),
|
||||
htmlPlugin(this.htmlOutput),
|
||||
highlightSpecialChars({render: renderSpecialChar}),
|
||||
drawSelection(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
bracketMatching(),
|
||||
highlightSelectionMatches(),
|
||||
search({top: true}),
|
||||
statusBar({
|
||||
label: "Output",
|
||||
bakeStats: this.bakeStats,
|
||||
eolHandler: this.eolChange.bind(this)
|
||||
}),
|
||||
this.outputEditorConf.lineWrapping.of(EditorView.lineWrapping),
|
||||
this.outputEditorConf.eol.of(EditorState.lineSeparator.of("\n")),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
keymap.of([
|
||||
...defaultKeymap,
|
||||
...searchKeymap
|
||||
]),
|
||||
]
|
||||
});
|
||||
|
||||
this.outputEditorView = new EditorView({
|
||||
state: initialState,
|
||||
parent: this.outputTextEl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for EOL change events
|
||||
* Sets the line separator
|
||||
*/
|
||||
eolChange(eolval) {
|
||||
const oldOutputVal = this.getOutput();
|
||||
|
||||
// Update the EOL value
|
||||
this.outputEditorView.dispatch({
|
||||
effects: this.outputEditorConf.eol.reconfigure(EditorState.lineSeparator.of(eolval))
|
||||
});
|
||||
|
||||
// Reset the output so that lines are recalculated, preserving the old EOL values
|
||||
this.setOutput(oldOutputVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets word wrap on the output editor
|
||||
* @param {boolean} wrap
|
||||
*/
|
||||
setWordWrap(wrap) {
|
||||
this.outputEditorView.dispatch({
|
||||
effects: this.outputEditorConf.lineWrapping.reconfigure(
|
||||
wrap ? EditorView.lineWrapping : []
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the current output
|
||||
* @returns {string}
|
||||
*/
|
||||
getOutput() {
|
||||
const doc = this.outputEditorView.state.doc;
|
||||
const eol = this.outputEditorView.state.lineBreak;
|
||||
return doc.sliceString(0, doc.length, eol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the current output
|
||||
* @param {string} data
|
||||
*/
|
||||
setOutput(data) {
|
||||
this.outputEditorView.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: this.outputEditorView.state.doc.length,
|
||||
insert: data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the current output to a rendered HTML value
|
||||
* @param {string} html
|
||||
*/
|
||||
setHTMLOutput(html) {
|
||||
this.htmlOutput.html = html;
|
||||
this.htmlOutput.changed = true;
|
||||
// This clears the text output, but also fires a View update which
|
||||
// triggers the htmlWidget to render the HTML.
|
||||
this.setOutput("");
|
||||
|
||||
// Execute script sections
|
||||
const scriptElements = document.getElementById("output-html").querySelectorAll("script");
|
||||
for (let i = 0; i < scriptElements.length; i++) {
|
||||
try {
|
||||
eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the HTML output
|
||||
*/
|
||||
clearHTMLOutput() {
|
||||
this.htmlOutput.html = "";
|
||||
this.htmlOutput.changed = true;
|
||||
// Fire a blank change to force the htmlWidget to update and remove any HTML
|
||||
this.outputEditorView.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
insert: ""
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the maximum number of tabs to display
|
||||
*/
|
||||
|
@ -245,8 +400,6 @@ class OutputWaiter {
|
|||
activeTab = this.manager.tabs.getActiveOutputTab();
|
||||
if (typeof inputNum !== "number") inputNum = parseInt(inputNum, 10);
|
||||
|
||||
const outputText = document.getElementById("output-text");
|
||||
const outputHtml = document.getElementById("output-html");
|
||||
const outputFile = document.getElementById("output-file");
|
||||
const outputHighlighter = document.getElementById("output-highlighter");
|
||||
const inputHighlighter = document.getElementById("input-highlighter");
|
||||
|
@ -278,95 +431,68 @@ class OutputWaiter {
|
|||
} else if (output.status === "error") {
|
||||
// style the tab if it's being shown
|
||||
this.toggleLoader(false);
|
||||
outputText.style.display = "block";
|
||||
outputText.classList.remove("blur");
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
this.outputTextEl.classList.remove("blur");
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.display = "none";
|
||||
inputHighlighter.display = "none";
|
||||
this.clearHTMLOutput();
|
||||
|
||||
if (output.error) {
|
||||
outputText.value = output.error;
|
||||
this.setOutput(output.error);
|
||||
} else {
|
||||
outputText.value = output.data.result;
|
||||
this.setOutput(output.data.result);
|
||||
}
|
||||
outputHtml.innerHTML = "";
|
||||
} else if (output.status === "baked" || output.status === "inactive") {
|
||||
document.querySelector("#output-loader .loading-msg").textContent = `Loading output ${inputNum}`;
|
||||
this.closeFile();
|
||||
let scriptElements, lines, length;
|
||||
|
||||
if (output.data === null) {
|
||||
outputText.style.display = "block";
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.display = "block";
|
||||
inputHighlighter.display = "block";
|
||||
|
||||
outputText.value = "";
|
||||
outputHtml.innerHTML = "";
|
||||
this.clearHTMLOutput();
|
||||
this.setOutput("");
|
||||
|
||||
this.toggleLoader(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.bakeStats.duration = output.data.duration;
|
||||
|
||||
switch (output.data.type) {
|
||||
case "html":
|
||||
outputText.style.display = "none";
|
||||
outputHtml.style.display = "block";
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.style.display = "none";
|
||||
inputHighlighter.style.display = "none";
|
||||
|
||||
outputText.value = "";
|
||||
outputHtml.innerHTML = output.data.result;
|
||||
|
||||
// Execute script sections
|
||||
scriptElements = outputHtml.querySelectorAll("script");
|
||||
for (let i = 0; i < scriptElements.length; i++) {
|
||||
try {
|
||||
eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
}
|
||||
}
|
||||
this.setHTMLOutput(output.data.result);
|
||||
break;
|
||||
case "ArrayBuffer":
|
||||
outputText.style.display = "block";
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
outputHighlighter.display = "none";
|
||||
inputHighlighter.display = "none";
|
||||
|
||||
outputText.value = "";
|
||||
outputHtml.innerHTML = "";
|
||||
this.clearHTMLOutput();
|
||||
this.setOutput("");
|
||||
|
||||
length = output.data.result.byteLength;
|
||||
this.setFile(await this.getDishBuffer(output.data.dish), activeTab);
|
||||
break;
|
||||
case "string":
|
||||
default:
|
||||
outputText.style.display = "block";
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.display = "block";
|
||||
inputHighlighter.display = "block";
|
||||
|
||||
outputText.value = Utils.printable(output.data.result, true);
|
||||
outputHtml.innerHTML = "";
|
||||
|
||||
lines = output.data.result.count("\n") + 1;
|
||||
length = output.data.result.length;
|
||||
this.clearHTMLOutput();
|
||||
this.setOutput(output.data.result);
|
||||
break;
|
||||
}
|
||||
this.toggleLoader(false);
|
||||
|
||||
if (output.data.type === "html") {
|
||||
const dishStr = await this.getDishStr(output.data.dish);
|
||||
length = dishStr.length;
|
||||
lines = dishStr.count("\n") + 1;
|
||||
}
|
||||
|
||||
this.setOutputInfo(length, lines, output.data.duration);
|
||||
debounce(this.backgroundMagic, 50, "backgroundMagic", this, [])();
|
||||
}
|
||||
}.bind(this));
|
||||
|
@ -383,14 +509,13 @@ class OutputWaiter {
|
|||
// Display file overlay in output area with details
|
||||
const fileOverlay = document.getElementById("output-file"),
|
||||
fileSize = document.getElementById("output-file-size"),
|
||||
outputText = document.getElementById("output-text"),
|
||||
fileSlice = buf.slice(0, 4096);
|
||||
|
||||
fileOverlay.style.display = "block";
|
||||
fileSize.textContent = buf.byteLength.toLocaleString() + " bytes";
|
||||
|
||||
outputText.classList.add("blur");
|
||||
outputText.value = Utils.printable(Utils.arrayBufferToStr(fileSlice));
|
||||
this.outputTextEl.classList.add("blur");
|
||||
this.setOutput(Utils.arrayBufferToStr(fileSlice));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,7 +523,7 @@ class OutputWaiter {
|
|||
*/
|
||||
closeFile() {
|
||||
document.getElementById("output-file").style.display = "none";
|
||||
document.getElementById("output-text").classList.remove("blur");
|
||||
this.outputTextEl.classList.remove("blur");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -466,7 +591,6 @@ class OutputWaiter {
|
|||
clearTimeout(this.outputLoaderTimeout);
|
||||
|
||||
const outputLoader = document.getElementById("output-loader"),
|
||||
outputElement = document.getElementById("output-text"),
|
||||
animation = document.getElementById("output-loader-animation");
|
||||
|
||||
if (value) {
|
||||
|
@ -483,7 +607,6 @@ class OutputWaiter {
|
|||
|
||||
// Show the loading screen
|
||||
this.outputLoaderTimeout = setTimeout(function() {
|
||||
outputElement.disabled = true;
|
||||
outputLoader.style.visibility = "visible";
|
||||
outputLoader.style.opacity = 1;
|
||||
}, 200);
|
||||
|
@ -494,7 +617,6 @@ class OutputWaiter {
|
|||
animation.removeChild(this.bombeEl);
|
||||
} catch (err) {}
|
||||
}.bind(this), 500);
|
||||
outputElement.disabled = false;
|
||||
outputLoader.style.opacity = 0;
|
||||
outputLoader.style.visibility = "hidden";
|
||||
}
|
||||
|
@ -717,8 +839,7 @@ class OutputWaiter {
|
|||
|
||||
debounce(this.set, 50, "setOutput", this, [inputNum])();
|
||||
|
||||
document.getElementById("output-html").scroll(0, 0);
|
||||
document.getElementById("output-text").scroll(0, 0);
|
||||
this.outputTextEl.scroll(0, 0); // TODO
|
||||
|
||||
if (changeInput) {
|
||||
this.manager.input.changeTab(inputNum, false);
|
||||
|
@ -996,32 +1117,6 @@ class OutputWaiter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information about the output.
|
||||
*
|
||||
* @param {number} length - The length of the current output string
|
||||
* @param {number} lines - The number of the lines in the current output string
|
||||
* @param {number} duration - The length of time (ms) it took to generate the output
|
||||
*/
|
||||
setOutputInfo(length, lines, duration) {
|
||||
if (!length) return;
|
||||
let width = length.toString().length;
|
||||
width = width < 4 ? 4 : width;
|
||||
|
||||
const lengthStr = length.toString().padStart(width, " ").replace(/ /g, " ");
|
||||
const timeStr = (duration.toString() + "ms").padStart(width, " ").replace(/ /g, " ");
|
||||
|
||||
let msg = "time: " + timeStr + "<br>length: " + lengthStr;
|
||||
|
||||
if (typeof lines === "number") {
|
||||
const linesStr = lines.toString().padStart(width, " ").replace(/ /g, " ");
|
||||
msg += "<br>lines: " + linesStr;
|
||||
}
|
||||
|
||||
document.getElementById("output-info").innerHTML = msg;
|
||||
document.getElementById("output-selection-info").innerHTML = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the BackgroundWorker to attempt Magic on the current output.
|
||||
*/
|
||||
|
@ -1111,9 +1206,7 @@ class OutputWaiter {
|
|||
async displayFileSlice() {
|
||||
document.querySelector("#output-loader .loading-msg").textContent = "Loading file slice...";
|
||||
this.toggleLoader(true);
|
||||
const outputText = document.getElementById("output-text"),
|
||||
outputHtml = document.getElementById("output-html"),
|
||||
outputFile = document.getElementById("output-file"),
|
||||
const outputFile = document.getElementById("output-file"),
|
||||
outputHighlighter = document.getElementById("output-highlighter"),
|
||||
inputHighlighter = document.getElementById("input-highlighter"),
|
||||
showFileOverlay = document.getElementById("show-file-overlay"),
|
||||
|
@ -1130,12 +1223,12 @@ class OutputWaiter {
|
|||
str = Utils.arrayBufferToStr(await this.getDishBuffer(output.dish).slice(sliceFrom, sliceTo));
|
||||
}
|
||||
|
||||
outputText.classList.remove("blur");
|
||||
this.outputTextEl.classList.remove("blur");
|
||||
showFileOverlay.style.display = "block";
|
||||
outputText.value = Utils.printable(str, true);
|
||||
this.clearHTMLOutput();
|
||||
this.setOutput(str);
|
||||
|
||||
outputText.style.display = "block";
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.display = "block";
|
||||
inputHighlighter.display = "block";
|
||||
|
@ -1149,9 +1242,7 @@ class OutputWaiter {
|
|||
async showAllFile() {
|
||||
document.querySelector("#output-loader .loading-msg").textContent = "Loading entire file at user instruction. This may cause a crash...";
|
||||
this.toggleLoader(true);
|
||||
const outputText = document.getElementById("output-text"),
|
||||
outputHtml = document.getElementById("output-html"),
|
||||
outputFile = document.getElementById("output-file"),
|
||||
const outputFile = document.getElementById("output-file"),
|
||||
outputHighlighter = document.getElementById("output-highlighter"),
|
||||
inputHighlighter = document.getElementById("input-highlighter"),
|
||||
showFileOverlay = document.getElementById("show-file-overlay"),
|
||||
|
@ -1164,12 +1255,12 @@ class OutputWaiter {
|
|||
str = Utils.arrayBufferToStr(await this.getDishBuffer(output.dish));
|
||||
}
|
||||
|
||||
outputText.classList.remove("blur");
|
||||
this.outputTextEl.classList.remove("blur");
|
||||
showFileOverlay.style.display = "none";
|
||||
outputText.value = Utils.printable(str, true);
|
||||
this.clearHTMLOutput();
|
||||
this.setOutput(str);
|
||||
|
||||
outputText.style.display = "block";
|
||||
outputHtml.style.display = "none";
|
||||
this.outputTextEl.style.display = "block";
|
||||
outputFile.style.display = "none";
|
||||
outputHighlighter.display = "block";
|
||||
inputHighlighter.display = "block";
|
||||
|
@ -1185,7 +1276,7 @@ class OutputWaiter {
|
|||
showFileOverlayClick(e) {
|
||||
const showFileOverlay = e.target;
|
||||
|
||||
document.getElementById("output-text").classList.add("blur");
|
||||
this.outputTextEl.classList.add("blur");
|
||||
showFileOverlay.style.display = "none";
|
||||
this.set(this.manager.tabs.getActiveOutputTab());
|
||||
}
|
||||
|
@ -1212,7 +1303,7 @@ class OutputWaiter {
|
|||
* Handler for copy click events.
|
||||
* Copies the output to the clipboard
|
||||
*/
|
||||
async copyClick() {
|
||||
async copyClick() { // TODO - do we need this?
|
||||
const dish = this.getOutputDish(this.manager.tabs.getActiveOutputTab());
|
||||
if (dish === null) {
|
||||
this.app.alert("Could not find data to copy. Has this output been baked yet?", 3000);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue