DEV: Populate table content using raw markdown (#7)

* Very exploratory MD work

* DEV: Populate table content using raw markdown

* DEV: 💄 Linting Fixes

Co-authored-by: Penar Musaraj <pmusaraj@gmail.com>
This commit is contained in:
Keegan George 2022-08-09 16:51:17 -07:00 committed by GitHub
parent 69bfac2226
commit 98a9081e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 67 deletions

View File

@ -6,9 +6,13 @@ import { iconNode } from "discourse-common/lib/icon-library";
import { create } from "virtual-dom"; import { create } from "virtual-dom";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; 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) => { 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() { function createButton() {
const openPopupBtn = document.createElement("button"); const openPopupBtn = document.createElement("button");
@ -35,12 +39,26 @@ export default apiInitializer("0.11.1", (api) => {
return ajax(`/posts/${this.id}`, { type: "GET" }) return ajax(`/posts/${this.id}`, { type: "GET" })
.then((post) => { .then((post) => {
showModal("insert-table-modal", { let markdownItURL = Session.currentProp("markdownItURL");
model: post,
}).setProperties({ if (markdownItURL) {
tableHtml: tempTable, loadScript(markdownItURL).then(() => {
tableId, 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); .catch(popupAjaxError);
} }

View File

@ -1,6 +1,6 @@
import { action } from "@ember/object"; import { action } from "@ember/object";
import loadScript from "discourse/lib/load-script"; 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 GlimmerComponent from "discourse/components/glimmer";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
@ -49,7 +49,7 @@ export default class SpreadsheetEditor extends GlimmerComponent {
schedule("afterRender", () => { schedule("afterRender", () => {
this.loadLibraries().then(() => { this.loadLibraries().then(() => {
if (this.isEditingTable) { if (this.isEditingTable) {
this.buildPopulatedTable(this.args.tableHtml); this.buildPopulatedTable(this.args.tableTokens);
} else { } else {
this.buildNewTable(); this.buildNewTable();
} }
@ -108,29 +108,46 @@ export default class SpreadsheetEditor extends GlimmerComponent {
return this.buildSpreadsheet(data, columns); return this.buildSpreadsheet(data, columns);
} }
buildPopulatedTable(table) { extractTableContent(data) {
const tableObject = tableToObj(table); return data
const headings = []; .flat()
const tableData = []; .filter((t) => t.type === "inline")
.map((t) => t.content);
}
tableObject.forEach((object) => { buildPopulatedTable(tableTokens) {
// Build Headings const contentRows = tokenRange(tableTokens, "tr_open", "tr_close");
if (!headings.includes(...Object.keys(object))) { const rows = [];
headings.push(...Object.keys(object)); 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 this.buildSpreadsheet(rows, headings);
return {
title: heading,
width: heading.length * 15,
};
});
return this.buildSpreadsheet(tableData, columns);
} }
buildSpreadsheet(data, columns, opts = {}) { buildSpreadsheet(data, columns, opts = {}) {

View File

@ -1,43 +1,5 @@
/* eslint-disable */ /* 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 * Generate markdown table from an array of objects
* *
@ -93,3 +55,27 @@ export function arrayToTable(array, columns, alignment = "center") {
export function findTableRegex() { export function findTableRegex() {
return /((\r?){2}|^)([^\r\n]*\|[^\r\n]*(\r?\n)?)+(?=(\r?\n){2}|$)/gm; 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;
}

View File

@ -1,6 +1,7 @@
<SpreadsheetEditor <SpreadsheetEditor
@model={{this.model}} @model={{this.model}}
@tableHtml={{this.tableHtml}} @tableHtml={{this.tableHtml}}
@tableTokens={{this.tableTokens}}
@tableId={{this.tableId}} @tableId={{this.tableId}}
@triggerModalClose={{action "closeEditModal"}} @triggerModalClose={{action "closeEditModal"}}
@toolbarEvent={{this.toolbarEvent}} @toolbarEvent={{this.toolbarEvent}}