From eb8fdcf79f422ad32ded622c29a116a7c6431a81 Mon Sep 17 00:00:00 2001 From: Ricardo Costa Date: Mon, 24 Jun 2024 23:41:43 +0100 Subject: [PATCH] Removed Revive & Added Fixes --- code/client/src/domain/editor/fugue/Fugue.ts | 67 +++-------------- .../src/domain/editor/fugue/FugueTree.ts | 9 --- .../domain/editor/slate/utils/selection.ts | 43 ----------- .../components/editor/hooks/useEvents.ts | 31 +------- code/client/tests/editor/fugue/fugue.test.ts | 74 ------------------- code/server/src/server.ts | 3 +- code/shared/src/document/types/operations.ts | 12 +-- 7 files changed, 12 insertions(+), 227 deletions(-) diff --git a/code/client/src/domain/editor/fugue/Fugue.ts b/code/client/src/domain/editor/fugue/Fugue.ts index 3486c6ec..4b112224 100644 --- a/code/client/src/domain/editor/fugue/Fugue.ts +++ b/code/client/src/domain/editor/fugue/Fugue.ts @@ -11,7 +11,6 @@ import { InlineStyleOperation, InsertOperation, Operation, - ReviveOperation, } from '@notespace/shared/src/document/types/operations'; /** @@ -44,9 +43,6 @@ export class Fugue { case 'block-style': this.updateBlockStyleRemote(operation); break; - case 'revive': - this.reviveRemote(operation); - break; default: throw new Error('Invalid operation type'); } @@ -94,7 +90,6 @@ export class Fugue { parent, side: isEmpty(leftOrigin.rightChildren) ? 'R' : 'L', styles, - cursor, }; } @@ -107,9 +102,8 @@ export class Fugue { * @param side * @param styles */ - private addNode = ({ cursor, id, value, parent, side, styles }: InsertOperation) => { - if (value === '\n') this.tree.addLineRoot(cursor.line || 0, id, parent, side, styles); - else this.tree.addNode(id, value, parent, side, styles || []); + private addNode = ({ id, value, parent, side, styles }: InsertOperation) => { + this.tree.addNode(id, value, parent, side, styles || []); }; /** @@ -126,7 +120,7 @@ export class Fugue { } else { cursor.column++; } - return this.removeNode(node.id, cursor); + return this.removeNode(node.id); }); } @@ -136,16 +130,15 @@ export class Fugue { */ deleteLocalByCursor(cursor: Cursor) { const node = this.getNodeByCursor(cursor); - if (node) return this.deleteLocalById(cursor, node.id); + if (node) return this.deleteLocalById(node.id); } /** * Deletes the node based on the given operation - * @param cursor * @param ids */ - deleteLocalById = ({ line, column }: Cursor, ...ids: Id[]): DeleteOperation[] => { - return ids.map(id => this.removeNode(id, { line, column: column++ })); + deleteLocalById = (...ids: Id[]): DeleteOperation[] => { + return ids.map(id => this.removeNode(id)); }; /** @@ -157,54 +150,12 @@ export class Fugue { /** * Deletes the node based on the given node id * @param id - * @param cursor */ - private removeNode(id: Id, cursor: Cursor): DeleteOperation { + private removeNode(id: Id): DeleteOperation { this.tree.deleteNode(id); - return { type: 'delete', id, cursor }; - } - - /** - * Relives the nodes from the given start index and given length. - * @param selection - */ - reviveLocal(selection: Selection): ReviveOperation[] { - const nodes = Array.from(this.traverseBySelection(selection, true)); - return nodes.map(node => { - if (node.value === '\n') { - selection.start.line++; - selection.start.column = 0; - } else selection.start.column++; - - return this.reviveNode(node.id, selection.start); - }); - } - - /** - * Revives the node at the given cursor - * @param cursor - */ - reviveLocalByCursor(cursor: Cursor) { - const node = this.getNodeByCursor(cursor); - if (node) return this.reviveNode(node.id, cursor); - } - - /** - * Revives a node based on the given id - * @param id - * @param cursor - */ - reviveNode(id: Id, cursor: Cursor): ReviveOperation { - this.tree.reviveNode(id); - return { type: 'revive', id, cursor }; + return { type: 'delete', id }; } - /** - * Revives a node based on the given operation - * @param operation - */ - reviveRemote = (operation: ReviveOperation) => this.tree.reviveNode(operation.id); - /** * Updates the style of the nodes by the given selection * @param selection @@ -339,7 +290,7 @@ export class Fugue { const iterator = this.traverseBySeparator(' ', cursor, reverse); const nodes: FugueNode[] = iterator.next().value; if (!nodes) return; - return this.deleteLocalById(cursor, ...nodes.map(node => node.id)); + return this.deleteLocalById(...nodes.map(node => node.id)); } /** diff --git a/code/client/src/domain/editor/fugue/FugueTree.ts b/code/client/src/domain/editor/fugue/FugueTree.ts index c1be8260..254d8207 100644 --- a/code/client/src/domain/editor/fugue/FugueTree.ts +++ b/code/client/src/domain/editor/fugue/FugueTree.ts @@ -101,15 +101,6 @@ export class FugueTree { } } - /** - * Re-enables the node with the given id. - * @param id - */ - reviveNode(id: Id) { - const node = this.getById(id); - if (node.isDeleted) node.isDeleted = false; - } - /** * Updates the depth of the ancestors of the given node by delta. * @param node the node whose ancestors' depths are to be updated. diff --git a/code/client/src/domain/editor/slate/utils/selection.ts b/code/client/src/domain/editor/slate/utils/selection.ts index 0eaba30b..ab7f520e 100644 --- a/code/client/src/domain/editor/slate/utils/selection.ts +++ b/code/client/src/domain/editor/slate/utils/selection.ts @@ -1,7 +1,6 @@ import { Editor, Node, Path, Point, Range, Text } from 'slate'; import { Cursor, emptyCursor, emptySelection, Selection } from '@domain/editor/cursor'; import { first, isEqual } from 'lodash'; -import { CustomElement } from '@domain/editor/slate/types'; /** * Checks if the current selection is active @@ -61,48 +60,6 @@ export function pointToCursor(editor: Editor, point: Point): Cursor { return cursor; } -export const cursorToPoint = (editor: Editor, cursor: Cursor): Point => { - const { line, column } = cursor; - let offset = column; - - // Get the path to the line node - const linePath = [line]; - - // Check if the path exists in the editor - if (!Editor.hasPath(editor, linePath)) { - throw new Error(`Cannot find a node at line ${line}`); - } - - // Get the node at the line path - const lineNode = Node.get(editor, linePath); - - // Check if the node is a valid block or container node - if (!Editor.isBlock(editor, lineNode as CustomElement)) { - throw new Error(`Node at line ${line} is not a block node`); - } - - // Traverse the children of the line node to find the correct text node - for (const [node, nodePath] of Node.children(editor, linePath)) { - if (Text.isText(node)) { - if (offset <= node.text.length) { - return { path: nodePath, offset }; - } - offset -= node.text.length; - } - } - - // If the offset is not found, return the end of the line node - const lastTextNode = Node.last(editor, linePath); - if (lastTextNode) { - const [lastNode, lastPath] = lastTextNode; - if (Text.isText(lastNode)) { - return { path: lastPath, offset: lastNode.text.length }; - } - } - - throw new Error('Cursor position is out of bounds'); -}; - /** * Returns the selection by range * @param editor diff --git a/code/client/src/ui/pages/document/components/editor/hooks/useEvents.ts b/code/client/src/ui/pages/document/components/editor/hooks/useEvents.ts index 3db39d78..8672ca2e 100644 --- a/code/client/src/ui/pages/document/components/editor/hooks/useEvents.ts +++ b/code/client/src/ui/pages/document/components/editor/hooks/useEvents.ts @@ -1,44 +1,15 @@ import useSocketListeners from '@services/communication/socket/useSocketListeners'; import { type Operation } from '@notespace/shared/src/document/types/operations'; -import { Editor, Transforms, Location } from 'slate'; -import { Cursor } from '@domain/editor/cursor'; -import { cursorToPoint, getSelection } from '@domain/editor/slate/utils/selection'; -import { isEqual } from 'lodash'; import { ServiceConnector } from '@domain/editor/connectors/service/connector'; /** * Hook client socket listeners to events - * @param editor * @param connector * @param onDone */ -function useEvents(editor: Editor, connector: ServiceConnector, onDone: () => void) { +function useEvents(connector: ServiceConnector, onDone: () => void) { function onOperation(operations: Operation[]) { connector.applyFugueOperations(operations); - const { start: selectionStart, end: selectionEnd } = getSelection(editor); - - operations.forEach((op: Operation) => { - if (['insert', 'delete', 'revive'].includes(op.type)) { - const { cursor } = op as Operation & { cursor: Cursor }; - - if (cursor.line !== selectionEnd.line) return; - if (cursor.column > selectionEnd.column) return; - - // update the cursor position - const delta = ['insert', 'revive'].includes(op.type) ? 1 : -1; - - // move start and end cursor if the selection is collapsed or inserting or reviving - if (delta > 0 || isEqual(selectionStart, selectionEnd)) { - selectionStart.column += delta; - } - selectionEnd.column += delta; - } - const newSelection: Location = { - anchor: cursorToPoint(editor, selectionStart), - focus: cursorToPoint(editor, selectionEnd), - }; - Transforms.select(editor, newSelection); - }); onDone(); } connector.on('operations', onOperation); diff --git a/code/client/tests/editor/fugue/fugue.test.ts b/code/client/tests/editor/fugue/fugue.test.ts index 2aafd1c5..8dc2f146 100644 --- a/code/client/tests/editor/fugue/fugue.test.ts +++ b/code/client/tests/editor/fugue/fugue.test.ts @@ -42,7 +42,6 @@ describe('Fugue', () => { value: 'a', parent: { sender: 'root', counter: 0 }, side: 'R', - cursor: { line: 0, column: 0 }, }; // when @@ -89,12 +88,10 @@ describe('Fugue', () => { value: 'x', parent: { sender: 'root', counter: 0 }, side: 'R', - cursor: { line: 0, column: 0 }, }; const deleteOperation: DeleteOperation = { type: 'delete', id: { sender: 'A', counter: 0 }, - cursor: { line: 0, column: 0 }, }; // when @@ -129,7 +126,6 @@ describe('Fugue', () => { value: 'x', parent: { sender: 'root', counter: 0 }, side: 'R', - cursor: { line: 0, column: 0 }, }; const styleOperation: InlineStyleOperation = { type: 'inline-style', @@ -262,76 +258,6 @@ describe('Fugue', () => { expect(fugue.toString()).toEqual(' '); }); - // test('should revive nodes locally', () => { - // // given - // const cursor: Cursor = { line: 0, column: 0 }; - // const selection: Selection = { start: { line: 0, column: 1 }, end: { line: 0, column: 3 } }; - // const selection2: Selection = { start: { line: 0, column: 0 }, end: { line: 1, column: 2 } }; - // - // // when - // fugue.insertLocal(cursor, 'a', 'b', 'c'); - // fugue.deleteLocal(selection); - // - // // then - // expect(fugue.toString()).toEqual('a'); - // - // // when - // const operations = fugue.insertLocal(selection.start, 'b', 'c'); - // - // // then - // expect(operations).toHaveLength(2); - // expect(fugue.toString()).toEqual('abc'); - // - // // when - // fugue.insertLocal({ line: 0, column: 3 }, '\n', 'd', 'e', 'f'); - // - // // then - // expect(fugue.toString()).toEqual('abc\ndef'); - // - // // when - // fugue.deleteLocal(selection2); - // - // // then - // expect(fugue.toString()).toEqual('f'); - // - // const operations2 = fugue.reviveLocal(selection2); - // - // // then - // expect(operations2).toHaveLength(6); - // expect(fugue.toString()).toEqual('abc\ndef'); - // }); - // - // test('should revive nodes remotely', () => { - // // given - // const insertOperation: InsertOperation = { - // type: 'insert', - // id: { sender: 'A', counter: 0 }, - // value: 'a', - // parent: { sender: 'root', counter: 0 }, - // side: 'R', - // }; - // const deleteOperation: DeleteOperation = { - // type: 'delete', - // id: { sender: 'A', counter: 0 }, - // }; - // - // // when - // fugue.insertRemote(insertOperation); - // fugue.deleteRemote(deleteOperation); - // - // // then - // expect(fugue.toString()).toEqual(''); - // - // // when - // const reviveOperation: ReviveOperation = { type: 'revive', id: insertOperation.id }; - // - // // when - // fugue.reviveRemote(reviveOperation); - // - // // then - // expect(fugue.toString()).toEqual('a'); - // }); - test('should delete a line by cursor', () => { // given const cursor1: Cursor = { line: 0, column: 0 }; diff --git a/code/server/src/server.ts b/code/server/src/server.ts index cd0e6718..fd2c69d7 100644 --- a/code/server/src/server.ts +++ b/code/server/src/server.ts @@ -27,7 +27,6 @@ function bootServer(args: string[]): void { // setup services and databases const databases = mode === 'dev' ? new TestDatabases() : new ProductionDatabases(); const services = new Services(databases); - ServerLogger.logWarning('Starting server in ' + `${mode} mode...`); // setup server and controllers @@ -35,7 +34,7 @@ function bootServer(args: string[]): void { const server = http.createServer(app); const io = new Server(server, config.SERVER_OPTIONS); const api = router(services, io); - app.set('trust proxy', 1); // trust first proxy + app.set('trust proxy', 1); // trust first proxy for secure cookies // setup middlewares app.use(cors(config.SERVER_OPTIONS.cors)); diff --git a/code/shared/src/document/types/operations.ts b/code/shared/src/document/types/operations.ts index 17e47741..9ef11804 100644 --- a/code/shared/src/document/types/operations.ts +++ b/code/shared/src/document/types/operations.ts @@ -1,6 +1,5 @@ import { Id } from "./types"; import { InlineStyle, BlockStyle } from "./styles"; -import { Cursor } from "./cursor"; export type InsertOperation = { type: "insert"; @@ -8,14 +7,12 @@ export type InsertOperation = { value: string; parent: Id; side: "L" | "R"; - cursor: Cursor; styles?: InlineStyle[]; }; export type DeleteOperation = { type: "delete"; id: Id; - cursor: Cursor; }; export type InlineStyleOperation = { @@ -32,15 +29,8 @@ export type BlockStyleOperation = { append: boolean; }; -export type ReviveOperation = { - type: "revive"; - id: Id; - cursor: Cursor; -}; - export type Operation = | InsertOperation | DeleteOperation | InlineStyleOperation - | BlockStyleOperation - | ReviveOperation; + | BlockStyleOperation;