From 98a9081e253fb25113c036b58cd684baf236f146 Mon Sep 17 00:00:00 2001 From: Keegan George Date: Tue, 9 Aug 2022 16:51:17 -0700 Subject: [PATCH] DEV: Populate table content using raw markdown (#7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Very exploratory MD work * DEV: Populate table content using raw markdown * DEV: 💄 Linting Fixes Co-authored-by: Penar Musaraj --- .../api-initializers/table-editor.js | 34 +++++++--- .../components/spreadsheet-editor.js | 59 +++++++++++------- javascripts/discourse/lib/utilities.js | 62 +++++++------------ .../templates/modal/insert-table-modal.hbs | 1 + 4 files changed, 89 insertions(+), 67 deletions(-) diff --git a/javascripts/discourse/api-initializers/table-editor.js b/javascripts/discourse/api-initializers/table-editor.js index 5e07b01..50187b3 100644 --- a/javascripts/discourse/api-initializers/table-editor.js +++ b/javascripts/discourse/api-initializers/table-editor.js @@ -6,9 +6,13 @@ import { iconNode } from "discourse-common/lib/icon-library"; import { create } from "virtual-dom"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; - +import Session from "discourse/models/session"; +import loadScript from "discourse/lib/load-script"; +import PrettyText, { buildOptions } from "pretty-text/pretty-text"; +import { tokenRange } from "../lib/utilities"; export default apiInitializer("0.11.1", (api) => { - const site = api.container.lookup("site:main"); + const site = api.container.lookup("site:main"), + siteSettings = api.container.lookup("site-settings:main"); function createButton() { const openPopupBtn = document.createElement("button"); @@ -35,12 +39,26 @@ export default apiInitializer("0.11.1", (api) => { return ajax(`/posts/${this.id}`, { type: "GET" }) .then((post) => { - showModal("insert-table-modal", { - model: post, - }).setProperties({ - tableHtml: tempTable, - tableId, - }); + let markdownItURL = Session.currentProp("markdownItURL"); + + if (markdownItURL) { + loadScript(markdownItURL).then(() => { + const prettyText = new PrettyText(buildOptions({ siteSettings })); + const tokens = prettyText.opts.engine.parse(post.raw, { + references: {}, + }); + const allTables = tokenRange(tokens, "table_open", "table_close"); + const tableTokens = allTables[tableId]; + + showModal("insert-table-modal", { + model: post, + }).setProperties({ + tableHtml: tempTable, + tableId, + tableTokens, + }); + }); + } }) .catch(popupAjaxError); } diff --git a/javascripts/discourse/components/spreadsheet-editor.js b/javascripts/discourse/components/spreadsheet-editor.js index eb5480d..56039ae 100644 --- a/javascripts/discourse/components/spreadsheet-editor.js +++ b/javascripts/discourse/components/spreadsheet-editor.js @@ -1,6 +1,6 @@ import { action } from "@ember/object"; import loadScript from "discourse/lib/load-script"; -import { arrayToTable, findTableRegex, tableToObj } from "../lib/utilities"; +import { arrayToTable, findTableRegex, tokenRange } from "../lib/utilities"; import GlimmerComponent from "discourse/components/glimmer"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -49,7 +49,7 @@ export default class SpreadsheetEditor extends GlimmerComponent { schedule("afterRender", () => { this.loadLibraries().then(() => { if (this.isEditingTable) { - this.buildPopulatedTable(this.args.tableHtml); + this.buildPopulatedTable(this.args.tableTokens); } else { this.buildNewTable(); } @@ -108,29 +108,46 @@ export default class SpreadsheetEditor extends GlimmerComponent { return this.buildSpreadsheet(data, columns); } - buildPopulatedTable(table) { - const tableObject = tableToObj(table); - const headings = []; - const tableData = []; + extractTableContent(data) { + return data + .flat() + .filter((t) => t.type === "inline") + .map((t) => t.content); + } - tableObject.forEach((object) => { - // Build Headings - if (!headings.includes(...Object.keys(object))) { - headings.push(...Object.keys(object)); + buildPopulatedTable(tableTokens) { + const contentRows = tokenRange(tableTokens, "tr_open", "tr_close"); + const rows = []; + let headings; + const rowWidthFactor = 8; + + contentRows.forEach((row, index) => { + if (index === 0) { + // headings + headings = this.extractTableContent(row).map((heading) => { + return { + title: heading, + width: heading.length * rowWidthFactor, + }; + }); + } else { + // rows: + const rowContent = this.extractTableContent(row); + + // If row content is larger than header, update column width: + rowContent.forEach((c, i) => { + const colWidth = rowContent[i].length * rowWidthFactor; + + if (headings[i].width < colWidth) { + headings[i].width = colWidth; + } + }); + + rows.push(rowContent); } - - // Build Table Data - tableData.push([...Object.values(object)]); }); - const columns = headings.map((heading) => { - return { - title: heading, - width: heading.length * 15, - }; - }); - - return this.buildSpreadsheet(tableData, columns); + return this.buildSpreadsheet(rows, headings); } buildSpreadsheet(data, columns, opts = {}) { diff --git a/javascripts/discourse/lib/utilities.js b/javascripts/discourse/lib/utilities.js index 2bcc3b4..42eb791 100644 --- a/javascripts/discourse/lib/utilities.js +++ b/javascripts/discourse/lib/utilities.js @@ -1,43 +1,5 @@ /* eslint-disable */ -/** - * Generate an object from an HTML table - * - * @see {@link https://gist.github.com/mattheo-gist/4151867|GitHub} - * - * @param {Table} table HTML Table element - * - * @return {Object} A JavaScript object - */ -export function tableToObj(table) { - var rows = table.rows; - var propCells = rows[0].cells; - var propNames = []; - var results = []; - var obj, row, cells; - - // Use the first row for the property names - // Could use a header section but result is the same if - // there is only one header row - for (var i = 0, iLen = propCells.length; i < iLen; i++) { - propNames.push(propCells[i].textContent || propCells[i].innerText); - } - - // Use the rows for data - // Could use tbody rows here to exclude header & footer - // but starting from 1 gives required result - for (var j = 1, jLen = rows.length; j < jLen; j++) { - cells = rows[j].cells; - obj = {}; - - for (var k = 0; k < iLen; k++) { - obj[propNames[k]] = cells[k].textContent || cells[k].innerText; - } - results.push(obj); - } - return results; -} - /** * Generate markdown table from an array of objects * @@ -93,3 +55,27 @@ export function arrayToTable(array, columns, alignment = "center") { export function findTableRegex() { return /((\r?){2}|^)([^\r\n]*\|[^\r\n]*(\r?\n)?)+(?=(\r?\n){2}|$)/gm; } + +export function tokenRange(tokens, start, end) { + const contents = []; + let startPushing = false; + let items = []; + + tokens.forEach((token) => { + if (token.type === start) { + startPushing = true; + } + + if (token.type === end) { + contents.push(items); + items = []; + startPushing = false; + } + + if (startPushing) { + items.push(token); + } + }); + + return contents; +} diff --git a/javascripts/discourse/templates/modal/insert-table-modal.hbs b/javascripts/discourse/templates/modal/insert-table-modal.hbs index 7183b8f..9ec9b77 100644 --- a/javascripts/discourse/templates/modal/insert-table-modal.hbs +++ b/javascripts/discourse/templates/modal/insert-table-modal.hbs @@ -1,6 +1,7 @@