From 2d8885959d885fb6f21fbb7fff5f8491300d93e0 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Wed, 26 Mar 2025 01:40:21 +0800 Subject: [PATCH] feat: support text marks --- .../prosemirror/ast/from-prosemirror.js | 46 +++++++++++++++- .../prosemirror/ast/to-prosemirror.js | 52 ++++++++++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/plugins/tiddlywiki/prosemirror/ast/from-prosemirror.js b/plugins/tiddlywiki/prosemirror/ast/from-prosemirror.js index 12d24fbad..38fbb7272 100644 --- a/plugins/tiddlywiki/prosemirror/ast/from-prosemirror.js +++ b/plugins/tiddlywiki/prosemirror/ast/from-prosemirror.js @@ -20,11 +20,55 @@ function paragraph(builder, node) { }; } +// Map ProseMirror mark types to HTML tags +const markTypeMap = { + strong: "strong", + em: "em", +}; +const markRuleMap = { + em: "italic", + strong: "bold", +}; +// Define mark priority (inner to outer) +const markPriority = ["code", "strong", "bold", "em", "italic", "underline", "strike", "strikethrough", "superscript", "subscript"]; function text(builder, node) { + if (!node.text) { + return { + type: "text", + text: "" + }; + } + if (node.marks && node.marks.length > 0) { + // Create base text node + let textNode = { + type: "text", + text: node.text + }; + const sortedMarks = [...node.marks].sort((a, b) => { + const indexA = markPriority.indexOf(a.type); + const indexB = markPriority.indexOf(b.type); + // Place unknown mark types at the end + if (indexA === -1) return 1; + if (indexB === -1) return -1; + return indexA - indexB; + }); + + // Apply marks from inner to outer + return sortedMarks.reduce((wrappedNode, mark) => { + const tag = markTypeMap[mark.type]; + const rule = markRuleMap[mark.type]; + return { + type: "element", + tag: tag, + rule, + children: [wrappedNode] + }; + }, textNode); + } return { type: "text", text: node.text - } + }; } function heading(builder, node) { diff --git a/plugins/tiddlywiki/prosemirror/ast/to-prosemirror.js b/plugins/tiddlywiki/prosemirror/ast/to-prosemirror.js index 3be1ea5a4..bcd04ed96 100644 --- a/plugins/tiddlywiki/prosemirror/ast/to-prosemirror.js +++ b/plugins/tiddlywiki/prosemirror/ast/to-prosemirror.js @@ -102,6 +102,49 @@ function buildListItem(context, node) { return wrapTextNodesInParagraphs(context, processedContent); } +function buildTextWithMark(context, node, markType) { + const content = convertNodes(context, node.children); + return content.map(childNode => { + if (childNode.type === "text") { + // Add the mark to the text node + const marks = childNode.marks || []; + return { + ...childNode, + marks: [...marks, { type: markType }] + }; + } + return childNode; + }); +} + +function buildStrong(context, node) { + return buildTextWithMark(context, node, "strong"); +} + +function buildEm(context, node) { + return buildTextWithMark(context, node, "em"); +} + +function buildCode(context, node) { + return buildTextWithMark(context, node, "code"); +} + +function buildUnderline(context, node) { + return buildTextWithMark(context, node, "underline"); +} + +function buildStrike(context, node) { + return buildTextWithMark(context, node, "strike"); +} + +function buildSup(context, node) { + return buildTextWithMark(context, node, "superscript"); +} + +function buildSub(context, node) { + return buildTextWithMark(context, node, "subscript"); +} + /** * Many node shares same type `element` in wikiAst, we need to distinguish them by tag. */ @@ -115,7 +158,14 @@ const elementBuilders = { h6: (context, node) => buildHeading(context, node, 6), ul: buildUnorderedList, ol: buildOrderedList, - li: buildListItem + li: buildListItem, + strong: buildStrong, + em: buildEm, + code: buildCode, + u: buildUnderline, + strike: buildStrike, + sup: buildSup, + sub: buildSub }; function element(context, node) {