mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-25 01:06:16 -04:00
Merge branch 'master' into hide-recipe-options
This commit is contained in:
commit
a1892d4411
443 changed files with 42231 additions and 17174 deletions
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import ChefWorker from "worker-loader?inline&fallback=false!../../core/ChefWorker.js";
|
||||
import ChefWorker from "worker-loader?inline=no-fallback!../../core/ChefWorker.js";
|
||||
|
||||
/**
|
||||
* Waiter to handle conversations with a ChefWorker in the background.
|
||||
|
@ -35,6 +35,14 @@ class BackgroundWorkerWaiter {
|
|||
log.debug("Registering new background ChefWorker");
|
||||
this.chefWorker = new ChefWorker();
|
||||
this.chefWorker.addEventListener("message", this.handleChefMessage.bind(this));
|
||||
this.chefWorker.postMessage({
|
||||
action: "setLogPrefix",
|
||||
data: "BGChefWorker"
|
||||
});
|
||||
this.chefWorker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
|
||||
let docURL = document.location.href.split(/[#?]/)[0];
|
||||
const index = docURL.lastIndexOf("/");
|
||||
|
@ -52,7 +60,7 @@ class BackgroundWorkerWaiter {
|
|||
*/
|
||||
handleChefMessage(e) {
|
||||
const r = e.data;
|
||||
log.debug("Receiving '" + r.action + "' from ChefWorker in the background");
|
||||
log.debug(`Receiving '${r.action}' from BGChefWorker`);
|
||||
|
||||
switch (r.action) {
|
||||
case "bakeComplete":
|
||||
|
@ -152,6 +160,18 @@ class BackgroundWorkerWaiter {
|
|||
this.manager.output.backgroundMagicResult(response.dish.value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the console log level in the workers.
|
||||
*/
|
||||
setLogLevel() {
|
||||
if (!this.chefWorker) return;
|
||||
this.chefWorker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,11 +40,11 @@ class BindingsWaiter {
|
|||
break;
|
||||
case "KeyI": // Focus input
|
||||
e.preventDefault();
|
||||
document.getElementById("input-text").focus();
|
||||
this.manager.input.inputEditorView.focus();
|
||||
break;
|
||||
case "KeyO": // Focus output
|
||||
e.preventDefault();
|
||||
document.getElementById("output-text").focus();
|
||||
this.manager.output.outputEditorView.focus();
|
||||
break;
|
||||
case "Period": // Focus next operation
|
||||
e.preventDefault();
|
||||
|
@ -126,7 +126,7 @@ class BindingsWaiter {
|
|||
break;
|
||||
case "KeyW": // Close tab
|
||||
e.preventDefault();
|
||||
this.manager.input.removeInput(this.manager.tabs.getActiveInputTab());
|
||||
this.manager.input.removeInput(this.manager.tabs.getActiveTab("input"));
|
||||
break;
|
||||
case "ArrowLeft": // Go to previous tab
|
||||
e.preventDefault();
|
||||
|
@ -148,6 +148,13 @@ class BindingsWaiter {
|
|||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (e.code) {
|
||||
case "F1":
|
||||
e.preventDefault();
|
||||
this.contextualHelp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,9 +171,14 @@ class BindingsWaiter {
|
|||
}
|
||||
document.getElementById("keybList").innerHTML = `
|
||||
<tr>
|
||||
<td><b>Command</b></td>
|
||||
<td><b>Shortcut (Win/Linux)</b></td>
|
||||
<td><b>Shortcut (Mac)</b></td>
|
||||
<th>Command</th>
|
||||
<th>Shortcut (Win/Linux)</th>
|
||||
<th>Shortcut (Mac)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Activate contextual help</td>
|
||||
<td>F1</td>
|
||||
<td>F1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Place cursor in search field</td>
|
||||
|
@ -255,6 +267,42 @@ class BindingsWaiter {
|
|||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows contextual help message based on where the mouse pointer is
|
||||
*/
|
||||
contextualHelp() {
|
||||
const hoveredHelpEls = document.querySelectorAll(":hover[data-help],:hover[data-help-proxy]");
|
||||
if (!hoveredHelpEls.length) return;
|
||||
|
||||
let helpEl = hoveredHelpEls[hoveredHelpEls.length - 1];
|
||||
const helpElSelector = helpEl.getAttribute("data-help-proxy");
|
||||
if (helpElSelector) {
|
||||
// A hovered element is directing us to another element for its help text
|
||||
helpEl = document.querySelector(helpElSelector);
|
||||
}
|
||||
this.displayHelp(helpEl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the help pane populated with help text associated with the given element
|
||||
*
|
||||
* @param {Element} el
|
||||
*/
|
||||
displayHelp(el) {
|
||||
const helpText = el.getAttribute("data-help");
|
||||
let helpTitle = el.getAttribute("data-help-title");
|
||||
|
||||
if (helpTitle)
|
||||
helpTitle = "<span class='text-muted'>Help topic:</span> " + helpTitle;
|
||||
else
|
||||
helpTitle = "<span class='text-muted'>Help topic</span>";
|
||||
|
||||
document.querySelector("#help-modal .modal-body").innerHTML = helpText;
|
||||
document.querySelector("#help-modal #help-title").innerHTML = helpTitle;
|
||||
|
||||
$("#help-modal").modal();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BindingsWaiter;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import Utils from "../../core/Utils.mjs";
|
||||
import { eolSeqToCode } from "../utils/editorUtils.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -100,9 +101,9 @@ class ControlsWaiter {
|
|||
const includeRecipe = document.getElementById("save-link-recipe-checkbox").checked;
|
||||
const includeInput = document.getElementById("save-link-input-checkbox").checked;
|
||||
const saveLinkEl = document.getElementById("save-link");
|
||||
const saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
|
||||
const saveLink = this.generateStateUrl(includeRecipe, includeInput, null, recipeConfig);
|
||||
|
||||
saveLinkEl.innerHTML = Utils.truncate(saveLink, 120);
|
||||
saveLinkEl.innerHTML = Utils.escapeHtml(Utils.truncate(saveLink, 120));
|
||||
saveLinkEl.setAttribute("href", saveLink);
|
||||
}
|
||||
|
||||
|
@ -128,17 +129,28 @@ class ControlsWaiter {
|
|||
includeRecipe = includeRecipe && (recipeConfig.length > 0);
|
||||
|
||||
// If we don't get passed an input, get it from the current URI
|
||||
if (input === null) {
|
||||
if (input === null && includeInput) {
|
||||
const params = this.app.getURIParams();
|
||||
if (params.input) {
|
||||
includeInput = true;
|
||||
input = params.input;
|
||||
} else {
|
||||
includeInput = false;
|
||||
}
|
||||
}
|
||||
|
||||
const inputChrEnc = this.manager.input.getChrEnc();
|
||||
const outputChrEnc = this.manager.output.getChrEnc();
|
||||
const inputEOL = eolSeqToCode[this.manager.input.getEOLSeq()];
|
||||
const outputEOL = eolSeqToCode[this.manager.output.getEOLSeq()];
|
||||
|
||||
const params = [
|
||||
includeRecipe ? ["recipe", recipeStr] : undefined,
|
||||
includeInput ? ["input", input] : undefined,
|
||||
includeInput && input.length ? ["input", Utils.escapeHtml(input)] : undefined,
|
||||
inputChrEnc !== 0 ? ["ienc", inputChrEnc] : undefined,
|
||||
outputChrEnc !== 0 ? ["oenc", outputChrEnc] : undefined,
|
||||
inputEOL !== "LF" ? ["ieol", inputEOL] : undefined,
|
||||
outputEOL !== "LF" ? ["oeol", outputEOL] : undefined
|
||||
];
|
||||
|
||||
const hash = params
|
||||
|
@ -438,6 +450,17 @@ ${navigator.userAgent}
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the height of the controls area and adjusts the recipe
|
||||
* height accordingly.
|
||||
*/
|
||||
calcControlsHeight() {
|
||||
const controls = document.getElementById("controls"),
|
||||
recList = document.getElementById("rec-list");
|
||||
|
||||
recList.style.bottom = controls.clientHeight + "px";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ControlsWaiter;
|
||||
|
|
|
@ -4,18 +4,8 @@
|
|||
* @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";
|
||||
import {chrEncWidth} from "../../core/lib/ChrEnc.mjs";
|
||||
|
||||
/**
|
||||
* Waiter to handle events related to highlighting in CyberChef.
|
||||
|
@ -32,436 +22,115 @@ 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 el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
|
||||
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 el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
|
||||
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.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputMouseup(e) {
|
||||
this.mouseButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for output mouseup events.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
outputMouseup(e) {
|
||||
this.mouseButtonDown = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
inputMousemove(e) {
|
||||
// Check that the left mouse button is pressed
|
||||
if (!this.mouseButtonDown ||
|
||||
e.which !== 1 ||
|
||||
this.mouseTarget !== INPUT)
|
||||
return;
|
||||
|
||||
const el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
|
||||
if (start !== 0 || end !== 0) {
|
||||
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
|
||||
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 el = e.target;
|
||||
const start = el.selectionStart;
|
||||
const end = el.selectionEnd;
|
||||
|
||||
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.
|
||||
*
|
||||
* @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 = "";
|
||||
document.getElementById("input-selection-info").innerHTML = "";
|
||||
document.getElementById("output-selection-info").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;
|
||||
|
||||
this.currentSelectionRanges = [];
|
||||
|
||||
// Confirm some non-empty ranges are set
|
||||
const selectionRanges = e.state.selection.ranges;
|
||||
|
||||
// Adjust offsets based on the width of the character set
|
||||
const inputCharacterWidth = chrEncWidth(this.manager.input.getChrEnc());
|
||||
const outputCharacterWidth = chrEncWidth(this.manager.output.getChrEnc());
|
||||
let ratio = 1;
|
||||
if (inputCharacterWidth !== outputCharacterWidth &&
|
||||
inputCharacterWidth !== 0 && outputCharacterWidth !== 0) {
|
||||
ratio = io === "input" ?
|
||||
inputCharacterWidth / outputCharacterWidth :
|
||||
outputCharacterWidth / inputCharacterWidth;
|
||||
}
|
||||
|
||||
// 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: Math.floor(range.from * ratio),
|
||||
end: Math.floor(range.to * ratio)
|
||||
}];
|
||||
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.
|
||||
*/
|
||||
highlightInput(pos) {
|
||||
if (!this.app.autoBake_ || this.app.baking) return false;
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), "reverse", pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
if (this.manager.tabs.getActiveTab("input") !== this.manager.tabs.getActiveTab("output")) return;
|
||||
|
||||
const io = direction === "forward" ? "output" : "input";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the relevant HTML to the specified highlight element such that highlighting appears
|
||||
* underneath the correct offset.
|
||||
* Sends selection updates to the relevant EditorView.
|
||||
*
|
||||
* @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) {
|
||||
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;
|
||||
// Add new SelectionRanges to existing ones
|
||||
for (const range of ranges) {
|
||||
if (typeof range.start !== "number" ||
|
||||
typeof range.end !== "number")
|
||||
continue;
|
||||
const selection = range.end <= range.start ?
|
||||
EditorSelection.cursor(range.start) :
|
||||
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;
|
||||
this.currentSelectionRanges.push(selection);
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
view.dispatch({
|
||||
selection: EditorSelection.create(this.currentSelectionRanges),
|
||||
scrollIntoView: true
|
||||
});
|
||||
} catch (err) {
|
||||
// Ignore Range Errors
|
||||
if (!err.toString().startsWith("RangeError")) {
|
||||
log.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,7 @@
|
|||
|
||||
import HTMLOperation from "../HTMLOperation.mjs";
|
||||
import Sortable from "sortablejs";
|
||||
import {fuzzyMatch, calcMatchRanges} from "../../core/lib/FuzzyMatch.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -108,28 +109,37 @@ class OperationsWaiter {
|
|||
const matchedOps = [];
|
||||
const matchedDescs = [];
|
||||
|
||||
const searchStr = inStr.toLowerCase();
|
||||
// Create version with no whitespace for the fuzzy match
|
||||
// Helps avoid missing matches e.g. query "TCP " would not find "Parse TCP"
|
||||
const inStrNWS = inStr.replace(/\s/g, "");
|
||||
|
||||
for (const opName in this.app.operations) {
|
||||
const op = this.app.operations[opName];
|
||||
const namePos = opName.toLowerCase().indexOf(searchStr);
|
||||
const descPos = op.description.toLowerCase().indexOf(searchStr);
|
||||
|
||||
if (namePos >= 0 || descPos >= 0) {
|
||||
// Match op name using fuzzy match
|
||||
const [nameMatch, score, idxs] = fuzzyMatch(inStrNWS, opName);
|
||||
|
||||
// Match description based on exact match
|
||||
const descPos = op.description.toLowerCase().indexOf(inStr.toLowerCase());
|
||||
|
||||
if (nameMatch || descPos >= 0) {
|
||||
const operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
|
||||
if (highlight) {
|
||||
operation.highlightSearchString(searchStr, namePos, descPos);
|
||||
operation.highlightSearchStrings(calcMatchRanges(idxs), [[descPos, inStr.length]]);
|
||||
}
|
||||
|
||||
if (namePos < 0) {
|
||||
matchedOps.push(operation);
|
||||
if (nameMatch) {
|
||||
matchedOps.push([operation, score]);
|
||||
} else {
|
||||
matchedDescs.push(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchedDescs.concat(matchedOps);
|
||||
// Sort matched operations based on fuzzy score
|
||||
matchedOps.sort((a, b) => b[1] - a[1]);
|
||||
|
||||
return matchedOps.map(a => a[0]).concat(matchedDescs);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,33 +26,30 @@ class OptionsWaiter {
|
|||
* @param {Object} options
|
||||
*/
|
||||
load(options) {
|
||||
for (const option in options) {
|
||||
this.app.options[option] = options[option];
|
||||
}
|
||||
Object.assign(this.app.options, options);
|
||||
|
||||
// Set options to match object
|
||||
const cboxes = document.querySelectorAll("#options-body input[type=checkbox]");
|
||||
let i;
|
||||
for (i = 0; i < cboxes.length; i++) {
|
||||
cboxes[i].checked = this.app.options[cboxes[i].getAttribute("option")];
|
||||
}
|
||||
document.querySelectorAll("#options-body input[type=checkbox]").forEach(cbox => {
|
||||
cbox.checked = this.app.options[cbox.getAttribute("option")];
|
||||
});
|
||||
|
||||
const nboxes = document.querySelectorAll("#options-body input[type=number]");
|
||||
for (i = 0; i < nboxes.length; i++) {
|
||||
nboxes[i].value = this.app.options[nboxes[i].getAttribute("option")];
|
||||
nboxes[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
|
||||
}
|
||||
document.querySelectorAll("#options-body input[type=number]").forEach(nbox => {
|
||||
nbox.value = this.app.options[nbox.getAttribute("option")];
|
||||
nbox.dispatchEvent(new CustomEvent("change", {bubbles: true}));
|
||||
});
|
||||
|
||||
const selects = document.querySelectorAll("#options-body select");
|
||||
for (i = 0; i < selects.length; i++) {
|
||||
const val = this.app.options[selects[i].getAttribute("option")];
|
||||
document.querySelectorAll("#options-body select").forEach(select => {
|
||||
const val = this.app.options[select.getAttribute("option")];
|
||||
if (val) {
|
||||
selects[i].value = val;
|
||||
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
|
||||
select.value = val;
|
||||
select.dispatchEvent(new CustomEvent("change", {bubbles: true}));
|
||||
} else {
|
||||
selects[i].selectedIndex = 0;
|
||||
select.selectedIndex = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialise options
|
||||
this.setWordWrap();
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,19 +133,8 @@ class OptionsWaiter {
|
|||
* Sets or unsets word wrap on the input and output depending on the wordWrap option value.
|
||||
*/
|
||||
setWordWrap() {
|
||||
document.getElementById("input-text").classList.remove("word-wrap");
|
||||
document.getElementById("output-text").classList.remove("word-wrap");
|
||||
document.getElementById("output-html").classList.remove("word-wrap");
|
||||
document.getElementById("input-highlighter").classList.remove("word-wrap");
|
||||
document.getElementById("output-highlighter").classList.remove("word-wrap");
|
||||
|
||||
if (!this.app.options.wordWrap) {
|
||||
document.getElementById("input-text").classList.add("word-wrap");
|
||||
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");
|
||||
}
|
||||
this.manager.input.setWordWrap(this.app.options.wordWrap);
|
||||
this.manager.output.setWordWrap(this.app.options.wordWrap);
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,7 +145,6 @@ class OptionsWaiter {
|
|||
*/
|
||||
themeChange(e) {
|
||||
const themeClass = e.target.value;
|
||||
|
||||
this.changeTheme(themeClass);
|
||||
}
|
||||
|
||||
|
@ -188,6 +173,8 @@ class OptionsWaiter {
|
|||
log.setLevel(level, false);
|
||||
this.manager.worker.setLogLevel();
|
||||
this.manager.input.setLogLevel();
|
||||
this.manager.output.setLogLevel();
|
||||
this.manager.background.setLogLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
|||
import HTMLOperation from "../HTMLOperation.mjs";
|
||||
import Sortable from "sortablejs";
|
||||
import Utils from "../../core/Utils.mjs";
|
||||
import {escapeControlChars} from "../utils/editorUtils.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -132,7 +133,7 @@ class RecipeWaiter {
|
|||
// Reinitialise the popover on the original element in the ops list because for some reason it
|
||||
// gets destroyed and recreated. If the clone isn't in the ops list, we use the original item instead.
|
||||
let enableOpsElement;
|
||||
if (evt.clone.parentNode && evt.clone.parentNode.classList.contains("op-list")) {
|
||||
if (evt.clone?.parentNode?.classList?.contains("op-list")) {
|
||||
enableOpsElement = evt.clone;
|
||||
} else {
|
||||
enableOpsElement = evt.item;
|
||||
|
@ -162,13 +163,13 @@ class RecipeWaiter {
|
|||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (e.target.className && e.target.className.indexOf("category-title") > -1) {
|
||||
if (e.target?.className?.indexOf("category-title") > -1) {
|
||||
// Hovering over the a
|
||||
e.target.classList.add("favourites-hover");
|
||||
} else if (e.target.parentNode.className && e.target.parentNode.className.indexOf("category-title") > -1) {
|
||||
} else if (e.target?.parentNode?.className?.indexOf("category-title") > -1) {
|
||||
// Hovering over the Edit button
|
||||
e.target.parentNode.classList.add("favourites-hover");
|
||||
} else if (e.target.parentNode.parentNode.className && e.target.parentNode.parentNode.className.indexOf("category-title") > -1) {
|
||||
} else if (e.target?.parentNode?.parentNode?.className?.indexOf("category-title") > -1) {
|
||||
// Hovering over the image on the Edit button
|
||||
e.target.parentNode.parentNode.classList.add("favourites-hover");
|
||||
}
|
||||
|
@ -210,7 +211,7 @@ class RecipeWaiter {
|
|||
* @fires Manager#statechange
|
||||
*/
|
||||
ingChange(e) {
|
||||
if (e && e.target && e.target.classList.contains("no-state-change")) return;
|
||||
if (e && e?.target?.classList?.contains("no-state-change")) return;
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
|
@ -357,7 +358,7 @@ class RecipeWaiter {
|
|||
};
|
||||
} else if (ingList[j].getAttribute("type") === "number") {
|
||||
// number
|
||||
ingredients[j] = parseFloat(ingList[j].value, 10);
|
||||
ingredients[j] = parseFloat(ingList[j].value);
|
||||
} else {
|
||||
// all others
|
||||
ingredients[j] = ingList[j].value;
|
||||
|
@ -609,7 +610,7 @@ class RecipeWaiter {
|
|||
|
||||
const registerList = [];
|
||||
for (let i = 0; i < registers.length; i++) {
|
||||
registerList.push(`$R${numPrevRegisters + i} = ${Utils.escapeHtml(Utils.truncate(Utils.printable(registers[i]), 100))}`);
|
||||
registerList.push(`$R${numPrevRegisters + i} = ${escapeControlChars(Utils.escapeHtml(Utils.truncate(registers[i], 100)))}`);
|
||||
}
|
||||
const registerListEl = `<div class="register-list">
|
||||
${registerList.join("<br>")}
|
||||
|
@ -625,42 +626,6 @@ class RecipeWaiter {
|
|||
adjustWidth() {
|
||||
const recList = document.getElementById("rec-list");
|
||||
|
||||
if (!this.ingredientRuleID) {
|
||||
this.ingredientRuleID = null;
|
||||
this.ingredientChildRuleID = null;
|
||||
|
||||
// Find relevant rules in the stylesheet
|
||||
// try/catch for chrome 64+ CORS error on cssRules.
|
||||
try {
|
||||
for (const i in document.styleSheets[0].cssRules) {
|
||||
if (document.styleSheets[0].cssRules[i].selectorText === ".ingredients") {
|
||||
this.ingredientRuleID = i;
|
||||
}
|
||||
if (document.styleSheets[0].cssRules[i].selectorText === ".ingredients > div") {
|
||||
this.ingredientChildRuleID = i;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.ingredientRuleID || !this.ingredientChildRuleID) return;
|
||||
|
||||
const ingredientRule = document.styleSheets[0].cssRules[this.ingredientRuleID];
|
||||
const ingredientChildRule = document.styleSheets[0].cssRules[this.ingredientChildRuleID];
|
||||
|
||||
if (recList.clientWidth < 450) {
|
||||
ingredientRule.style.gridTemplateColumns = "auto auto";
|
||||
ingredientChildRule.style.gridColumn = "1 / span 2";
|
||||
} else if (recList.clientWidth < 620) {
|
||||
ingredientRule.style.gridTemplateColumns = "auto auto auto";
|
||||
ingredientChildRule.style.gridColumn = "1 / span 3";
|
||||
} else {
|
||||
ingredientRule.style.gridTemplateColumns = "auto auto auto auto";
|
||||
ingredientChildRule.style.gridColumn = "1 / span 4";
|
||||
}
|
||||
|
||||
// Hide Chef icon on Bake button if the page is compressed
|
||||
const bakeIcon = document.querySelector("#bake img");
|
||||
|
||||
|
@ -676,7 +641,7 @@ class RecipeWaiter {
|
|||
const controlsContent = document.getElementById("controls-content");
|
||||
const scale = (controls.clientWidth - 1) / controlsContent.scrollWidth;
|
||||
|
||||
controlsContent.style.transform = `translate(-50%, -50%) scale(${scale})`;
|
||||
controlsContent.style.transform = `scale(${scale})`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,8 +30,7 @@ class SeasonalWaiter {
|
|||
window.addEventListener("keydown", this.konamiCodeListener.bind(this));
|
||||
|
||||
// CyberChef Challenge
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("43 6f 6e 67 72 61 74 75 6c 61 74 69 6f 6e 73 2c 20 79 6f 75 20 68 61 76 65 20 63 6f 6d 70 6c 65 74 65 64 20 43 79 62 65 72 43 68 65 66 20 63 68 61 6c 6c 65 6e 67 65 20 23 31 21 0a 0a 54 68 69 73 20 63 68 61 6c 6c 65 6e 67 65 20 65 78 70 6c 6f 72 65 64 20 68 65 78 61 64 65 63 69 6d 61 6c 20 65 6e 63 6f 64 69 6e 67 2e 20 54 6f 20 6c 65 61 72 6e 20 6d 6f 72 65 2c 20 76 69 73 69 74 20 77 69 6b 69 70 65 64 69 61 2e 6f 72 67 2f 77 69 6b 69 2f 48 65 78 61 64 65 63 69 6d 61 6c 2e 0a 0a 54 68 65 20 63 6f 64 65 20 66 6f 72 20 74 68 69 73 20 63 68 61 6c 6c 65 6e 67 65 20 69 73 20 39 64 34 63 62 63 65 66 2d 62 65 35 32 2d 34 37 35 31 2d 61 32 62 32 2d 38 33 33 38 65 36 34 30 39 34 31 36 20 28 6b 65 65 70 20 74 68 69 73 20 70 72 69 76 61 74 65 29 2e 0a 0a 54 68 65 20 6e 65 78 74 20 63 68 61 6c 6c 65 6e 67 65 20 63 61 6e 20 62 65 20 66 6f 75 6e 64 20 61 74 20 68 74 74 70 73 3a 2f 2f 70 61 73 74 65 62 69 6e 2e 63 6f 6d 2f 47 53 6e 54 41 6d 6b 56 2e");
|
||||
log.info("43 6f 6e 67 72 61 74 75 6c 61 74 69 6f 6e 73 2c 20 79 6f 75 20 68 61 76 65 20 63 6f 6d 70 6c 65 74 65 64 20 43 79 62 65 72 43 68 65 66 20 63 68 61 6c 6c 65 6e 67 65 20 23 31 21 0a 0a 54 68 69 73 20 63 68 61 6c 6c 65 6e 67 65 20 65 78 70 6c 6f 72 65 64 20 68 65 78 61 64 65 63 69 6d 61 6c 20 65 6e 63 6f 64 69 6e 67 2e 20 54 6f 20 6c 65 61 72 6e 20 6d 6f 72 65 2c 20 76 69 73 69 74 20 77 69 6b 69 70 65 64 69 61 2e 6f 72 67 2f 77 69 6b 69 2f 48 65 78 61 64 65 63 69 6d 61 6c 2e 0a 0a 54 68 65 20 63 6f 64 65 20 66 6f 72 20 74 68 69 73 20 63 68 61 6c 6c 65 6e 67 65 20 69 73 20 39 64 34 63 62 63 65 66 2d 62 65 35 32 2d 34 37 35 31 2d 61 32 62 32 2d 38 33 33 38 65 36 34 30 39 34 31 36 20 28 6b 65 65 70 20 74 68 69 73 20 70 72 69 76 61 74 65 29 2e 0a 0a 54 68 65 20 6e 65 78 74 20 63 68 61 6c 6c 65 6e 67 65 20 63 61 6e 20 62 65 20 66 6f 75 6e 64 20 61 74 20 68 74 74 70 73 3a 2f 2f 70 61 73 74 65 62 69 6e 2e 63 6f 6d 2f 47 53 6e 54 41 6d 6b 56 2e");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,24 +48,6 @@ class TabWaiter {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently active input tab number
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getActiveInputTab() {
|
||||
return this.getActiveTab("input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently active output tab number
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getActiveOutputTab() {
|
||||
return this.getActiveTab("output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the li element for the tab of a given input number
|
||||
*
|
||||
|
@ -83,26 +65,6 @@ class TabWaiter {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the li element for an input tab of the given input number
|
||||
*
|
||||
* @param {inputNum} - The inputNum of the tab we're trying to get
|
||||
* @returns {Element}
|
||||
*/
|
||||
getInputTabItem(inputNum) {
|
||||
return this.getTabItem(inputNum, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the li element for an output tab of the given input number
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {Element}
|
||||
*/
|
||||
getOutputTabItem(inputNum) {
|
||||
return this.getTabItem(inputNum, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of tab numbers for the currently displayed tabs
|
||||
*
|
||||
|
@ -120,24 +82,6 @@ class TabWaiter {
|
|||
return nums;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of tab numbers for the currently displayed input tabs
|
||||
*
|
||||
* @returns {number[]}
|
||||
*/
|
||||
getInputTabList() {
|
||||
return this.getTabList("input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of tab numbers for the currently displayed output tabs
|
||||
*
|
||||
* @returns {number[]}
|
||||
*/
|
||||
getOutputTabList() {
|
||||
return this.getTabList("output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tab element for the tab bar
|
||||
*
|
||||
|
@ -154,11 +98,8 @@ class TabWaiter {
|
|||
|
||||
const newTabContent = document.createElement("div");
|
||||
newTabContent.classList.add(`${io}-tab-content`);
|
||||
|
||||
newTabContent.innerText = `Tab ${inputNum.toString()}`;
|
||||
|
||||
newTabContent.addEventListener("wheel", this.manager[io].scrollTab.bind(this.manager[io]), {passive: false});
|
||||
|
||||
newTab.appendChild(newTabContent);
|
||||
|
||||
if (io === "input") {
|
||||
|
@ -166,52 +107,24 @@ class TabWaiter {
|
|||
newTabButtonIcon = document.createElement("i");
|
||||
newTabButton.type = "button";
|
||||
newTabButton.className = "btn btn-primary bmd-btn-icon btn-close-tab";
|
||||
|
||||
newTabButtonIcon.classList.add("material-icons");
|
||||
newTabButtonIcon.innerText = "clear";
|
||||
|
||||
newTabButton.appendChild(newTabButtonIcon);
|
||||
|
||||
newTabButton.addEventListener("click", this.manager.input.removeTabClick.bind(this.manager.input));
|
||||
|
||||
newTab.appendChild(newTabButton);
|
||||
}
|
||||
|
||||
return newTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tab element for the input tab bar
|
||||
*
|
||||
* @param {number} inputNum - The inputNum of the new input tab
|
||||
* @param {boolean} [active=false] - If true, sets the tab to active
|
||||
* @returns {Element}
|
||||
*/
|
||||
createInputTabElement(inputNum, active=false) {
|
||||
return this.createTabElement(inputNum, active, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tab element for the output tab bar
|
||||
*
|
||||
* @param {number} inputNum - The inputNum of the new output tab
|
||||
* @param {boolean} [active=false] - If true, sets the tab to active
|
||||
* @returns {Element}
|
||||
*/
|
||||
createOutputTabElement(inputNum, active=false) {
|
||||
return this.createTabElement(inputNum, active, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the tab bar for both the input and output
|
||||
*/
|
||||
showTabBar() {
|
||||
document.getElementById("input-tabs-wrapper").style.display = "block";
|
||||
document.getElementById("output-tabs-wrapper").style.display = "block";
|
||||
|
||||
document.getElementById("input-wrapper").classList.add("show-tabs");
|
||||
document.getElementById("output-wrapper").classList.add("show-tabs");
|
||||
|
||||
document.getElementById("save-all-to-file").style.display = "inline-block";
|
||||
}
|
||||
|
||||
|
@ -221,10 +134,8 @@ class TabWaiter {
|
|||
hideTabBar() {
|
||||
document.getElementById("input-tabs-wrapper").style.display = "none";
|
||||
document.getElementById("output-tabs-wrapper").style.display = "none";
|
||||
|
||||
document.getElementById("input-wrapper").classList.remove("show-tabs");
|
||||
document.getElementById("output-wrapper").classList.remove("show-tabs");
|
||||
|
||||
document.getElementById("save-all-to-file").style.display = "none";
|
||||
}
|
||||
|
||||
|
@ -271,30 +182,6 @@ class TabWaiter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the input tabs, and changes to activeTab
|
||||
*
|
||||
* @param {number[]} nums - The inputNums to be displayed as tabs
|
||||
* @param {number} activeTab - The tab to change to
|
||||
* @param {boolean} tabsLeft - True if there are input tabs to the left of the displayed tabs
|
||||
* @param {boolean} tabsRight - True if there are input tabs to the right of the displayed tabs
|
||||
*/
|
||||
refreshInputTabs(nums, activeTab, tabsLeft, tabsRight) {
|
||||
this.refreshTabs(nums, activeTab, tabsLeft, tabsRight, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the output tabs, and changes to activeTab
|
||||
*
|
||||
* @param {number[]} nums - The inputNums to be displayed as tabs
|
||||
* @param {number} activeTab - The tab to change to
|
||||
* @param {boolean} tabsLeft - True if there are output tabs to the left of the displayed tabs
|
||||
* @param {boolean} tabsRight - True if there are output tabs to the right of the displayed tabs
|
||||
*/
|
||||
refreshOutputTabs(nums, activeTab, tabsLeft, tabsRight) {
|
||||
this.refreshTabs(nums, activeTab, tabsLeft, tabsRight, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the active tab to a different tab
|
||||
*
|
||||
|
@ -305,9 +192,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);
|
||||
|
@ -322,26 +206,6 @@ class TabWaiter {
|
|||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the active input tab to a different tab
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {boolean} - False if the tab is not currently being displayed
|
||||
*/
|
||||
changeInputTab(inputNum) {
|
||||
return this.changeTab(inputNum, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the active output tab to a different tab
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {boolean} - False if the tab is not currently being displayed
|
||||
*/
|
||||
changeOutputTab(inputNum) {
|
||||
return this.changeTab(inputNum, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tab header to display a preview of the tab contents
|
||||
*
|
||||
|
@ -361,26 +225,6 @@ class TabWaiter {
|
|||
tab.firstElementChild.innerText = headerData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the input tab header to display a preview of the tab contents
|
||||
*
|
||||
* @param {number} inputNum - The inputNum of the tab to update the header of
|
||||
* @param {string} data - The data to display in the tab header
|
||||
*/
|
||||
updateInputTabHeader(inputNum, data) {
|
||||
this.updateTabHeader(inputNum, data, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the output tab header to display a preview of the tab contents
|
||||
*
|
||||
* @param {number} inputNum - The inputNum of the tab to update the header of
|
||||
* @param {string} data - The data to display in the tab header
|
||||
*/
|
||||
updateOutputTabHeader(inputNum, data) {
|
||||
this.updateTabHeader(inputNum, data, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tab background to display the progress of the current tab
|
||||
*
|
||||
|
@ -401,28 +245,6 @@ class TabWaiter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the input tab background to display its progress
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @param {number} progress
|
||||
* @param {number} total
|
||||
*/
|
||||
updateInputTabProgress(inputNum, progress, total) {
|
||||
this.updateTabProgress(inputNum, progress, total, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the output tab background to display its progress
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @param {number} progress
|
||||
* @param {number} total
|
||||
*/
|
||||
updateOutputTabProgress(inputNum, progress, total) {
|
||||
this.updateTabProgress(inputNum, progress, total, "output");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TabWaiter;
|
||||
|
|
182
src/web/waiters/TimingWaiter.mjs
Normal file
182
src/web/waiters/TimingWaiter.mjs
Normal file
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Waiter to handle timing of the baking process.
|
||||
*/
|
||||
class TimingWaiter {
|
||||
|
||||
/**
|
||||
* TimingWaiter constructor.
|
||||
*
|
||||
* @param {App} app - The main view object for CyberChef.
|
||||
* @param {Manager} manager - The CyberChef event manager.
|
||||
*/
|
||||
constructor(app, manager) {
|
||||
this.app = app;
|
||||
this.manager = manager;
|
||||
|
||||
this.inputs = {};
|
||||
/*
|
||||
Inputs example:
|
||||
"1": {
|
||||
"inputEncodingStart": 0,
|
||||
"inputEncodingEnd": 0,
|
||||
"trigger": 0
|
||||
"chefWorkerTasked": 0,
|
||||
"bakeComplete": 0,
|
||||
"bakeDuration": 0,
|
||||
"settingOutput": 0,
|
||||
"outputDecodingStart": 0,
|
||||
"outputDecodingEnd": 0,
|
||||
"complete": 0
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the time for an input
|
||||
*
|
||||
* @param {string} event
|
||||
* @param {number} inputNum
|
||||
* @param {number} value
|
||||
*/
|
||||
recordTime(event, inputNum, value=Date.now()) {
|
||||
inputNum = inputNum.toString();
|
||||
if (!Object.keys(this.inputs).includes(inputNum)) {
|
||||
this.inputs[inputNum] = {};
|
||||
}
|
||||
log.debug(`Recording ${event} for input ${inputNum}`);
|
||||
this.inputs[inputNum][event] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The duration of the main stages of a bake
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {number}
|
||||
*/
|
||||
duration(inputNum) {
|
||||
const input = this.inputs[inputNum.toString()];
|
||||
|
||||
// If this input has not been encoded yet, we cannot calculate a time
|
||||
if (!input ||
|
||||
!input.trigger ||
|
||||
!input.inputEncodingEnd ||
|
||||
!input.inputEncodingStart)
|
||||
return 0;
|
||||
|
||||
// input encoding can happen before a bake is triggered, so it is calculated separately
|
||||
const inputEncodingTotal = input.inputEncodingEnd - input.inputEncodingStart;
|
||||
|
||||
let total = 0, outputDecodingTotal = 0;
|
||||
|
||||
if (input.bakeComplete && input.bakeComplete > input.trigger)
|
||||
total = input.bakeComplete - input.trigger;
|
||||
|
||||
if (input.settingOutput && input.settingOutput > input.trigger)
|
||||
total = input.settingOutput - input.trigger;
|
||||
|
||||
if (input.outputDecodingStart && (input.outputDecodingStart > input.trigger) &&
|
||||
input.outputDecodingEnd && (input.outputDecodingEnd > input.trigger)) {
|
||||
total = input.outputDecodingEnd - input.trigger;
|
||||
outputDecodingTotal = input.outputDecodingEnd - input.outputDecodingStart;
|
||||
}
|
||||
|
||||
if (input.complete && input.complete > input.trigger)
|
||||
total = inputEncodingTotal + input.bakeDuration + outputDecodingTotal;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total time for a completed bake
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {number}
|
||||
*/
|
||||
overallDuration(inputNum) {
|
||||
const input = this.inputs[inputNum.toString()];
|
||||
|
||||
// If this input has not been encoded yet, we cannot calculate a time
|
||||
if (!input ||
|
||||
!input.trigger ||
|
||||
!input.inputEncodingEnd ||
|
||||
!input.inputEncodingStart)
|
||||
return 0;
|
||||
|
||||
// input encoding can happen before a bake is triggered, so it is calculated separately
|
||||
const inputEncodingTotal = input.inputEncodingEnd - input.inputEncodingStart;
|
||||
|
||||
let total = 0;
|
||||
if (input.bakeComplete && input.bakeComplete > input.trigger)
|
||||
total = input.bakeComplete - input.trigger;
|
||||
|
||||
if (input.settingOutput && input.settingOutput > input.trigger)
|
||||
total = input.settingOutput - input.trigger;
|
||||
|
||||
if (input.outputDecodingStart && input.outputDecodingStart > input.trigger)
|
||||
total = input.outputDecodingStart - input.trigger;
|
||||
|
||||
if (input.outputDecodingEnd && input.outputDecodingEnd > input.trigger)
|
||||
total = input.outputDecodingEnd - input.trigger;
|
||||
|
||||
if (input.complete && input.complete > input.trigger)
|
||||
total = input.complete - input.trigger;
|
||||
|
||||
return total + inputEncodingTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out the time between stages
|
||||
*
|
||||
* @param {number} inputNum
|
||||
* @returns {string}
|
||||
*/
|
||||
printStages(inputNum) {
|
||||
const input = this.inputs[inputNum.toString()];
|
||||
if (!input || !input.trigger) return "";
|
||||
|
||||
const total = this.overallDuration(inputNum),
|
||||
inputEncoding = input.inputEncodingEnd - input.inputEncodingStart,
|
||||
outputDecoding = input.outputDecodingEnd - input.outputDecodingStart,
|
||||
overhead = total - inputEncoding - outputDecoding - input.bakeDuration;
|
||||
|
||||
return `Input encoding: ${inputEncoding}ms
|
||||
Recipe duration: ${input.bakeDuration}ms
|
||||
Output decoding: ${outputDecoding}ms
|
||||
<span class="small">Threading overhead: ${overhead}ms</span>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs every interval
|
||||
*
|
||||
* @param {number} inputNum
|
||||
*/
|
||||
logAllTimes(inputNum) {
|
||||
const input = this.inputs[inputNum.toString()];
|
||||
if (!input || !input.trigger) return;
|
||||
|
||||
try {
|
||||
log.debug(`Trigger: ${input.trigger}
|
||||
inputEncodingStart: ${input.inputEncodingStart} | ${input.inputEncodingStart - input.trigger}ms since trigger
|
||||
inputEncodingEnd: ${input.inputEncodingEnd} | ${input.inputEncodingEnd - input.inputEncodingStart}ms input encoding time
|
||||
chefWorkerTasked: ${input.chefWorkerTasked} | ${input.chefWorkerTasked - input.trigger}ms since trigger
|
||||
bakeDuration: | ${input.bakeDuration}ms duration in worker
|
||||
bakeComplete: ${input.bakeComplete} | ${input.bakeComplete - input.chefWorkerTasked}ms since worker tasked
|
||||
settingOutput: ${input.settingOutput} | ${input.settingOutput - input.bakeComplete}ms since worker finished
|
||||
outputDecodingStart: ${input.outputDecodingStart} | ${input.outputDecodingStart - input.settingOutput}ms since output set
|
||||
outputDecodingEnd: ${input.outputDecodingEnd} | ${input.outputDecodingEnd - input.outputDecodingStart}ms output encoding time
|
||||
complete: ${input.complete} | ${input.complete - input.outputDecodingEnd}ms since output decoded
|
||||
Total: | ${input.complete - input.trigger}ms since trigger`);
|
||||
} catch (err) {}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TimingWaiter;
|
|
@ -23,11 +23,11 @@ class WindowWaiter {
|
|||
|
||||
/**
|
||||
* Handler for window resize events.
|
||||
* Resets the layout of CyberChef's panes after 200ms (so that continuous resizing doesn't cause
|
||||
* Resets adjustable component sizes after 200ms (so that continuous resizing doesn't cause
|
||||
* continuous resetting).
|
||||
*/
|
||||
windowResize() {
|
||||
debounce(this.app.resetLayout, 200, "windowResize", this.app, [])();
|
||||
debounce(this.app.adjustComponentSizes, 200, "windowResize", this.app, [])();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import ChefWorker from "worker-loader?inline&fallback=false!../../core/ChefWorker.js";
|
||||
import DishWorker from "worker-loader?inline&fallback=false!../workers/DishWorker.mjs";
|
||||
import ChefWorker from "worker-loader?inline=no-fallback!../../core/ChefWorker.js";
|
||||
import DishWorker from "worker-loader?inline=no-fallback!../workers/DishWorker.mjs";
|
||||
import { debounce } from "../../core/Utils.mjs";
|
||||
|
||||
/**
|
||||
|
@ -72,6 +72,10 @@ class WorkerWaiter {
|
|||
|
||||
this.dishWorker.worker = new DishWorker();
|
||||
this.dishWorker.worker.addEventListener("message", this.handleDishMessage.bind(this));
|
||||
this.dishWorker.worker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
|
||||
if (this.dishWorkerQueue.length > 0) {
|
||||
this.postDishMessage(this.dishWorkerQueue.splice(0, 1)[0]);
|
||||
|
@ -89,22 +93,27 @@ class WorkerWaiter {
|
|||
return -1;
|
||||
}
|
||||
|
||||
log.debug("Adding new ChefWorker");
|
||||
log.debug(`Adding new ChefWorker (${this.chefWorkers.length + 1}/${this.maxWorkers})`);
|
||||
|
||||
// Create a new ChefWorker and send it the docURL
|
||||
const newWorker = new ChefWorker();
|
||||
newWorker.addEventListener("message", this.handleChefMessage.bind(this));
|
||||
newWorker.postMessage({
|
||||
action: "setLogPrefix",
|
||||
data: "ChefWorker"
|
||||
});
|
||||
newWorker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
|
||||
let docURL = document.location.href.split(/[#?]/)[0];
|
||||
const index = docURL.lastIndexOf("/");
|
||||
if (index > 0) {
|
||||
docURL = docURL.substring(0, index);
|
||||
}
|
||||
|
||||
newWorker.postMessage({"action": "docURL", "data": docURL});
|
||||
newWorker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
|
||||
|
||||
// Store the worker, whether or not it's active, and the inputNum as an object
|
||||
const newWorkerObj = {
|
||||
|
@ -177,7 +186,7 @@ class WorkerWaiter {
|
|||
handleChefMessage(e) {
|
||||
const r = e.data;
|
||||
let inputNum = 0;
|
||||
log.debug(`Receiving ${r.action} from ChefWorker.`);
|
||||
log.debug(`Receiving '${r.action}' from ChefWorker.`);
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(r.data, "inputNum")) {
|
||||
inputNum = r.data.inputNum;
|
||||
|
@ -188,6 +197,8 @@ class WorkerWaiter {
|
|||
switch (r.action) {
|
||||
case "bakeComplete":
|
||||
log.debug(`Bake ${inputNum} complete.`);
|
||||
this.manager.timing.recordTime("bakeComplete", inputNum);
|
||||
this.manager.timing.recordTime("bakeDuration", inputNum, r.data.duration);
|
||||
|
||||
if (r.data.error) {
|
||||
this.app.handleError(r.data.error);
|
||||
|
@ -217,7 +228,7 @@ class WorkerWaiter {
|
|||
break;
|
||||
case "workerLoaded":
|
||||
this.app.workerLoaded = true;
|
||||
log.debug("ChefWorker loaded.");
|
||||
log.debug("ChefWorker loaded");
|
||||
if (!this.loaded) {
|
||||
this.app.loaded();
|
||||
this.loaded = true;
|
||||
|
@ -266,7 +277,7 @@ class WorkerWaiter {
|
|||
if (progress !== false) {
|
||||
this.manager.output.updateOutputStatus("error", inputNum);
|
||||
|
||||
if (inputNum === this.manager.tabs.getActiveInputTab()) {
|
||||
if (inputNum === this.manager.tabs.getActiveTab("input")) {
|
||||
this.manager.recipe.updateBreakpointIndicator(progress);
|
||||
}
|
||||
|
||||
|
@ -315,36 +326,42 @@ class WorkerWaiter {
|
|||
* Cancels the current bake by terminating and removing all ChefWorkers
|
||||
*
|
||||
* @param {boolean} [silent=false] - If true, don't set the output
|
||||
* @param {boolean} killAll - If true, kills all chefWorkers regardless of status
|
||||
* @param {boolean} [killAll=false] - If true, kills all chefWorkers regardless of status
|
||||
*/
|
||||
cancelBake(silent, killAll) {
|
||||
cancelBake(silent=false, killAll=false) {
|
||||
const deactiveOutputs = new Set();
|
||||
|
||||
for (let i = this.chefWorkers.length - 1; i >= 0; i--) {
|
||||
if (this.chefWorkers[i].active || killAll) {
|
||||
const inputNum = this.chefWorkers[i].inputNum;
|
||||
this.removeChefWorker(this.chefWorkers[i]);
|
||||
this.manager.output.updateOutputStatus("inactive", inputNum);
|
||||
deactiveOutputs.add(inputNum);
|
||||
}
|
||||
}
|
||||
this.setBakingStatus(false);
|
||||
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
this.manager.output.updateOutputStatus("inactive", this.inputs[i].inputNum);
|
||||
}
|
||||
this.inputs.forEach(input => {
|
||||
deactiveOutputs.add(input.inputNum);
|
||||
});
|
||||
|
||||
for (let i = 0; i < this.inputNums.length; i++) {
|
||||
this.manager.output.updateOutputStatus("inactive", this.inputNums[i]);
|
||||
}
|
||||
this.inputNums.forEach(inputNum => {
|
||||
deactiveOutputs.add(inputNum);
|
||||
});
|
||||
|
||||
const tabList = this.manager.tabs.getOutputTabList();
|
||||
for (let i = 0; i < tabList.length; i++) {
|
||||
this.manager.tabs.getOutputTabItem(tabList[i]).style.background = "";
|
||||
}
|
||||
deactiveOutputs.forEach(num => {
|
||||
this.manager.output.updateOutputStatus("inactive", num);
|
||||
});
|
||||
|
||||
const tabList = this.manager.tabs.getTabList("output");
|
||||
tabList.forEach(tab => {
|
||||
this.manager.tabs.getTabItem(tab, "output").style.background = "";
|
||||
});
|
||||
|
||||
this.inputs = [];
|
||||
this.inputNums = [];
|
||||
this.totalOutputs = 0;
|
||||
this.loadingOutputs = 0;
|
||||
if (!silent) this.manager.output.set(this.manager.tabs.getActiveOutputTab());
|
||||
if (!silent) this.manager.output.set(this.manager.tabs.getActiveTab("output"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -455,6 +472,7 @@ class WorkerWaiter {
|
|||
if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
|
||||
transferable = [input];
|
||||
}
|
||||
this.manager.timing.recordTime("chefWorkerTasked", nextInput.inputNum);
|
||||
this.chefWorkers[workerIdx].worker.postMessage({
|
||||
action: "bake",
|
||||
data: {
|
||||
|
@ -550,10 +568,12 @@ class WorkerWaiter {
|
|||
* @param {boolean} inputData.step - If true, only execute the next operation in the recipe
|
||||
* @param {number} inputData.progress - The current progress through the recipe. Used when stepping
|
||||
*/
|
||||
async bakeAllInputs(inputData) {
|
||||
async bakeInputs(inputData) {
|
||||
log.debug(`Baking input list [${inputData.nums.join(",")}]`);
|
||||
|
||||
return await new Promise(resolve => {
|
||||
if (this.app.baking) return;
|
||||
const inputNums = inputData.nums;
|
||||
const inputNums = inputData.nums.filter(n => n > 0);
|
||||
const step = inputData.step;
|
||||
|
||||
// Use cancelBake to clear out the inputs
|
||||
|
@ -586,6 +606,7 @@ class WorkerWaiter {
|
|||
numBakes = this.inputNums.length;
|
||||
}
|
||||
for (let i = 0; i < numBakes; i++) {
|
||||
this.manager.timing.recordTime("trigger", this.inputNums[0]);
|
||||
this.manager.input.inputWorker.postMessage({
|
||||
action: "bakeNext",
|
||||
data: {
|
||||
|
@ -595,6 +616,7 @@ class WorkerWaiter {
|
|||
});
|
||||
this.loadingOutputs++;
|
||||
}
|
||||
if (numBakes === 0) this.bakingComplete();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -626,7 +648,7 @@ class WorkerWaiter {
|
|||
*/
|
||||
handleDishMessage(e) {
|
||||
const r = e.data;
|
||||
log.debug(`Receiving ${r.action} from DishWorker`);
|
||||
log.debug(`Receiving '${r.action}' from DishWorker`);
|
||||
|
||||
switch (r.action) {
|
||||
case "dishReturned":
|
||||
|
@ -645,7 +667,7 @@ class WorkerWaiter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Asks the ChefWorker to return the dish as the specified type
|
||||
* Asks the DishWorker to return the dish as the specified type
|
||||
*
|
||||
* @param {Dish} dish
|
||||
* @param {string} type
|
||||
|
@ -653,10 +675,9 @@ class WorkerWaiter {
|
|||
*/
|
||||
getDishAs(dish, type, callback) {
|
||||
const id = this.callbackID++;
|
||||
|
||||
this.callbacks[id] = callback;
|
||||
|
||||
if (this.dishWorker.worker === null) this.setupDishWorker();
|
||||
|
||||
this.postDishMessage({
|
||||
action: "getDishAs",
|
||||
data: {
|
||||
|
@ -668,7 +689,7 @@ class WorkerWaiter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Asks the ChefWorker to get the title of the dish
|
||||
* Asks the DishWorker to get the title of the dish
|
||||
*
|
||||
* @param {Dish} dish
|
||||
* @param {number} maxLength
|
||||
|
@ -677,9 +698,7 @@ class WorkerWaiter {
|
|||
*/
|
||||
getDishTitle(dish, maxLength, callback) {
|
||||
const id = this.callbackID++;
|
||||
|
||||
this.callbacks[id] = callback;
|
||||
|
||||
if (this.dishWorker.worker === null) this.setupDishWorker();
|
||||
|
||||
this.postDishMessage({
|
||||
|
@ -692,6 +711,29 @@ class WorkerWaiter {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the DishWorker to translate a buffer into a specific character encoding
|
||||
*
|
||||
* @param {ArrayBuffer} buffer
|
||||
* @param {number} encoding
|
||||
* @param {Function} callback
|
||||
* @returns {string}
|
||||
*/
|
||||
bufferToStr(buffer, encoding, callback) {
|
||||
const id = this.callbackID++;
|
||||
this.callbacks[id] = callback;
|
||||
if (this.dishWorker.worker === null) this.setupDishWorker();
|
||||
|
||||
this.postDishMessage({
|
||||
action: "bufferToStr",
|
||||
data: {
|
||||
buffer: buffer,
|
||||
encoding: encoding,
|
||||
id: id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a message to be sent to the dishWorker
|
||||
*
|
||||
|
@ -729,12 +771,18 @@ class WorkerWaiter {
|
|||
* Sets the console log level in the workers.
|
||||
*/
|
||||
setLogLevel() {
|
||||
for (let i = 0; i < this.chefWorkers.length; i++) {
|
||||
this.chefWorkers[i].worker.postMessage({
|
||||
this.chefWorkers.forEach(cw => {
|
||||
cw.worker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.dishWorker.worker) return;
|
||||
this.dishWorker.worker.postMessage({
|
||||
action: "setLogLevel",
|
||||
data: log.getLevel()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -794,7 +842,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…
Add table
Add a link
Reference in a new issue