I have an editor with plenty of extensions with some custom Node Views. I want to get the HTML of my content to simply put it on my page and store it in Database to retrieve the document when someone would like to edit content. I’m using tiptap and their editor.getHTML()
which uses DOMSerializer
. The problem is that it returns the HTML code which doesnt take into account custom Node Views. Should I use view.dom.innerHTML
instead? The problem with it, at least for now is that it doesnt work properly with my custom math nodes (inline and display). I could store both JSON
of my ProseMirror editor (for editing purposes) and HTML of my editor (for displaying purposes) but I would like to store just one information.
No, definitely not. You could define a custom DOMSerializer
that renders your nodes the way you want (possibly sharing code with your node views, though often, the interactive elements used for in-editor node views don’t match what these nodes should be rendered as in static HTML).
Why can’t I use view.dom.innerHTML
? Of course it has elements which are needed only for in-editor editing but I can always don’t render these elements when editor is in editable: false
mode.
By defining custom DOMSerializer
you mean that I should make my toDOM
method in line with my Node View? That means that the parseDOM
should also be changed to match toDOM
right?
You don’t necessarily need to use the toDOM
from the schema—you can also use new DOMSerializer
to create a serializer with custom serializer functions (you’ll usually want to use one from a schema as a base, so you don’t have to redefine every node).
OK but I still don’t get why can I use view.dom.innerHTML
. If there is no custom node views, it should be the same as the one from serializer.
I did the following:
parseHTML() {
return [
{
tag: "span.math-src",
},
];
},
renderHTML({ HTMLAttributes, node }) {
let dom = document.createElement("math-inline");
dom.className = "math-node";
let tex = node.textContent;
let src = document.createElement("span");
src.className = "math-src";
src.innerText = tex;
let render = document.createElement("span");
render.className = "math-render";
katex.render(tex, render, {
displayMode: false,
globalGroup: true,
});
dom.appendChild(src);
dom.appendChild(render);
return dom;
}
In short, in static html I want to have a child span.math-src
which contains raw latex text, and span.math-render
which contains rendered html. When parsing a node, all I need is a content of span.math-src
. The prolem is that with the current parse rule, the stuff from span.math-render
is also parsed and two more apragraph are added (outside of the math-inline
node). What should I change to skip parsing of span.math-render
dom node?
EDIT Solved by adding
parseHTML() {
return [
{
tag: "math-inline",
contentElement: ".math-src",
},
];
},
Is it the correct way? And how to add event listeners to the static HTML?
No idea what parseHTML
/renderHTML
are here, but if that is passed through to parseDOM
I guess this works. You could also use a getContent
property to completely override the way the content is parsed, but I don’t think that is better in this case.
OK s othe very last question is how to add event listeners to the static HTML. I have spoiler
element and I want to reveal it after clicking on it. I have
renderHTML({ HTMLAttributes }) {
let dom = document.createElement("spoiler");
dom.className = "spoiler";
dom.dataset.spoiler = "reveal-spoiler";
dom.addEventListener("click", () => {
console.log("Hi");
if (!dom.classList.contains("is-visible")) {
dom.classList.add("is-visible");
}
});
dom.onclick = () => {
if (!dom.classList.contains("is-visible")) {
dom.classList.add("is-visible");
}
};
// Option 2
let contentDOM = document.createElement("div");
dom.appendChild(contentDOM);
return {
dom,
contentDOM,
};
return [
"spoiler",
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
0,
];
},
But it works only in editing mode. If I use editor.getHTML()
and display it, nothing happens after click. (renderHTML
is Tiptap’s equivalent of toDOM
)