Skip to content

Commit

Permalink
fix: add markdown to block test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
qinluhe committed Oct 5, 2024
1 parent 75214a0 commit db1d5b4
Show file tree
Hide file tree
Showing 23 changed files with 816 additions and 291 deletions.
1 change: 1 addition & 0 deletions frontend/appflowy_web_app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"dexie-react-hooks": "^1.1.7",
"emoji-mart": "^5.5.2",
"emoji-regex": "^10.2.1",
"escape-string-regexp": "^5.0.0",
"events": "^3.3.0",
"google-protobuf": "^3.15.12",
"highlight.js": "^11.10.0",
Expand Down
8 changes: 8 additions & 0 deletions frontend/appflowy_web_app/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function generateId () {
export function withTestingYjsEditor (editor: Editor, doc: Y.Doc) {
const yjdEditor = withYjs(editor, doc, {
localOrigin: CollabOrigin.Local,
readOnly: true,
});

return yjdEditor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const CONTAINER_BLOCK_TYPES = [
BlockType.BulletedListBlock,
BlockType.NumberedListBlock,
BlockType.Page,
];
];
export const SOFT_BREAK_TYPES = [BlockType.CalloutBlock, BlockType.CodeBlock];
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,30 @@ import {
getSharedRoot,
handleCollapsedBreakWithTxn,
handleDeleteEntireDocumentWithTxn,
handleIndentBlockWithTxn,
handleLiftBlockOnBackspaceAndEnterWithTxn,
handleLiftBlockOnTabWithTxn,
handleMergeBlockBackwardWithTxn,
handleNonParagraphBlockBackspaceWithTxn,
handleRangeBreak,
handleLiftBlockOnBackspaceWithTxn,
handleMergeBlockForwardWithTxn,
removeRangeWithTxn, handleIndentBlockWithTxn, handleLiftBlockOnTabWithTxn, turnToBlock,
handleNonParagraphBlockBackspaceAndEnterWithTxn,
handleRangeBreak,
removeRangeWithTxn,
turnToBlock,
} from '@/application/slate-yjs/utils/yjsOperations';
import {
BlockData,
BlockType,
InlineBlockType,
Mention,
MentionType, TodoListBlockData,
ToggleListBlockData, YBlock,
YjsEditorKey, YSharedRoot,
MentionType,
TodoListBlockData,
ToggleListBlockData,
YjsEditorKey,
} from '@/application/types';
import { FormulaNode } from '@/components/editor/editor.type';
import { renderDate } from '@/utils/time';
import { BasePoint, BaseRange, Editor, Element, Node, NodeEntry, Range, Text, Transforms } from 'slate';
import isEqual from 'lodash-es/isEqual';
import { BasePoint, BaseRange, Editor, Element, Node, NodeEntry, Path, Range, Text, Transforms } from 'slate';
import { ReactEditor } from 'slate-react';

export const CustomEditor = {
Expand Down Expand Up @@ -79,9 +84,8 @@ export const CustomEditor = {
},

setBlockData<T = BlockData> (editor: YjsEditor, blockId: string, updateData: T, select?: boolean) {
const readonly = editor.isElementReadOnly(editor);

if (readonly) {
if (editor.readOnly) {

Check warning on line 88 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L88

Added line #L88 was not covered by tests
return;
}

Expand All @@ -91,25 +95,36 @@ export const CustomEditor = {
...oldData,
...updateData,
};
const operations = [() => {
block.set(YjsEditorKey.block_data, JSON.stringify(newData));
}];
const entry = Editor.above(editor, {

Check warning on line 98 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L98

Added line #L98 was not covered by tests
const newProperties = {
data: newData,
} as Partial<Element>;
const [entry] = editor.nodes({
at: [],

Check warning on line 103 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L100-L103

Added lines #L100 - L103 were not covered by tests
match: (n) => !Editor.isEditor(n) && Element.isElement(n) && n.blockId === blockId,
});

executeOperations(editor.sharedRoot, operations, 'setBlockData');

if (!select) return;

if (!entry) {
Transforms.select(editor, Editor.start(editor, [0]));
console.error('Block not found');
return;
}

const nodePath = entry[1];
const [, path] = entry;

Check warning on line 112 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L112

Added line #L112 was not covered by tests
let atChild = false;
const { selection } = editor;

if (selection && Path.isAncestor(path, selection.anchor.path)) {
atChild = true;

Check warning on line 117 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L114-L117

Added lines #L114 - L117 were not covered by tests
}

Check warning on line 119 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L119

Added line #L119 was not covered by tests
Transforms.setNodes(editor, newProperties, { at: path });

Check warning on line 121 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L121

Added line #L121 was not covered by tests
if (!select) return;

Check warning on line 123 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L123

Added line #L123 was not covered by tests
if (atChild) {
Transforms.select(editor, Editor.start(editor, path));
}

Transforms.select(editor, Editor.start(editor, nodePath));
},
// Insert break line at the specified path
insertBreak (editor: YjsEditor, at?: BaseRange) {
Expand Down Expand Up @@ -142,11 +157,11 @@ export const CustomEditor = {
const blockType = block.get(YjsEditorKey.block_type) as BlockType;

if (blockType !== BlockType.Paragraph) {
handleNonParagraphBlockBackspaceWithTxn(sharedRoot, block);
handleNonParagraphBlockBackspaceAndEnterWithTxn(sharedRoot, block);

Check warning on line 160 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L160

Added line #L160 was not covered by tests
return;
}

if (path.length > 1 && handleLiftBlockOnBackspaceWithTxn(editor, sharedRoot, block, point)) {
if (path.length > 1 && handleLiftBlockOnBackspaceAndEnterWithTxn(editor, sharedRoot, block, point)) {

Check warning on line 164 in frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/command/index.ts#L164

Added line #L164 was not covered by tests
return;
}

Expand Down Expand Up @@ -256,6 +271,12 @@ export const CustomEditor = {
const operations: (() => void)[] = [];
const sharedRoot = getSharedRoot(editor);
const sourceBlock = getBlock(blockId, sharedRoot);
const sourceType = sourceBlock.get(YjsEditorKey.block_type) as BlockType;
const oldData = dataStringTOJson(sourceBlock.get(YjsEditorKey.block_data));

if (sourceType === type && isEqual(oldData, data)) {
return;
}

operations.push(() => {
turnToBlock(sharedRoot, sourceBlock, type, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function withYHistory<T extends YjsEditor> (
): T & YHistoryEditor {
const e = editor as T & YHistoryEditor;

if (Editor.isElementReadOnly(e, e)) {
if (e.readOnly) {
return e;
}

Expand All @@ -52,6 +52,7 @@ export function withYHistory<T extends YjsEditor> (

e.onChange = () => {
onChange();

const selection = e.selection;

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type LocalChange = {
};

export interface YjsEditor extends Editor {
readOnly: boolean;
isYjsEditor: (value: unknown) => value is YjsEditor;
connect: () => void;
disconnect: () => void;
Expand Down Expand Up @@ -71,16 +72,18 @@ export function withYjs<T extends Editor> (
editor: T,
doc: Y.Doc,
opts?: {
readOnly: boolean;
localOrigin: CollabOrigin;
readSummary?: boolean;
onContentChange?: (content: Descendant[]) => void;
},
): T & YjsEditor {
const { localOrigin = CollabOrigin.Local, readSummary, onContentChange } = opts ?? {};
const { localOrigin = CollabOrigin.Local, readSummary, onContentChange, readOnly = true } = opts ?? {};
const e = editor as T & YjsEditor;
const { apply, onChange } = e;

e.interceptLocalChange = false;
e.readOnly = readOnly;

e.sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot;

Expand Down
2 changes: 2 additions & 0 deletions frontend/appflowy_web_app/src/application/slate-yjs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export enum EditorMarkFormat {
StrikeThrough = 'strikethrough',
Code = 'code',
Href = 'href',
Formula = 'formula',
Mention = 'mention',
FontColor = 'font_color',
BgColor = 'bg_color',
Align = 'align',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { CustomEditor } from '@/application/slate-yjs/command';
import { EditorMarkFormat } from '@/application/slate-yjs/types';
import { getText } from '@/application/slate-yjs/utils/yjsOperations';
import { calculateOffsetRelativeToParent } from '@/application/slate-yjs/utils/positions';
import { getBlock, getNodeAtPath, getText } from '@/application/slate-yjs/utils/yjsOperations';
import { YjsEditorKey, YSharedRoot } from '@/application/types';
import {
Operation,
Element,
Descendant,
Editor,
Element,
InsertTextOperation,
Operation,
RemoveTextOperation,
Descendant,
SetNodeOperation, Path,
SetNodeOperation,
} from 'slate';
import * as Y from 'yjs';

Expand All @@ -37,39 +37,15 @@ function applyInsertText (ydoc: Y.Doc, editor: Editor, op: InsertTextOperation,
const textId = node.textId as string;
const sharedRoot = ydoc.getMap(YjsEditorKey.data_section) as YSharedRoot;
const yText = getText(textId, sharedRoot);

Check warning on line 40 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L40

Added line #L40 was not covered by tests
if (!yText) return;
const point = { path, offset };

const relativeOffset = Math.min(calculateOffsetRelativeToParent(node, point), yText.toJSON().length);

yText.insert(relativeOffset, text);
}

function getNodeAtPath (children: Descendant[], path: Path): Descendant | null {
let currentNode: Descendant | null = null;
let currentChildren = children;

for (let i = 0; i < path.length; i++) {
const index = path[i];

if (index >= currentChildren.length) {
return null;
}

currentNode = currentChildren[index];
if (i === path.length - 1) {
return currentNode;
}

if (!Element.isElement(currentNode) || !currentNode.children) {
return null;
}

currentChildren = currentNode.children;
}

return currentNode;
}

function applyRemoveText (ydoc: Y.Doc, editor: Editor, op: RemoveTextOperation, slateContent: Descendant[]) {
const { path, offset, text } = op;

Expand All @@ -81,6 +57,9 @@ function applyRemoveText (ydoc: Y.Doc, editor: Editor, op: RemoveTextOperation,

const sharedRoot = ydoc.getMap(YjsEditorKey.data_section) as YSharedRoot;
const yText = getText(textId, sharedRoot);

Check warning on line 60 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L60

Added line #L60 was not covered by tests
if (!yText) return;

Check warning on line 62 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L62

Added line #L62 was not covered by tests
const point = { path, offset };

const relativeOffset = Math.min(calculateOffsetRelativeToParent(node, point), yText.toJSON().length);
Expand All @@ -100,26 +79,45 @@ function applySetNode (ydoc: Y.Doc, editor: Editor, op: SetNodeOperation, slateC
const properties = Object.keys(newProperties);

const isLeaf = properties.some((prop: string) => leafKeys.includes(prop));

Check warning on line 81 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L79-L81

Added lines #L79 - L81 were not covered by tests
const isData = properties.some((prop: string) => prop === 'data');
const sharedRoot = ydoc.getMap(YjsEditorKey.data_section) as YSharedRoot;

if (!isLeaf) {
console.log('set_node', newProperties);
return;
}
if (isLeaf) {
const node = getNodeAtPath(slateContent, path.slice(0, -1)) as Element;
const textId = node.textId;

const node = getNodeAtPath(slateContent, path.slice(0, -1)) as Element;
const textId = node.textId;
if (!textId) return;

Check warning on line 90 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L84-L90

Added lines #L84 - L90 were not covered by tests
if (!textId) return;
const yText = getText(textId, sharedRoot);
const [start, end] = Editor.edges(editor, path);

Check warning on line 93 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L93

Added line #L93 was not covered by tests
const sharedRoot = ydoc.getMap(YjsEditorKey.data_section) as YSharedRoot;
const yText = getText(textId, sharedRoot);
const [start, end] = Editor.edges(editor, path);
const startRelativeOffset = Math.min(calculateOffsetRelativeToParent(node, start), yText.toJSON().length);
const endRelativeOffset = Math.min(calculateOffsetRelativeToParent(node, end), yText.toJSON().length);

Check warning on line 96 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L96

Added line #L96 was not covered by tests
const startRelativeOffset = Math.min(calculateOffsetRelativeToParent(node, start), yText.toJSON().length);
const endRelativeOffset = Math.min(calculateOffsetRelativeToParent(node, end), yText.toJSON().length);
const length = endRelativeOffset - startRelativeOffset;

Check warning on line 98 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L98

Added line #L98 was not covered by tests
const length = endRelativeOffset - startRelativeOffset;
yText.format(startRelativeOffset, length, newProperties);
return;
}

Check warning on line 102 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L102

Added line #L102 was not covered by tests
if (isData) {
const node = getNodeAtPath(slateContent, path) as Element;
const blockId = node.blockId as string;

Check warning on line 106 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L106

Added line #L106 was not covered by tests
if (!blockId) {
console.error('blockId is not found in node', node, newProperties);
return;
}

Check warning on line 111 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L111

Added line #L111 was not covered by tests
yText.format(startRelativeOffset, length, newProperties);
const block = getBlock(blockId, sharedRoot);

Check warning on line 113 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L113

Added line #L113 was not covered by tests
if (
'data' in newProperties
) {
block.set(YjsEditorKey.block_data, JSON.stringify(newProperties.data));
return;
}
}

console.error('set_node operation is not supported', op);

Check warning on line 122 in frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts

View check run for this annotation

Codecov / codecov/patch

frontend/appflowy_web_app/src/application/slate-yjs/utils/applyToYjs.ts#L115-L122

Added lines #L115 - L122 were not covered by tests
}
Loading

0 comments on commit db1d5b4

Please sign in to comment.