Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

Commit

Permalink
Cleanup code
Browse files Browse the repository at this point in the history
  • Loading branch information
tiberiuichim committed May 27, 2020
1 parent fdca1d7 commit 0231f41
Showing 1 changed file with 155 additions and 113 deletions.
268 changes: 155 additions & 113 deletions src/TextBlock/TextBlockEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { useMemo } from 'react';
import { Editor, Transforms, Range, Node, Point } from 'slate';
import SlateEditor from './../editor';
import {
fixSelection,
// fixSelection,
isCursorAtBlockEnd,
isCursorAtBlockStart,
} from './../editor/utils';
Expand All @@ -18,6 +18,121 @@ import ShortcutListing from './ShortcutListing';
import { LISTTYPES } from './constants';
import { withHandleBreak } from './decorators';

function getPreviousBlock(index, properties) {
if (index === 0) return;

// join this block with previous block, if previous block is slate
const blocksFieldname = getBlocksFieldname(properties);
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);

const blocks_layout = properties[blocksLayoutFieldname];
const prevBlockId = blocks_layout.items[index - 1];
const prevBlock = properties[blocksFieldname][prevBlockId];
return prevBlock;
}

function isCursorInList(editor) {
const [listItemWithSelection, listItemWithSelectionPath] = Editor.above(
editor,
{
match: (n) => n.type === 'list-item',
},
);

// whether the selection is inside a list item
const listItemCase =
Range.isCollapsed(editor.selection) && listItemWithSelection;

return [listItemCase, listItemWithSelectionPath, listItemCase];
}

function handleBackspaceInList(editor, prevBlock) {
const [listItemWithSelection, listItemWithSelectionPath] = Editor.above(
editor,
{
match: (n) => n.type === 'list-item',
},
);

// whether the selection is inside a list item
const listItemCase =
Range.isCollapsed(editor.selection) && listItemWithSelection;

// if the selection is collapsed and at node and offset 0
// or collapsed inside a list item
if (isCursorAtBlockStart(editor) || listItemCase) {
// are we in a list-item and is cursor at the beginning of the list item?
if (listItemCase && editor.selection.anchor.offset === 0) {
if (
Node.parent(editor, listItemWithSelectionPath).children.indexOf(
listItemWithSelection,
) === 0
) {
// the cursor is inside the first list-item
event.stopPropagation();
event.preventDefault();
return false; // TODO: join with previous <li> element, if exists
}
// else handle by deleting the list-item
Transforms.liftNodes(editor);
Transforms.mergeNodes(editor);
Transforms.mergeNodes(editor, { at: [1] });
//console.log('editor.children', editor.children);

event.stopPropagation();
event.preventDefault();

return;
}
}
return true;
}

function handleBackspaceInText(editor, prevBlock) {
// To work around current architecture limitations, read the value
// from previous block. Replace it in the current editor (over
// which we have control), join with current block value, then use
// this result for previous block, delete current block

const prev = prevBlock.value;

// collapse the selection to its start point
Transforms.collapse(editor, { edge: 'start' });

// TODO: do we really want to insert this text here?

// insert a space before the left edge of the selection
editor.apply({
type: 'insert_text',
path: [0, 0],
offset: 0,
text: ' ',
});

// collapse the selection to its start point
Transforms.collapse(editor, { edge: 'start' });

// insert the contents of the previous editor into the current editor
Transforms.insertNodes(editor, prev, {
at: Editor.start(editor, []),
});

// not needed currently: delete the useless space inserted above
//Editor.deleteBackward(editor, { unit: 'character' });

// merge the contents separated by the collapsed selection
Transforms.mergeNodes(editor);
}

function blockIsEmpty(editor) {
const value = editor.children;
// TODO: this is very optimistic, we might have void nodes that are
// meaningful. We should test if only one child, with empty text
if (plaintext_serialize(value || []).length === 0) {
return true;
}
}

