Draft.js: How to insert new block before atomic

3.9k views Asked by At

I would like to add new line after block. My current function is next:

   _insert_new_block(editorState) {
      const selection = editorState.getSelection();
      const newBlock = new ContentBlock({
         key: genKey(),
         type: 'unstyled',
         text: ' ',
         characterList: List()
      });
      const contentState = editorState.getCurrentContent();
      const new_block_map = contentState.getBlockMap().set(newBlock.key, newBlock);
      const newContentState = contentState.set('blockMap', new_block_map);
      const new_contentState = contentState.merge({
        blockMap: new_block_map,
        selectionBefore: selection.merge({
          anchorKey: newBlock.key,
          anchorOffset: 0,
          focusKey: newBlock.key,
          focusOffset: 0,
          isBackward: false
        }),
        selectionAfter: selection
      });
      return EditorState.push(
         editorState,
         new_contentState,
         'insert-fragment'
      );
   }

New block is inserted in the end of my content but i get this error when i click on newly create block -

getUpdatedSelectionState.js:38 Uncaught TypeError: Cannot read property 'get' of undefined

and a file where error is located

'use strict';

var DraftOffsetKey = __webpack_require__(331);

var nullthrows = __webpack_require__(305);

function getUpdatedSelectionState(editorState, anchorKey, anchorOffset, focusKey, focusOffset) {
  var selection = nullthrows(editorState.getSelection());
  if (process.env.NODE_ENV !== 'production') {
    if (!anchorKey || !focusKey) {
      /*eslint-disable no-console */
      console.warn('Invalid selection state.', arguments, editorState.toJS());
      /*eslint-enable no-console */
      return selection;
    }
  }

  var anchorPath = DraftOffsetKey.decode(anchorKey);
  var anchorBlockKey = anchorPath.blockKey;
  var anchorLeaf = editorState.getBlockTree(anchorBlockKey).getIn([anchorPath.decoratorKey, 'leaves', anchorPath.leafKey]);

  var focusPath = DraftOffsetKey.decode(focusKey);
  var focusBlockKey = focusPath.blockKey;
  var focusLeaf = editorState.getBlockTree(focusBlockKey).getIn([focusPath.decoratorKey, 'leaves', focusPath.leafKey]);

  var anchorLeafStart = anchorLeaf.get('start');
  var focusLeafStart = focusLeaf.get('start');

  var anchorBlockOffset = anchorLeaf ? anchorLeafStart + anchorOffset : null;
  var focusBlockOffset = focusLeaf ? focusLeafStart + focusOffset : null;

  var areEqual = selection.getAnchorKey() === anchorBlockKey && selection.getAnchorOffset() === anchorBlockOffset && selection.getFocusKey() === focusBlockKey && selection.getFocusOffset() === focusBlockOffset;

  if (areEqual) {
    return selection;
  }

  var isBackward = false;
  if (anchorBlockKey === focusBlockKey) {
    var anchorLeafEnd = anchorLeaf.get('end');
    var focusLeafEnd = focusLeaf.get('end');
    if (focusLeafStart === anchorLeafStart && focusLeafEnd === anchorLeafEnd) {
      isBackward = focusOffset < anchorOffset;
    } else {
      isBackward = focusLeafStart < anchorLeafStart;
    }
  } else {
    var startKey = editorState.getCurrentContent().getBlockMap().keySeq().skipUntil(function (v) {
      return v === anchorBlockKey || v === focusBlockKey;
    }).first();
    isBackward = startKey === focusBlockKey;
  }

  return selection.merge({
    anchorKey: anchorBlockKey,
    anchorOffset: anchorBlockOffset,
    focusKey: focusBlockKey,
    focusOffset: focusBlockOffset,
    isBackward: isBackward
  });
}

module.exports = getUpdatedSelectionState;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))

what can cause this error and how to properly perform insertion?

1

There are 1 answers

0
Pavel Poberezhnyi On BEST ANSWER

Here is a function for inserting new block

export default (direction, editorState) => {
    const selection = editorState.getSelection();
    const contentState = editorState.getCurrentContent();
    const currentBlock = contentState.getBlockForKey(selection.getEndKey());

   const blockMap = contentState.getBlockMap()
   // Split the blocks
   const blocksBefore = blockMap.toSeq().takeUntil(function (v) {
      return v === currentBlock
   })
   const blocksAfter = blockMap.toSeq().skipUntil(function (v) {
      return v === currentBlock
   }).rest()
   const newBlockKey = genKey()
   let newBlocks = direction === 'before' ? [
      [newBlockKey, new ContentBlock({
         key: newBlockKey,
         type: 'unstyled',
         text: '',
         characterList: List(),
      })],
      [currentBlock.getKey(), currentBlock],
   ] : [
      [currentBlock.getKey(), currentBlock],
      [newBlockKey, new ContentBlock({
         key: newBlockKey,
         type: 'unstyled',
         text: '',
         characterList: List(),
      })],
   ];
   const newBlockMap = blocksBefore.concat(newBlocks, blocksAfter).toOrderedMap()
   const newContentState = contentState.merge({
      blockMap: newBlockMap,
      selectionBefore: selection,
      selectionAfter: selection,
   })
   return EditorState.push(editorState, newContentState, 'insert-fragment');
}

and in any place you can use this function like that

var editorState = insert_block('before', editorState);