Output over 1MiB is passed back as an ArrayBuffer and an output file card is displayed.

This commit is contained in:
n1474335 2017-12-26 00:44:40 +00:00
parent 0e7989111f
commit af71ca6a25
7 changed files with 130 additions and 35 deletions

View File

@ -76,10 +76,15 @@ Chef.prototype.bake = async function(input, recipeConfig, options, progress, ste
progress = err.progress;
}
// Depending on the size of the output, we may send it back as a string or an ArrayBuffer.
// This can prevent unnecessary casting as an ArrayBuffer can be easily downloaded as a file.
// 1048576 bytes = 1 MiB
const returnType = this.dish.size() > 1048576 ? Dish.ARRAY_BUFFER : Dish.STRING;
return {
result: this.dish.type === Dish.HTML ?
this.dish.get(Dish.HTML) :
this.dish.get(Dish.STRING),
this.dish.get(returnType),
type: Dish.enumLookup(this.dish.type),
progress: progress,
duration: new Date().getTime() - startTime,

View File

@ -349,7 +349,14 @@ const Utils = {
* @returns {byteArray}
*
* @example
* // returns []
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("Привет", "utf8");
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
*/
convertToByteArray: function(str, type) {
switch (type.toLowerCase()) {
@ -511,6 +518,22 @@ const Utils = {
},
/**
* Converts an ArrayBuffer to a string.
*
* @param {ArrayBuffer} arrayBuffer
* @returns {string}
*
* @example
* // returns "hello"
* Utils.arrayBufferToStr(Uint8Array.from([104,101,108,108,111]).buffer);
*/
arrayBufferToStr: function(arrayBuffer) {
const byteArray = Array.prototype.slice.call(new Uint8Array(arrayBuffer));
return Utils.byteArrayToUtf8(byteArray);
},
/**
* Base64's the input byte array using the given alphabet, returning a string.
*

View File

@ -79,13 +79,13 @@ InputWaiter.prototype.setFile = function(file) {
fileName = document.getElementById("input-file-name"),
fileSize = document.getElementById("input-file-size"),
fileType = document.getElementById("input-file-type"),
fileUploaded = document.getElementById("input-file-uploaded");
fileLoaded = document.getElementById("input-file-loaded");
fileOverlay.style.display = "block";
fileName.textContent = file.name;
fileSize.textContent = file.size.toLocaleString() + " bytes";
fileType.textContent = file.type;
fileUploaded.textContent = "0%";
fileLoaded.textContent = "0%";
};
@ -210,8 +210,8 @@ InputWaiter.prototype.inputDrop = function(e) {
InputWaiter.prototype.handleLoaderMessage = function(e) {
const r = e.data;
if (r.hasOwnProperty("progress")) {
const fileUploaded = document.getElementById("input-file-uploaded");
fileUploaded.textContent = r.progress + "%";
const fileLoaded = document.getElementById("input-file-loaded");
fileLoaded.textContent = r.progress + "%";
}
if (r.hasOwnProperty("fileBuffer")) {
@ -246,6 +246,7 @@ InputWaiter.prototype.clearIoClick = function() {
document.getElementById("output-info").innerHTML = "";
document.getElementById("input-selection-info").innerHTML = "";
document.getElementById("output-selection-info").innerHTML = "";
document.getElementById("output-file").style.display = "none";
window.dispatchEvent(this.manager.statechange);
};

View File

@ -31,47 +31,85 @@ OutputWaiter.prototype.get = function() {
/**
* Sets the output in the output textarea.
*
* @param {string} dataStr - The output string/HTML
* @param {string|ArrayBuffer} data - The output string/HTML/ArrayBuffer
* @param {string} type - The data type of the output
* @param {number} duration - The length of time (ms) it took to generate the output
*/
OutputWaiter.prototype.set = function(dataStr, type, duration) {
OutputWaiter.prototype.set = function(data, type, duration) {
const outputText = document.getElementById("output-text");
const outputHtml = document.getElementById("output-html");
const outputFile = document.getElementById("output-file");
const outputHighlighter = document.getElementById("output-highlighter");
const inputHighlighter = document.getElementById("input-highlighter");
let scriptElements, lines, length;
if (type === "html") {
outputText.style.display = "none";
outputHtml.style.display = "block";
outputHighlighter.display = "none";
inputHighlighter.display = "none";
switch (type) {
case "html":
outputText.style.display = "none";
outputHtml.style.display = "block";
outputFile.style.display = "none";
outputHighlighter.display = "none";
inputHighlighter.display = "none";
outputText.value = "";
outputHtml.innerHTML = dataStr;
outputText.value = "";
outputHtml.innerHTML = data;
length = data.length;
// Execute script sections
const scriptElements = outputHtml.querySelectorAll("script");
for (let i = 0; i < scriptElements.length; i++) {
try {
eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
} catch (err) {
console.error(err);
// Execute script sections
scriptElements = outputHtml.querySelectorAll("script");
for (let i = 0; i < scriptElements.length; i++) {
try {
eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
} catch (err) {
console.error(err);
}
}
}
} else {
outputText.style.display = "block";
outputHtml.style.display = "none";
outputHighlighter.display = "block";
inputHighlighter.display = "block";
break;
case "ArrayBuffer":
outputText.style.display = "block";
outputHtml.style.display = "none";
outputHighlighter.display = "none";
inputHighlighter.display = "none";
outputText.value = Utils.printable(dataStr, true);
outputHtml.innerHTML = "";
outputText.value = "";
outputHtml.innerHTML = "";
length = data.byteLength;
this.setFile(new File([data], "output.dat"));
break;
case "string":
default:
outputText.style.display = "block";
outputHtml.style.display = "none";
outputFile.style.display = "none";
outputHighlighter.display = "block";
inputHighlighter.display = "block";
outputText.value = Utils.printable(data, true);
outputHtml.innerHTML = "";
lines = data.count("\n") + 1;
length = data.length;
break;
}
this.manager.highlighter.removeHighlights();
const lines = dataStr.count("\n") + 1;
this.setOutputInfo(dataStr.length, lines, duration);
this.setOutputInfo(length, lines, duration);
};
/**
* Shows file details.
*
* @param {File} file
*/
OutputWaiter.prototype.setFile = function(file) {
// Display file overlay in output area with details
const fileOverlay = document.getElementById("output-file"),
fileSize = document.getElementById("output-file-size");
fileOverlay.style.display = "block";
fileSize.textContent = file.size.toLocaleString() + " bytes";
};
@ -86,6 +124,8 @@ OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
let width = length.toString().length;
width = width < 4 ? 4 : width;
lines = typeof lines === "number" ? lines : "";
const lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
const linesStr = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
const timeStr = Utils.pad(duration.toString() + "ms", width, " ").replace(/ /g, "&nbsp;");

View File

@ -111,7 +111,19 @@ WorkerWaiter.prototype.bakingComplete = function(response) {
this.app.handleError(response.error);
}
this.app.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result;
switch (response.type) {
case "html":
this.app.dishStr = Utils.stripHtmlTags(response.result, true);
break;
case "ArrayBuffer":
this.app.dishStr = "";
break;
case "string":
default:
this.app.dishStr = response.result;
break;
}
this.app.progress = response.progress;
this.manager.recipe.updateBreakpointIndicator(response.progress);
this.manager.output.set(response.result, response.type, response.duration);

View File

@ -190,7 +190,7 @@
Name: <span id="input-file-name"></span><br>
Size: <span id="input-file-size"></span><br>
Type: <span id="input-file-type"></span><br>
Uploaded: <span id="input-file-uploaded"></span>
Loaded: <span id="input-file-loaded"></span>
</div>
</div>
</div>
@ -216,6 +216,19 @@
<div id="output-highlighter" class="no-select"></div>
<div id="output-html"></div>
<textarea id="output-text" readonly="readonly"></textarea>
<div id="output-file">
<div style="position: relative; height: 100%;">
<div class="card">
<img aria-hidden="true" src="<%- require('../static/images/cyberchef-256x256.png') %>" alt="File icon"/>
<div class="card-body">
Size: <span id="output-file-size"></span><br>
Download<br>
Display in output<br>
Options for how much to display
</div>
</div>
</div>
</div>
<div id="output-loader">
<div class="loader"></div>
<div class="loading-msg"></div>

View File

@ -77,7 +77,8 @@
transition: all 0.5s ease;
}
#input-file {
#input-file,
#output-file {
position: absolute;
left: 0;
top: 0;