From e2af3c78e7550502ec0d7384af29f4302a539306 Mon Sep 17 00:00:00 2001 From: Mark Jones Date: Thu, 26 Apr 2018 00:33:19 +0100 Subject: [PATCH 1/2] Added ToTable operation to output data as ASCII or HTML tables. --- src/core/config/Categories.js | 1 + src/core/config/OperationConfig.js | 33 +++++ src/core/config/modules/Default.js | 2 + src/core/operations/ToTable.js | 189 +++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100755 src/core/operations/ToTable.js diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index b2c404f61..33ec4a997 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -67,6 +67,7 @@ const Categories = [ "Encode text", "Decode text", "Swap endianness", + "To Table", ] }, { diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index bbe80a09d..5d2ca478c 100644 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -37,6 +37,7 @@ import SeqUtils from "../operations/SeqUtils.js"; import Shellcode from "../operations/Shellcode.js"; import StrUtils from "../operations/StrUtils.js"; import Tidy from "../operations/Tidy.js"; +import ToTable from "../operations/ToTable.js"; import Unicode from "../operations/Unicode.js"; import URL_ from "../operations/URL.js"; @@ -613,6 +614,38 @@ const OperationConfig = { } ] }, + "To Table": { + module: "Default", + description: "Renders data as a table. Data can be split on different characters and output as a HTML or ASCII table with optional header row.", + inputType: "string", + outputType: "html", + highlight: false, + highlightReverse: false, + manualBake: false, + args: [ + { + name: "Select separator", + type: "populateOption", + value: ToTable.SEPARATORS, + target: 1 + }, + { + name: "Separator", + type: "string", + value: "," + }, + { + name: "First row header?", + type: "boolean", + value: false + }, + { + name: "Format", + type: "option", + value: ToTable.FORMATS + } + ] + }, "From Hex": { module: "Default", description: "Converts a hexadecimal byte string back into its raw value.

e.g. ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a becomes the UTF-8 encoded string Γειά σου", diff --git a/src/core/config/modules/Default.js b/src/core/config/modules/Default.js index e5f070cfd..6b9f60f99 100644 --- a/src/core/config/modules/Default.js +++ b/src/core/config/modules/Default.js @@ -27,6 +27,7 @@ import Rotate from "../../operations/Rotate.js"; import SeqUtils from "../../operations/SeqUtils.js"; import StrUtils from "../../operations/StrUtils.js"; import Tidy from "../../operations/Tidy.js"; +import ToTable from "../../operations/ToTable.js"; import Unicode from "../../operations/Unicode.js"; import UUID from "../../operations/UUID.js"; import XKCD from "../../operations/XKCD.js"; @@ -163,6 +164,7 @@ OpModules.Default = { "Mean": Arithmetic.runMean, "Median": Arithmetic.runMedian, "Standard Deviation": Arithmetic.runStdDev, + "To Table": ToTable.runToTable, "Windows Filetime to UNIX Timestamp": Filetime.runFromFiletimeToUnix, "UNIX Timestamp to Windows Filetime": Filetime.runToFiletimeFromUnix, "XKCD Random Number": XKCD.runRandomNumber, diff --git a/src/core/operations/ToTable.js b/src/core/operations/ToTable.js new file mode 100755 index 000000000..342271922 --- /dev/null +++ b/src/core/operations/ToTable.js @@ -0,0 +1,189 @@ +import Utils from "../Utils.js"; + +/** + * ToTable operations. + * + * @author Mark Jones [github.com/justanothermark] + * @namespace + */ + const ToTable = { + /** + * @constant + * @default + */ + SEPARATORS: [ + {name: "Comma", value:","}, + {name: "Tab", value: escape("\t")}, + {name: "Pipe", value: "|"}, + {name: "Custom", value: ""} + ], + + /** + * @constant + * @default + */ + FORMATS: [ + 'ASCII', + 'HTML' + ], + + /** + * To Table operation. + * + * @param {string} input + * @param {Object[]} args + * @returns {html} + */ + runToTable: function (input, args) { + let separator = args[1]; + let firstRowHeader = args[2]; + let format = args[3]; + let tableData = []; + + // If the separator contains any tabs, convert them to tab characters. + separator = separator.replace('\\t', '\t'); + + // Process the input into a nested array of elements. + let rows = input.split('\n'); + rows.forEach(function(element) { + if (separator == '') { + tableData.push([element]); + } + else { + tableData.push(element.split(separator)); + } + }); + + // Render the data in the requested format. + let output = ''; + switch (format) { + case 'ASCII': + output = asciiOutput(tableData); + break; + + default: + output = htmlOutput(tableData); + break; + } + + return output; + + /** + * Outputs an array of data as an ASCII table. + * + * @param {Array[]} tableData + * @returns {string} + */ + function asciiOutput(tableData) { + const horizontalBorder = '-'; + const verticalBorder = '|'; + const crossBorder = '+'; + + let output = ''; + let longestCells = []; + + // Find longestCells value per column to pad cells equally. + tableData.forEach(function(row, index) { + row.forEach(function(cell, cellIndex) { + if (longestCells[cellIndex] == undefined || cell.length > longestCells[cellIndex]) { + longestCells[cellIndex] = cell.length; + } + }); + }); + + // Calculate the complete row length. This is the length of the + // longest cell for each column plus 3 characters per cell + // (1 padding each side of the value and 1 for the cell border) + // plus 1 for the final cell border. + let rowLength = (longestCells.length * 3) + 1; + longestCells.forEach(function(celllongestCells) { + rowLength += celllongestCells; + }); + + // Add the top border of the table to the output. + output += outputHorizontalBorder(longestCells); + + // If the first row is a header, remove the row from the data and + // add it to the output with another horizontal border. + if (firstRowHeader) { + let row = tableData.shift(); + output += outputRow(row, longestCells); + output += outputHorizontalBorder(longestCells); + } + + // Add the rest of the table rows. + tableData.forEach(function(row, index) { + output += outputRow(row, longestCells); + }); + + // Close the table with a final horizontal border. + output += outputHorizontalBorder(longestCells); + + return output; + + /** + * Outputs a row of correctly padded cells. + */ + function outputRow(row, longestCells) { + let rowOutput = verticalBorder; + row.forEach(function(cell, index) { + rowOutput += ' ' + cell + ' '.repeat(longestCells[index] - cell.length) + ' ' + verticalBorder; + }); + rowOutput += '\n'; + return rowOutput; + } + + /** + * Outputs a horizontal border with a different character where + * the horizontal border meets a vertical border. + */ + function outputHorizontalBorder(longestCells) { + let rowOutput = crossBorder; + longestCells.forEach(function(cellLength) { + rowOutput += horizontalBorder.repeat(cellLength + 2) + crossBorder; + }); + rowOutput += '\n'; + return rowOutput; + } + } + + /** + * Outputs a table of data as a HTML table. + */ + function htmlOutput(tableData) { + // Start the HTML output with suitable classes for styling. + let output = ""; + + // If the first row is a header then put it in with "; + output += outputRow(row, 'th'); + output += ""; + } + + // Output the rest of the rows in the . + output += ""; + tableData.forEach(function(row, index) { + output += outputRow(row, 'td'); + }); + + // Close the body and table elements. + output += "
cells. + if (firstRowHeader) { + let row = tableData.shift(); + output += "
"; + return output; + + function outputRow(row, cellType) { + let output = ""; + row.forEach(function(cell) { + output += "<" + cellType + ">" + cell + ""; + }); + output += ""; + return output; + } + } + + return output; + } +}; + +export default ToTable; \ No newline at end of file From 411bba53a821257df9af528b7d2428370b6afc6f Mon Sep 17 00:00:00 2001 From: Mark Jones Date: Thu, 26 Apr 2018 13:00:35 +0100 Subject: [PATCH 2/2] Fix code style issues raised by linting. --- src/core/operations/ToTable.js | 64 +++++++++++++++------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/src/core/operations/ToTable.js b/src/core/operations/ToTable.js index 342271922..83887f26f 100755 --- a/src/core/operations/ToTable.js +++ b/src/core/operations/ToTable.js @@ -1,19 +1,17 @@ -import Utils from "../Utils.js"; - /** * ToTable operations. * * @author Mark Jones [github.com/justanothermark] * @namespace */ - const ToTable = { +const ToTable = { /** * @constant * @default */ SEPARATORS: [ - {name: "Comma", value:","}, - {name: "Tab", value: escape("\t")}, + {name: "Comma", value: ","}, + {name: "Tab", value: "\\t"}, {name: "Pipe", value: "|"}, {name: "Custom", value: ""} ], @@ -23,8 +21,8 @@ import Utils from "../Utils.js"; * @default */ FORMATS: [ - 'ASCII', - 'HTML' + "ASCII", + "HTML" ], /** @@ -41,23 +39,22 @@ import Utils from "../Utils.js"; let tableData = []; // If the separator contains any tabs, convert them to tab characters. - separator = separator.replace('\\t', '\t'); + separator = separator.replace("\\t", "\t"); // Process the input into a nested array of elements. - let rows = input.split('\n'); + let rows = input.split("\n"); rows.forEach(function(element) { - if (separator == '') { + if (separator === "") { tableData.push([element]); - } - else { + } else { tableData.push(element.split(separator)); } }); // Render the data in the requested format. - let output = ''; + let output = ""; switch (format) { - case 'ASCII': + case "ASCII": output = asciiOutput(tableData); break; @@ -75,31 +72,22 @@ import Utils from "../Utils.js"; * @returns {string} */ function asciiOutput(tableData) { - const horizontalBorder = '-'; - const verticalBorder = '|'; - const crossBorder = '+'; + const horizontalBorder = "-"; + const verticalBorder = "|"; + const crossBorder = "+"; - let output = ''; + let output = ""; let longestCells = []; // Find longestCells value per column to pad cells equally. tableData.forEach(function(row, index) { row.forEach(function(cell, cellIndex) { - if (longestCells[cellIndex] == undefined || cell.length > longestCells[cellIndex]) { + if (longestCells[cellIndex] === undefined || cell.length > longestCells[cellIndex]) { longestCells[cellIndex] = cell.length; } }); }); - // Calculate the complete row length. This is the length of the - // longest cell for each column plus 3 characters per cell - // (1 padding each side of the value and 1 for the cell border) - // plus 1 for the final cell border. - let rowLength = (longestCells.length * 3) + 1; - longestCells.forEach(function(celllongestCells) { - rowLength += celllongestCells; - }); - // Add the top border of the table to the output. output += outputHorizontalBorder(longestCells); @@ -127,9 +115,9 @@ import Utils from "../Utils.js"; function outputRow(row, longestCells) { let rowOutput = verticalBorder; row.forEach(function(cell, index) { - rowOutput += ' ' + cell + ' '.repeat(longestCells[index] - cell.length) + ' ' + verticalBorder; + rowOutput += " " + cell + " ".repeat(longestCells[index] - cell.length) + " " + verticalBorder; }); - rowOutput += '\n'; + rowOutput += "\n"; return rowOutput; } @@ -142,7 +130,7 @@ import Utils from "../Utils.js"; longestCells.forEach(function(cellLength) { rowOutput += horizontalBorder.repeat(cellLength + 2) + crossBorder; }); - rowOutput += '\n'; + rowOutput += "\n"; return rowOutput; } } @@ -158,20 +146,26 @@ import Utils from "../Utils.js"; if (firstRowHeader) { let row = tableData.shift(); output += ""; - output += outputRow(row, 'th'); + output += outputRow(row, "th"); output += ""; } // Output the rest of the rows in the . output += ""; tableData.forEach(function(row, index) { - output += outputRow(row, 'td'); + output += outputRow(row, "td"); }); // Close the body and table elements. output += ""; return output; + /** + * Outputs a table row. + * + * @param {string[]} row + * @param {string} cellType + */ function outputRow(row, cellType) { let output = ""; row.forEach(function(cell) { @@ -181,9 +175,7 @@ import Utils from "../Utils.js"; return output; } } - - return output; } }; -export default ToTable; \ No newline at end of file +export default ToTable;