mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-07-23 09:01:21 +00:00

* feat: support withYHistory * fix: inline elements * fix: insert break in single line * fix: add enter key behavior tests * fix: add test cases * fix: add test cases
148 lines
4.3 KiB
TypeScript
148 lines
4.3 KiB
TypeScript
import { BlockId, BlockType, YBlocks, YChildrenMap, YjsEditorKey, YTextMap } from '@/application/types';
|
|
import { nanoid } from 'nanoid';
|
|
import { Op } from 'quill-delta';
|
|
import * as Y from 'yjs';
|
|
|
|
export interface FromBlockJSON {
|
|
type: string;
|
|
children: FromBlockJSON[];
|
|
data: Record<string, number | string | boolean>;
|
|
text: Op[];
|
|
}
|
|
|
|
export class DocumentTest {
|
|
public doc: Y.Doc;
|
|
|
|
private blocks: YBlocks;
|
|
|
|
private childrenMap: YChildrenMap;
|
|
|
|
private textMap: YTextMap;
|
|
|
|
private pageId: string;
|
|
|
|
constructor () {
|
|
const doc = new Y.Doc();
|
|
|
|
this.doc = doc;
|
|
const collab = doc.getMap(YjsEditorKey.data_section);
|
|
const document = new Y.Map();
|
|
const blocks = new Y.Map() as YBlocks;
|
|
const pageId = nanoid(8);
|
|
const meta = new Y.Map();
|
|
const childrenMap = new Y.Map() as YChildrenMap;
|
|
const textMap = new Y.Map() as YTextMap;
|
|
|
|
const block = new Y.Map();
|
|
|
|
block.set(YjsEditorKey.block_id, pageId);
|
|
block.set(YjsEditorKey.block_type, BlockType.Page);
|
|
block.set(YjsEditorKey.block_children, pageId);
|
|
block.set(YjsEditorKey.block_external_id, pageId);
|
|
block.set(YjsEditorKey.block_external_type, YjsEditorKey.text);
|
|
block.set(YjsEditorKey.block_data, '');
|
|
blocks.set(pageId, block);
|
|
|
|
document.set(YjsEditorKey.page_id, pageId);
|
|
document.set(YjsEditorKey.blocks, blocks);
|
|
document.set(YjsEditorKey.meta, meta);
|
|
meta.set(YjsEditorKey.children_map, childrenMap);
|
|
meta.set(YjsEditorKey.text_map, textMap);
|
|
collab.set(YjsEditorKey.document, document);
|
|
|
|
this.blocks = blocks;
|
|
this.childrenMap = childrenMap;
|
|
this.textMap = textMap;
|
|
this.pageId = pageId;
|
|
}
|
|
|
|
insertParagraph (text: string) {
|
|
const blockId = nanoid(8);
|
|
const block = new Y.Map();
|
|
|
|
block.set(YjsEditorKey.block_id, blockId);
|
|
block.set(YjsEditorKey.block_type, BlockType.Paragraph);
|
|
block.set(YjsEditorKey.block_children, blockId);
|
|
block.set(YjsEditorKey.block_external_id, blockId);
|
|
block.set(YjsEditorKey.block_external_type, YjsEditorKey.text);
|
|
block.set(YjsEditorKey.block_parent, this.pageId);
|
|
block.set(YjsEditorKey.block_data, '');
|
|
this.blocks.set(blockId, block);
|
|
const pageChildren = this.childrenMap.get(this.pageId) ?? new Y.Array<BlockId>();
|
|
|
|
pageChildren.push([blockId]);
|
|
this.childrenMap.set(this.pageId, pageChildren);
|
|
|
|
const blockText = new Y.Text();
|
|
|
|
blockText.insert(0, text);
|
|
this.textMap.set(blockId, blockText);
|
|
|
|
return blockText;
|
|
}
|
|
|
|
fromJSON (json: FromBlockJSON[]) {
|
|
|
|
this.fromJSONChildren(json, this.pageId);
|
|
|
|
return this.doc;
|
|
}
|
|
|
|
private fromJSONChildren (children: FromBlockJSON[], parentId: BlockId) {
|
|
const parentChildren = this.childrenMap.get(parentId) ?? new Y.Array<BlockId>();
|
|
|
|
for (const child of children) {
|
|
const blockId = nanoid(8);
|
|
const block = new Y.Map();
|
|
|
|
block.set(YjsEditorKey.block_id, blockId);
|
|
block.set(YjsEditorKey.block_type, child.type);
|
|
block.set(YjsEditorKey.block_children, blockId);
|
|
block.set(YjsEditorKey.block_external_id, blockId);
|
|
block.set(YjsEditorKey.block_external_type, YjsEditorKey.text);
|
|
block.set(YjsEditorKey.block_parent, parentId);
|
|
block.set(YjsEditorKey.block_data, JSON.stringify(child.data));
|
|
this.blocks.set(blockId, block);
|
|
|
|
parentChildren.push([blockId]);
|
|
if (!this.childrenMap.has(parentId)) {
|
|
this.childrenMap.set(parentId, parentChildren);
|
|
}
|
|
|
|
const blockText = new Y.Text();
|
|
|
|
blockText.applyDelta(child.text);
|
|
|
|
this.textMap.set(blockId, blockText);
|
|
|
|
const blockChildren = new Y.Array<BlockId>();
|
|
|
|
this.childrenMap.set(blockId, blockChildren);
|
|
|
|
this.fromJSONChildren(child.children, blockId);
|
|
}
|
|
}
|
|
|
|
toJSON () {
|
|
return this.toJSONChildren(this.pageId);
|
|
}
|
|
|
|
private toJSONChildren (parentId: BlockId): FromBlockJSON[] {
|
|
const parentChildren = this.childrenMap.get(parentId) ?? [];
|
|
const children = [];
|
|
|
|
for (const childId of parentChildren) {
|
|
const child = this.blocks.get(childId);
|
|
|
|
children.push({
|
|
type: child.get(YjsEditorKey.block_type),
|
|
data: JSON.parse(child.get(YjsEditorKey.block_data)),
|
|
text: this.textMap.get(childId).toDelta(),
|
|
children: this.toJSONChildren(childId),
|
|
});
|
|
}
|
|
|
|
return children;
|
|
}
|
|
}
|