Skip to content

Commit

Permalink
Merge branch 'main' into feat/inline-toolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
gohabereg authored Aug 30, 2024
2 parents 21d7ecf + efcfe22 commit 5b5f38e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 2 deletions.
4 changes: 2 additions & 2 deletions packages/collaboration-manager/src/CollaborationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ export class CollaborationManager {

switch (operation.type) {
case OperationType.Insert:
this.#model.insertText(blockIndex, dataKey, operation.data.newValue, textRange[0]);
this.#model.insertData(operation.index, operation.data.newValue);
break;
case OperationType.Delete:
this.#model.removeText(blockIndex, dataKey, textRange[0], textRange[1]);
this.#model.removeData(operation.index);
break;
case OperationType.Modify:
console.log('modify operation is not implemented yet');
Expand Down
2 changes: 2 additions & 0 deletions packages/model/src/EditorJSModel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ describe('EditorJSModel', () => {
'initializeDocument',
'setProperty',
'addBlock',
'insertData',
'removeData',
'updateTuneData',
'updateValue',
'removeBlock',
Expand Down
20 changes: 20 additions & 0 deletions packages/model/src/EditorJSModel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Stryker disable all -- we don't count mutation test coverage fot this file as it just proxy calls to EditorDocument
/* istanbul ignore file -- we don't count test coverage fot this file as it just proxy calls to EditorDocument */
import type { Index } from './entities/index.js';
import { type BlockNodeSerialized, EditorDocument } from './entities/index.js';
import { EventBus, EventType } from './EventBus/index.js';
import type { ModelEvents, CaretManagerCaretUpdatedEvent, CaretManagerEvents } from './EventBus/index.js';
Expand Down Expand Up @@ -188,6 +189,25 @@ export class EditorJSModel extends EventBus {
return this.#document.removeBlock(...parameters);
}

/**
* Inserts data to the specified index
*
* @param index - index to insert data
* @param data - data to insert
*/
public insertData(index: Index, data: unknown): void {
this.#document.insertData(index, data);
}

/**
* Removes data from the specified index
*
* @param index - index to remove data from
*/
public removeData(index: Index): void {
this.#document.removeData(index);
}

/**
* Updates the ValueNode data associated with the BlockNode at the specified index.
*
Expand Down
92 changes: 92 additions & 0 deletions packages/model/src/entities/EditorDocument/EditorDocument.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,98 @@ describe('EditorDocument', () => {
});
});

describe('.insertData()', () => {
let document: EditorDocument;
const dataKey = 'text' as DataKey;
const text = 'Some text';
const blockIndex = 0;
let block: BlockNode;

beforeEach(() => {
const blockData = {
name: 'header' as BlockToolName,
data: {},
};

document = new EditorDocument();

document.initialize([ blockData ]);

block = document.getBlock(0);
});

it('should call .insertText() method if text index provided', () => {
const spy = jest.spyOn(document, 'insertText');
const index = new IndexBuilder().addBlockIndex(blockIndex)
.addDataKey(dataKey)
.addTextRange([0, 0])
.build();

document.insertData(index, text);

expect(spy)
.toHaveBeenCalledWith(blockIndex, dataKey, text, 0);
});

it('should call .addBlock() if block index is provided', () => {
const spy = jest.spyOn(document, 'addBlock');
const index = new IndexBuilder()
.addBlockIndex(blockIndex)
.build();


document.insertData(index, block);

expect(spy)
.toHaveBeenCalledWith(block, blockIndex);
});
});

describe('.removeData()', () => {
let document: EditorDocument;
const dataKey = 'text' as DataKey;
const blockIndex = 0;

beforeEach(() => {
const blockData = {
name: 'header' as BlockToolName,
data: {},
};

document = new EditorDocument();

document.initialize([ blockData ]);
});

it('should call .removeText() method if text index provided', () => {
const spy = jest.spyOn(document, 'removeText');
const rangeEnd = 5;
const index = new IndexBuilder()
.addBlockIndex(blockIndex)
.addDataKey(dataKey)
.addTextRange([0, rangeEnd])
.build();

document.removeData(index);

expect(spy)
.toHaveBeenCalledWith(blockIndex, dataKey, 0, rangeEnd);
});

it('should call .removeBlock() if block index is provided', () => {
const spy = jest.spyOn(document, 'removeBlock');
const index = new IndexBuilder()
.addBlockIndex(blockIndex)
.build();


document.removeData(index);

expect(spy)
.toHaveBeenCalledWith(blockIndex);
});
});

describe('.removeText()', () => {
let document: EditorDocument;
const dataKey = 'text' as DataKey;
Expand Down
41 changes: 41 additions & 0 deletions packages/model/src/entities/EditorDocument/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../../EventBus/events/index.js';
import type { Constructor } from '../../utils/types.js';
import { BaseDocumentEvent } from '../../EventBus/events/BaseEvent.js';
import type { Index } from '../Index/index.js';

/**
* EditorDocument class represents the top-level container for a tree-like structure of BlockNodes in an editor document.
Expand Down Expand Up @@ -323,6 +324,46 @@ export class EditorDocument extends EventBus {
return this.#children[blockIndex].getFragments(dataKey, start, end, tool);
}

/**
* Inserts data to the specified index
*
* @param index - index to insert data
* @param data - data to insert
*/
public insertData(index: Index, data: unknown): void {
switch (true) {
case index.isTextIndex:
this.insertText(index.blockIndex!, index.dataKey!, data as string, index.textRange![0]);
break;

case index.isBlockIndex:
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
this.addBlock(data as Parameters<EditorDocument['addBlock']>[0], index.blockIndex);
break;
default:
throw new Error('Unsupported index');
}
}

/**
* Removes data from the specified index
*
* @param index - index to remove data from
*/
public removeData(index: Index): void {
switch (true) {
case index.isTextIndex:
this.removeText(index.blockIndex!, index.dataKey!, index.textRange![0], index.textRange![1]);
break;

case index.isBlockIndex:
this.removeBlock(index.blockIndex!);
break;
default:
throw new Error('Unsupported index');
}
}

/**
* Listens to BlockNode events and bubbles them to the EditorDocument
*
Expand Down
62 changes: 62 additions & 0 deletions packages/model/src/entities/Index/Index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DocumentIndex } from '../../EventBus/index.js';
import type { DataKey } from '../BlockNode/index.js';
import type { BlockTuneName } from '../BlockTune/index.js';
import { IndexBuilder } from '../index.js';
import { Index } from './index.js';

describe('Index', () => {
Expand Down Expand Up @@ -198,4 +199,65 @@ describe('Index', () => {
expect(index.validate()).toBe(true);
});
});

describe('.isBlockIndex', () => {
it('should return true if index points to the block', () => {
const index = new IndexBuilder().addBlockIndex(0)
.build();

expect(index.isBlockIndex).toBe(true);
});

it('should return false if index does not include block index', () => {
const index = new Index();

expect(index.isBlockIndex).toBe(false);
});

it('should return false if index points to the text range', () => {
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey('dataKey' as DataKey)
.addTextRange([0, 0])
.build();

expect(index.isBlockIndex).toBe(false);
});

it('should return false if index points to the tune data', () => {
const index = new IndexBuilder().addBlockIndex(0)
.addTuneName('tuneName' as BlockTuneName)
.addTuneKey('tuneKey')
.build();

expect(index.isBlockIndex).toBe(false);
});
});

describe('.isTextIndex', () => {
it('should return true if index points to the text', () => {
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey('dataKey' as DataKey)
.addTextRange([0, 0])
.build();

expect(index.isTextIndex).toBe(true);
});

it('should return false if index does not include text range', () => {
const index = new IndexBuilder().addBlockIndex(0)
.addDataKey('dataKey' as DataKey)
.build();

expect(index.isTextIndex).toBe(false);
});

it('should return false if index points to the tune data', () => {
const index = new IndexBuilder().addBlockIndex(0)
.addTuneName('tuneName' as BlockTuneName)
.addTuneKey('tuneKey')
.build();

expect(index.isTextIndex).toBe(false);
});
});
});
14 changes: 14 additions & 0 deletions packages/model/src/entities/Index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,18 @@ export class Index {
return true;
}
}

/**
* Returns true if index points to the text data
*/
public get isTextIndex(): boolean {
return this.blockIndex !== undefined && this.dataKey !== undefined && this.textRange !== undefined;
}

/**
* Returns true if index points to the block node
*/
public get isBlockIndex(): boolean {
return this.blockIndex !== undefined && this.tuneName === undefined && this.dataKey === undefined && this.textRange === undefined;
}
}

0 comments on commit 5b5f38e

Please sign in to comment.