/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * * @emails oncall+draft_js */ 'use strict'; var DraftEntitySegments = require("./DraftEntitySegments"); var getRangesForDraftEntity = require("./getRangesForDraftEntity"); var invariant = require("fbjs/lib/invariant"); /** * Given a SelectionState and a removal direction, determine the entire range * that should be removed from a ContentState. This is based on any entities * within the target, with their `mutability` values taken into account. * * For instance, if we are attempting to remove part of an "immutable" entity * range, the entire entity must be removed. The returned `SelectionState` * will be adjusted accordingly. */ function getCharacterRemovalRange(entityMap, startBlock, endBlock, selectionState, direction) { var start = selectionState.getStartOffset(); var end = selectionState.getEndOffset(); var startEntityKey = startBlock.getEntityAt(start); var endEntityKey = endBlock.getEntityAt(end - 1); if (!startEntityKey && !endEntityKey) { return selectionState; } var newSelectionState = selectionState; if (startEntityKey && startEntityKey === endEntityKey) { newSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, true, true); } else if (startEntityKey && endEntityKey) { var startSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, false, true); var endSelectionState = getEntityRemovalRange(entityMap, endBlock, newSelectionState, direction, endEntityKey, false, false); newSelectionState = newSelectionState.merge({ anchorOffset: startSelectionState.getAnchorOffset(), focusOffset: endSelectionState.getFocusOffset(), isBackward: false }); } else if (startEntityKey) { var _startSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, false, true); newSelectionState = newSelectionState.merge({ anchorOffset: _startSelectionState.getStartOffset(), isBackward: false }); } else if (endEntityKey) { var _endSelectionState = getEntityRemovalRange(entityMap, endBlock, newSelectionState, direction, endEntityKey, false, false); newSelectionState = newSelectionState.merge({ focusOffset: _endSelectionState.getEndOffset(), isBackward: false }); } return newSelectionState; } function getEntityRemovalRange(entityMap, block, selectionState, direction, entityKey, isEntireSelectionWithinEntity, isEntityAtStart) { var start = selectionState.getStartOffset(); var end = selectionState.getEndOffset(); var entity = entityMap.__get(entityKey); var mutability = entity.getMutability(); var sideToConsider = isEntityAtStart ? start : end; // `MUTABLE` entities can just have the specified range of text removed // directly. No adjustments are needed. if (mutability === 'MUTABLE') { return selectionState; } // Find the entity range that overlaps with our removal range. var entityRanges = getRangesForDraftEntity(block, entityKey).filter(function (range) { return sideToConsider <= range.end && sideToConsider >= range.start; }); !(entityRanges.length == 1) ? process.env.NODE_ENV !== "production" ? invariant(false, 'There should only be one entity range within this removal range.') : invariant(false) : void 0; var entityRange = entityRanges[0]; // For `IMMUTABLE` entity types, we will remove the entire entity range. if (mutability === 'IMMUTABLE') { return selectionState.merge({ anchorOffset: entityRange.start, focusOffset: entityRange.end, isBackward: false }); } // For `SEGMENTED` entity types, determine the appropriate segment to // remove. if (!isEntireSelectionWithinEntity) { if (isEntityAtStart) { end = entityRange.end; } else { start = entityRange.start; } } var removalRange = DraftEntitySegments.getRemovalRange(start, end, block.getText().slice(entityRange.start, entityRange.end), entityRange.start, direction); return selectionState.merge({ anchorOffset: removalRange.start, focusOffset: removalRange.end, isBackward: false }); } module.exports = getCharacterRemovalRange;