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 { 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);
}

View File

@ -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 = {}) {

View File

@ -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;
}

View File

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