Add carriage return detection for pasted and switched inputs.

Fix switching the output to input not working properly.
Add nicer confirmation boxes for zipping outputs.
This commit is contained in:
j433866 2019-08-22 11:53:41 +01:00
parent 9f2d1453ed
commit f43a868607
6 changed files with 399 additions and 246 deletions

View File

@ -568,11 +568,18 @@
</div>
<div class="checkbox option-item">
<label for="syncTabs">
<input type="checkbox" option="syncTabs" id="syncTabs">
Keep the current tab in sync between the input and output.
</label>
</div>
<label for="syncTabs">
<input type="checkbox" option="syncTabs" id="syncTabs">
Keep the current tab in sync between the input and output.
</label>
</div>
<div class="checkbox option-item">
<label for="preserveCR" data-toggle="tooltip" data-placement="right" data-html="true" title="As HTML textareas don't support carriage returns, editing input must be turned off to preserve them.<br><br>When this option is enabled, editing will be disabled when an input with carriage returns is detected to preserve them. Otherwise, editing will remain enabled but carriage returns will not be preserved.">
<input type="checkbox" option="preserveCR" id="preserveCR">
Preserve carriage returns.
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>

View File

@ -53,7 +53,9 @@ function main() {
logLevel: "info",
autoMagic: true,
imagePreview: true,
syncTabs: true
syncTabs: true,
preserveCR: true,
userSetCR: false
};
document.removeEventListener("DOMContentLoaded", main, false);

View File

