First import the classes you need to modify
import { Textblock, Heading, Paragraph, Attribute, Block } from "prosemirror/dist/model"
Add the new attribute to Textblock. We only wanted alignment for text, if you want it for everything probably best to do this on Block
Textblock.updateAttrs({
align: new Attribute({default: "left"})
})
Because heading has it’s own get attrs()
we need to add it there also
Heading.updateAttrs({
align: new Attribute({default: "left"})
})
Now we need to represent this attribute in the DOM, this is done with to to_dom transform, which defers to the serializeDOM
method of a node type
Paragraph.prototype.serializeDOM = (function(oldSerialize) {
return function (node, s) {
let ele = oldSerialize.call(this, node, s)
this.setDomDisplayProperties(node, ele) //will be explained next
return ele
}
}) (Paragraph.prototype.serializeDOM)
This maintains the old serialize implementation, but adds some additional functionality. You’ll need to do this to every NodeType that needs alignment. Since each NoteType defines its own, I haven’t found a good way to make it fully reusable. I did crate the setDomDisplayProperties
method to handle actually adding the change to the DOM element, which is reuseable
Textblock.prototype.setDomDisplayProperties = function setDomDisplayProperties(node, ele) {
ele.style.textAlign = node.attrs.align
}
So now it should render! Like I mentioned serializeDOM
has to be changed for all NodeTypes, here’s heading’s for good measure:
Heading.prototype.serializeDOM = (function(oldSerialize) {
return function serializeDOM(node, s) {
let ele = oldSerialize.call(this,node, s)
this.setDomDisplayProperties(node, ele)
return ele
}
}) (Heading.prototype.serializeDOM)
One final thing we need to do is make sure it works the other way, from_dom, which comes into play when copy and pasting or with drag and drop.
First we register a new parser. By default they have a rank of 50, so we give ours a lower rank to make sure it matches first
export function fromHTMLBlock(dom, state) {
state.wrapIn(dom, this, this.deserializeDOMAttrs(dom))
}
Paragraph.register('parseDOM', 'p', {
parse: fromHTMLBlock,
rank: 40
})
fromHTMLDOM is pretty much the same as the ‘block’ parser but calls this.deserializeDOMAttrs(dom)
to add the attributes as well.
Textblock.prototype.deserializeDOMAttrs = function deserializeDOMAttrs(dom) {
let attrs = {}
attrs.align = dom.style.textAlign || "left"
return attrs
}
This will be inherited by all textblocks, but they can define their own or add to the returned value in a different parse funtion, if they have additional properties. Heading, for example:
for (let i = 1; i <= 6; i++) Heading.registerComputed("parseDOM", "h" + i, type => {
if (i <= type.maxLevel) return {
parse: function(dom, state) {
let attrs = this.deserializeDOMAttrs(dom)
attrs.level = i
state.wrapIn(dom, this, attrs)
},
rank: 40
}
})
I think that about covers it, hope this helped!
Leave a Reply