Schema Definition
Schema definition for the Font Family mark type:
{
fontFamily: {
attrs: {
family: { default: 'Arial' }
},
style: 'font-family: ' + node.attrs.family
}, 0]
}
}Model Representation
Example model representation:
{
type: 'text',
text: 'Monospace text',
marks: [{
type: 'fontFamily',
attrs: { family: 'monospace' }
}]
}HTML Serialization
Converting model to HTML:
function serializeFontFamilyMark(text, mark) {
const family = mark.attrs?.family || 'Arial';
return '<span style="font-family: ' + escapeHtml(family) + '">' +
text + '</span>';
}HTML Deserialization
Parsing HTML to model:
function extractFontFamilyMark(element) {
if (element.tagName === 'SPAN' && element.style.fontFamily) {
const family = extractFontFamily(element.style.fontFamily);
return {
type: 'fontFamily',
attrs: { family }
};
}
return null;
}
function extractFontFamily(fontFamilyString) {
// Extract first font from font-family string
// e.g., "Arial, sans-serif" -> "Arial"
return fontFamilyString.split(',')[0].trim().replace(/['"]/g, '');
}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:
// Setting font family
function setFontFamily(family) {
addMark({
type: 'fontFamily',
attrs: { family }
});
}
// Font family selector
function showFontFamilyPicker() {
const families = ['Arial', 'Times New Roman', 'Courier New', 'monospace'];
// Show font selector
}Common Issues
Common Pitfalls: These are issues frequently encountered when implementing this node type. Review carefully before implementation.
Common issues and solutions:
// Issue: Font family with quotes
// Solution: Handle quoted font names
function normalizeFontFamily(family) {
return family.replace(/['"]/g, '');
}
// Issue: Font fallback chain
// Solution: Extract primary font from fallback chain
function extractPrimaryFont(fontFamily) {
return fontFamily.split(',')[0].trim();
}
// Issue: Web-safe fonts
// Solution: Validate font availability
function validateFontFamily(family) {
const webSafeFonts = [
'Arial', 'Times New Roman', 'Courier New',
'Verdana', 'Georgia', 'Palatino'
];
return webSafeFonts.includes(family) || family === 'monospace';
}Implementation
Complete implementation example:
class FontFamilyMark {
constructor(attrs) {
this.type = 'fontFamily';
this.attrs = { family: attrs?.family || 'Arial' };
}
toDOM() {
return ['span', {
style: 'font-family: ' + this.attrs.family
}, 0];
}
static fromDOM(element) {
if (element.tagName === 'SPAN' && element.style.fontFamily) {
return new FontFamilyMark({
family: extractFontFamily(element.style.fontFamily)
});
}
return null;
}
}