@ -222,8 +222,6 @@ class InputWaiter {
if (Object.prototype.hasOwnProperty.call(r, "progress") &&
Object.prototype.hasOwnProperty.call(r, "inputNum")) {
this.manager.tabs.updateInputTabProgress(r.inputNum, r.progress, 100);
} else if (Object.prototype.hasOwnProperty.call(r, "fileBuffer")) {
this.manager.tabs.updateInputTabProgress(r.inputNum, 100, 100);
}
const transferable = Object.prototype.hasOwnProperty.call(r, "fileBuffer") ? [r.fileBuffer] : undefined;
@ -305,6 +303,9 @@ class InputWaiter {
case "removeChefWorker":
this.removeChefWorker();
break;
case "fileLoaded":
this.fileLoaded(r.data.inputNum);
break;
default:
log.error(`Unknown action ${r.action}.`);
}
@ -331,7 +332,7 @@ class InputWaiter {
* @param {number} inputData.size - The size in bytes of the input file
* @param {string} inputData.type - The MIME type of the input file
* @param {number} inputData.progress - The load progress of the input file
* @param {boolean} [silent=false] - If true, fires the manager statechange event
* @param {boolean} [silent=false] - If false, fires the manager statechange event
*/
async set(inputData, silent=false) {
return new Promise(function(resolve, reject) {
@ -373,7 +374,7 @@ class InputWaiter {
if (!silent) window.dispatchEvent(this.manager.statechange);
} else {
this.setFile(inputData);
this.setFile(inputData, silent);
}
}.bind(this));
@ -389,8 +390,9 @@ class InputWaiter {
* @param {number} inputData.size - The size in bytes of the input file
* @param {string} inputData.type - The MIME type of the input file
* @param {number} inputData.progress - The load progress of the input file
* @param {boolean} [silent=true] - If false, fires the manager statechange event
*/
setFile(inputData) {
setFile(inputData, silent=true) {
const activeTab = this.manager.tabs.getActiveInputTab();
if (inputData.inputNum !== activeTab) return;
@ -414,6 +416,30 @@ class InputWaiter {
this.setInputInfo(inputData.size, null);
this.displayFilePreview(inputData);
if (!silent) window.dispatchEvent(this.manager.statechange);
}
/**
* Update file details when a file completes loading
*
* @param {number} inputNum - The inputNum of the input which has finished loading
*/
fileLoaded(inputNum) {
this.manager.tabs.updateInputTabProgress(inputNum, 100, 100);
const activeTab = this.manager.tabs.getActiveInputTab();
if (activeTab !== inputNum) return;
this.inputWorker.postMessage({
action: "setInput",
data: {
inputNum: inputNum,
silent: false
}
});
this.updateFileProgress(inputNum, 100);
}
/**
@ -495,19 +521,6 @@ class InputWaiter {
fileLoaded.textContent = progress + "%";
fileLoaded.style.color = "";
}
if (progress === 100 && progress !== oldProgress) {
// Don't set the input if the progress hasn't changed
this.inputWorker.postMessage({
action: "setInput",
data: {
inputNum: inputNum,
silent: false
}
});
window.dispatchEvent(this.manager.statechange);
}
}
/**
@ -711,13 +724,17 @@ class InputWaiter {
*
* @param {event} e
*/
inputPaste(e) {
async inputPaste(e) {
e.preventDefault();
e.stopPropagation();
const pastedData = e.clipboardData.getData("Text");
if (pastedData.length < (this.app.options.ioDisplayThreshold * 1024)) {
const preserve = await this.preserveCarriageReturns(pastedData);
if (pastedData.length < (this.app.options.ioDisplayThreshold * 1024) && !preserve) {
// Pasting normally fires the inputChange() event before
// changing the value, so instead change it here ourselves
// and manually fire inputChange()
e.preventDefault();
const inputText = document.getElementById("input-text");
const selStart = inputText.selectionStart;
const selEnd = inputText.selectionEnd;
@ -728,9 +745,6 @@ class InputWaiter {
inputText.setSelectionRange(selStart + pastedData.length, selStart + pastedData.length);
this.debounceInputChange(e);
} else {
e.preventDefault();
e.stopPropagation();
const file = new File([pastedData], "PastedData", {
type: "text/plain",
lastModified: Date.now()
@ -815,6 +829,45 @@ class InputWaiter {
}
}
/**
* Checks if an input contains carriage returns.
* If a CR is detected, checks if the preserve CR option has been set,
* and if not, asks the user for their preference.
*
* @param {string} input - The input to be checked
* @returns {boolean} - If true, the input contains a CR which should be
* preserved, so display an overlay so it can't be edited
*/
async preserveCarriageReturns(input) {
if (input.indexOf("\r") >= 0) {
const optionsStr = "This behaviour can be changed in the <a href='#' onclick='document.getElementById(\"options\").click()'>options</a>";
if (!this.app.options.userSetCR) {
let preserve = await new Promise(function(resolve, reject) {
this.app.confirm(
"Carriage Return Detected",
"A carriage return was detected in your input. As HTML textareas can't display carriage returns, editing must be turned off to preserve them. <br>Alternatively, you can enable editing but your carriage returns will not be preserved.<br><br>This preference will be saved, and can be toggled in the options.",
"Preserve Carriage Returns",
"Enable Editing", resolve, this);
}.bind(this));
if (preserve === undefined) {
this.app.alert(`Not preserving carriage returns. ${optionsStr}`, 4000);
preserve = false;
}
this.manager.options.updateOption("preserveCR", preserve);
this.manager.options.updateOption("userSetCR", true);
} else {
if (this.app.options.preserveCR) {
this.app.alert(`Carriage return(s) detected in input, so editing has been disabled to preserve them. ${optionsStr}`, 6000);
} else {
this.app.alert(`Carriage return(s) detected in input. Editing is remaining enabled, but any carriage returns will be removed. ${optionsStr}`, 6000);
}
}
return this.app.options.preserveCR;
} else {
return false;
}
}
/**
* Load files from the UI into the inputWorker
*

View File

@ -1,174 +1,180 @@
/**
* Waiter to handle events related to the CyberChef options.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @constructor
* @param {App} app - The main view object for CyberChef.
*/
const OptionsWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
};
/**
* Loads options and sets values of switches and inputs to match them.
*
* @param {Object} options
* Waiter to handle events related to the CyberChef options.
*/
OptionsWaiter.prototype.load = function(options) {
for (const option in options) {
this.app.options[option] = options[option];
class OptionsWaiter {
/**
* OptionsWaiter 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;
}
// 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")];
}
/**
* Loads options and sets values of switches and inputs to match them.
*
* @param {Object} options
*/
load(options) {
for (const option in options) {
this.app.options[option] = options[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}));
}
// 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")];
}
const selects = document.querySelectorAll("#options-body select");
for (i = 0; i < selects.length; i++) {
const val = this.app.options[selects[i].getAttribute("option")];
if (val) {
selects[i].value = val;
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
} else {
selects[i].selectedIndex = 0;
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}));
}
const selects = document.querySelectorAll("#options-body select");
for (i = 0; i < selects.length; i++) {
const val = this.app.options[selects[i].getAttribute("option")];
if (val) {
selects[i].value = val;
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
} else {
selects[i].selectedIndex = 0;
}
}
}
};
/**
* Handler for options click events.
* Dispays the options pane.
*
* @param {event} e
*/
OptionsWaiter.prototype.optionsClick = function(e) {
e.preventDefault();
$("#options-modal").modal();
};
/**
* Handler for reset options click events.
* Resets options back to their default values.
*/
OptionsWaiter.prototype.resetOptionsClick = function() {
this.load(this.app.doptions);
};
/**
* Handler for switch change events.
* Modifies the option state and saves it to local storage.
*
* @param {event} e
*/
OptionsWaiter.prototype.switchChange = function(e) {
const el = e.target;
const option = el.getAttribute("option");
const state = el.checked;
log.debug(`Setting ${option} to ${state}`);
this.app.options[option] = state;
if (this.app.isLocalStorageAvailable())
localStorage.setItem("options", JSON.stringify(this.app.options));
};
/**
* Handler for number change events.
* Modifies the option value and saves it to local storage.
*
* @param {event} e
*/
OptionsWaiter.prototype.numberChange = function(e) {
const el = e.target;
const option = el.getAttribute("option");
const val = parseInt(el.value, 10);
log.debug(`Setting ${option} to ${val}`);
this.app.options[option] = val;
if (this.app.isLocalStorageAvailable())
localStorage.setItem("options", JSON.stringify(this.app.options));
};
/**
* Handler for select change events.
* Modifies the option value and saves it to local storage.
*
* @param {event} e
*/
OptionsWaiter.prototype.selectChange = function(e) {
const el = e.target;
const option = el.getAttribute("option");
log.debug(`Setting ${option} to ${el.value}`);
this.app.options[option] = el.value;
if (this.app.isLocalStorageAvailable())
localStorage.setItem("options", JSON.stringify(this.app.options));
};
/**
* Sets or unsets word wrap on the input and output depending on the wordWrap option value.
*/
OptionsWaiter.prototype.setWordWrap = function() {
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");
/**
* Handler for options click events.
* Dispays the options pane.
*
* @param {event} e
*/
optionsClick(e) {
e.preventDefault();
$("#options-modal").modal();
}
};
/**
* Changes the theme by setting the class of the <html> element.
*
* @param {Event} e
*/
OptionsWaiter.prototype.themeChange = function (e) {
const themeClass = e.target.value;
document.querySelector(":root").className = themeClass;
};
/**
* Handler for reset options click events.
* Resets options back to their default values.
*/
resetOptionsClick() {
this.load(this.app.doptions);
}
/**
* Changes the console logging level.
*
* @param {Event} e
*/
OptionsWaiter.prototype.logLevelChange = function (e) {
const level = e.target.value;
log.setLevel(level, false);
this.manager.worker.setLogLevel();
this.manager.input.setLogLevel();
};
/**
* Handler for switch change events.
*
* @param {event} e
*/
switchChange(e) {
const el = e.target;
const option = el.getAttribute("option");
const state = el.checked;
this.updateOption(option, state);
}
/**
* Handler for number change events.
*
* @param {event} e
*/
numberChange(e) {
const el = e.target;
const option = el.getAttribute("option");
const val = parseInt(el.value, 10);
this.updateOption(option, val);
}
/**
* Handler for select change events.
*
* @param {event} e
*/
selectChange(e) {
const el = e.target;
const option = el.getAttribute("option");
this.updateOption(option, el.value);
}
/**
* Modifies an option value and saves it to local storage.
*
* @param {string} option - The option to be updated
* @param {string|number|boolean} value - The new value of the option
*/
updateOption(option, value) {
log.debug(`Setting ${option} to ${value}`);
this.app.options[option] = value;
if (this.app.isLocalStorageAvailable())
localStorage.setItem("options", JSON.stringify(this.app.options));
}
/**
* 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");
}
}
/**
* Changes the theme by setting the class of the <html> element.
*
* @param {Event} e
*/
themeChange(e) {
const themeClass = e.target.value;
document.querySelector(":root").className = themeClass;
}
/**
* Changes the console logging level.
*
* @param {Event} e
*/
logLevelChange(e) {
const level = e.target.value;
log.setLevel(level, false);
this.manager.worker.setLogLevel();
this.manager.input.setLogLevel();
}
}
export default OptionsWaiter;

View File

@ -217,6 +217,9 @@ class OutputWaiter {
*/
removeAllOutputs() {
this.outputs = {};
this.resetSwitch();
const tabsList = document.getElementById("output-tabs");
const tabsListChildren = tabsList.children;
@ -516,9 +519,10 @@ class OutputWaiter {
this.app.alert("Could not find any output data to download. Has this output been baked?", 3000);
return;
}
let fileName = window.prompt("Please enter a filename: ", "download.dat");
const fileName = window.prompt("Please enter a filename: ", "download.dat");
if (fileName === null) fileName = "download.dat";
// Assume if the user clicks cancel they don't want to download
if (fileName === null) return;
const data = await dish.get(Dish.ARRAY_BUFFER),
file = new File([data], fileName);
@ -529,12 +533,22 @@ class OutputWaiter {
* Handler for save all click event
* Saves all outputs to a single archvie file
*/
saveAllClick() {
async saveAllClick() {
const downloadButton = document.getElementById("save-all-to-file");
if (downloadButton.firstElementChild.innerHTML === "archive") {
this.downloadAllFiles();
} else if (window.confirm("Cancel zipping of outputs?")) {
this.terminateZipWorker();
} else {
const cancel = await new Promise(function(resolve, reject) {
this.app.confirm(
"Cancel zipping?",
"The outputs are currently being zipped for download.<br>Cancel zipping?",
"Continue zipping",
"Cancel zipping",
resolve, this);
}.bind(this));
if (!cancel && cancel !== undefined) {
this.terminateZipWorker();
}
}
}
@ -544,57 +558,61 @@ class OutputWaiter {
* be zipped for download
*/
async downloadAllFiles() {
return new Promise(resolve => {
const inputNums = Object.keys(this.outputs);
for (let i = 0; i < inputNums.length; i++) {
const iNum = inputNums[i];
if (this.outputs[iNum].status !== "baked" ||
this.outputs[iNum].bakeId !== this.manager.worker.bakeId) {
if (window.confirm("Not all outputs have been baked yet. Continue downloading outputs?")) {
break;
} else {
return;
}
const inputNums = Object.keys(this.outputs);
for (let i = 0; i < inputNums.length; i++) {
const iNum = inputNums[i];
if (this.outputs[iNum].status !== "baked" ||
this.outputs[iNum].bakeId !== this.manager.worker.bakeId) {
const continueDownloading = await new Promise(function(resolve, reject) {
this.app.confirm(
"Incomplete outputs",
"Not all outputs have been baked yet. Continue downloading outputs?",
"Download", "Cancel", resolve, this);
}.bind(this));
if (continueDownloading) {
break;
} else {
return;
}
}
}
let fileName = window.prompt("Please enter a filename: ", "download.zip");
let fileName = window.prompt("Please enter a filename: ", "download.zip");
if (fileName === null || fileName === "") {
// Don't zip the files if there isn't a filename
this.app.alert("No filename was specified.", 3000);
return;
}
if (fileName === null || fileName === "") {
// Don't zip the files if there isn't a filename
this.app.alert("No filename was specified.", 3000);
return;
}
if (!fileName.match(/.zip$/)) {
fileName += ".zip";
}
if (!fileName.match(/.zip$/)) {
fileName += ".zip";
}
let fileExt = window.prompt("Please enter a file extension for the files, or leave blank to detect automatically.", "");
let fileExt = window.prompt("Please enter a file extension for the files, or leave blank to detect automatically.", "");
if (fileExt === null) fileExt = "";
if (fileExt === null) fileExt = "";
if (this.zipWorker !== null) {
this.terminateZipWorker();
}
if (this.zipWorker !== null) {
this.terminateZipWorker();
}
const downloadButton = document.getElementById("save-all-to-file");
const downloadButton = document.getElementById("save-all-to-file");
downloadButton.classList.add("spin");
downloadButton.title = `Zipping ${inputNums.length} files...`;
downloadButton.setAttribute("data-original-title", `Zipping ${inputNums.length} files...`);
downloadButton.classList.add("spin");
downloadButton.title = `Zipping ${inputNums.length} files...`;
downloadButton.setAttribute("data-original-title", `Zipping ${inputNums.length} files...`);
downloadButton.firstElementChild.innerHTML = "autorenew";
downloadButton.firstElementChild.innerHTML = "autorenew";
log.debug("Creating ZipWorker");
this.zipWorker = new ZipWorker();
this.zipWorker.postMessage({
outputs: this.outputs,
filename: fileName,
fileExtension: fileExt
});
this.zipWorker.addEventListener("message", this.handleZipWorkerMessage.bind(this));
log.debug("Creating ZipWorker");
this.zipWorker = new ZipWorker();
this.zipWorker.postMessage({
outputs: this.outputs,
filename: fileName,
fileExtension: fileExt
});
this.zipWorker.addEventListener("message", this.handleZipWorkerMessage.bind(this));
}
/**
@ -1213,14 +1231,39 @@ class OutputWaiter {
* Moves the current output into the input textarea.
*/
async switchClick() {
const active = await this.getDishBuffer(this.getOutputDish(this.manager.tabs.getActiveOutputTab()));
const activeTab = this.manager.tabs.getActiveOutputTab();
const transferable = [];
const switchButton = document.getElementById("switch");
switchButton.classList.add("spin");
switchButton.disabled = true;
switchButton.firstElementChild.innerHTML = "autorenew";
$(switchButton).tooltip("hide");
let active = await this.getDishBuffer(this.getOutputDish(activeTab));
if (!this.outputExists(activeTab)) {
this.resetSwitchButton();
return;
}
if (this.outputs[activeTab].data.type === "string" &&
active.byteLength <= this.app.options.ioDisplayThreshold * 1024) {
const dishString = await this.getDishStr(this.getOutputDish(activeTab));
if (!await this.manager.input.preserveCarriageReturns(dishString)) {
active = dishString;
}
} else {
transferable.push(active);
}
this.manager.input.inputWorker.postMessage({
action: "inputSwitch",
data: {
inputNum: this.manager.tabs.getActiveInputTab(),
inputNum: activeTab,
outputData: active
}
}, [active]);
}, transferable);
}
/**
@ -1238,6 +1281,9 @@ class OutputWaiter {
inputSwitch(switchData) {
this.switchOrigData = switchData;
document.getElementById("undo-switch").disabled = false;
this.resetSwitchButton();
}
/**
@ -1246,17 +1292,35 @@ class OutputWaiter {
*/
undoSwitchClick() {
this.manager.input.updateInputObj(this.switchOrigData.inputNum, this.switchOrigData.data);
this.manager.input.fileLoaded(this.switchOrigData.inputNum);
this.resetSwitch();
}
/**
* Removes the switch data and resets the switch buttons
*/
resetSwitch() {
if (this.switchOrigData !== undefined) {
delete this.switchOrigData;
}
const undoSwitch = document.getElementById("undo-switch");
undoSwitch.disabled = true;
$(undoSwitch).tooltip("hide");
this.manager.input.inputWorker.postMessage({
action: "setInput",
data: {
inputNum: this.switchOrigData.inputNum,
silent: false
}
});
this.resetSwitchButton();
}
/**
* Resets the switch button to its usual state
*/
resetSwitchButton() {
const switchButton = document.getElementById("switch");
switchButton.classList.remove("spin");
switchButton.disabled = false;
switchButton.firstElementChild.innerHTML = "open_in_browser";
}
/**

View File

@ -202,6 +202,7 @@ self.bakeInput = function(inputNum, bakeId) {
if (inputObj === null ||
inputObj === undefined ||
inputObj.status !== "loaded") {
self.postMessage({
action: "queueInputError",
data: {
@ -441,7 +442,7 @@ self.updateTabHeader = function(inputNum) {
*
* @param {object} inputData
* @param {number} inputData.inputNum - The input to get the data for
* @param {boolean} inputData.silent - If false, the manager statechange event won't be fired
* @param {boolean} inputData.silent - If false, the manager statechange event will be fired
*/
self.setInput = function(inputData) {
const inputNum = inputData.inputNum;
@ -590,7 +591,7 @@ self.updateInputObj = function(inputData) {
const inputNum = inputData.inputNum;
const data = inputData.data;
if (self.getInputObj(inputNum) === -1) return;
if (self.getInputObj(inputNum) === undefined) return;
self.inputs[inputNum].data = data;
};
@ -663,11 +664,19 @@ self.handleLoaderMessage = function(r) {
if ("fileBuffer" in r) {
log.debug(`Input file ${inputNum} loaded.`);
self.loadingInputs--;
self.updateInputValue({
inputNum: inputNum,
value: r.fileBuffer
});
self.postMessage({
action: "fileLoaded",
data: {
inputNum: inputNum
}
});
const idx = self.getLoaderWorkerIdx(r.id);
self.loadNextFile(idx);
} else if ("progress" in r) {
@ -782,7 +791,7 @@ self.loadFiles = function(filesData) {
}
self.getLoadProgress();
self.setInput({inputNum: activeTab, silent: false});
self.setInput({inputNum: activeTab, silent: true});
};
/**
@ -1025,7 +1034,7 @@ self.inputSwitch = function(switchData) {
const currentData = currentInput.data;
if (currentInput === undefined || currentInput === null) return;
if (typeof switchData.outputData === "object") {
if (typeof switchData.outputData !== "string") {
const output = new Uint8Array(switchData.outputData),
types = detectFileType(output);
let type = "unknown",
@ -1036,15 +1045,22 @@ self.inputSwitch = function(switchData) {
}
// ArrayBuffer
currentInput.data = {
fileBuffer: switchData.outputData,
name: `output.${ext}`,
size: switchData.outputData.byteLength.toLocaleString(),
type: type
};
self.updateInputObj({
inputNum: switchData.inputNum,
data: {
fileBuffer: switchData.outputData,
name: `output.${ext}`,
size: switchData.outputData.byteLength.toLocaleString(),
type: type
}
});
} else {
// String
currentInput.data = switchData.outputData;
self.updateInputValue({
inputNum: switchData.inputNum,
value: switchData.outputData,
force: true
});
}
self.postMessage({
@ -1055,6 +1071,11 @@ self.inputSwitch = function(switchData) {
}
});
self.setInput({inputNum: switchData.inputNum, silent: false});
self.postMessage({
action: "fileLoaded",
data: {
inputNum: switchData.inputNum
}
});
};