getkirby / kirby

Kirby's core application folder
https://getkirby.com
Other
1.27k stars 167 forks source link

Classes added by Custom Nodes are stripped out of the Writer field when refreshing the page/ProseMirror re-rendering the Writer #6587

Closed RM1234567890 closed 1 month ago

RM1234567890 commented 2 months ago

Description

Following the Kirby docs, I have created a plugin to add a custom Node to the Writer field. The custom Node adds a class to the paragraph tag, so it can be styled using css.

After applying the custom Node to the selected text and saving the page, the text and style is saved to the content txt file like this: <p class=\"custom-class-name\">Selected text with custom Node saved.</p>

However, in the panel, if I refresh the page, the style is removed and stripped out from the Writer field. If I refresh again, without changing anything in that specific writer field, the content txt file remains unchanged.

If I edit the text in the Writer to make text italic (for example) and save again, it won’t retain the custom class previously applied as a Node, unless I apply the Node again. Without applying the Node again, it will only save the text as was edited with the italic or any other changes: <p>Selected text with <em>custom node</em> saved.</p>

Expected behavior

  1. After applying the custom Node to selected text in the Writer field, the class is added to the paragraph tag in the panel.

  2. After saving the page, the text and style is saved to the content txt file like this: <p class=\"custom-class-name\">Selected text with custom Node saved.</p> ^These steps currently work.

  3. Refreshing the page in the panel, the custom class around the p tag is not stripped out of the Writer field.

Screenshots

  1. Custom Node applied to text in the Writer field and the custom class is added to the paragraph tag:

    Screenshot 2024-07-30 at 12 41 29
  2. The text and style is saved to the content txt file:

    Screenshot 2024-07-30 at 12 37 04
  3. After refreshing the page in the panel, it shows that the class is stripped from the paragraph tag.

    Screenshot 2024-07-30 at 12 37 39

To reproduce

  1. Create a plugin to create a Custom Node for the Writer that will add a class around the paragraph tag. The code is available here: https://forum.getkirby.com/t/custom-writer-marks-in-kirby-4/31236/5
  2. Add a Node named 'customNode' to your Writer field.
  3. Highlight the text in the Writer.
  4. Click on Nodes dropdown and select the new Node named 'Custom Node'.
  5. Inspect the Writer to confirm that the custom class has been applied to the paragraph tag around the selected text.
  6. Save the page.
  7. See the content txt file to confirm the custom class has been saved.
  8. Refresh the page in the panel to see that the custom class has been stripped out.
  9. Confirm by using inspect element to see the custom class no longer appears around the selected text.

Your setup

Kirby Version
4.3.0

Console output
No problem listed in the console.

Your system (please complete the following information)

distantnative commented 1 month ago

Ok I found a solution:

The problem is that your custom node is competing with the regular paragraph node. Both targeted at <p> tags in the content. While your custom node's parseDOM definition rightfully only tries to claim <p> tags with the right class and dismissing others (by returning false in the getAttrs closure if the class isn't present), the default paragraph node has no such restriction and just claims any <p> tag.

Which makes it important in which order those nodes are checked.

The bad behavior you experience is because the default paragraph node gets checked first, claims it and that's done. Your custom node isn't checked at all (this is after the full reload where the HTML text from the backend is passed to ProseMirror again to be rendered in the writer input). So, when you add text as your custom node and save, that works - data model is correct and correctly gets rendered to the content file. When loading again though, ProseMirror interprets that <p> tag as a normal paragraph node.

What can be done to fix it? Using the priority option: https://prosemirror.net/docs/ref/#model.GenericParseRule.priority (inside the parseDOM part):

tag: "p",
priority: 51,
getAttrs: (node) =>

It seems like 50 is the default priority also for the default paragraph node. When setting it to anything higher than 50, on reload the custom node is now selected for me.

distantnative commented 1 month ago

Let me know if this doesn't work for you and I'll reopen the issue.

RM1234567890 commented 1 month ago

This solution works perfectly, thank you!