Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 9x 9x 9x 1709x 9x 766x 766x 766x 3597x 3597x 3597x 1888x 1888x 1888x 1888x 368x 368x 496x 496x 496x 496x 496x 496x 496x 1709x 1709x 1709x 1709x 1709x 1709x 1709x 1709x 1508x 1508x 1508x 1508x 1709x 2475x 2475x 2475x 2475x 3597x 3597x 3597x 3597x 3597x 766x 766x 766x | import {Anchor} from 'json-joy/lib/json-crdt-extensions/peritext/rga/constants';
import {SliceHeaderShift, SliceStacking} from 'json-joy/lib/json-crdt-extensions/peritext/slice/constants';
import type {ViewRange, ViewSlice} from 'json-joy/lib/json-crdt-extensions/peritext/editor/types';
import type {SlateDocument, SlateDescendantNode, SlateTextNode, SlateElementNode} from '../types';
import type {SliceTypeStep, SliceTypeSteps} from 'json-joy/lib/json-crdt-extensions/peritext';
const isInline = (node: unknown): node is SlateTextNode =>
typeof node === 'object' && !!node && typeof (node as SlateTextNode).text === 'string';
/**
* Converts Slate.js state to a {@link ViewRange} flat string with
* annotation ranges, which is the natural view format for a Peritext model.
*
* Usage:
*
* ```typescript
* FromSlate.convert(node);
* ```
*/
export class FromSlate {
static readonly convert = (doc: SlateDocument): ViewRange => new FromSlate().convert(doc);
private text = '';
private slices: ViewSlice[] = [];
private conv(node: SlateDescendantNode, path: SliceTypeSteps, nodeDiscriminator: number): void {
Iif (!node || typeof node !== 'object') return;
const start = this.text.length;
if ('text' in node) {
const {text, ...tagMap} = node as SlateTextNode;
this.text += text;
const tags = Object.keys(tagMap);
if (tags.length) {
const end = start + text.length;
for (const tag of tags) {
const data = tagMap[tag];
const dataEmpty = !data || data === true;
const stacking: SliceStacking = dataEmpty ? SliceStacking.One : SliceStacking.Many;
const header =
(stacking << SliceHeaderShift.Stacking) +
(Anchor.Before << SliceHeaderShift.X1Anchor) +
(Anchor.After << SliceHeaderShift.X2Anchor);
const slice: ViewSlice = [header, start, end, tag];
if (!dataEmpty) slice.push(data);
this.slices.push(slice);
}
}
} else {
const element = node as SlateElementNode;
const {type, children, ...data} = element;
const step: SliceTypeStep = nodeDiscriminator || data ? [type, nodeDiscriminator, data] : type;
const length = children?.length ?? 0;
const hasNoChildren = length === 0;
const isFirstChildInline = isInline((children as SlateElementNode['children'])?.[0]);
const doEmitSplitMarker = hasNoChildren || isFirstChildInline;
if (doEmitSplitMarker) {
this.text += '\n';
const header =
(SliceStacking.Marker << SliceHeaderShift.Stacking) +
(Anchor.Before << SliceHeaderShift.X1Anchor) +
(Anchor.Before << SliceHeaderShift.X2Anchor);
const slice: ViewSlice = [header, start, start, [...path, step]];
this.slices.push(slice);
}
Eif (length > 0) this.cont([...path, step], children!);
}
}
private cont(path: SliceTypeSteps, content: SlateDescendantNode[]): void {
let prevTag: string = '';
let discriminator: number = 0;
const length = content.length;
for (let i = 0; i < length; i++) {
const child = content[i];
const tag = child.type as string;
discriminator = tag === prevTag ? discriminator + 1 : 0;
this.conv(child, path, discriminator);
prevTag = tag;
}
}
public convert(node: SlateDocument): ViewRange {
let length = 0;
Eif (node && (length = node.length) > 0) this.cont([], node);
return [this.text, 0, this.slices] as ViewRange;
}
}
|