Таблицы ProseMirror-Markdown не отображаются должным образом
Мне нужна поддержка таблиц с помощью текстового редактора ProseMirror-Markdown в приложении Angular, которое я сейчас разрабатываю. Я немного застрял. Я решил пойти с prosemirror-markdown и его MarkdownSerializer из-за существующей функциональности в проекте, который теперь женат на ProseMirror-Markdown.
// heading example
get schema() {
return {
toMarkdown: (state, node) => {
state.write(`${state.repeat('#', node.attrs.level)} `)
state.renderInline(node)
state.closeBlock(node)
},
}
}
К сожалению, я столкнулся с теми же проблемами, что и автор сообщения для проблемы TipTap GitHub с таблицами prosemirror-markdown и GFM
Отсутствует официальная поддержка таблиц. Недостатком использования prosemirror-markdown является то, что таблицы не поддерживаются (и не будут). Я мог бы написать эту часть самостоятельно, но это означает, что мы должны отбросить некоторые расширенные функциональные возможности для таблиц, таких как несколько строк, вложенные таблицы, использование списков внутри таблиц и т. Д. Может быть, нам следует предоставить узел Table с поддержкой уценки и ExtendedTable без поддержки уценки?
После этого я попытался реализовать функцию parseMarkdown(), и это намного сложнее. В prosemirror-markdown есть MarkdownParser, который использует markdown-it под капотом. Это хорошо, но означает, что мы ограничены этим парсером. Я всегда думал, что есть парсеры уценки с действительно простым API для расширения, но я думаю, что я ошибся.:(
Я использую MarkdownIt для разбора и сериализации, ниже приведен соответствующий package.json
записей:
{...,
"markdown-it": "^9.1.0",
"markdown-it-table": "^2.0.4",
"prosemirror-keymap": "^1.0.0",
"prosemirror-markdown": "^1.3.1",
"prosemirror-model": "^1.0.0",
"prosemirror-state": "^1.0.0",
"prosemirror-transform": "^1.0.0",
"prosemirror-view": "^1.0.10",
"prosemirror-commands": "^1.0.0",
"prosemirror-example-setup": "^1.0.0",
"prosemirror-menu": "^1.0.0",
"prosemirror-schema-basic": "^1.0.0",
...}
Я добавил несколько пользовательских токенов в анализатор и таблицу уценок, которая правильно отображает на высоком уровне:
Однако, несмотря на то, что я очистил все неразрешенные ошибки токена, я получаю частично визуализированную таблицу в виде редактора:
Это токены, которые были добавлены в анализатор при инициализации:
+ table: {block: "table"},
+ thead: {block: "table_row"},
+ tr: {block: "table_row"},
+ td: {block: "table_cell"},
+ th: {block: "table_cell"},
+ tbody: {block: "tbody"},
Это узлы таблиц, которые определяются в схеме:
// Helper for creating a schema that supports tables.
function getCellAttrs(dom, extraAttrs) {
let widthAttr = dom.getAttribute("data-colwidth")
let widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(",").map(s => Number(s)) : null
let colspan = Number(dom.getAttribute("colspan") || 1)
let result = {
colspan,
rowspan: Number(dom.getAttribute("rowspan") || 1),
colwidth: widths && widths.length == colspan ? widths : null
}
for (let prop in extraAttrs) {
let getter = extraAttrs[prop].getFromDOM
let value = getter && getter(dom)
if (value != null) result[prop] = value
}
return result
}
function setCellAttrs(node, extraAttrs) {
let attrs = {}
if (node.attrs.colspan != 1) attrs.colspan = node.attrs.colspan
if (node.attrs.rowspan != 1) attrs.rowspan = node.attrs.rowspan
if (node.attrs.colwidth)
attrs["data-colwidth"] = node.attrs.colwidth.join(",")
for (let prop in extraAttrs) {
let setter = extraAttrs[prop].setDOMAttr
if (setter) setter(node.attrs[prop], attrs)
}
return attrs
}
export function tableNodes(options) {
let extraAttrs = options.cellAttributes || {}
let cellAttrs = {
colspan: {default: 1},
rowspan: {default: 1},
colwidth: {default: null}
}
for (let prop in extraAttrs)
cellAttrs[prop] = {default: extraAttrs[prop].default}
return {
table: {
content: "table_row+",
tableRole: "table",
isolating: true,
group: options.tableGroup,
parseDOM: [{tag: "table"}],
toDOM() { return ["table", ["tbody", 0]] }
},
table_row: {
content: "(table_cell | table_header)*",
tableRole: "row",
parseDOM: [{tag: "tr"}],
toDOM() { return ["tr", 0] }
},
cell: {
content: options.cellContent,
attrs: cellAttrs,
tableRole: "cell",
isolating: true,
parseDOM: [{tag: "td", getAttrs: dom => getCellAttrs(dom, extraAttrs)}],
toDOM(node) { return ["td", setCellAttrs(node, extraAttrs), 0] }
},
table_header: {
content: options.cellContent,
attrs: cellAttrs,
tableRole: "header_cell",
isolating: true,
parseDOM: [{tag: "th", getAttrs: dom => getCellAttrs(dom, extraAttrs)}],
toDOM(node) { return ["th", setCellAttrs(node, extraAttrs), 0] }
}
}
}
export function tableNodeTypes(schema) {
let result = schema.cached.tableNodeTypes
if (!result) {
result = schema.cached.tableNodeTypes = {}
for (let name in schema.nodes) {
let type = schema.nodes[name], role = type.spec.tableRole
if (role) result[role] = type
}
}
return result
}
Кто-нибудь имеет опыт работы с этим или может предложить альтернативный подход? Любая помощь по этому вопросу будет принята с благодарностью!