2018-05-21 19:37:32 +02:00
/ * *
* @ author Mark Jones [ github . com / justanothermark ]
* @ copyright Crown Copyright 2018
* @ license Apache - 2.0
* /
2019-07-09 13:23:59 +02:00
import Operation from "../Operation.mjs" ;
import Utils from "../Utils.mjs" ;
2018-05-21 19:37:32 +02:00
/ * *
* To Table operation
* /
class ToTable extends Operation {
/ * *
* ToTable constructor
* /
constructor ( ) {
super ( ) ;
this . name = "To Table" ;
this . module = "Default" ;
2022-10-13 11:52:19 +02:00
this . description = "Data can be split on different characters and rendered as an HTML, ASCII or Markdown table with an optional header row.<br><br>Supports the CSV (Comma Separated Values) file format by default. Change the cell delimiter argument to <code>\\t</code> to support TSV (Tab Separated Values) or <code>|</code> for PSV (Pipe Separated Values).<br><br>You can enter as many delimiters as you like. Each character will be treat as a separate possible delimiter." ;
2018-08-21 20:07:13 +02:00
this . infoURL = "https://wikipedia.org/wiki/Comma-separated_values" ;
2018-05-21 19:37:32 +02:00
this . inputType = "string" ;
this . outputType = "html" ;
this . args = [
{
"name" : "Cell delimiters" ,
"type" : "binaryShortString" ,
"value" : ","
} ,
{
"name" : "Row delimiters" ,
"type" : "binaryShortString" ,
2018-11-09 18:40:19 +01:00
"value" : "\\r\\n"
2018-05-21 19:37:32 +02:00
} ,
{
"name" : "Make first row header" ,
"type" : "boolean" ,
"value" : false
} ,
{
"name" : "Format" ,
"type" : "option" ,
2022-10-13 11:52:19 +02:00
"value" : [ "ASCII" , "HTML" , "Markdown" ]
2018-05-21 19:37:32 +02:00
}
] ;
}
/ * *
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { html }
* /
run ( input , args ) {
const [ cellDelims , rowDelims , firstRowHeader , format ] = args ;
// Process the input into a nested array of elements.
2019-01-31 16:18:37 +01:00
const tableData = Utils . parseCSV ( Utils . escapeHtml ( input ) , cellDelims . split ( "" ) , rowDelims . split ( "" ) ) ;
2018-05-21 19:37:32 +02:00
if ( ! tableData . length ) return "" ;
// Render the data in the requested format.
switch ( format ) {
case "ASCII" :
return asciiOutput ( tableData ) ;
case "HTML" :
2022-10-13 11:52:19 +02:00
return htmlOutput ( tableData ) ;
case "Markdown" :
return markdownOutput ( tableData ) ;
2018-05-21 19:37:32 +02:00
default :
return htmlOutput ( tableData ) ;
}
/ * *
* Outputs an array of data as an ASCII table .
*
* @ param { string [ ] [ ] } tableData
* @ returns { string }
* /
function asciiOutput ( tableData ) {
const horizontalBorder = "-" ;
const verticalBorder = "|" ;
const crossBorder = "+" ;
let output = "" ;
const 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 ;
}
} ) ;
} ) ;
// 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 ) {
const 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 .
*
* @ param { string [ ] [ ] } tableData
* @ returns { string }
* /
function htmlOutput ( tableData ) {
// Start the HTML output with suitable classes for styling.
2018-07-13 15:03:13 +02:00
let output = "<table class='table table-hover table-sm table-bordered table-nonfluid'>" ;
2018-05-21 19:37:32 +02:00
// If the first row is a header then put it in <thead> with <th> cells.
if ( firstRowHeader ) {
const row = tableData . shift ( ) ;
2018-07-15 14:25:44 +02:00
output += "<thead class='thead-light'>" ;
2018-05-21 19:37:32 +02:00
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 ;
/ * *
* Outputs a table row .
*
* @ param { string [ ] } row
* @ param { string } cellType
* /
function outputRow ( row , cellType ) {
let output = "<tr>" ;
row . forEach ( function ( cell ) {
output += "<" + cellType + ">" + cell + "</" + cellType + ">" ;
} ) ;
output += "</tr>" ;
return output ;
}
}
2022-10-13 11:52:19 +02:00
function markdownOutput ( tableData ) {
const headerDivider = "-" ;
const verticalBorder = "|" ;
let output = "" ;
const 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 ;
}
} ) ;
} ) ;
// Ignoring the checkbox, as current Mardown renderer in CF doesn't handle table without headers
const row = tableData . shift ( ) ;
output += outputRow ( row , longestCells ) ;
let rowOutput = verticalBorder ;
row . forEach ( function ( cell , index ) {
rowOutput += " " + headerDivider + " " + verticalBorder ;
} ) ;
output += rowOutput += "\n" ;
// Add the rest of the table rows.
tableData . forEach ( function ( row , index ) {
output += outputRow ( row , 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 ;
}
}
2018-05-21 19:37:32 +02:00
}
}
export default ToTable ;