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.
 
 
 
 

199 rivejä
5.5 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 { BlockMap } from "./BlockMap";
  13. import type { BlockNodeRecord } from "./BlockNodeRecord";
  14. import type DraftEntityInstance from "./DraftEntityInstance";
  15. import type { DraftEntityMutability } from "./DraftEntityMutability";
  16. import type { DraftEntityType } from "./DraftEntityType";
  17. const BlockMapBuilder = require("./BlockMapBuilder");
  18. const CharacterMetadata = require("./CharacterMetadata");
  19. const ContentBlock = require("./ContentBlock");
  20. const ContentBlockNode = require("./ContentBlockNode");
  21. const DraftEntity = require("./DraftEntity");
  22. const SelectionState = require("./SelectionState");
  23. const generateRandomKey = require("./generateRandomKey");
  24. const gkx = require("./gkx");
  25. const Immutable = require("immutable");
  26. const sanitizeDraftText = require("./sanitizeDraftText");
  27. const {
  28. List,
  29. Record,
  30. Repeat
  31. } = Immutable;
  32. const defaultRecord: {
  33. entityMap: ?any,
  34. blockMap: ?BlockMap,
  35. selectionBefore: ?SelectionState,
  36. selectionAfter: ?SelectionState,
  37. ...
  38. } = {
  39. entityMap: null,
  40. blockMap: null,
  41. selectionBefore: null,
  42. selectionAfter: null
  43. };
  44. const ContentStateRecord = (Record(defaultRecord): any);
  45. class ContentState extends ContentStateRecord {
  46. getEntityMap(): any {
  47. // TODO: update this when we fully remove DraftEntity
  48. return DraftEntity;
  49. }
  50. getBlockMap(): BlockMap {
  51. return this.get('blockMap');
  52. }
  53. getSelectionBefore(): SelectionState {
  54. return this.get('selectionBefore');
  55. }
  56. getSelectionAfter(): SelectionState {
  57. return this.get('selectionAfter');
  58. }
  59. getBlockForKey(key: string): BlockNodeRecord {
  60. const block: BlockNodeRecord = this.getBlockMap().get(key);
  61. return block;
  62. }
  63. getKeyBefore(key: string): ?string {
  64. return this.getBlockMap().reverse().keySeq().skipUntil(v => v === key).skip(1).first();
  65. }
  66. getKeyAfter(key: string): ?string {
  67. return this.getBlockMap().keySeq().skipUntil(v => v === key).skip(1).first();
  68. }
  69. getBlockAfter(key: string): ?BlockNodeRecord {
  70. return this.getBlockMap().skipUntil((_, k) => k === key).skip(1).first();
  71. }
  72. getBlockBefore(key: string): ?BlockNodeRecord {
  73. return this.getBlockMap().reverse().skipUntil((_, k) => k === key).skip(1).first();
  74. }
  75. getBlocksAsArray(): Array<BlockNodeRecord> {
  76. return this.getBlockMap().toArray();
  77. }
  78. getFirstBlock(): BlockNodeRecord {
  79. return this.getBlockMap().first();
  80. }
  81. getLastBlock(): BlockNodeRecord {
  82. return this.getBlockMap().last();
  83. }
  84. getPlainText(delimiter?: string): string {
  85. return this.getBlockMap().map(block => {
  86. return block ? block.getText() : '';
  87. }).join(delimiter || '\n');
  88. }
  89. getLastCreatedEntityKey(): string {
  90. // TODO: update this when we fully remove DraftEntity
  91. return DraftEntity.__getLastCreatedEntityKey();
  92. }
  93. hasText(): boolean {
  94. const blockMap = this.getBlockMap();
  95. return blockMap.size > 1 || // make sure that there are no zero width space chars
  96. escape(blockMap.first().getText()).replace(/%u200B/g, '').length > 0;
  97. }
  98. createEntity(type: DraftEntityType, mutability: DraftEntityMutability, data?: Object): ContentState {
  99. // TODO: update this when we fully remove DraftEntity
  100. DraftEntity.__create(type, mutability, data);
  101. return this;
  102. }
  103. mergeEntityData(key: string, toMerge: {
  104. [key: string]: any,
  105. ...
  106. }): ContentState {
  107. // TODO: update this when we fully remove DraftEntity
  108. DraftEntity.__mergeData(key, toMerge);
  109. return this;
  110. }
  111. replaceEntityData(key: string, newData: {
  112. [key: string]: any,
  113. ...
  114. }): ContentState {
  115. // TODO: update this when we fully remove DraftEntity
  116. DraftEntity.__replaceData(key, newData);
  117. return this;
  118. }
  119. addEntity(instance: DraftEntityInstance): ContentState {
  120. // TODO: update this when we fully remove DraftEntity
  121. DraftEntity.__add(instance);
  122. return this;
  123. }
  124. getEntity(key: string): DraftEntityInstance {
  125. // TODO: update this when we fully remove DraftEntity
  126. return DraftEntity.__get(key);
  127. }
  128. static createFromBlockArray( // TODO: update flow type when we completely deprecate the old entity API
  129. blocks: Array<BlockNodeRecord> | {
  130. contentBlocks: Array<BlockNodeRecord>,
  131. ...
  132. }, entityMap: ?any): ContentState {
  133. // TODO: remove this when we completely deprecate the old entity API
  134. const theBlocks = Array.isArray(blocks) ? blocks : blocks.contentBlocks;
  135. const blockMap = BlockMapBuilder.createFromArray(theBlocks);
  136. const selectionState = blockMap.isEmpty() ? new SelectionState() : SelectionState.createEmpty(blockMap.first().getKey());
  137. return new ContentState({
  138. blockMap,
  139. entityMap: entityMap || DraftEntity,
  140. selectionBefore: selectionState,
  141. selectionAfter: selectionState
  142. });
  143. }
  144. static createFromText(text: string, delimiter: string | RegExp = /\r\n?|\n/g): ContentState {
  145. const strings = text.split(delimiter);
  146. const blocks = strings.map(block => {
  147. block = sanitizeDraftText(block);
  148. const ContentBlockNodeRecord = gkx('draft_tree_data_support') ? ContentBlockNode : ContentBlock;
  149. return new ContentBlockNodeRecord({
  150. key: generateRandomKey(),
  151. text: block,
  152. type: 'unstyled',
  153. characterList: List(Repeat(CharacterMetadata.EMPTY, block.length))
  154. });
  155. });
  156. return ContentState.createFromBlockArray(blocks);
  157. }
  158. }
  159. module.exports = ContentState;