
First import the classes you need to modify
1 | 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
1 2 3 | Textblock.updateAttrs({ align: new Attribute({default: "left"}) }) |
Because heading has it’s own get attrs()
we need to add it there also
1 2 3 | 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
1 2 3 4 5 6 7 | 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
1 2 3 | 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:
1 2 3 4 5 6 7 | 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
1 2 3 | export function fromHTMLBlock(dom, state) { state.wrapIn(dom, this, this.deserializeDOMAttrs(dom)) } |
1 2 3 4 | 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.
1 2 3 4 5 | 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:
01 02 03 04 05 06 07 08 09 10 | 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