Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

128 строки
4.0 KiB

  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. * @emails oncall+draft_js
  10. */
  11. 'use strict';
  12. import type { BlockNodeRecord } from "./BlockNodeRecord";
  13. import type ContentState from "./ContentState";
  14. import type { EntityMap } from "./EntityMap";
  15. import type SelectionState from "./SelectionState";
  16. import type { List } from "immutable";
  17. const CharacterMetadata = require("./CharacterMetadata");
  18. const findRangesImmutable = require("./findRangesImmutable");
  19. const invariant = require("fbjs/lib/invariant");
  20. function removeEntitiesAtEdges(contentState: ContentState, selectionState: SelectionState): ContentState {
  21. const blockMap = contentState.getBlockMap();
  22. const entityMap = contentState.getEntityMap();
  23. const updatedBlocks = {};
  24. const startKey = selectionState.getStartKey();
  25. const startOffset = selectionState.getStartOffset();
  26. const startBlock = blockMap.get(startKey);
  27. const updatedStart = removeForBlock(entityMap, startBlock, startOffset);
  28. if (updatedStart !== startBlock) {
  29. updatedBlocks[startKey] = updatedStart;
  30. }
  31. const endKey = selectionState.getEndKey();
  32. const endOffset = selectionState.getEndOffset();
  33. let endBlock = blockMap.get(endKey);
  34. if (startKey === endKey) {
  35. endBlock = updatedStart;
  36. }
  37. const updatedEnd = removeForBlock(entityMap, endBlock, endOffset);
  38. if (updatedEnd !== endBlock) {
  39. updatedBlocks[endKey] = updatedEnd;
  40. }
  41. if (!Object.keys(updatedBlocks).length) {
  42. return contentState.set('selectionAfter', selectionState);
  43. }
  44. return contentState.merge({
  45. blockMap: blockMap.merge(updatedBlocks),
  46. selectionAfter: selectionState
  47. });
  48. }
  49. /**
  50. * Given a list of characters and an offset that is in the middle of an entity,
  51. * returns the start and end of the entity that is overlapping the offset.
  52. * Note: This method requires that the offset be in an entity range.
  53. */
  54. function getRemovalRange(characters: List<CharacterMetadata>, entityKey: ?string, offset: number): {
  55. start: number,
  56. end: number,
  57. ...
  58. } {
  59. let removalRange; // Iterates through a list looking for ranges of matching items
  60. // based on the 'isEqual' callback.
  61. // Then instead of returning the result, call the 'found' callback
  62. // with each range.
  63. // Then filters those ranges based on the 'filter' callback
  64. //
  65. // Here we use it to find ranges of characters with the same entity key.
  66. findRangesImmutable(characters, // the list to iterate through
  67. (a, b) => a.getEntity() === b.getEntity(), // 'isEqual' callback
  68. element => element.getEntity() === entityKey, // 'filter' callback
  69. (start: number, end: number) => {
  70. // 'found' callback
  71. if (start <= offset && end >= offset) {
  72. // this entity overlaps the offset index
  73. removalRange = {
  74. start,
  75. end
  76. };
  77. }
  78. });
  79. invariant(typeof removalRange === 'object', 'Removal range must exist within character list.');
  80. return removalRange;
  81. }
  82. function removeForBlock(entityMap: EntityMap, block: BlockNodeRecord, offset: number): BlockNodeRecord {
  83. let chars = block.getCharacterList();
  84. const charBefore = offset > 0 ? chars.get(offset - 1) : undefined;
  85. const charAfter = offset < chars.count() ? chars.get(offset) : undefined;
  86. const entityBeforeCursor = charBefore ? charBefore.getEntity() : undefined;
  87. const entityAfterCursor = charAfter ? charAfter.getEntity() : undefined;
  88. if (entityAfterCursor && entityAfterCursor === entityBeforeCursor) {
  89. const entity = entityMap.__get(entityAfterCursor);
  90. if (entity.getMutability() !== 'MUTABLE') {
  91. let {
  92. start,
  93. end
  94. } = getRemovalRange(chars, entityAfterCursor, offset);
  95. let current;
  96. while (start < end) {
  97. current = chars.get(start);
  98. chars = chars.set(start, CharacterMetadata.applyEntity(current, null));
  99. start++;
  100. }
  101. return block.set('characterList', chars);
  102. }
  103. }
  104. return block;
  105. }
  106. module.exports = removeEntitiesAtEdges;