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

Commit

Permalink
Converting list to paragraph, list splitting w/ 1 issue
Browse files Browse the repository at this point in the history
  • Loading branch information
silviubogan committed Jun 25, 2020
1 parent 806ccc6 commit 5547066
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 31 deletions.
7 changes: 5 additions & 2 deletions src/TextBlock/TextBlockEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ const TextBlockEdit = (props) => {
return withHandleBreak(index, onAddBlock, onChangeBlock, onSelectBlock);
}, [index, onAddBlock, onChangeBlock, onSelectBlock]);

const configureWithList = useMemo(() => withList(), []);
const configureWithList = useMemo(
() => withList({ onChangeBlock, onAddBlock, onSelectBlock, index }),
[index, onAddBlock, onChangeBlock, onSelectBlock],
);

const configuredOnKeyDownList = useMemo(() => onKeyDownList(), []);

Expand All @@ -106,7 +109,7 @@ const TextBlockEdit = (props) => {
properties={properties}
onAddBlock={onAddBlock}
// TODO: uncomment this piece of code (it was commented just for testing purposes):
decorators={[configureWithList/* , configuredWithHandleBreak */]}
decorators={[configureWithList /* , configuredWithHandleBreak */]}
onSelectBlock={onSelectBlock}
value={value}
data={data}
Expand Down
150 changes: 124 additions & 26 deletions src/TextBlock/decorators/withList.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { Editor, Path, Point, Range, Transforms, Text, Node } from 'slate';
import { castArray } from 'lodash';
import {
simulateBackspaceAtEndOfEditor,
createDefaultFragment,
createAndSelectNewSlateBlock,
splitEditorInTwoFragments,
replaceAllContentInEditorWith,
} from '../utils';

// TODO: 2 x Enter in the middle of a list should split the list in 2 parts, and just that or also insert a new empty block in the middle?

/**
* See {@link Range.isCollapsed}.
Expand Down Expand Up @@ -126,14 +135,49 @@ const withResetBlockType = (options) => (editor) => {
return editor;
};

const thereIsNoListItemBelowSelection = (editor) => {
let sel = editor.selection;
if (Range.isExpanded(sel)) {
Transforms.collapse(editor, { edge: 'start' });
}
// path of paragraph (TODO: what if there is no paragraph, but a nested list?)
let pg = Path.parent(sel.anchor.path);
// Path of list-item
let p = Path.parent(pg);
// Path of numbered/bulleted list
let pp = Path.parent(p);

let listItems = Node.children(editor, pp);

for (let [node, path] of listItems) {
if (Path.isAfter(path, p)) {
return false;
}
}

return true;
};

const withList = ({
typeUl = 'bulleted-list',
typeOl = 'numbered-list',
typeLi = 'list-item',
typeP = 'paragraph',
onChangeBlock,
onAddBlock,
onSelectBlock,
index,
} = {}) => (editor) => {
const { insertBreak } = editor;

const createAndSelectNewBlockAfter = (blockValue) => {
return createAndSelectNewSlateBlock(blockValue, index, {
onChangeBlock,
onAddBlock,
onSelectBlock,
});
};

/**
* Add a new list item if selection is in a LIST_ITEM > typeP.
*/
Expand All @@ -146,13 +190,11 @@ const withList = ({
);
// if the selection is inside a paragraph
if (paragraphNode.type === typeP) {
const [listItemNode, listItemPath] = Editor.parent(
editor,
paragraphPath,
);
const listItemEntry = Editor.parent(editor, paragraphPath);
const [listItemNode, listItemPath] = listItemEntry;

// if the paragraph is inside a list item
if (listItemNode.type === typeLi) {
if (listItemEntry && listItemNode.type === typeLi) {
// if selection is expanded, delete it
if (!Range.isCollapsed(editor.selection)) {
Transforms.delete(editor);
Expand All @@ -167,6 +209,8 @@ const withList = ({
const nextParagraphPath = Path.next(paragraphPath);
const nextListItemPath = Path.next(listItemPath);

// console.log('isStart', isStart);

/**
* If cursor on start of paragraph, if the paragraph is empty, remove the paragraph (and the list item), then break the block!
* if it is not empty, insert a new empty list item.
Expand All @@ -175,6 +219,7 @@ const withList = ({
if (isBlockTextEmpty(paragraphNode)) {
console.log('remove list item and split here');
} else {
console.log('inserting new list item');
Transforms.insertNodes(
editor,
{
Expand All @@ -186,6 +231,8 @@ const withList = ({
}
}

console.log('isEnd', isEnd);

/**
* If not end, split nodes, wrap a list item on the new paragraph and move it to the next list item
*/
Expand All @@ -204,18 +251,59 @@ const withList = ({
to: nextListItemPath,
});
} else {
/**
* If end, insert a list item after and select it
*/
Transforms.insertNodes(
editor,
{
type: typeLi,
children: [{ type: typeP, children: [{ text: '' }] }],
},
{ at: nextListItemPath },
);
Transforms.select(editor, nextListItemPath);
if (isBlockTextEmpty(paragraphNode)) {
if (thereIsNoListItemBelowSelection(editor)) {
simulateBackspaceAtEndOfEditor(editor);
const bottomBlockValue = createDefaultFragment();
createAndSelectNewBlockAfter(bottomBlockValue);
} else {
console.log('should split the list in two Volto blocks!');
let [upBlock, bottomBlock] = splitEditorInTwoFragments(editor);

let [listNode, listPath] = Editor.parent(editor, listItemPath);

let theType = listNode.type;

let newUpBlock = [
{
type: theType,
children: upBlock[0].children.slice(
0,
upBlock[0].children.length - 1,
),
},
];

let newBottomBlock = [
{
type: theType,
children: bottomBlock[0].children.slice(
1,
bottomBlock[0].children.length,
),
},
];

console.log('newUpBlock', newUpBlock);
console.log('newBottomBlock', newBottomBlock);

replaceAllContentInEditorWith(editor, newUpBlock);
createAndSelectNewBlockAfter(newBottomBlock);
}
} else {
/**
* If end, insert a list item after and select it
*/
Transforms.insertNodes(
editor,
{
type: typeLi,
children: [{ type: typeP, children: [{ text: '' }] }],
},
{ at: nextListItemPath },
);
Transforms.select(editor, nextListItemPath);
}
}

/**
Expand All @@ -231,21 +319,31 @@ const withList = ({
return;
}
}
} else if (editor.selection && isRangeAtRoot(editor.selection)) {
const paragraphEntry = Editor.parent(editor, editor.selection);

if (paragraphEntry) {
// const [paragraphNode, paragraphPath] = paragraphEntry;
const [upBlock, bottomBlock] = splitEditorInTwoFragments(editor);
replaceAllContentInEditorWith(editor, upBlock);
createAndSelectNewBlockAfter(bottomBlock);
}
return;
}

insertBreak();
};

const onResetListType = () => {
unwrapNodesByType(editor, typeLi, { split: true });
unwrapNodesByType(editor, [typeUl, typeOl], { split: true });
};
// const onResetListType = () => {
// unwrapNodesByType(editor, typeLi, { split: true });
// unwrapNodesByType(editor, [typeUl, typeOl], { split: true });
// };

editor = withResetBlockType({
types: [typeLi],
defaultType: typeP,
onUnwrap: onResetListType,
})(editor);
// editor = withResetBlockType({
// types: [typeLi],
// defaultType: typeP,
// onUnwrap: onResetListType,
// })(editor);

return editor;
};
Expand Down
4 changes: 3 additions & 1 deletion src/TextBlock/keyDownHandlers/listsKeyDownHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export const onKeyDownList = ({
[ListHotkey.ENTER, ListHotkey.DELETE_BACKWARD].includes(e.key) &&
isBlockTextEmpty(paragraphNode);

if (shiftTab || deleteOnEmptyBlock) {
if (!isFirstChild(listItemPath) && (shiftTab || deleteOnEmptyBlock)) {
const moved = moveUp(editor, listNode, listPath, listItemPath, options);
if (moved) e.preventDefault();
}
Expand All @@ -205,3 +205,5 @@ export const onKeyDownList = ({
}
}
};

export default onKeyDownList;
41 changes: 39 additions & 2 deletions src/editor/components/BlockButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSlate } from 'slate-react';
import { isBlockActive, toggleBlock } from '../utils';
import Button from './Button';

import { Editor, Transforms } from 'slate';
import { Editor, Transforms, Node, Text, Range } from 'slate';
import { castArray } from 'lodash';

// TODO: put all these functions into an utils.js file
Expand All @@ -20,6 +20,7 @@ const unwrapNodesByType = (editor, types, options = {}) => {

const unwrapList = (
editor,
willWrapAgain,
{
typeUl = 'bulleted-list',
typeOl = 'numbered-list',
Expand All @@ -28,6 +29,41 @@ const unwrapList = (
) => {
unwrapNodesByType(editor, typeLi);
unwrapNodesByType(editor, [typeUl, typeOl], { split: true });

if (!willWrapAgain) {
let output = [];
let count = 0;
let children = Node.children(editor, []);
for (let [node, path] of children) {
// node is a paragraph
if (count === 0) {
output = output.concat(...node.children);
} else {
output = output.concat({ text: ' ' }, ...node.children);
}
++count;
}
if (count === 0) {
output.push({ text: '' });
}

Editor.withoutNormalizing(editor, () => {
for (let i = 0; i < count; ++i) {
Transforms.removeNodes(editor, [0]);
}
// console.log('output', JSON.stringify(output, null, 2));
Transforms.insertNodes(editor, [{ type: 'paragraph', children: output }]);
});

// Transforms.mergeNodes(editor, {
// at: {
// anchor: Editor.start(editor, []),
// focus: Editor.end(editor, []),
// },
// });

// console.log('editor.children', JSON.stringify(editor.children, null, 2));
}
};

/**
Expand Down Expand Up @@ -66,8 +102,9 @@ const toggleList = (
},
) => {
const isActive = isNodeInSelection(editor, typeList);
const willWrapAgain = !isActive;

unwrapList(editor, { typeUl, typeOl, typeLi });
unwrapList(editor, willWrapAgain, { typeUl, typeOl, typeLi });

Transforms.setNodes(editor, {
type: typeP,
Expand Down

0 comments on commit 5547066

Please sign in to comment.