Skip to content

Commit

Permalink
Add ability to escape blocks after a double return
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Rose Robertson committed Feb 17, 2017
1 parent e8d0beb commit 94d0db3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 73 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
131 changes: 66 additions & 65 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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']
};

/**
Expand All @@ -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';
Expand Down
33 changes: 25 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ const defaults = {
'header-four',
'header-five',
'header-six',
]
],
doubleBreakoutBlocks: [
'blockquote',
'unordered-list-item',
'ordered-list-item',
'code-block',
],
}

/**
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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()
Expand All @@ -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
Expand Down

0 comments on commit 94d0db3

Please sign in to comment.