Quellcode durchsuchen

Added ToTable operation to output data as ASCII or HTML tables.

Mark Jones vor 7 Jahren
Ursprung
Commit
e2af3c78e7

+ 1 - 0
src/core/config/Categories.js

@@ -67,6 +67,7 @@ const Categories = [
             "Encode text",
             "Decode text",
             "Swap endianness",
+            "To Table",
         ]
     },
     {

+ 33 - 0
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.<br><br>e.g. <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code> becomes the UTF-8 encoded string <code>Γειά σου</code>",

+ 2 - 0
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,

+ 189 - 0
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 = "<table class='table table-hover table-condensed table-bordered table-nonfluid'>";
+
+            // If the first row is a header then put it in <thead> with <th> cells.
+            if (firstRowHeader) {
+                let row = tableData.shift();
+                output += "<thead>";
+                output += outputRow(row, 'th');
+                output += "</thead>";
+            }
+
+            // Output the rest of the rows in the <tbody>.
+            output += "<tbody>";
+            tableData.forEach(function(row, index) {
+                output += outputRow(row, 'td');
+            });
+
+            // Close the body and table elements.
+            output += "</tbody></table>";
+            return output;
+
+            function outputRow(row, cellType) {
+                let output = "<tr>";
+                row.forEach(function(cell) {
+                    output += "<" + cellType + ">" + cell + "</" + cellType + ">";
+                });
+                output += "</tr>";
+                return output;
+            }
+        }
+
+        return output;
+    }
+};
+
+export default ToTable;