From 94d0db3ea75b6b8c8e71d6540187029d6e0c189e Mon Sep 17 00:00:00 2001 From: Rose Robertson Date: Fri, 17 Feb 2017 14:57:02 -0800 Subject: [PATCH] Add ability to escape blocks after a double return The original functionality remains, but a new option, of `doubleBreakoutBlocks` has been added that won't break out until the user has hit return out of a blank line. --- README.md | 1 + lib/index.js | 131 ++++++++++++++++++++++++++------------------------- src/index.js | 33 +++++++++---- 3 files changed, 92 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index b42fcea..2199a4b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ The options and their defaults are: | --- | --- | --- | --- | | `breakoutBlockType` | `String` | Block type to insert when breaking out | `'unstyled'` | `breakoutBlocks` | `Array` | List of block types to break out from | `['header-one', 'header-two', 'header-three', 'header-four', 'header-five', 'header-six']` +| `doubleBreakoutBlocks` | `Array` | List of block types to that require return on a blank line in order to break | `['blockquote', 'unordered-list-item', 'ordered-list-item', 'code-block']` ## Developing diff --git a/lib/index.js b/lib/index.js index ff72f84..a9b914d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,9 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; - exports.default = blockBreakoutPlugin; var _draftJs = require('draft-js'); @@ -18,7 +15,8 @@ var _immutable = require('immutable'); */ var defaults = { breakoutBlockType: 'unstyled', - breakoutBlocks: ['header-one', 'header-two', 'header-three', 'header-four', 'header-five', 'header-six'] + breakoutBlocks: ['header-one', 'header-two', 'header-three', 'header-four', 'header-five', 'header-six'], + doubleBreakoutBlocks: ['blockquote', 'unordered-list-item', 'ordered-list-item', 'code-block'] }; /** @@ -37,87 +35,90 @@ var defaults = { * @return {Object} Object defining the draft-js API methods */ function blockBreakoutPlugin() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var breakoutBlockType = options.breakoutBlockType || defaults.breakoutBlockType; var breakoutBlocks = options.breakoutBlocks || defaults.breakoutBlocks; + var doubleBreakoutBlocks = options.doubleBreakoutBlocks || defaults.doubleBreakoutBlocks; return { handleReturn: function handleReturn(e, _ref) { - var getEditorState = _ref.getEditorState; - var setEditorState = _ref.setEditorState; + var getEditorState = _ref.getEditorState, + setEditorState = _ref.setEditorState; var editorState = getEditorState(); var currentBlockType = _draftJs.RichUtils.getCurrentBlockType(editorState); + var isSingleBreakoutBlock = breakoutBlocks.indexOf(currentBlockType) > -1; + var isDoubleBreakoutBlock = doubleBreakoutBlocks.indexOf(currentBlockType) > -1; // Does the current block type match a type we care about? - if (breakoutBlocks.indexOf(currentBlockType) > -1) { + if (isSingleBreakoutBlock || isDoubleBreakoutBlock) { var selection = editorState.getSelection(); // Check if the selection is collapsed if (selection.isCollapsed()) { - var _ret = function () { - var contentState = editorState.getCurrentContent(); - var currentBlock = contentState.getBlockForKey(selection.getEndKey()); - var endOffset = selection.getEndOffset(); - var atEndOfBlock = endOffset === currentBlock.getLength(); - var atStartOfBlock = endOffset === 0; - - // Check we’re at the start/end of the current block - if (atEndOfBlock || atStartOfBlock) { - var emptyBlockKey = (0, _draftJs.genKey)(); - var emptyBlock = new _draftJs.ContentBlock({ - key: emptyBlockKey, - text: '', - type: breakoutBlockType, - characterList: (0, _immutable.List)(), - depth: 0 - }); - var blockMap = contentState.getBlockMap(); - // Split the blocks - var blocksBefore = blockMap.toSeq().takeUntil(function (v) { - return v === currentBlock; - }); - var blocksAfter = blockMap.toSeq().skipUntil(function (v) { - return v === currentBlock; - }).rest(); - - var augmentedBlocks = void 0; - var focusKey = void 0; - // Choose which order to apply the augmented blocks in depending - // on whether we’re at the start or the end - if (atEndOfBlock) { + var contentState = editorState.getCurrentContent(); + var currentBlock = contentState.getBlockForKey(selection.getEndKey()); + var endOffset = selection.getEndOffset(); + var atEndOfBlock = endOffset === currentBlock.getLength(); + var atStartOfBlock = endOffset === 0; + + // Check we’re at the start/end of the current block + if (atEndOfBlock && isSingleBreakoutBlock || atStartOfBlock) { + var emptyBlockKey = (0, _draftJs.genKey)(); + var emptyBlock = new _draftJs.ContentBlock({ + key: emptyBlockKey, + text: '', + type: breakoutBlockType, + characterList: (0, _immutable.List)(), + depth: 0 + }); + var blockMap = contentState.getBlockMap(); + // Split the blocks + var blocksBefore = blockMap.toSeq().takeUntil(function (v) { + return v === currentBlock; + }); + + var blocksAfter = blockMap.toSeq().skipUntil(function (v) { + return v === currentBlock; + }).rest(); + + var augmentedBlocks = void 0; + var focusKey = void 0; + // Choose which order to apply the augmented blocks in depending + // on whether we’re at the start or the end + if (atEndOfBlock) { + if (isDoubleBreakoutBlock) { + // Discard Current as it was blank + augmentedBlocks = [[emptyBlockKey, emptyBlock]]; + } else { // Current first, empty block afterwards augmentedBlocks = [[currentBlock.getKey(), currentBlock], [emptyBlockKey, emptyBlock]]; - focusKey = emptyBlockKey; - } else { - // Empty first, current block afterwards - augmentedBlocks = [[emptyBlockKey, emptyBlock], [currentBlock.getKey(), currentBlock]]; - focusKey = currentBlock.getKey(); } - // Join back together with the current + new block - var newBlocks = blocksBefore.concat(augmentedBlocks, blocksAfter).toOrderedMap(); - var newContentState = contentState.merge({ - blockMap: newBlocks, - selectionBefore: selection, - selectionAfter: selection.merge({ - anchorKey: focusKey, - anchorOffset: 0, - focusKey: focusKey, - focusOffset: 0, - isBackward: false - }) - }); - // Set the state - setEditorState(_draftJs.EditorState.push(editorState, newContentState, 'split-block')); - return { - v: 'handled' - }; + focusKey = emptyBlockKey; + } else { + // Empty first, current block afterwards + augmentedBlocks = [[emptyBlockKey, emptyBlock], [currentBlock.getKey(), currentBlock]]; + focusKey = currentBlock.getKey(); } - }(); - - if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; + // Join back together with the current + new block + var newBlocks = blocksBefore.concat(augmentedBlocks, blocksAfter).toOrderedMap(); + var newContentState = contentState.merge({ + blockMap: newBlocks, + selectionBefore: selection, + selectionAfter: selection.merge({ + anchorKey: focusKey, + anchorOffset: 0, + focusKey: focusKey, + focusOffset: 0, + isBackward: false + }) + }); + // Set the state + setEditorState(_draftJs.EditorState.push(editorState, newContentState, 'split-block')); + return 'handled'; + } } } return 'not-handled'; diff --git a/src/index.js b/src/index.js index 8b533a0..c348e8c 100644 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,13 @@ const defaults = { 'header-four', 'header-five', 'header-six', - ] + ], + doubleBreakoutBlocks: [ + 'blockquote', + 'unordered-list-item', + 'ordered-list-item', + 'code-block', + ], } /** @@ -41,14 +47,17 @@ export default function blockBreakoutPlugin (options = {}) { const breakoutBlockType = options.breakoutBlockType || defaults.breakoutBlockType const breakoutBlocks = options.breakoutBlocks || defaults.breakoutBlocks + const doubleBreakoutBlocks = options.doubleBreakoutBlocks || defaults.doubleBreakoutBlocks return { handleReturn (e, { getEditorState, setEditorState }) { const editorState = getEditorState() const currentBlockType = RichUtils.getCurrentBlockType(editorState) + const isSingleBreakoutBlock = breakoutBlocks.indexOf(currentBlockType) > -1 + const isDoubleBreakoutBlock = doubleBreakoutBlocks.indexOf(currentBlockType) > -1 // Does the current block type match a type we care about? - if (breakoutBlocks.indexOf(currentBlockType) > -1) { + if (isSingleBreakoutBlock || isDoubleBreakoutBlock) { const selection = editorState.getSelection() // Check if the selection is collapsed @@ -60,7 +69,7 @@ export default function blockBreakoutPlugin (options = {}) { const atStartOfBlock = (endOffset === 0) // Check we’re at the start/end of the current block - if (atEndOfBlock || atStartOfBlock) { + if ((atEndOfBlock && isSingleBreakoutBlock) || atStartOfBlock) { const emptyBlockKey = genKey() const emptyBlock = new ContentBlock({ key: emptyBlockKey, @@ -74,6 +83,7 @@ export default function blockBreakoutPlugin (options = {}) { const blocksBefore = blockMap.toSeq().takeUntil(function (v) { return v === currentBlock }) + const blocksAfter = blockMap.toSeq().skipUntil(function (v) { return v === currentBlock }).rest() @@ -83,11 +93,18 @@ export default function blockBreakoutPlugin (options = {}) { // Choose which order to apply the augmented blocks in depending // on whether we’re at the start or the end if (atEndOfBlock) { - // Current first, empty block afterwards - augmentedBlocks = [ - [currentBlock.getKey(), currentBlock], - [emptyBlockKey, emptyBlock], - ] + if (isDoubleBreakoutBlock) { + // Discard Current as it was blank + augmentedBlocks = [ + [emptyBlockKey, emptyBlock], + ] + } else { + // Current first, empty block afterwards + augmentedBlocks = [ + [currentBlock.getKey(), currentBlock], + [emptyBlockKey, emptyBlock], + ] + } focusKey = emptyBlockKey } else { // Empty first, current block afterwards