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

118 строки
4.7 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 { DraftRemovalDirection } from "./DraftRemovalDirection";
  14. import type { EntityMap } from "./EntityMap";
  15. import type SelectionState from "./SelectionState";
  16. const DraftEntitySegments = require("./DraftEntitySegments");
  17. const getRangesForDraftEntity = require("./getRangesForDraftEntity");
  18. const invariant = require("fbjs/lib/invariant");
  19. /**
  20. * Given a SelectionState and a removal direction, determine the entire range
  21. * that should be removed from a ContentState. This is based on any entities
  22. * within the target, with their `mutability` values taken into account.
  23. *
  24. * For instance, if we are attempting to remove part of an "immutable" entity
  25. * range, the entire entity must be removed. The returned `SelectionState`
  26. * will be adjusted accordingly.
  27. */
  28. function getCharacterRemovalRange(entityMap: EntityMap, startBlock: BlockNodeRecord, endBlock: BlockNodeRecord, selectionState: SelectionState, direction: DraftRemovalDirection): SelectionState {
  29. const start = selectionState.getStartOffset();
  30. const end = selectionState.getEndOffset();
  31. const startEntityKey = startBlock.getEntityAt(start);
  32. const endEntityKey = endBlock.getEntityAt(end - 1);
  33. if (!startEntityKey && !endEntityKey) {
  34. return selectionState;
  35. }
  36. let newSelectionState = selectionState;
  37. if (startEntityKey && startEntityKey === endEntityKey) {
  38. newSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, true, true);
  39. } else if (startEntityKey && endEntityKey) {
  40. const startSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, false, true);
  41. const endSelectionState = getEntityRemovalRange(entityMap, endBlock, newSelectionState, direction, endEntityKey, false, false);
  42. newSelectionState = newSelectionState.merge({
  43. anchorOffset: startSelectionState.getAnchorOffset(),
  44. focusOffset: endSelectionState.getFocusOffset(),
  45. isBackward: false
  46. });
  47. } else if (startEntityKey) {
  48. const startSelectionState = getEntityRemovalRange(entityMap, startBlock, newSelectionState, direction, startEntityKey, false, true);
  49. newSelectionState = newSelectionState.merge({
  50. anchorOffset: startSelectionState.getStartOffset(),
  51. isBackward: false
  52. });
  53. } else if (endEntityKey) {
  54. const endSelectionState = getEntityRemovalRange(entityMap, endBlock, newSelectionState, direction, endEntityKey, false, false);
  55. newSelectionState = newSelectionState.merge({
  56. focusOffset: endSelectionState.getEndOffset(),
  57. isBackward: false
  58. });
  59. }
  60. return newSelectionState;
  61. }
  62. function getEntityRemovalRange(entityMap: EntityMap, block: BlockNodeRecord, selectionState: SelectionState, direction: DraftRemovalDirection, entityKey: string, isEntireSelectionWithinEntity: boolean, isEntityAtStart: boolean): SelectionState {
  63. let start = selectionState.getStartOffset();
  64. let end = selectionState.getEndOffset();
  65. const entity = entityMap.__get(entityKey);
  66. const mutability = entity.getMutability();
  67. const sideToConsider = isEntityAtStart ? start : end; // `MUTABLE` entities can just have the specified range of text removed
  68. // directly. No adjustments are needed.
  69. if (mutability === 'MUTABLE') {
  70. return selectionState;
  71. } // Find the entity range that overlaps with our removal range.
  72. const entityRanges = getRangesForDraftEntity(block, entityKey).filter(range => sideToConsider <= range.end && sideToConsider >= range.start);
  73. invariant(entityRanges.length == 1, 'There should only be one entity range within this removal range.');
  74. const entityRange = entityRanges[0]; // For `IMMUTABLE` entity types, we will remove the entire entity range.
  75. if (mutability === 'IMMUTABLE') {
  76. return selectionState.merge({
  77. anchorOffset: entityRange.start,
  78. focusOffset: entityRange.end,
  79. isBackward: false
  80. });
  81. } // For `SEGMENTED` entity types, determine the appropriate segment to
  82. // remove.
  83. if (!isEntireSelectionWithinEntity) {
  84. if (isEntityAtStart) {
  85. end = entityRange.end;
  86. } else {
  87. start = entityRange.start;
  88. }
  89. }
  90. const removalRange = DraftEntitySegments.getRemovalRange(start, end, block.getText().slice(entityRange.start, entityRange.end), entityRange.start, direction);
  91. return selectionState.merge({
  92. anchorOffset: removalRange.start,
  93. focusOffset: removalRange.end,
  94. isBackward: false
  95. });
  96. }
  97. module.exports = getCharacterRemovalRange;