mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-02 06:01:02 +01:00
Overhauled Highlighting to work with new editor and support multiple selections
This commit is contained in:
parent
2785459257
commit
890f645eeb
@ -186,7 +186,7 @@ async function getDishTitle(data) {
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {string} direction
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {Object[]} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
|
@ -76,7 +76,7 @@ class ToHex extends Operation {
|
||||
}
|
||||
|
||||
const lineSize = args[1],
|
||||
len = (delim === "\r\n" ? 1 : delim.length) + commaLen;
|
||||
len = delim.length + commaLen;
|
||||
|
||||
const countLF = function(p) {
|
||||
// Count the number of LFs from 0 upto p
|
||||
@ -105,7 +105,7 @@ class ToHex extends Operation {
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
let delim, commaLen;
|
||||
let delim, commaLen = 0;
|
||||
if (args[0] === "0x with comma") {
|
||||
delim = "0x";
|
||||
commaLen = 1;
|
||||
@ -114,7 +114,7 @@ class ToHex extends Operation {
|
||||
}
|
||||
|
||||
const lineSize = args[1],
|
||||
len = (delim === "\r\n" ? 1 : delim.length) + commaLen,
|
||||
len = delim.length + commaLen,
|
||||
width = len + 2;
|
||||
|
||||
const countLF = function(p) {
|
||||
|
@ -153,10 +153,6 @@ class Manager {
|
||||
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.addInputClick.bind(this.input));
|
||||
document.getElementById("btn-previous-input-tab").addEventListener("mousedown", this.input.previousTabClick.bind(this.input));
|
||||
@ -188,10 +184,6 @@ class Manager {
|
||||
document.getElementById("undo-switch").addEventListener("click", this.output.undoSwitchClick.bind(this.output));
|
||||
document.getElementById("maximise-output").addEventListener("click", this.output.maximiseOutputClick.bind(this.output));
|
||||
document.getElementById("magic").addEventListener("click", this.output.magicClick.bind(this.output));
|
||||
document.getElementById("output-text").addEventListener("scroll", this.highlighter.outputScroll.bind(this.highlighter));
|
||||
document.getElementById("output-text").addEventListener("mouseup", this.highlighter.outputMouseup.bind(this.highlighter));
|
||||
document.getElementById("output-text").addEventListener("mousemove", this.highlighter.outputMousemove.bind(this.highlighter));
|
||||
this.addMultiEventListener("#output-text", "mousedown dblclick select", this.highlighter.outputMousedown, this.highlighter);
|
||||
this.addDynamicListener("#output-file-download", "click", this.output.downloadFile, this.output);
|
||||
this.addDynamicListener("#output-file-show-all", "click", this.output.showAllFile, this.output);
|
||||
this.addDynamicListener("#output-file-slice i", "click", this.output.displayFileSlice, this.output);
|
||||
|
@ -4,17 +4,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* HighlighterWaiter data type enum for the input.
|
||||
* @enum
|
||||
*/
|
||||
const INPUT = 0;
|
||||
|
||||
/**
|
||||
* HighlighterWaiter data type enum for the output.
|
||||
* @enum
|
||||
*/
|
||||
const OUTPUT = 1;
|
||||
import {EditorSelection} from "@codemirror/state";
|
||||
|
||||
|
||||
/**
|
||||
@ -32,309 +22,81 @@ class HighlighterWaiter {
|
||||
this.app = app;
|
||||
this.manager = manager;
|
||||
|
||||
this.mouseButtonDown = false;
|
||||
this.mouseTarget = null;
|
||||
this.currentSelectionRanges = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the current text selection is running backwards or forwards.
|
||||
* StackOverflow answer id: 12652116
|
||||
* Handler for selection change events in the input and output
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isSelectionBackwards() {
|
||||
let backwards = false;
|
||||
const sel = window.getSelection();
|
||||
|
||||
if (!sel.isCollapsed) {
|
||||
const range = document.createRange();
|
||||
range.setStart(sel.anchorNode, sel.anchorOffset);
|
||||
range.setEnd(sel.focusNode, sel.focusOffset);
|
||||
backwards = range.collapsed;
|
||||
range.detach();
|
||||
}
|
||||
return backwards;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the text offset of a position in an HTML element, ignoring HTML tags.
|
||||
*
|
||||
* @private
|
||||
* @param {element} node - The parent HTML node.
|
||||
* @param {number} offset - The offset since the last HTML element.
|
||||
* @returns {number}
|
||||
*/
|
||||
_getOutputHtmlOffset(node, offset) {
|
||||
const sel = window.getSelection();
|
||||
const range = document.createRange();
|
||||
|
||||
range.selectNodeContents(document.getElementById("output-html"));
|
||||
range.setEnd(node, offset);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
return sel.toString().length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current selection offsets in the output HTML, ignoring HTML tags.
|
||||
*
|
||||
* @private
|
||||
* @returns {Object} pos
|
||||
* @returns {number} pos.start
|
||||
* @returns {number} pos.end
|
||||
*/
|
||||
_getOutputHtmlSelectionOffsets() {
|
||||
const sel = window.getSelection();
|
||||
let range,
|
||||
start = 0,
|
||||
end = 0,
|
||||
backwards = false;
|
||||
|
||||
if (sel.rangeCount) {
|
||||
range = sel.getRangeAt(sel.rangeCount - 1);
|
||||
backwards = this._isSelectionBackwards();
|
||||
start = this._getOutputHtmlOffset(range.startContainer, range.startOffset);
|
||||
end = this._getOutputHtmlOffset(range.endContainer, range.endOffset);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
if (backwards) {
|
||||
// If selecting backwards, reverse the start and end offsets for the selection to
|
||||
// prevent deselecting as the drag continues.
|
||||
sel.collapseToEnd();
|
||||
sel.extend(sel.anchorNode, range.startOffset);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
start: start,
|
||||
end: end
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input scroll events.
|
||||
* Scrolls the highlighter pane to match the input textarea position.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputScroll(e) {
|
||||
const el = e.target;
|
||||
document.getElementById("input-highlighter").scrollTop = el.scrollTop;
|
||||
document.getElementById("input-highlighter").scrollLeft = el.scrollLeft;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output scroll events.
|
||||
* Scrolls the highlighter pane to match the output textarea position.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputScroll(e) {
|
||||
const el = e.target;
|
||||
document.getElementById("output-highlighter").scrollTop = el.scrollTop;
|
||||
document.getElementById("output-highlighter").scrollLeft = el.scrollLeft;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input mousedown events.
|
||||
* Calculates the current selection info, and highlights the corresponding data in the output.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputMousedown(e) {
|
||||
this.mouseButtonDown = true;
|
||||
this.mouseTarget = INPUT;
|
||||
this.removeHighlights();
|
||||
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
this.highlightOutput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output mousedown events.
|
||||
* Calculates the current selection info, and highlights the corresponding data in the input.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputMousedown(e) {
|
||||
this.mouseButtonDown = true;
|
||||
this.mouseTarget = OUTPUT;
|
||||
this.removeHighlights();
|
||||
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
this.highlightInput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input mouseup events.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputMouseup(e) {
|
||||
this.mouseButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output mouseup events.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputMouseup(e) {
|
||||
this.mouseButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for input mousemove events.
|
||||
* Calculates the current selection info, and highlights the corresponding data in the output.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputMousemove(e) {
|
||||
// Check that the left mouse button is pressed
|
||||
if (!this.mouseButtonDown ||
|
||||
e.which !== 1 ||
|
||||
this.mouseTarget !== INPUT)
|
||||
return;
|
||||
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
this.highlightOutput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output mousemove events.
|
||||
* Calculates the current selection info, and highlights the corresponding data in the input.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputMousemove(e) {
|
||||
// Check that the left mouse button is pressed
|
||||
if (!this.mouseButtonDown ||
|
||||
e.which !== 1 ||
|
||||
this.mouseTarget !== OUTPUT)
|
||||
return;
|
||||
|
||||
const sel = document.getSelection();
|
||||
const start = sel.baseOffset;
|
||||
const end = sel.extentOffset;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
this.highlightInput([{start: start, end: end}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given start and end offsets, writes the HTML for the selection info element with the correct
|
||||
* padding.
|
||||
*
|
||||
* @param {number} start - The start offset.
|
||||
* @param {number} end - The end offset.
|
||||
* @returns {string}
|
||||
*/
|
||||
selectionInfo(start, end) {
|
||||
const len = end.toString().length;
|
||||
const width = len < 2 ? 2 : len;
|
||||
const startStr = start.toString().padStart(width, " ").replace(/ /g, " ");
|
||||
const endStr = end.toString().padStart(width, " ").replace(/ /g, " ");
|
||||
const lenStr = (end-start).toString().padStart(width, " ").replace(/ /g, " ");
|
||||
|
||||
return "start: " + startStr + "<br>end: " + endStr + "<br>length: " + lenStr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes highlighting and selection information.
|
||||
*/
|
||||
removeHighlights() {
|
||||
document.getElementById("input-highlighter").innerHTML = "";
|
||||
document.getElementById("output-highlighter").innerHTML = "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Highlights the given offsets in the output.
|
||||
* Highlights the given offsets in the input or output.
|
||||
* We will only highlight if:
|
||||
* - input hasn't changed since last bake
|
||||
* - last bake was a full bake
|
||||
* - all operations in the recipe support highlighting
|
||||
*
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* @param {string} io
|
||||
* @param {ViewUpdate} e
|
||||
*/
|
||||
highlightOutput(pos) {
|
||||
selectionChange(io, e) {
|
||||
// Confirm we are not currently baking
|
||||
if (!this.app.autoBake_ || this.app.baking) return false;
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), "forward", pos);
|
||||
|
||||
// Confirm this was a user-generated event to prevent looping
|
||||
// from setting the selection in this class
|
||||
if (!e.transactions[0].isUserEvent("select")) return false;
|
||||
|
||||
const view = io === "input" ?
|
||||
this.manager.output.outputEditorView :
|
||||
this.manager.input.inputEditorView;
|
||||
|
||||
this.currentSelectionRanges = [];
|
||||
|
||||
// Confirm some non-empty ranges are set
|
||||
const selectionRanges = e.state.selection.ranges.filter(r => !r.empty);
|
||||
if (!selectionRanges.length) {
|
||||
this.resetSelections(view);
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through ranges and send request for output offsets for each one
|
||||
const direction = io === "input" ? "forward" : "reverse";
|
||||
for (const range of selectionRanges) {
|
||||
const pos = [{
|
||||
start: range.from,
|
||||
end: range.to
|
||||
}];
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), direction, pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Highlights the given offsets in the input.
|
||||
* We will only highlight if:
|
||||
* - input hasn't changed since last bake
|
||||
* - last bake was a full bake
|
||||
* - all operations in the recipe support highlighting
|
||||
*
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* Resets the current set of selections in the given view
|
||||
* @param {EditorView} view
|
||||
*/
|
||||
highlightInput(pos) {
|
||||
if (!this.app.autoBake_ || this.app.baking) return false;
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), "reverse", pos);
|
||||
resetSelections(view) {
|
||||
this.currentSelectionRanges = [];
|
||||
|
||||
// Clear current selection in output or input
|
||||
view.dispatch({
|
||||
selection: EditorSelection.create([EditorSelection.range(0, 0)])
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays highlight offsets sent back from the Chef.
|
||||
*
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {Object[]} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* @param {string} direction
|
||||
*/
|
||||
displayHighlights(pos, direction) {
|
||||
if (!pos) return;
|
||||
|
||||
if (this.manager.tabs.getActiveInputTab() !== this.manager.tabs.getActiveOutputTab()) return;
|
||||
|
||||
const io = direction === "forward" ? "output" : "input";
|
||||
|
||||
// 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"),
|
||||
pos);
|
||||
this.highlight(io, pos);
|
||||
}
|
||||
|
||||
|
||||
@ -342,74 +104,35 @@ class HighlighterWaiter {
|
||||
* Adds the relevant HTML to the specified highlight element such that highlighting appears
|
||||
* underneath the correct offset.
|
||||
*
|
||||
* @param {element} textarea - The input or output textarea.
|
||||
* @param {element} highlighter - The input or output highlighter element.
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* @param {string} io - The input or output
|
||||
* @param {Object[]} ranges - An array of position objects to highlight
|
||||
* @param {number} ranges.start - The start offset
|
||||
* @param {number} ranges.end - The end offset
|
||||
*/
|
||||
async highlight(textarea, highlighter, pos) {
|
||||
// if (!this.app.options.showHighlighter) return false;
|
||||
// if (!this.app.options.attemptHighlight) return false;
|
||||
async highlight(io, ranges) {
|
||||
if (!this.app.options.showHighlighter) return false;
|
||||
if (!this.app.options.attemptHighlight) return false;
|
||||
if (!ranges || !ranges.length) 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 view = io === "input" ?
|
||||
this.manager.input.inputEditorView :
|
||||
this.manager.output.outputEditorView;
|
||||
|
||||
// const startPlaceholder = "[startHighlight]";
|
||||
// const startPlaceholderRegex = /\[startHighlight\]/g;
|
||||
// const endPlaceholder = "[endHighlight]";
|
||||
// const endPlaceholderRegex = /\[endHighlight\]/g;
|
||||
// // let text = textarea.value; // TODO
|
||||
// Add new SelectionRanges to existing ones
|
||||
for (const range of ranges) {
|
||||
if (!range.start || !range.end) continue;
|
||||
this.currentSelectionRanges.push(
|
||||
EditorSelection.range(range.start, range.end)
|
||||
);
|
||||
}
|
||||
|
||||
// // 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;
|
||||
// }
|
||||
|
||||
// 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>") + " ";
|
||||
|
||||
// // Adjust width to allow for scrollbars
|
||||
// highlighter.style.width = textarea.clientWidth + "px";
|
||||
// highlighter.innerHTML = text;
|
||||
// highlighter.scrollTop = textarea.scrollTop;
|
||||
// highlighter.scrollLeft = textarea.scrollLeft;
|
||||
// Set selection
|
||||
if (this.currentSelectionRanges.length) {
|
||||
view.dispatch({
|
||||
selection: EditorSelection.create(this.currentSelectionRanges),
|
||||
scrollIntoView: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ class InputWaiter {
|
||||
const initialState = EditorState.create({
|
||||
doc: null,
|
||||
extensions: [
|
||||
// Editor extensions
|
||||
history(),
|
||||
highlightSpecialChars({render: renderSpecialChar}),
|
||||
drawSelection(),
|
||||
@ -95,13 +96,19 @@ class InputWaiter {
|
||||
bracketMatching(),
|
||||
highlightSelectionMatches(),
|
||||
search({top: true}),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
// Custom extensions
|
||||
statusBar({
|
||||
label: "Input",
|
||||
eolHandler: this.eolChange.bind(this)
|
||||
}),
|
||||
|
||||
// Mutable state
|
||||
this.inputEditorConf.lineWrapping.of(EditorView.lineWrapping),
|
||||
this.inputEditorConf.eol.of(EditorState.lineSeparator.of("\n")),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
// Keymap
|
||||
keymap.of([
|
||||
// Explicitly insert a tab rather than indenting the line
|
||||
{ key: "Tab", run: insertTab },
|
||||
@ -112,6 +119,12 @@ class InputWaiter {
|
||||
...defaultKeymap,
|
||||
...searchKeymap
|
||||
]),
|
||||
|
||||
// Event listeners
|
||||
EditorView.updateListener.of(e => {
|
||||
if (e.selectionSet)
|
||||
this.manager.highlighter.selectionChange("input", e);
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
@ -771,9 +784,6 @@ class InputWaiter {
|
||||
const fileOverlay = document.getElementById("input-file");
|
||||
if (fileOverlay.style.display === "block") return;
|
||||
|
||||
// Remove highlighting from input and output panes as the offsets might be different now
|
||||
this.manager.highlighter.removeHighlights();
|
||||
|
||||
const value = this.getInput();
|
||||
const activeTab = this.manager.tabs.getActiveInputTab();
|
||||
|
||||
@ -1033,9 +1043,6 @@ class InputWaiter {
|
||||
this.manager.output.removeAllOutputs();
|
||||
this.manager.output.terminateZipWorker();
|
||||
|
||||
this.manager.highlighter.removeHighlights();
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
const tabsList = document.getElementById("input-tabs");
|
||||
const tabsListChildren = tabsList.children;
|
||||
|
||||
@ -1073,9 +1080,6 @@ class InputWaiter {
|
||||
const inputNum = this.manager.tabs.getActiveInputTab();
|
||||
if (inputNum === -1) return;
|
||||
|
||||
this.manager.highlighter.removeHighlights();
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
this.updateInputValue(inputNum, "", true);
|
||||
|
||||
this.set({
|
||||
|
@ -67,6 +67,7 @@ class OutputWaiter {
|
||||
const initialState = EditorState.create({
|
||||
doc: null,
|
||||
extensions: [
|
||||
// Editor extensions
|
||||
EditorState.readOnly.of(true),
|
||||
htmlPlugin(this.htmlOutput),
|
||||
highlightSpecialChars({render: renderSpecialChar}),
|
||||
@ -76,18 +77,30 @@ class OutputWaiter {
|
||||
bracketMatching(),
|
||||
highlightSelectionMatches(),
|
||||
search({top: true}),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
// Custom extensiosn
|
||||
statusBar({
|
||||
label: "Output",
|
||||
bakeStats: this.bakeStats,
|
||||
eolHandler: this.eolChange.bind(this)
|
||||
}),
|
||||
|
||||
// Mutable state
|
||||
this.outputEditorConf.lineWrapping.of(EditorView.lineWrapping),
|
||||
this.outputEditorConf.eol.of(EditorState.lineSeparator.of("\n")),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
// Keymap
|
||||
keymap.of([
|
||||
...defaultKeymap,
|
||||
...searchKeymap
|
||||
]),
|
||||
|
||||
// Event listeners
|
||||
EditorView.updateListener.of(e => {
|
||||
if (e.selectionSet)
|
||||
this.manager.highlighter.selectionChange("output", e);
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
@ -817,9 +830,6 @@ class OutputWaiter {
|
||||
|
||||
this.hideMagicButton();
|
||||
|
||||
this.manager.highlighter.removeHighlights();
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
if (!this.manager.tabs.changeOutputTab(inputNum)) {
|
||||
let direction = "right";
|
||||
if (currentNum > inputNum) {
|
||||
@ -1343,21 +1353,6 @@ class OutputWaiter {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the output contains carriage returns
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
async containsCR() {
|
||||
const dish = this.getOutputDish(this.manager.tabs.getActiveOutputTab());
|
||||
if (dish === null) return;
|
||||
|
||||
if (dish.type === Dish.STRING) {
|
||||
const data = await dish.get(Dish.STRING);
|
||||
return data.indexOf("\r") >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for switch click events.
|
||||
* Moves the current output into the input textarea.
|
||||
|
@ -305,9 +305,6 @@ class TabWaiter {
|
||||
changeTab(inputNum, io) {
|
||||
const tabsList = document.getElementById(`${io}-tabs`);
|
||||
|
||||
this.manager.highlighter.removeHighlights();
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
let found = false;
|
||||
for (let i = 0; i < tabsList.children.length; i++) {
|
||||
const tabNum = parseInt(tabsList.children.item(i).getAttribute("inputNum"), 10);
|
||||
|
@ -794,7 +794,7 @@ class WorkerWaiter {
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {string} direction
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {Object[]} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user