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 1764x 9x 788x 788x 788x 3737x 3737x 3737x 1973x 1973x 1973x 1973x 378x 378x 551x 551x 551x 551x 551x 551x 551x 1764x 1764x 1764x 1764x 1764x 1764x 1764x 1764x 1563x 1563x 1563x 1563x 1764x 2552x 2552x 2552x 2552x 3737x 3737x 3737x 3737x 3737x 788x 788x 788x | 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;
}
}
|