I created a schema for image with caption.
<figure>
<figcontent>
<img>
<figcaption>
</figcontent>
<figure>
figure: {
content: 'figcontent',
group: 'block',
attrs: {
style: {
default: 'display:flex;justify-content:center;',
},
},
marks: '',
draggable: true,
selectable: true,
parseDOM: [{tag: 'figure'}],
toDOM(node) {
return ['figure', {style: 'display:flex;justify-content:center;'}, 0]
},
},
figcontent: {
content: 'image figcaption',
attrs: {
class: {default: MEDISTREAM_EDITOR_CLASS + '__figcontent'},
},
group: 'figure',
marks: '',
selectable: false,
parseDOM: [{tag: 'div'}],
toDOM: node => ['div', {class: node.attrs.class}, 0],
},
figcaption: {
content: 'inline*',
attrs: {
class: {default: MEDISTREAM_EDITOR_CLASS + '__figcaption'},
},
group: 'figcontent',
marks: 'strong link',
parseDOM: [{tag: 'figcaption'}],
toDOM(node) {
return ['figcaption', {class: node.attrs.class}, 0]
},
},
image: {
attrs: {
src: {
default:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII',
},
alt: {default: null},
title: {default: null},
width: {default: '200px'},
height: {default: 'auto'},
class: {default: MEDISTREAM_EDITOR_CLASS + '__img'},
},
group: 'figcontent',
draggable: false,
selectable: false,
toDOM(node) {
const {src, alt, title, width, height} = node.attrs
return [
'img',
{
src,
alt,
title,
width,
height,
class: node.attrs.class,
},
]
},
parseDOM: [
{
tag: 'img[src]',
/**
* @param {HTMLElement} dom
*/
getAttrs: dom => ({
src: dom.getAttribute('src'),
title: dom.getAttribute('title'),
alt: dom.getAttribute('alt'),
width: dom.getAttribute('width'),
height: dom.getAttribute('height'),
}),
},
],
},
From here, I created a NodeView for figure
node so I can show user the image editing controllers such as resize handle, align buttons and etc.
class FigureNodeView {
/**
*
* @param {Node} node
* @param {EditorView} view
* @param {() => number} getPos
*/
constructor(node, view, getPos) {
this.node = node
this.view = view
this.getPos = getPos
this.dom = document.createElement('figure')
this.dom.className = MEDISTREAM_EDITOR_CLASS + '__figure'
this.contentDOM = document.createElement('span')
this.contentDOM.style.position = 'relative'
this.img = document.createElement('img')
this.img.className = MEDISTREAM_EDITOR_CLASS + '__img'
this.node.descendants(node => {
if (node.type.name === 'image') {
this.img.src = node.attrs.src
}
})
this.figcaption = document.createElement('figcaption')
this.figcaption.className = MEDISTREAM_EDITOR_CLASS + '__figcaption'
this.dom.append(this.contentDOM)
this.contentDOM.append(this.img)
this.contentDOM.append(this.figcaption)
}
selectNode() {
this.dom.classList.add('ProseMirror-selectednode')
this._showImageControls()
}
deselectNode() {
this.dom.classList.remove('ProseMirror-selectednode')
this._hideImageControls()
}
_showImageControls() {
const resizeHandle = document.createElement('span')
resizeHandle.className = MEDISTREAM_EDITOR_CLASS + '__image-resize-handle'
resizeHandle.style.display = 'inline'
resizeHandle.onmousedown = this._resizeHandleMouseDown.bind(this)
this.resizeHandle = resizeHandle
this.contentDOM.append(resizeHandle)
const optionPanel = document.createElement('div')
const alignLeftButton = document.createElement('div')
alignLeftButton.onclick = () => {
console.log(this.dom) <-------------- this.dom is not what's on the view...
}
const alignRightButton = document.createElement('div')
const alignCenterButton = document.createElement('div')
const stretchImageButton = document.createElement('div')
optionPanel.append(alignLeftButton)
optionPanel.append(alignCenterButton)
optionPanel.append(alignRightButton)
optionPanel.append(stretchImageButton)
this.contentDOM.append(optionPanel)
}
this.dom
in the _showImageControls is not the same node that is in the view. So I can’t manipulate its attributes to align differently…