UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

179 lines 7.11 kB
import { s } from '../../../json-crdt-patch'; import { SliceStacking } from '../slice/constants'; import { CommonSliceType } from '../slice'; import { SliceBehavior } from './SliceBehavior'; import { printTree } from 'tree-dump/lib/printTree'; /** * Slice registry contains a record of possible inline an block formatting * annotations. Each entry in the registry is a {@link SliceBehavior} that * specifies the behavior, tag, and other properties of the slice. * * @todo Consider moving the registry under the `/transfer` directory. Or maybe * `/slices` directory. */ export class SliceRegistry { /** * Creates a new slice registry with common tag registered. */ static withCommon = () => { const undefSchema = s.con(undefined); const registry = new SliceRegistry(); //----------------------------- Inline elements with "One" stacking behavior const i0 = (tag, name, fromHtml) => { registry.add(new SliceBehavior(SliceStacking.One, tag, name, void 0, false, void 0, fromHtml)); }; const i1 = (tag, name, htmlTags) => { const fromHtml = {}; for (const htmlTag of htmlTags) fromHtml[htmlTag] = () => [tag, null]; i0(tag, name, fromHtml); }; i1(-6 /* TAG.i */, 'Italic', ['i', 'em']); i1(-3 /* TAG.b */, 'Bold', ['b', 'strong']); i1(-12 /* TAG.s */, 'Strikethrough', ['s', 'strike']); i0(-9 /* TAG.u */, 'Underline'); i0(-15 /* TAG.code */, 'Code'); i0(-16 /* TAG.mark */, 'Highlight'); i0(-33 /* TAG.kbd */, 'Keyboard'); i0(-22 /* TAG.del */, 'Delete'); i0(-23 /* TAG.ins */, 'Insert'); i0(-24 /* TAG.sup */, 'Superscript'); i0(-25 /* TAG.sub */, 'Subscript'); i0(-27 /* TAG.math */, 'Math'); // --------------------------- Inline elements with "Many" stacking behavior const aSchema = s.obj({}, { href: s.str(''), title: s.str(''), }); registry.add(new SliceBehavior(SliceStacking.Many, -17 /* TAG.a */, 'Link', aSchema, false, void 0, { a: (jsonml) => { const attr = jsonml[1] || {}; const data = { href: attr.href ?? '', title: attr.title ?? '', }; return [-17 /* TAG.a */, { data, inline: true }]; }, })); const colSchema = s.obj({}, { color: s.str(''), }); registry.add(new SliceBehavior(SliceStacking.Many, -29 /* TAG.col */, 'Color', colSchema, false, void 0, { col: (jsonml) => { const attr = jsonml[1] || {}; const data = { color: attr.color ?? '', }; return [-29 /* TAG.col */, { data, inline: true }]; }, })); // TODO: add more default annotations with "Many" stacking behavior // comment = SliceTypeCon.comment, // font = SliceTypeCon.font, // col = SliceTypeCon.col, // bg = SliceTypeCon.bg, // hidden = SliceTypeCon.hidden, // footnote = SliceTypeCon.footnote, // ref = SliceTypeCon.ref, // iaside = SliceTypeCon.iaside, // iembed = SliceTypeCon.iembed, // bookmark = SliceTypeCon.bookmark, // -------------------------- Block elements with "Marker" stacking behavior const commonBlockSchema = s.obj({}, { indent: s.con(0), align: s.str('left'), }); const b0 = (tag, name, container) => { registry.add(new SliceBehavior(SliceStacking.Marker, tag, name, commonBlockSchema, container)); }; b0(0 /* TAG.p */, 'Paragraph', false); b0(1 /* TAG.blockquote */, 'Blockquote', true); b0(2 /* TAG.codeblock */, 'Code block', false); b0(5 /* TAG.pre */, 'Pre-formatted', false); b0(6 /* TAG.ul */, 'Unordered list', true); b0(7 /* TAG.ol */, 'Ordered list', true); b0(8 /* TAG.tl */, 'Task list', true); b0(9 /* TAG.li */, 'List item', true); b0(11 /* TAG.h1 */, 'Heading 1', false); b0(12 /* TAG.h2 */, 'Heading 2', false); b0(13 /* TAG.h3 */, 'Heading 3', false); b0(14 /* TAG.h4 */, 'Heading 4', false); b0(15 /* TAG.h5 */, 'Heading 5', false); b0(16 /* TAG.h6 */, 'Heading 6', false); b0(19 /* TAG.title */, 'Title', false); b0(20 /* TAG.subtitle */, 'Subtitle', false); // b0(TAG.br, false); // b0(TAG.nl, false); // b0(TAG.hr, false); // b0(TAG.page, false); // b0(TAG.aside, true); // b0(TAG.embed, false); // b0(TAG.column, true); // b0(TAG.contents, true); // b0(TAG.table, true); // b0(TAG.row, true); // b0(TAG.cell, true); // b0(TAG.collapselist, true); // b0(TAG.collapse, true); // b0(TAG.note, true); // b0(TAG.mathblock, false); return registry; }; map = new Map(); _fromHtml = new Map(); clear() { this.map.clear(); this._fromHtml.clear(); } add(entry) { const { tag, fromHtml } = entry; this.map.set(tag, entry); const _fromHtml = this._fromHtml; if (fromHtml) { for (const htmlTag in fromHtml) { const converter = fromHtml[htmlTag]; const converters = _fromHtml.get(htmlTag) ?? []; converters.push([entry, converter]); _fromHtml.set(htmlTag, converters); } } const tagStr = CommonSliceType[tag]; if (tagStr && typeof tagStr === 'string' && (!fromHtml || !(tagStr in fromHtml))) _fromHtml.set(tagStr, [[entry, () => [tag, null]]]); } get(tag) { return this.map.get(tag); } isContainer(tag) { const entry = this.map.get(tag); return entry?.container ?? false; } toHtml(el) { const entry = this.map.get(el[0]); return entry?.toHtml ? entry?.toHtml(el) : void 0; } fromHtml(el) { const tag = el[0] + ''; const converters = this._fromHtml.get(tag); if (converters) { for (const [entry, converter] of converters) { const result = converter(el); if (result) { if (entry.isInline()) { const attr = result[1] ?? (result[1] = {}); attr.inline = entry.isInline(); attr.stacking = !attr.inline ? SliceStacking.Marker : (entry.stacking ?? SliceStacking.Many); } return result; } } } return; } /** ----------------------------------------------------- {@link Printable} */ toString(tab = '') { return ('SliceRegistry' + printTree(tab, [...this.map.values()].map((entry) => (tab) => entry.toString(tab)))); } } //# sourceMappingURL=SliceRegistry.js.map