Schema Definition
Schema definition for the Custom Block node type:
{
customBlock: {
content: 'block*',
group: 'block',
attrs: {
type: { default: '' },
data: { default: '{}' }
},
}
}Model Representation
Example model representation:
{
type: 'customBlock',
attrs: {
type: 'my-custom-block',
data: JSON.stringify({ custom: 'data' })
},
children: []
}HTML Serialization
Converting model to HTML:
function serializeCustomBlock(node) {
return '<div data-type="custom-block" data-block-type="' + node.attrs.type +
'" data-block-data="' + escapeHtml(node.attrs.data) + '">' +
serializeChildren(node.children) + '</div>';
}HTML Deserialization
Parsing HTML to model:
function parseCustomBlock(domNode) {
return {
type: 'customBlock',
attrs: {
type: domNode.getAttribute('data-block-type') || '',
data: domNode.getAttribute('data-block-data') || '{}'
},
children: Array.from(domNode.childNodes)
.map(node => parseNode(node))
.filter(Boolean)
};
}View Integration
View Integration Notes: Pay special attention to contenteditable behavior, selection handling, and event management when implementing this node type in your view layer.
View integration code:
// Rendering custom block
const customBlock = document.createElement('div');
customBlock.setAttribute('data-type', 'custom-block');
customBlock.setAttribute('data-block-type', node.attrs.type);
customBlock.setAttribute('data-block-data', node.attrs.data);
customBlock.contentEditable = 'true';
node.children.forEach(child => {
customBlock.appendChild(renderNode(child));
});Common Issues
Common Pitfalls: These are issues frequently encountered when implementing this node type. Review carefully before implementation.
Common issues and solutions:
// Issue: Custom block type registration
// Solution: Register custom block renderers
const customBlockRenderers = {
'my-custom-block': (node, data) => {
// Custom rendering logic
}
};
// Issue: Custom block data validation
// Solution: Validate custom block data
function validateCustomBlockData(data, type) {
// Validate based on block type
return true;
}Implementation
Complete implementation example:
class CustomBlockNode {
constructor(attrs, children) {
this.type = 'customBlock';
this.attrs = {
type: attrs?.type || '',
data: attrs?.data || '{}'
};
this.children = children || [];
}
toDOM() {
const customBlock = document.createElement('div');
customBlock.setAttribute('data-type', 'custom-block');
customBlock.setAttribute('data-block-type', this.attrs.type);
customBlock.setAttribute('data-block-data', this.attrs.data);
this.children.forEach(child => {
customBlock.appendChild(child.toDOM());
});
return customBlock;
}
static fromDOM(domNode) {
return new CustomBlockNode(
{
type: domNode.getAttribute('data-block-type') || '',
data: domNode.getAttribute('data-block-data') || '{}'
},
Array.from(domNode.childNodes)
.map(node => parseNode(node))
.filter(Boolean)
);
}
}