const TextBlockEdit = (props) => {
const {
data,
Expand Down Expand Up @@ -104,137 +219,64 @@ const TextBlockEdit = (props) => {
},

Backspace: ({ editor, event }) => {
const { value } = data;

// can be undefined
const [listItemWithSelection, listItemWithSelectionPath] = Editor.above(
editor,
{
match: (n) => n.type === 'list-item',
},
);

// whether the selection is inside a list item
const listItemCase =
Range.isCollapsed(editor.selection) && listItemWithSelection;

// if the selection is collapsed and at node and offset 0
// or collapsed inside a list item
if (isCursorAtBlockStart(editor) || listItemCase) {
// TODO: this is very optimistic, we might have void nodes that are
// meaningful. We should test if only one child, with empty text
if (plaintext_serialize(value || []).length === 0) {
event.preventDefault();
return onDeleteBlock(block, true);
}

// are we in a list-item and is cursor at the beginning of the list item?
if (listItemCase && editor.selection.anchor.offset === 0) {
if (
Node.parent(editor, listItemWithSelectionPath).children.indexOf(
listItemWithSelection,
) === 0
) {
// the cursor is inside the first list-item
event.stopPropagation();
event.preventDefault();
return false; // TODO: join with previous <li> element, if exists
}
// else handle by deleting the list-item
Transforms.liftNodes(editor);
Transforms.mergeNodes(editor);
Transforms.mergeNodes(editor, { at: [1] });
//console.log('editor.children', editor.children);

event.stopPropagation();
event.preventDefault();

return;
}

// join this block with previous block, if previous block is slate
const blocksFieldname = getBlocksFieldname(properties);
const blocksLayoutFieldname = getBlocksLayoutFieldname(properties);

const blocks_layout = properties[blocksLayoutFieldname];
const prevBlockId = blocks_layout.items[index - 1];
const prevBlock = properties[blocksFieldname][prevBlockId];

if (prevBlock['@type'] !== 'slate') {
return;
}

// To work around current architecture limitations, read the value
// from previous block. Replace it in the current editor (over
// which we have control), join with current block value, then use
// this result for previous block, delete current block

event.stopPropagation();
if (blockIsEmpty(editor)) {
event.preventDefault();
return onDeleteBlock(block, true);
}

const prev = prevBlock.value;
const [prevBlock = {}, prevBlockId] = getPreviousBlock(
index,
properties,
);

// collapse the selection to its start point
Transforms.collapse(editor, { edge: 'start' });
if (prevBlock['@type'] !== 'slate') return;

// TODO: do we really want to insert this text here?
const isAtBlockStart = isCursorAtBlockStart(editor);

// insert a space before the left edge of the selection
editor.apply({
type: 'insert_text',
path: [0, 0],
offset: 0,
text: ' ',
});
if (!isAtBlockStart) return;

// collapse the selection to its start point
Transforms.collapse(editor, { edge: 'start' });
event.stopPropagation();
event.preventDefault();

// insert the contents of the previous editor into the current editor
Transforms.insertNodes(editor, prev, {
at: Editor.start(editor, []),
});
if (isCursorInList(editor)) {
handleBackspaceInList(editor);
} else {
handleBackspaceInText(editor);
}

// not needed currently: delete the useless space inserted above
//Editor.deleteBackward(editor, { unit: 'character' });

// merge the contents separated by the collapsed selection
Transforms.mergeNodes(editor);

const selection = JSON.parse(JSON.stringify(editor.selection));
const combined = JSON.parse(JSON.stringify(editor.children));

// TODO: don't remove undo history, etc
// TODO: after Enter, the current filled-with-previous-block
// block is visible for a fraction of second

// setTimeout is needed to ensure setState has been successfully
// executed in Form.jsx. See
// https://github.com/plone/volto/issues/1519
onDeleteBlock(block, true);
setTimeout(() => {
onChangeBlock(prevBlockId, {
'@type': 'slate',
value: combined,
selection,
plaintext: plaintext_serialize(combined || []),
});
const selection = JSON.parse(JSON.stringify(editor.selection));
const combined = JSON.parse(JSON.stringify(editor.children));

// TODO: don't remove undo history, etc
// TODO: after Enter, the current filled-with-previous-block
// block is visible for a fraction of second

// setTimeout ensures setState has been successfully
// executed in Form.jsx. See
// https://github.com/plone/volto/issues/1519
setTimeout(() => {
onChangeBlock(prevBlockId, {
'@type': 'slate',
value: combined,
selection,
plaintext: plaintext_serialize(combined || []),
});
}
return true;
setTimeout(() => onDeleteBlock(block, true));
});

return;
},

...settings.slate?.keyDownHandlers,
};
}, [
block,
blockNode,
data,
index,
onChangeBlock,
onDeleteBlock,
onFocusNextBlock,
onFocusPreviousBlock,
onDeleteBlock,
onChangeBlock,
properties,
]);

Expand Down

0 comments on commit 0231f41

Please sign in to comment.