|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /**
- * 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
- * @flow
- * @emails oncall+draft_js
- */
- 'use strict';
-
- import type { BlockNodeRecord } from "./BlockNodeRecord";
- import type ContentState from "./ContentState";
- import type { EntityMap } from "./EntityMap";
- import type SelectionState from "./SelectionState";
- import type { List } from "immutable";
-
- const CharacterMetadata = require("./CharacterMetadata");
-
- const findRangesImmutable = require("./findRangesImmutable");
-
- const invariant = require("fbjs/lib/invariant");
-
- function removeEntitiesAtEdges(contentState: ContentState, selectionState: SelectionState): ContentState {
- const blockMap = contentState.getBlockMap();
- const entityMap = contentState.getEntityMap();
- const updatedBlocks = {};
- const startKey = selectionState.getStartKey();
- const startOffset = selectionState.getStartOffset();
- const startBlock = blockMap.get(startKey);
- const updatedStart = removeForBlock(entityMap, startBlock, startOffset);
-
- if (updatedStart !== startBlock) {
- updatedBlocks[startKey] = updatedStart;
- }
-
- const endKey = selectionState.getEndKey();
- const endOffset = selectionState.getEndOffset();
- let endBlock = blockMap.get(endKey);
-
- if (startKey === endKey) {
- endBlock = updatedStart;
- }
-
- const 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: List<CharacterMetadata>, entityKey: ?string, offset: number): {
- start: number,
- end: number,
- ...
- } {
- let 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
- (a, b) => a.getEntity() === b.getEntity(), // 'isEqual' callback
- element => element.getEntity() === entityKey, // 'filter' callback
- (start: number, end: number) => {
- // 'found' callback
- if (start <= offset && end >= offset) {
- // this entity overlaps the offset index
- removalRange = {
- start,
- end
- };
- }
- });
- invariant(typeof removalRange === 'object', 'Removal range must exist within character list.');
- return removalRange;
- }
-
- function removeForBlock(entityMap: EntityMap, block: BlockNodeRecord, offset: number): BlockNodeRecord {
- let chars = block.getCharacterList();
- const charBefore = offset > 0 ? chars.get(offset - 1) : undefined;
- const charAfter = offset < chars.count() ? chars.get(offset) : undefined;
- const entityBeforeCursor = charBefore ? charBefore.getEntity() : undefined;
- const entityAfterCursor = charAfter ? charAfter.getEntity() : undefined;
-
- if (entityAfterCursor && entityAfterCursor === entityBeforeCursor) {
- const entity = entityMap.__get(entityAfterCursor);
-
- if (entity.getMutability() !== 'MUTABLE') {
- let {
- start,
- end
- } = getRemovalRange(chars, entityAfterCursor, offset);
- let 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;
|