From cf06b7ee4ec5a4dfafb0c89ac5672902436fc849 Mon Sep 17 00:00:00 2001 From: Toan Vu Date: Mon, 12 Oct 2020 17:31:16 -0400 Subject: [PATCH] Add multiple lines and stylable text support for breakToText --- .../oboeditor/util/keydown-util.test.js | 53 +++-------- .../scripts/oboeditor/util/keydown-util.js | 88 ++++++------------- 2 files changed, 38 insertions(+), 103 deletions(-) diff --git a/packages/app/obojobo-document-engine/__tests__/oboeditor/util/keydown-util.test.js b/packages/app/obojobo-document-engine/__tests__/oboeditor/util/keydown-util.test.js index a093022b51..1828aaec4a 100644 --- a/packages/app/obojobo-document-engine/__tests__/oboeditor/util/keydown-util.test.js +++ b/packages/app/obojobo-document-engine/__tests__/oboeditor/util/keydown-util.test.js @@ -1,10 +1,13 @@ -import { Transforms } from 'slate' +import { Transforms, Point } from 'slate' import { ReactEditor } from 'slate-react' jest.mock('slate-react') import KeyDownUtil from 'src/scripts/oboeditor/util/keydown-util' describe('KeyDown Util', () => { + beforeEach(() => { + jest.clearAllMocks() + }) test('deleteEmptyParent', () => { jest.spyOn(Transforms, 'removeNodes').mockReturnValue(true) jest.spyOn(Transforms, 'move').mockReturnValue(true) @@ -316,7 +319,6 @@ describe('KeyDown Util', () => { test('breakToText inserts text', () => { jest.spyOn(Transforms, 'insertNodes').mockReturnValue(true) - jest.spyOn(Transforms, 'collapse').mockReturnValue(true) const editor = { children: [ @@ -342,7 +344,6 @@ describe('KeyDown Util', () => { expect(event.preventDefault).toHaveBeenCalled() expect(Transforms.insertNodes).toHaveBeenCalled() - expect(Transforms.collapse).toHaveBeenCalled() // make sure the inserted node is correct type const insertedNode = Transforms.insertNodes.mock.calls[0][1] @@ -351,9 +352,9 @@ describe('KeyDown Util', () => { expect(insertedNode.children[0].children[0]).toEqual({ text: '' }) }) - test('breakToText converts to text', () => { - jest.spyOn(Transforms, 'setNodes').mockReturnValue(true) - jest.spyOn(Transforms, 'collapse').mockReturnValue(true) + test('breakToText skips when multile node are selected', () => { + jest.spyOn(Point, 'isBefore').mockReturnValue(false) + jest.spyOn(Point, 'equals').mockReturnValue(false) const editor = { children: [ @@ -363,8 +364,8 @@ describe('KeyDown Util', () => { } ], selection: { - anchor: { path: [0, 0], offset: 1 }, - focus: { path: [0, 0], offset: 1 } + anchor: { path: [0, 0], offset: 4 }, + focus: { path: [0, 0], offset: 4 } }, isInline: () => false, isVoid: () => false @@ -378,40 +379,6 @@ describe('KeyDown Util', () => { KeyDownUtil.breakToText(event, editor, [editor.children[0], [0]], true) expect(event.preventDefault).toHaveBeenCalled() - expect(Transforms.setNodes).toHaveBeenCalled() - expect(Transforms.collapse).toHaveBeenCalled() - }) - - test('breakToText converts to text when selection is at the start of a node', () => { - jest.spyOn(Transforms, 'setNodes').mockReturnValue(true) - jest.spyOn(Transforms, 'collapse').mockReturnValue(true) - jest.spyOn(Transforms, 'select').mockReturnValue(true) - - const editor = { - children: [ - { - type: 'mockNode', - children: [{ text: 'some' }] - } - ], - selection: { - anchor: { path: [0, 0], offset: 0 }, - focus: { path: [0, 0], offset: 0 } - }, - isInline: () => false, - isVoid: () => false - } - - const event = { - preventDefault: jest.fn() - } - - KeyDownUtil.breakToText(event, editor, [editor.children[0], [0]], true) - - expect(event.preventDefault).toHaveBeenCalled() - expect(Transforms.insertNodes).toHaveBeenCalled() - expect(Transforms.setNodes).toHaveBeenCalled() - expect(Transforms.select).toHaveBeenCalled() - expect(Transforms.collapse).toHaveBeenCalled() + expect(Transforms.insertNodes).not.toHaveBeenCalled() }) }) diff --git a/packages/app/obojobo-document-engine/src/scripts/oboeditor/util/keydown-util.js b/packages/app/obojobo-document-engine/src/scripts/oboeditor/util/keydown-util.js index d302b31a20..882b168794 100644 --- a/packages/app/obojobo-document-engine/src/scripts/oboeditor/util/keydown-util.js +++ b/packages/app/obojobo-document-engine/src/scripts/oboeditor/util/keydown-util.js @@ -1,4 +1,4 @@ -import { Text, Editor, Transforms, Range, Path, Element, Point } from 'slate' +import { Text, Editor, Transforms, Range, Path, Element, Point, Node } from 'slate' const TEXT_NODE = 'ObojoboDraft.Chunks.Text' const TEXT_LINE_NODE = 'ObojoboDraft.Chunks.Text.TextLine' @@ -75,76 +75,44 @@ const KeyDownUtil = { }, breakToText: (event, editor, entry) => { const [node, nodePath] = entry - const nodeRange = Editor.range(editor, nodePath) - const nodeEnd = Editor.end(editor, nodeRange) + const nodeEnd = Editor.end(editor, [...nodePath, node.children.length - 1]) const selectionEnd = Editor.end(editor, editor.selection) - const nodeStart = Editor.start(editor, nodeRange) const selectionStart = Editor.start(editor, editor.selection) - const toStartOfNode = { - anchor: selectionStart, - focus: nodeStart - } event.preventDefault() - const toEndOfNode = { - anchor: selectionEnd, - focus: nodeEnd - } + // When multiple nodes are selected, only split the last node. + if (Point.isBefore(selectionEnd, nodeEnd) || Point.equals(selectionEnd, nodeEnd)) { + const textRange = { + anchor: selectionEnd, + focus: nodeEnd + } - // If the Range is collapsed at the end of the node, just insert text - if (Range.isCollapsed(toEndOfNode)) { - return Transforms.insertNodes( - editor, - { - type: TEXT_NODE, - content: {}, - children: [ - { - type: TEXT_NODE, - subtype: TEXT_LINE_NODE, - content: { indent: 0, align: 'left' }, - children: [{ text: '' }] - } - ] - }, - { split: true } - ) - } + const toEndOfNode = { + anchor: selectionStart, + focus: nodeEnd + } - if (Range.isCollapsed(toStartOfNode)) { - // Duplicate the node that's being split - const newNode = { ...node } + const newTexts = Node.fragment(editor, textRange) + const newNode = { + type: TEXT_NODE, + content: { triggers: [] }, + children: [ + { + type: TEXT_NODE, + subtype: TEXT_LINE_NODE, + content: { indent: 0, align: 'left' }, + children: [...newTexts[0].children] + } + ] + } - // Insert the duplicate below this node Transforms.insertNodes(editor, newNode, { at: toEndOfNode }) - // Transform the duplicated node to a text node - const nextPath = [...nodePath] - nextPath[nextPath.length - 1]++ - Transforms.setNodes(editor, { type: TEXT_NODE, content: {} }, { at: nextPath }) - - // Move the selection to the start of the duplicated (now text) node - Transforms.select(editor, nextPath) - Transforms.collapse(editor, 'start') - - return + // Move the cursor to the beginning of the duplicated (now text) node + Transforms.select(editor, selectionStart) + Transforms.move(editor, { distance: 1, unit: 'offset' }) } - - // Set the heading after the selection to text - Transforms.setNodes( - editor, - { - type: TEXT_NODE, - content: {} - }, - { - at: toEndOfNode, - split: true - } - ) - Transforms.delete(editor, { at: Range.intersection(nodeRange, editor.selection) }) - return Transforms.collapse(editor, { edge: 'end' }) } }