draft-js
Version:
A React framework for building text editors.
122 lines (100 loc) • 3.82 kB
JavaScript
/**
* 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
*/
;
var CharacterMetadata = require("./CharacterMetadata");
var findRangesImmutable = require("./findRangesImmutable");
var invariant = require("fbjs/lib/invariant");
function removeEntitiesAtEdges(contentState, selectionState) {
var blockMap = contentState.getBlockMap();
var entityMap = contentState.getEntityMap();
var updatedBlocks = {};
var startKey = selectionState.getStartKey();
var startOffset = selectionState.getStartOffset();
var startBlock = blockMap.get(startKey);
var updatedStart = removeForBlock(entityMap, startBlock, startOffset);
if (updatedStart !== startBlock) {
updatedBlocks[startKey] = updatedStart;
}
var endKey = selectionState.getEndKey();
var endOffset = selectionState.getEndOffset();
var endBlock = blockMap.get(endKey);
if (startKey === endKey) {
endBlock = updatedStart;
}
var updatedEnd = removeForBlock(entityMap, endBlock, endOffset);
if (updatedEnd !== endBlock) {
updatedBlocks[endKey] = updatedEnd;
}
if (!Object.keys(updatedBlocks).length) {
return contentState.set('selectionAfter', selectionState);
}
return contentState.merge({
blockMap: blockMap.merge(updatedBlocks),
selectionAfter: selectionState
});
}
/**
* Given a list of characters and an offset that is in the middle of an entity,
* returns the start and end of the entity that is overlapping the offset.
* Note: This method requires that the offset be in an entity range.
*/
function getRemovalRange(characters, entityKey, offset) {
var removalRange; // Iterates through a list looking for ranges of matching items
// based on the 'isEqual' callback.
// Then instead of returning the result, call the 'found' callback
// with each range.
// Then filters those ranges based on the 'filter' callback
//
// Here we use it to find ranges of characters with the same entity key.
findRangesImmutable(characters, // the list to iterate through
function (a, b) {
return a.getEntity() === b.getEntity();
}, // 'isEqual' callback
function (element) {
return element.getEntity() === entityKey;
}, // 'filter' callback
function (start, end) {
// 'found' callback
if (start <= offset && end >= offset) {
// this entity overlaps the offset index
removalRange = {
start: start,
end: end
};
}
});
!(typeof removalRange === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Removal range must exist within character list.') : invariant(false) : void 0;
return removalRange;
}
function removeForBlock(entityMap, block, offset) {
var chars = block.getCharacterList();
var charBefore = offset > 0 ? chars.get(offset - 1) : undefined;
var charAfter = offset < chars.count() ? chars.get(offset) : undefined;
var entityBeforeCursor = charBefore ? charBefore.getEntity() : undefined;
var entityAfterCursor = charAfter ? charAfter.getEntity() : undefined;
if (entityAfterCursor && entityAfterCursor === entityBeforeCursor) {
var entity = entityMap.__get(entityAfterCursor);
if (entity.getMutability() !== 'MUTABLE') {
var _getRemovalRange = getRemovalRange(chars, entityAfterCursor, offset),
start = _getRemovalRange.start,
end = _getRemovalRange.end;
var current;
while (start < end) {
current = chars.get(start);
chars = chars.set(start, CharacterMetadata.applyEntity(current, null));
start++;
}
return block.set('characterList', chars);
}
}
return block;
}
module.exports = removeEntitiesAtEdges;