Schema Definition
Schema definition for the Section node type:
{
section: {
content: 'block+',
group: 'block',
attrs: {
level: { default: 1 }
},
}
}Model Representation
Example model representation:
{
type: 'section',
attrs: { level: 1 },
children: [
{
type: 'heading',
level: 2,
children: [{ type: 'text', text: 'Section Title' }]
},
{
type: 'paragraph',
children: [{ type: 'text', text: 'Section content' }]
}
]
}HTML Serialization
Converting model to HTML:
function serializeSection(node) {
return '<section data-level="' + node.attrs.level + '">' +
serializeChildren(node.children) + '</section>';
}HTML Deserialization
Parsing HTML to model:
function parseSection(domNode) {
return {
type: 'section',
attrs: { level: parseInt(domNode.getAttribute('data-level')) || 1 },
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 section
const section = document.createElement('section');
section.setAttribute('data-level', node.attrs.level);
section.contentEditable = 'true';
node.children.forEach(child => {
section.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: Section nesting
// Solution: Handle nested sections
function validateSectionNesting(section, parent) {
const level = parseInt(section.getAttribute('data-level'));
const parentLevel = parent ? parseInt(parent.getAttribute('data-level')) : 0;
return level > parentLevel;
}
// Issue: Section structure
// Solution: Ensure proper section structure
function validateSectionStructure(section) {
// Ensure section has at least one heading
return section.querySelector('h1, h2, h3, h4, h5, h6') !== null;
}Implementation
Complete implementation example:
class SectionNode {
constructor(attrs, children) {
this.type = 'section';
this.attrs = { level: attrs?.level || 1 };
this.children = children || [];
}
toDOM() {
const section = document.createElement('section');
section.setAttribute('data-level', this.attrs.level);
this.children.forEach(child => {
section.appendChild(child.toDOM());
});
return section;
}
static fromDOM(domNode) {
return new SectionNode(
{ level: parseInt(domNode.getAttribute('data-level')) || 1 },
Array.from(domNode.childNodes)
.map(node => parseNode(node))
.filter(Boolean)
);
}
}