From f06175b72dda3335cc5164b664294811b315142a Mon Sep 17 00:00:00 2001 From: Renato Atilio Date: Fri, 18 Apr 2025 00:20:55 -0300 Subject: [PATCH] UX: prosemirror rich editor nodes cleanup / slightly better UX (#32361) We don't want "ghost" `content` within mention/hashtag, as they're already rendering their non-editable content on `toDOM`. `atom: true` is not necessary for content-less nodes Re-use existing heading node spec instead of re-creating. A UX improvement from these changes is a better Cmd-Left/Home navigation when these nodes begin a paragraph and the caret is after them. --- .../static/prosemirror/extensions/hashtag.js | 6 +++--- .../static/prosemirror/extensions/heading.js | 18 +++--------------- .../static/prosemirror/extensions/mention.js | 4 +--- .../static/prosemirror/extensions/onebox.js | 2 -- .../javascripts/lib/rich-editor-extension.js | 2 -- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/hashtag.js b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/hashtag.js index ad01f33801e..0ac0ce0faf0 100644 --- a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/hashtag.js +++ b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/hashtag.js @@ -7,8 +7,6 @@ const extension = { attrs: { name: {} }, inline: true, group: "inline", - content: "text*", - atom: true, draggable: true, selectable: false, parseDOM: [ @@ -53,7 +51,9 @@ const extension = { span_open(state, token, tokens, i) { if (token.attrGet("class") === "hashtag-raw") { state.openNode(state.schema.nodes.hashtag, { - name: tokens[i + 1].content.slice(1), + // this is not ideal, but working around the span_open/close structure + // a text is expected just after the span_open token + name: tokens.splice(i + 1, 1)[0].content.slice(1), }); return true; } diff --git a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/heading.js b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/heading.js index 397e359f994..d57e6935d92 100644 --- a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/heading.js +++ b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/heading.js @@ -1,23 +1,11 @@ +import { schema } from "prosemirror-markdown"; + /** @type {RichEditorExtension} */ const extension = { nodeSpec: { heading: { - attrs: { level: { default: 1 } }, - // Overriding ProseMirror's default to allow inline content + ...schema.nodes.heading.spec, content: "inline*", - group: "block", - defining: true, - parseDOM: [ - { tag: "h1", attrs: { level: 1 } }, - { tag: "h2", attrs: { level: 2 } }, - { tag: "h3", attrs: { level: 3 } }, - { tag: "h4", attrs: { level: 4 } }, - { tag: "h5", attrs: { level: 5 } }, - { tag: "h6", attrs: { level: 6 } }, - ], - toDOM(node) { - return ["h" + node.attrs.level, 0]; - }, }, }, }; diff --git a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/mention.js b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/mention.js index 7af9a909bbf..4f116d912d0 100644 --- a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/mention.js +++ b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/mention.js @@ -8,8 +8,6 @@ const extension = { attrs: { name: {} }, inline: true, group: "inline", - content: "text*", - atom: true, draggable: true, selectable: false, parseDOM: [ @@ -55,7 +53,7 @@ const extension = { getAttrs: (token, tokens, i) => ({ // this is not ideal, but working around the mention_open/close structure // a text is expected just after the mention_open token - name: tokens[i + 1].content.slice(1), + name: tokens.splice(i + 1, 1)[0].content.slice(1), }), }, }, diff --git a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/onebox.js b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/onebox.js index 3d15f0857d2..cb654c536e4 100644 --- a/app/assets/javascripts/discourse/app/static/prosemirror/extensions/onebox.js +++ b/app/assets/javascripts/discourse/app/static/prosemirror/extensions/onebox.js @@ -15,7 +15,6 @@ const extension = { attrs: { url: {}, html: {} }, selectable: true, group: "block", - atom: true, draggable: true, parseDOM: [ { @@ -44,7 +43,6 @@ const extension = { inline: true, group: "inline", selectable: true, - atom: true, draggable: true, parseDOM: [ { diff --git a/plugins/discourse-local-dates/assets/javascripts/lib/rich-editor-extension.js b/plugins/discourse-local-dates/assets/javascripts/lib/rich-editor-extension.js index eb44a7282cb..7892cc60da8 100644 --- a/plugins/discourse-local-dates/assets/javascripts/lib/rich-editor-extension.js +++ b/plugins/discourse-local-dates/assets/javascripts/lib/rich-editor-extension.js @@ -5,7 +5,6 @@ const extension = { local_date: { attrs: { date: {}, time: {}, timezone: { default: null } }, group: "inline", - atom: true, inline: true, parseDOM: [ { @@ -42,7 +41,6 @@ const extension = { timezone: { default: null }, }, group: "inline", - atom: true, inline: true, parseDOM: [ {