|
@@ -340,50 +340,6 @@ const Utils = {
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
- /**
|
|
|
|
- * Translates a hex string into an array of bytes.
|
|
|
|
- *
|
|
|
|
- * @param {string} hexStr
|
|
|
|
- * @returns {byteArray}
|
|
|
|
- *
|
|
|
|
- * @example
|
|
|
|
- * // returns [0xfe, 0x09, 0xa7]
|
|
|
|
- * Utils.hexToByteArray("fe09a7");
|
|
|
|
- */
|
|
|
|
- hexToByteArray: function(hexStr) {
|
|
|
|
- // TODO: Handle errors i.e. input string is not hex
|
|
|
|
- if (!hexStr) return [];
|
|
|
|
- hexStr = hexStr.replace(/\s+/g, "");
|
|
|
|
- const byteArray = [];
|
|
|
|
- for (let i = 0; i < hexStr.length; i += 2) {
|
|
|
|
- byteArray.push(parseInt(hexStr.substr(i, 2), 16));
|
|
|
|
- }
|
|
|
|
- return byteArray;
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Translates an array of bytes to a hex string.
|
|
|
|
- *
|
|
|
|
- * @param {byteArray} byteArray
|
|
|
|
- * @param {string} [delim=" "]
|
|
|
|
- * @returns {string}
|
|
|
|
- *
|
|
|
|
- * @example
|
|
|
|
- * // returns "fe09a7"
|
|
|
|
- * Utils.byteArrayToHex([0xfe, 0x09, 0xa7], "");
|
|
|
|
- */
|
|
|
|
- byteArrayToHex: function(byteArray, delim) {
|
|
|
|
- if (!byteArray) return "";
|
|
|
|
- delim = typeof delim === "undefined" ? " " : delim;
|
|
|
|
- let hexStr = "";
|
|
|
|
- for (let i = 0; i < byteArray.length; i++) {
|
|
|
|
- hexStr += Utils.hex(byteArray[i]) + delim;
|
|
|
|
- }
|
|
|
|
- return hexStr.slice(0, hexStr.length - delim.length);
|
|
|
|
- },
|
|
|
|
-
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Converts a string to a byte array.
|
|
* Converts a string to a byte array.
|
|
* Treats the string as UTF-8 if any values are over 255.
|
|
* Treats the string as UTF-8 if any values are over 255.
|
|
@@ -828,7 +784,7 @@ const Utils = {
|
|
if (removeScriptAndStyle) {
|
|
if (removeScriptAndStyle) {
|
|
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
|
|
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
|
|
}
|
|
}
|
|
- return htmlStr.replace(/<[^>\n]+>/g, "");
|
|
|
|
|
|
+ return htmlStr.replace(/<[^>]+>/g, "");
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
@@ -946,16 +902,19 @@ const Utils = {
|
|
* @returns {html}
|
|
* @returns {html}
|
|
*/
|
|
*/
|
|
displayFilesAsHTML: function(files) {
|
|
displayFilesAsHTML: function(files) {
|
|
|
|
+ /* <NL> and <SP> used to denote newlines and spaces in HTML markup.
|
|
|
|
+ * If a non-html operation is used, all markup will be removed but these
|
|
|
|
+ * whitespace chars will remain for formatting purposes.
|
|
|
|
+ */
|
|
|
|
+
|
|
const formatDirectory = function(file) {
|
|
const formatDirectory = function(file) {
|
|
- const html = "<div class='panel panel-default'>" +
|
|
|
|
- "<div class='panel-heading' role='tab'>" +
|
|
|
|
- "<h4 class='panel-title'>" +
|
|
|
|
- Utils.escapeHtml(file.fileName) +
|
|
|
|
- // The following line is for formatting when HTML is stripped
|
|
|
|
- "<span style='display: none'>\n0 bytes\n</span>" +
|
|
|
|
- "</h4>" +
|
|
|
|
- "</div>" +
|
|
|
|
- "</div>";
|
|
|
|
|
|
+ const html = `<div class='panel panel-default' style='white-space: normal;'>
|
|
|
|
+ <div class='panel-heading' role='tab'>
|
|
|
|
+ <h4 class='panel-title'>
|
|
|
|
+ <NL>${Utils.escapeHtml(file.fileName)}
|
|
|
|
+ </h4>
|
|
|
|
+ </div>
|
|
|
|
+ </div>`;
|
|
return html;
|
|
return html;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -966,52 +925,52 @@ const Utils = {
|
|
);
|
|
);
|
|
const blobUrl = URL.createObjectURL(blob);
|
|
const blobUrl = URL.createObjectURL(blob);
|
|
|
|
|
|
- const downloadAnchorElem = "<a href='" + blobUrl + "' " +
|
|
|
|
- "title='Download " + Utils.escapeHtml(file.fileName) + "' " +
|
|
|
|
- "download='" + Utils.escapeHtml(file.fileName) + "'>\u21B4</a>";
|
|
|
|
-
|
|
|
|
- const expandFileContentsElem = "<a href='#collapse" + i + "' " +
|
|
|
|
- "class='collapsed' " +
|
|
|
|
- "data-toggle='collapse' " +
|
|
|
|
- "aria-expanded='true' " +
|
|
|
|
- "aria-controls='collapse" + i + "' " +
|
|
|
|
- "title=\"Show/hide contents of '" + Utils.escapeHtml(file.fileName) + "'\">🔍</a>";
|
|
|
|
-
|
|
|
|
- const hexFileData = Utils.byteArrayToHex(new Uint8Array(file.bytes));
|
|
|
|
-
|
|
|
|
- const switchFileDataToInput = "<a href='#switchFileToInput" + i + "' " +
|
|
|
|
- "class='file-switch' " +
|
|
|
|
- "fileValue='" + hexFileData + "'>⇧</a>";
|
|
|
|
-
|
|
|
|
- const html = "<div class='panel panel-default'>" +
|
|
|
|
- "<div class='panel-heading' role='tab' id='heading" + i + "'>" +
|
|
|
|
- "<h4 class='panel-title'>" +
|
|
|
|
- "<div>" +
|
|
|
|
- Utils.escapeHtml(file.fileName) +
|
|
|
|
- " " + expandFileContentsElem +
|
|
|
|
- " " + downloadAnchorElem +
|
|
|
|
- " " + switchFileDataToInput +
|
|
|
|
- "<span class='pull-right'>" +
|
|
|
|
- // These are for formatting when stripping HTML
|
|
|
|
- "<span style='display: none'>\n</span>" +
|
|
|
|
- file.size.toLocaleString() + " bytes" +
|
|
|
|
- "<span style='display: none'>\n</span>" +
|
|
|
|
- "</span>" +
|
|
|
|
- "</div>" +
|
|
|
|
- "</h4>" +
|
|
|
|
- "</div>" +
|
|
|
|
- "<div id='collapse" + i + "' class='panel-collapse collapse' " +
|
|
|
|
- "role='tabpanel' aria-labelledby='heading" + i + "'>" +
|
|
|
|
- "<div class='panel-body'>" +
|
|
|
|
- "<pre><code>" + Utils.escapeHtml(file.contents) + "</pre></code></div>" +
|
|
|
|
- "</div>" +
|
|
|
|
- "</div>";
|
|
|
|
|
|
+ const viewFileElem = `<a href='#collapse${i}'
|
|
|
|
+ class='collapsed'
|
|
|
|
+ data-toggle='collapse'
|
|
|
|
+ aria-expanded='true'
|
|
|
|
+ aria-controls='collapse${i}'
|
|
|
|
+ title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">👁️</a>`;
|
|
|
|
+
|
|
|
|
+ const downloadFileElem = `<a href='${blobUrl}'
|
|
|
|
+ title='Download ${Utils.escapeHtml(file.fileName)}'
|
|
|
|
+ download='${Utils.escapeHtml(file.fileName)}'>💾</a>`;
|
|
|
|
+
|
|
|
|
+ const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
|
|
|
|
+
|
|
|
|
+ const switchToInputElem = `<a href='#switchFileToInput${i}'
|
|
|
|
+ class='file-switch'
|
|
|
|
+ title='Move file to input as hex'
|
|
|
|
+ fileValue='${hexFileData}'>⇧</a>`;
|
|
|
|
+
|
|
|
|
+ const html = `<div class='panel panel-default' style='white-space: normal;'>
|
|
|
|
+ <div class='panel-heading' role='tab' id='heading${i}'>
|
|
|
|
+ <h4 class='panel-title'>
|
|
|
|
+ <div>
|
|
|
|
+ ${Utils.escapeHtml(file.fileName)}<NL>
|
|
|
|
+ ${viewFileElem}<SP>
|
|
|
|
+ ${downloadFileElem}<SP>
|
|
|
|
+ ${switchToInputElem}<SP>
|
|
|
|
+ <span class='pull-right'>
|
|
|
|
+ <NL>${file.size.toLocaleString()} bytes
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ </h4>
|
|
|
|
+ </div>
|
|
|
|
+ <div id='collapse${i}' class='panel-collapse collapse'
|
|
|
|
+ role='tabpanel' aria-labelledby='heading${i}'>
|
|
|
|
+ <div class='panel-body'>
|
|
|
|
+ <NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>`;
|
|
return html;
|
|
return html;
|
|
};
|
|
};
|
|
|
|
|
|
- let html = "<div style='padding: 5px;'>" +
|
|
|
|
- files.length +
|
|
|
|
- " file(s) found</div>\n";
|
|
|
|
|
|
+ let html = `<div style='padding: 5px; white-space: normal;'>
|
|
|
|
+ ${files.length} file(s) found<NL>
|
|
|
|
+ </div>`;
|
|
|
|
+
|
|
files.forEach(function(file, i) {
|
|
files.forEach(function(file, i) {
|
|
if (typeof file.contents !== "undefined") {
|
|
if (typeof file.contents !== "undefined") {
|
|
html += formatFile(file, i);
|
|
html += formatFile(file, i);
|
|
@@ -1019,7 +978,10 @@ const Utils = {
|
|
html += formatDirectory(file);
|
|
html += formatDirectory(file);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
- return html;
|
|
|
|
|
|
+
|
|
|
|
+ return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
|
|
|
|
+ .replace(/<NL>/g, "\n") // Replace <NP> with newlines
|
|
|
|
+ .replace(/<SP>/g, " "); // Replace <SP> with spaces
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|