You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

removeEntitiesAtEdges.js 3.7 KiB

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