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:
parent
69bfac2226
commit
98a9081e25
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = {}) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
Loading…
Reference in New Issue