Files
5etools-mirror-2.github.io/js/converter-table.js
TheGiddyLimit 8117ebddc5 v1.198.1
2024-01-01 19:34:49 +00:00

141 lines
4.2 KiB
JavaScript

"use strict";
class TableParser extends BaseParser {
/**
* Parses tables from HTML.
* @param inText Input text.
* @param options Options object.
* @param options.cbWarning Warning callback.
* @param options.cbOutput Output callback.
* @param options.isAppend Default output append mode.
* @param options.source Entity source.
* @param options.page Entity page.
* @param options.titleCaseFields Array of fields to be title-cased in this entity (if enabled).
* @param options.isTitleCase Whether title-case fields should be title-cased in this entity.
*/
static doParseHtml (inText, options) {
options = this._getValidOptions(options);
if (!inText || !inText.trim()) return options.cbWarning("No input!");
inText = this._getCleanInput(inText, options);
const handleTable = ($table, caption) => {
const tbl = {
type: "table",
caption,
colLabels: [],
colStyles: [],
rows: [],
};
const getCleanHeaderText = ($ele) => {
let txt = $ele.text().trim();
// if it's all-uppercase, title-case it
if (txt.toUpperCase() === txt) txt = txt.toTitleCase();
return txt;
};
// Caption
if ($table.find(`caption`)) {
tbl.caption = $table.find(`caption`).text().trim();
}
// Columns
if ($table.find(`thead`)) {
const $headerRows = $table.find(`thead tr`);
if ($headerRows.length !== 1) options.cbWarning(`Table header had ${$headerRows.length} rows!`);
$headerRows.each((i, r) => {
const $r = $(r);
if (i === 0) { // use first tr as column headers
$r.find(`th, td`).each((i, h) => tbl.colLabels.push(getCleanHeaderText($(h))));
} else { // use others as rows
const row = [];
$r.find(`th, td`).each((i, h) => row.push(getCleanHeaderText($(h))));
if (row.length) tbl.rows.push(row);
}
});
$table.find(`thead`).remove();
} else if ($table.find(`th`)) {
$table.find(`th`).each((i, h) => tbl.colLabels.push(getCleanHeaderText($(h))));
$table.find(`th`).parent().remove();
}
// Rows
const handleTableRow = (i, r) => {
const $r = $(r);
const row = [];
$r.find(`td`).each((i, cell) => {
const $cell = $(cell);
row.push($cell.text().trim());
});
tbl.rows.push(row);
};
if ($table.find(`tbody`)) {
$table.find(`tbody tr`).each(handleTableRow);
} else {
$table.find(`tr`).each(handleTableRow);
}
MarkdownConverter.postProcessTable(tbl);
options.cbOutput(tbl, options.isAppend);
};
const $input = $(inText);
if ($input.is("table")) {
handleTable($input);
} else {
// TODO pull out any preceding text to use as the caption; pass this in
const caption = "";
$input.find("table").each((i, e) => {
const $table = $(e);
handleTable($table, caption);
});
}
}
/**
* Parses tables from Markdown.
* @param inText Input text.
* @param options Options object.
* @param options.cbWarning Warning callback.
* @param options.cbOutput Output callback.
* @param options.isAppend Default output append mode.
* @param options.source Entity source.
* @param options.page Entity page.
* @param options.titleCaseFields Array of fields to be title-cased in this entity (if enabled).
* @param options.isTitleCase Whether title-case fields should be title-cased in this entity.
*/
static doParseMarkdown (inText, options) {
if (!inText || !inText.trim()) return options.cbWarning("No input!");
inText = this._getCleanInput(inText, options);
const lines = inText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split(/\n/g);
const stack = [];
let cur = null;
lines.forEach(l => {
if (l.trim().startsWith("##### ")) {
if (cur && cur.lines.length) stack.push(cur);
cur = {caption: l.trim().replace(/^##### /, ""), lines: []};
} else {
cur = cur || {lines: []};
cur.lines.push(l);
}
});
if (cur && cur.lines.length) stack.push(cur);
const toOutput = stack.map(tbl => MarkdownConverter.getConvertedTable(tbl.lines, tbl.caption)).reverse();
toOutput.forEach((out, i) => {
if (options.isAppend) options.cbOutput(out, true);
else {
if (i === 0) options.cbOutput(out, false);
else options.cbOutput(out, true);
}
});
}
}
globalThis.TableParser = TableParser;