From 8a05b01bd59af695ea85c84ce047b83dd089d2ce Mon Sep 17 00:00:00 2001 From: Brandon Stull Date: Fri, 23 Jun 2023 14:55:20 -0400 Subject: [PATCH] #2095 Simplifies excerpt obonode's citation area, removes unused logic left over from older iterations of the excerpt obonode design, changes 'Box / Excerpt' to just 'Excerpt' in insert menu and makes corresponding adjustment to visual editor tutorial. --- .../documents/oboeditor-tutorial.json | 2 +- .../__snapshots__/converter.test.js.snap | 41 +-- .../editor-registration.test.js.snap | 25 +- .../editor-component.test.js.snap | 15 -- .../components/citation/editor-component.jsx | 9 - .../citation/editor-component.test.js | 21 -- .../components/edge-controls.jsx | 2 + .../components/{line => }/edge-controls.scss | 4 +- .../editor-component.test.js.snap | 19 -- .../components/line/editor-component.jsx | 18 -- .../components/line/editor-component.test.js | 29 -- .../obojobo-chunks-excerpt/converter.js | 15 +- .../obojobo-chunks-excerpt/converter.test.js | 1 + .../editor-component.scss | 8 +- .../editor-registration.js | 110 +++----- .../editor-registration.test.js | 252 ++++++++---------- .../obojobo-chunks-excerpt/empty-node.json | 11 +- 17 files changed, 179 insertions(+), 403 deletions(-) delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/citation/__snapshots__/editor-component.test.js.snap delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.jsx delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.test.js rename packages/obonode/obojobo-chunks-excerpt/components/{line => }/edge-controls.scss (93%) delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/line/__snapshots__/editor-component.test.js.snap delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.jsx delete mode 100644 packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.test.js diff --git a/packages/app/obojobo-document-engine/src/scripts/oboeditor/documents/oboeditor-tutorial.json b/packages/app/obojobo-document-engine/src/scripts/oboeditor/documents/oboeditor-tutorial.json index 27a8e1660b..0d42354235 100644 --- a/packages/app/obojobo-document-engine/src/scripts/oboeditor/documents/oboeditor-tutorial.json +++ b/packages/app/obojobo-document-engine/src/scripts/oboeditor/documents/oboeditor-tutorial.json @@ -3483,7 +3483,7 @@ "id": "889429ed-f7ee-4a61-940a-4d4b6d8089e7", "type": "ObojoboDraft.Pages.Page", "content": { - "title": "Box/Excerpt" + "title": "Excerpt" }, "children": [ { diff --git a/packages/obonode/obojobo-chunks-excerpt/__snapshots__/converter.test.js.snap b/packages/obonode/obojobo-chunks-excerpt/__snapshots__/converter.test.js.snap index 2520cd0b52..61e120fee8 100644 --- a/packages/obonode/obojobo-chunks-excerpt/__snapshots__/converter.test.js.snap +++ b/packages/obonode/obojobo-chunks-excerpt/__snapshots__/converter.test.js.snap @@ -20,24 +20,10 @@ Object { Object { "children": Array [ Object { - "children": Array [ - Object { - "text": "citation text", - }, - ], - "content": Object { - "align": "center", - "hangingIndent": 0, - "indent": 0, - }, - "subtype": "ObojoboDraft.Chunks.Excerpt.CitationLine", - "type": "ObojoboDraft.Chunks.Excerpt", + "text": "citation text", }, ], - "content": Object { - "hangingIndent": 0, - "indent": 0, - }, + "content": Object {}, "subtype": "ObojoboDraft.Chunks.Excerpt.CitationText", "type": "ObojoboDraft.Chunks.Excerpt", }, @@ -71,24 +57,10 @@ Object { Object { "children": Array [ Object { - "children": Array [ - Object { - "text": "Citation Text", - }, - ], - "content": Object { - "align": "center", - "hangingIndent": 0, - "indent": 0, - }, - "subtype": "ObojoboDraft.Chunks.Excerpt.CitationLine", - "type": "ObojoboDraft.Chunks.Excerpt", + "text": "Citation Text", }, ], - "content": Object { - "hangingIndent": 0, - "indent": 0, - }, + "content": Object {}, "subtype": "ObojoboDraft.Chunks.Excerpt.CitationText", "type": "ObojoboDraft.Chunks.Excerpt", }, @@ -109,9 +81,7 @@ Object { "type": "OboNode", }, ], - "content": Object { - "citation": "Citation Line", - }, + "content": Object {}, "id": "mockKey", "type": "ObojoboDraft.Chunks.Excerpt", } @@ -125,7 +95,6 @@ Object { }, ], "content": Object { - "citation": "Citation Line", "triggers": "mock-triggers", }, "id": "mockKey", diff --git a/packages/obonode/obojobo-chunks-excerpt/__snapshots__/editor-registration.test.js.snap b/packages/obonode/obojobo-chunks-excerpt/__snapshots__/editor-registration.test.js.snap index 3598465d5c..5a8bd7b623 100644 --- a/packages/obonode/obojobo-chunks-excerpt/__snapshots__/editor-registration.test.js.snap +++ b/packages/obonode/obojobo-chunks-excerpt/__snapshots__/editor-registration.test.js.snap @@ -1,25 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Excerpt editor renderNode renders excerpt citation line when passed 1`] = ` - -`; - exports[`Excerpt editor renderNode renders excerpt citation text when passed 1`] = ` - -
- Child component -
-
- Child component -
-
- Child component -
- -`; diff --git a/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.jsx b/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.jsx deleted file mode 100644 index 8fd1414fc6..0000000000 --- a/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import '../../viewer-component.scss' - -import React from 'react' - -const Citation = props => { - return {props.children} -} - -export default Citation diff --git a/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.test.js b/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.test.js deleted file mode 100644 index 799f1396e0..0000000000 --- a/packages/obonode/obojobo-chunks-excerpt/components/citation/editor-component.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import Citation from './editor-component' -import renderer from 'react-test-renderer' -import React from 'react' - -describe('Citation Node', () => { - test('Node builds the expected component', () => { - const Child = () =>
Child component
- - const component = renderer.create( - - - - - - ) - - const tree = component.toJSON() - - expect(tree).toMatchSnapshot() - }) -}) diff --git a/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.jsx b/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.jsx index 9c6300b22b..5989491e11 100644 --- a/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.jsx +++ b/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.jsx @@ -1,3 +1,5 @@ +import './edge-controls.scss' + import React from 'react' const EdgeControls = ({ position, edges, selectedEdge, onChangeEdge }) => { diff --git a/packages/obonode/obojobo-chunks-excerpt/components/line/edge-controls.scss b/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.scss similarity index 93% rename from packages/obonode/obojobo-chunks-excerpt/components/line/edge-controls.scss rename to packages/obonode/obojobo-chunks-excerpt/components/edge-controls.scss index 982418f678..704e587709 100644 --- a/packages/obonode/obojobo-chunks-excerpt/components/line/edge-controls.scss +++ b/packages/obonode/obojobo-chunks-excerpt/components/edge-controls.scss @@ -73,11 +73,11 @@ $lighter-blue: lighten($color-obojobo-blue, 60%); } &.is-edge-fade::after { - background-image: url('../../images/icon-fade-edge.png'); + background-image: url('../images/icon-fade-edge.png'); } &.is-edge-jagged::after { - background-image: url('../../images/icon-jagged-edge.png'); + background-image: url('../images/icon-jagged-edge.png'); } } diff --git a/packages/obonode/obojobo-chunks-excerpt/components/line/__snapshots__/editor-component.test.js.snap b/packages/obonode/obojobo-chunks-excerpt/components/line/__snapshots__/editor-component.test.js.snap deleted file mode 100644 index 1831b8f2b8..0000000000 --- a/packages/obonode/obojobo-chunks-excerpt/components/line/__snapshots__/editor-component.test.js.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Citation Node Node builds the expected component 1`] = ` - -
- Child component -
-
- Child component -
-
- Child component -
-
-`; diff --git a/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.jsx b/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.jsx deleted file mode 100644 index 1629272c09..0000000000 --- a/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import '../../viewer-component.scss' -import './edge-controls.scss' - -import React from 'react' - -const Line = props => { - return ( - - {props.children} - - ) -} - -export default Line diff --git a/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.test.js b/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.test.js deleted file mode 100644 index e6e9bccdbe..0000000000 --- a/packages/obonode/obojobo-chunks-excerpt/components/line/editor-component.test.js +++ /dev/null @@ -1,29 +0,0 @@ -import Line from './editor-component' -import renderer from 'react-test-renderer' -import React from 'react' - -describe('Citation Node', () => { - test('Node builds the expected component', () => { - const Child = () =>
Child component
- - const element = { - content: { - align: 'center', - indent: 0, - hangingIndent: 0 - } - } - - const component = renderer.create( - - - - - - ) - - const tree = component.toJSON() - - expect(tree).toMatchSnapshot() - }) -}) diff --git a/packages/obonode/obojobo-chunks-excerpt/converter.js b/packages/obonode/obojobo-chunks-excerpt/converter.js index 131244e7b2..803156f13b 100644 --- a/packages/obonode/obojobo-chunks-excerpt/converter.js +++ b/packages/obonode/obojobo-chunks-excerpt/converter.js @@ -5,7 +5,7 @@ import withoutUndefined from 'obojobo-document-engine/src/scripts/common/util/wi const EXCERPT_NODE = 'ObojoboDraft.Chunks.Excerpt' const EXCERPT_CONTENT_NODE = 'ObojoboDraft.Chunks.Excerpt.ExcerptContent' const CITE_TEXT_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationText' -const CITE_LINE_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationLine' + /** * Generates an Obojobo Excerpt Node from a Slate node. * Copies the id, type, triggers, and condenses ExcerptLine children and their @@ -20,7 +20,7 @@ const slateToObo = node => { // but it's only ever going to be a single line of centered text // so there's really no reason to go to the trouble here // this seems a bit magical, though - may be a convenience function somewhere? - const citationText = node.children[1].children[0].children[0].text + const citationText = node.children[1].children[0].text return { id: node.id, @@ -72,15 +72,8 @@ const oboToSlate = node => { slateNode.children.push({ type: EXCERPT_NODE, subtype: CITE_TEXT_NODE, - content: { indent: 0, hangingIndent: 0 }, - children: [ - { - type: EXCERPT_NODE, - subtype: CITE_LINE_NODE, - content: { indent: 0, hangingIndent: 0, align: 'center' }, - children: [{ text: node.content.citation }] - } - ] + content: {}, + children: [{ text: node.content.citation }] }) delete slateNode.content.excerpt diff --git a/packages/obonode/obojobo-chunks-excerpt/converter.test.js b/packages/obonode/obojobo-chunks-excerpt/converter.test.js index 7fbcc3efaa..0e80efd188 100644 --- a/packages/obonode/obojobo-chunks-excerpt/converter.test.js +++ b/packages/obonode/obojobo-chunks-excerpt/converter.test.js @@ -118,6 +118,7 @@ describe('Excerpt Converter', () => { } } const slateNode = Converter.oboToSlate(oboNode) + expect(slateNode.children[1].children).toEqual([{ text: 'Citation Text' }]) expect(slateNode).toMatchSnapshot() }) diff --git a/packages/obonode/obojobo-chunks-excerpt/editor-component.scss b/packages/obonode/obojobo-chunks-excerpt/editor-component.scss index 5292f95dfe..20167fb7b2 100644 --- a/packages/obonode/obojobo-chunks-excerpt/editor-component.scss +++ b/packages/obonode/obojobo-chunks-excerpt/editor-component.scss @@ -24,7 +24,13 @@ $lighter-blue: lighten($color-obojobo-blue, 60%); } } - > blockquote .delete-button { + // this is a bit of a hack to force the placeholder to do what we want + // but it's easier than fixing it 'properly' + > blockquote > cite span::before { + transform: translateX(-50%); + } + + > blockquote > .excerpt-content > .delete-button { position: absolute; left: auto; top: 0; diff --git a/packages/obonode/obojobo-chunks-excerpt/editor-registration.js b/packages/obonode/obojobo-chunks-excerpt/editor-registration.js index d3f4e7ba1c..e9ed3aa50c 100644 --- a/packages/obonode/obojobo-chunks-excerpt/editor-registration.js +++ b/packages/obonode/obojobo-chunks-excerpt/editor-registration.js @@ -4,9 +4,7 @@ import { Editor, Element, Node, Text, Transforms } from 'slate' import decreaseIndent from './changes/decrease-indent' import increaseIndent from './changes/increase-indent' import indentOrTab from './changes/indent-or-tab' -import Citation from './components/citation/editor-component' import ExcerptContent from './components/excerpt-content/editor-component' -import Line from './components/line/editor-component' import Converter from './converter' import EditorComponent from './editor-component' import emptyNode from './empty-node.json' @@ -15,8 +13,6 @@ import Icon from './icon' const EXCERPT_NODE = 'ObojoboDraft.Chunks.Excerpt' const EXCERPT_CONTENT = 'ObojoboDraft.Chunks.Excerpt.ExcerptContent' const CITE_TEXT_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationText' -const CITE_LINE_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationLine' -const EXCERPT_TEXT_LINE_NODE = 'ObojoboDraft.Chunks.Excerpt.ExcerptLine' const TEXT_NODE = 'ObojoboDraft.Chunks.Text' const TEXT_LINE_NODE = 'ObojoboDraft.Chunks.Text.TextLine' @@ -29,7 +25,7 @@ const disallowedChildren = [ const Excerpt = { name: EXCERPT_NODE, icon: Icon, - menuLabel: 'Box / Excerpt', + menuLabel: 'Excerpt', isInsertable: true, isContent: true, disallowedChildren: disallowedChildren, @@ -38,21 +34,21 @@ const Excerpt = { emptyNode }, plugins: { - // Editor Plugins - These get attached to the editor object and override it's default functions - // They may affect multiple nodes simultaneously + // this probably isn't possible since excerpts should always have at least one empty text node + // this should transform any text thrown into an excerpt directly just in case insertData(data, editor, next) { // Insert Slate fragments normally if (data.types.includes('application/x-slate-fragment')) return next(data) // If the node that we will be inserting into is not a Excerpt node use the regular logic const [first] = Editor.nodes(editor, { match: node => Element.isElement(node) }) - if (first[0].type !== EXCERPT_NODE) return next(data) + if (first[0].type !== TEXT_NODE) return next(data) - // When inserting plain text into a Excerpt node insert all lines as excerpt + // When inserting plain text into an Excerpt node, transform the text into a Text node const plainText = data.getData('text/plain') const fragment = plainText.split('\n').map(text => ({ - type: EXCERPT_NODE, - subtype: EXCERPT_TEXT_LINE_NODE, + type: TEXT_NODE, + subtype: TEXT_LINE_NODE, content: { indent: 0, hangingIndent: false }, children: [{ text }] })) @@ -63,29 +59,12 @@ const Excerpt = { // They affect individual nodes independently of one another decorate([node, path], editor) { // Define a placeholder decoration - const placeholders = [] if ( - Element.isElement(node) && - node.subtype === EXCERPT_TEXT_LINE_NODE && - Node.string(node) === '' && - path[path.length - 1] === 0 - ) { - const point = Editor.start(editor, path) - - placeholders.push({ - placeholder: 'Type your excerpt here', - anchor: point, - focus: point - }) - } - - if ( - Element.isElement(node) && - node.subtype === CITE_LINE_NODE && - Node.string(node) === '' && - path[path.length - 1] === 0 + node.type === EXCERPT_NODE && + node.subtype === CITE_TEXT_NODE && + Node.string(node) === '' ) { const point = Editor.start(editor, path) @@ -100,8 +79,20 @@ const Excerpt = { }, onKeyDown(entry, editor, event) { switch (event.key) { + // revisit later to potentially move any existing + // citation text into the last Text node in the excerpt content case 'Backspace': + if (!editor.selection.focus.offset) { + event.preventDefault() + } + break + case 'Delete': + if (editor.selection.anchor.offset === entry[0].children[1].children[0].text.length) { + event.preventDefault() + return + } + return KeyDownUtil.deleteEmptyParent(event, editor, entry, event.key === 'Delete') case 'Tab': @@ -114,8 +105,12 @@ const Excerpt = { // TAB return indentOrTab(entry, editor, event) + // preventing anything from happening here for now + // TODO: adjust the logic here to create new text nodes + // outside of the Excerpt node rather than inside it case 'Enter': - return KeyDownUtil.breakToText(event, editor, entry) + return event.preventDefault() + // return KeyDownUtil.breakToText(event, editor, entry) } }, normalizeNode(entry, editor, next) { @@ -144,53 +139,17 @@ const Excerpt = { } } - // CITE_TEXT_NODE must contain one and only one CITE_LINE_NODE + // CITE_TEXT_NODE must contain only text if ( Element.isElement(node) && node.type === EXCERPT_NODE && node.subtype === CITE_TEXT_NODE ) { - let citeLineNode = null - const nodesToRemove = [] - - for (const [child, childPath] of Node.children(editor, path)) { - switch (child.subtype) { - case CITE_LINE_NODE: - if (!citeLineNode) { - citeLineNode = child - } else { - nodesToRemove.push(childPath) - } - - break - - default: - nodesToRemove.push(childPath) - } - } - - if (nodesToRemove.length > 0) { - for (const node of nodesToRemove) { - Transforms.removeNodes(editor, { at: node }) + // this is kind of inelegant but should hopefully do the job + for (const [child] of Node.children(editor, path)) { + if (!Text.isText(child)) { + Transforms.removeNodes(editor, { at: child }) } - - return - } - - if (!citeLineNode) { - Transforms.insertNodes( - editor, - [ - { - type: EXCERPT_NODE, - subtype: CITE_LINE_NODE, - content: { indent: 0, hangingIndent: 0, align: 'center' }, - children: [{ text: '' }] - } - ], - { at: path } - ) - return } } @@ -250,11 +209,8 @@ const Excerpt = { }, renderNode(props) { switch (props.element.subtype) { - case CITE_LINE_NODE: - return - case CITE_TEXT_NODE: - return + return case EXCERPT_CONTENT: return diff --git a/packages/obonode/obojobo-chunks-excerpt/editor-registration.test.js b/packages/obonode/obojobo-chunks-excerpt/editor-registration.test.js index 7a04171336..6fb813ae77 100644 --- a/packages/obonode/obojobo-chunks-excerpt/editor-registration.test.js +++ b/packages/obonode/obojobo-chunks-excerpt/editor-registration.test.js @@ -14,10 +14,10 @@ import Excerpt from './editor-registration' import KeyDownUtil from 'obojobo-document-engine/src/scripts/oboeditor/util/keydown-util' const EXCERPT_NODE = 'ObojoboDraft.Chunks.Excerpt' -const EXCERPT_TEXT_LINE_NODE = 'ObojoboDraft.Chunks.Excerpt.ExcerptLine' const EXCERPT_CONTENT = 'ObojoboDraft.Chunks.Excerpt.ExcerptContent' const CITE_TEXT_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationText' -const CITE_LINE_NODE = 'ObojoboDraft.Chunks.Excerpt.CitationLine' +const TEXT_NODE = 'ObojoboDraft.Chunks.Text' +const TEXT_LINE_NODE = 'ObojoboDraft.Chunks.Text.TextLine' describe('Excerpt editor', () => { describe('insertData', () => { @@ -47,26 +47,26 @@ describe('Excerpt editor', () => { expect(next).toHaveBeenCalled() }) - test('inserts all lines as ExcerptTextLines if pasting into Code', () => { + test('inserts all lines as TextLines if pasting into Code', () => { const data = { types: ['application/html'], getData: () => 'line1 \n line2' } const next = jest.fn() - Editor.nodes.mockReturnValueOnce([[{ type: EXCERPT_NODE }]]) + Editor.nodes.mockReturnValueOnce([[{ type: TEXT_NODE }]]) Excerpt.plugins.insertData(data, {}, next) expect(Transforms.insertFragment).toHaveBeenCalledWith({}, [ { - type: EXCERPT_NODE, - subtype: EXCERPT_TEXT_LINE_NODE, + type: TEXT_NODE, + subtype: TEXT_LINE_NODE, content: { indent: 0, hangingIndent: false }, children: [{ text: 'line1 ' }] }, { - type: EXCERPT_NODE, - subtype: EXCERPT_TEXT_LINE_NODE, + type: TEXT_NODE, + subtype: TEXT_LINE_NODE, content: { indent: 0, hangingIndent: false }, children: [{ text: ' line2' }] } @@ -100,29 +100,16 @@ describe('Excerpt editor', () => { expect(Excerpt.plugins.renderNode(props)).toMatchSnapshot() }) - test('renders excerpt citation line when passed', () => { - const props = { - attributes: { dummy: 'dummyData' }, - element: { - type: EXCERPT_NODE, - subtype: CITE_LINE_NODE, - content: {} - } - } - - expect(Excerpt.plugins.renderNode(props)).toMatchSnapshot() - }) - test('renders excerpt citation text when passed', () => { const props = { attributes: { dummy: 'dummyData' }, element: { type: EXCERPT_NODE, subtype: CITE_TEXT_NODE, - content: {} + content: {}, + children: [{ text: 'citation text' }] } } - expect(Excerpt.plugins.renderNode(props)).toMatchSnapshot() }) }) @@ -134,40 +121,14 @@ describe('Excerpt editor', () => { expect(placeholders).toEqual([]) }) - test('renders a placeholder for excerpt', () => { + test('renders placeholder citation text', () => { const editor = { children: [{ children: [{ text: '' }] }] } const node = { - subtype: EXCERPT_TEXT_LINE_NODE, - children: [{ text: '' }] - } - - const point = { key: 'pointKey' } - - Element.isElement.mockReturnValue(true) - Node.string.mockReturnValue('') - Editor.start.mockReturnValue(point) - - const actualPlaceholders = Excerpt.plugins.decorate([node, [0]], editor) - - expect(actualPlaceholders).toEqual([ - { - placeholder: 'Type your excerpt here', - anchor: point, - focus: point - } - ]) - }) - - test('renders a placeholder for excerpt', () => { - const editor = { - children: [{ children: [{ text: '' }] }] - } - - const node = { - subtype: CITE_LINE_NODE, + type: EXCERPT_NODE, + subtype: CITE_TEXT_NODE, children: [{ text: '' }] } @@ -233,7 +194,48 @@ describe('Excerpt editor', () => { Excerpt.plugins.onKeyDown([{}, [0]], {}, event) - expect(KeyDownUtil.breakToText).toHaveBeenCalled() + expect(event.preventDefault).toHaveBeenCalled() + expect(KeyDownUtil.breakToText).not.toHaveBeenCalled() + }) + + test('deals with [Delete]', () => { + const editor = { + selection: { + anchor: { + path: [0, 0], + offset: 0 + } + }, + children: [] + } + + const event = { + key: 'Delete', + preventDefault: jest.fn() + } + // entry is the whole excerpt + let mockEntry = { + children: [ + // the first child is the ExcerptContent - we don't care about that here + {}, + // the second child is the citation text + { children: [{ text: 'mockText' }] } + ] + } + + Excerpt.plugins.onKeyDown([mockEntry, [0]], editor, event) + expect(event.preventDefault).not.toHaveBeenCalled() + expect(KeyDownUtil.deleteEmptyParent).toHaveBeenCalled() + + KeyDownUtil.deleteEmptyParent.mockReset() + + mockEntry = { + children: [{}, { children: [{ text: '' }] }] + } + + Excerpt.plugins.onKeyDown([mockEntry, [0]], editor, event) + expect(event.preventDefault).toHaveBeenCalledTimes(1) + expect(KeyDownUtil.deleteEmptyParent).not.toHaveBeenCalled() }) test('deals with [Backspace]', () => { @@ -242,9 +244,41 @@ describe('Excerpt editor', () => { preventDefault: jest.fn() } - Excerpt.plugins.onKeyDown([{}, [0]], {}, event) + // entry is the whole excerpt + const mockEntry = { + children: [ + // the first child is the ExcerptContent - we don't care about that here + {}, + // the second child is the citation text + { children: [{ text: 'mockText' }] } + ] + } - expect(KeyDownUtil.deleteEmptyParent).toHaveBeenCalled() + let editor = { + selection: { + focus: { + path: [0, 0], + offset: 1 + } + }, + children: [] + } + + Excerpt.plugins.onKeyDown([mockEntry, [0]], editor, event) + expect(event.preventDefault).not.toHaveBeenCalled() + + editor = { + selection: { + focus: { + path: [0, 0], + offset: 0 + } + }, + children: [] + } + + Excerpt.plugins.onKeyDown([mockEntry, [0]], editor, event) + expect(event.preventDefault).toHaveBeenCalledTimes(1) }) }) @@ -316,87 +350,6 @@ describe('Excerpt editor', () => { expect(wrapNodesSpy).not.toHaveBeenCalled() }) - test('removes extra citation line nodes', () => { - const childPaths = [[0], [1], [2]] - const children = [{ subtype: CITE_LINE_NODE }, { subtype: CITE_LINE_NODE }, { subtype: '' }] - - Node.children.mockReturnValue([ - [children[0], childPaths[0]], - [children[1], childPaths[1]], - [children[2], childPaths[2]] - ]) - - Excerpt.plugins.normalizeNode( - [ - { - type: EXCERPT_NODE, - subtype: CITE_TEXT_NODE - }, - [0] - ], - editor, - jest.fn() - ) - - expect(removeNodesSpy).toHaveBeenCalledTimes(2) - - expect(removeNodesSpy).not.toHaveBeenCalledWith(editor, { at: childPaths[0] }) - expect(removeNodesSpy).toHaveBeenCalledWith(editor, { at: childPaths[1] }) - expect(removeNodesSpy).toHaveBeenCalledWith(editor, { at: childPaths[2] }) - }) - - test('does not remove citation line node if there is only one', () => { - const childPaths = [[0]] - const children = [{ subtype: CITE_LINE_NODE }] - - Node.children.mockReturnValue([[children[0], childPaths[0]]]) - - Excerpt.plugins.normalizeNode( - [ - { - type: EXCERPT_NODE, - subtype: CITE_TEXT_NODE - }, - [0] - ], - editor, - jest.fn() - ) - - expect(removeNodesSpy).not.toHaveBeenCalled() - }) - - test('adds an empty citation line node if there are not any', () => { - Node.children.mockReturnValue([]) - - Excerpt.plugins.normalizeNode( - [ - { - type: EXCERPT_NODE, - subtype: CITE_TEXT_NODE - }, - [0] - ], - editor, - jest.fn() - ) - - expect(insertNodesSpy).toHaveBeenCalled() - - expect(insertNodesSpy).toHaveBeenCalledWith( - editor, - [ - { - type: EXCERPT_NODE, - subtype: CITE_LINE_NODE, - content: { indent: 0, hangingIndent: 0, align: 'center' }, - children: [{ text: '' }] - } - ], - { at: [0] } - ) - }) - test('removes children if more than 1 excerpt content or cite text node', () => { const excerptChildren = [ [{ subtype: EXCERPT_CONTENT }, [0]], @@ -430,6 +383,33 @@ describe('Excerpt editor', () => { expect(removeNodesSpy).toHaveBeenCalledTimes(3) }) + test('removes non-text children from citation text node', () => { + Node.children.mockReturnValue([ + [{ text: 'citation text' }, [0]], + [{ subtype: 'OtherType' }, [1]], + [{ subtype: 'OtherType' }, [2]] + ]) + + Text.isText + .mockReturnValueOnce(true) + .mockReturnValueOnce(false) + .mockReturnValueOnce(false) + + Excerpt.plugins.normalizeNode( + [ + { + type: EXCERPT_NODE, + subtype: CITE_TEXT_NODE + }, + [0] + ], + editor, + jest.fn() + ) + + expect(removeNodesSpy).toHaveBeenCalledTimes(2) + }) + test('adds content node if one does not exist', () => { Node.children.mockReturnValue([]) diff --git a/packages/obonode/obojobo-chunks-excerpt/empty-node.json b/packages/obonode/obojobo-chunks-excerpt/empty-node.json index ea4ae764e3..e3a07085e1 100644 --- a/packages/obonode/obojobo-chunks-excerpt/empty-node.json +++ b/packages/obonode/obojobo-chunks-excerpt/empty-node.json @@ -42,15 +42,8 @@ { "type": "ObojoboDraft.Chunks.Excerpt", "subtype": "ObojoboDraft.Chunks.Excerpt.CitationText", - "content": { "indent": 0, "hangingIndent": 0 }, - "children": [ - { - "type": "ObojoboDraft.Chunks.Excerpt", - "subtype": "ObojoboDraft.Chunks.Excerpt.CitationLine", - "content": { "indent": 0, "hangingIndent": 0, "align": "center" }, - "children": [{ "text": "" }] - } - ] + "content": {}, + "children": [{ "text": "" }] } ] }