Schema Definition
Schema definition for the Italic mark type:
{
italic: {
// Marks don't have content, they wrap text nodes
}
}Model Representation
Example model representation:
{
type: 'text',
text: 'Italic text',
marks: [{ type: 'italic' }]
}HTML Serialization
Converting model to HTML:
function serializeItalicMark(text, mark) {
return '<em>' + text + '</em>';
}HTML Deserialization
Parsing HTML to model:
function extractItalicMark(element) {
if (element.tagName === 'EM' || element.tagName === 'I') {
return { type: 'italic' };
}
return null;
}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:
// Toggling italic
function toggleItalic() {
const selection = window.getSelection();
if (!selection.rangeCount) return;
const range = selection.getRangeAt(0);
const hasItalic = hasMarkInSelection(range, 'italic');
if (hasItalic) {
removeMark('italic');
} else {
addMark({ type: 'italic' });
}
}Common Issues
Common Pitfalls: These are issues frequently encountered when implementing this node type. Review carefully before implementation.
Common issues and solutions:
// Issue: <i> vs <em> normalization
// Solution: Always convert <i> to <em>
function normalizeItalic(element) {
element.querySelectorAll('i').forEach(i => {
const em = document.createElement('em');
em.innerHTML = i.innerHTML;
i.parentNode.replaceChild(em, i);
});
}
// Issue: Bold and italic together
// Solution: Handle nested marks correctly
// <strong><em>text</em></strong> or <em><strong>text</strong></em>
function applyBoldAndItalic(text) {
// Order matters for semantic HTML
return '<strong><em>' + text + '</em></strong>';
}Implementation
Complete implementation example:
class ItalicMark {
constructor() {
this.type = 'italic';
}
toDOM() {
return ['em', 0];
}
static fromDOM(element) {
if (element.tagName === 'EM' || element.tagName === 'I') {
return new ItalicMark();
}
return null;
}
}