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

DraftEditorContentsExperimental.react.js.flow 6.0 KiB

3 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. * This file is a fork of DraftEditorContents.react.js for tree nodes
  12. *
  13. * This is unstable and not part of the public API and should not be used by
  14. * production systems. This file may be update/removed without notice.
  15. */
  16. 'use strict';
  17. import type { BlockNodeRecord } from "./BlockNodeRecord";
  18. import type { DraftBlockRenderMap } from "./DraftBlockRenderMap";
  19. import type { DraftInlineStyle } from "./DraftInlineStyle";
  20. import type EditorState from "./EditorState";
  21. import type { BidiDirection } from "fbjs/lib/UnicodeBidiDirection";
  22. const DraftEditorBlockNode = require("./DraftEditorBlockNode.react");
  23. const DraftOffsetKey = require("./DraftOffsetKey");
  24. const React = require("react");
  25. const nullthrows = require("fbjs/lib/nullthrows");
  26. type Props = {
  27. blockRenderMap: DraftBlockRenderMap,
  28. blockRendererFn: (block: BlockNodeRecord) => ?Object,
  29. blockStyleFn?: (block: BlockNodeRecord) => string,
  30. customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,
  31. customStyleMap?: Object,
  32. editorKey?: string,
  33. editorState: EditorState,
  34. textDirectionality?: BidiDirection,
  35. ...
  36. };
  37. /**
  38. * `DraftEditorContents` is the container component for all block components
  39. * rendered for a `DraftEditor`. It is optimized to aggressively avoid
  40. * re-rendering blocks whenever possible.
  41. *
  42. * This component is separate from `DraftEditor` because certain props
  43. * (for instance, ARIA props) must be allowed to update without affecting
  44. * the contents of the editor.
  45. */
  46. class DraftEditorContentsExperimental extends React.Component<Props> {
  47. shouldComponentUpdate(nextProps: Props): boolean {
  48. const prevEditorState = this.props.editorState;
  49. const nextEditorState = nextProps.editorState;
  50. const prevDirectionMap = prevEditorState.getDirectionMap();
  51. const nextDirectionMap = nextEditorState.getDirectionMap(); // Text direction has changed for one or more blocks. We must re-render.
  52. if (prevDirectionMap !== nextDirectionMap) {
  53. return true;
  54. }
  55. const didHaveFocus = prevEditorState.getSelection().getHasFocus();
  56. const nowHasFocus = nextEditorState.getSelection().getHasFocus();
  57. if (didHaveFocus !== nowHasFocus) {
  58. return true;
  59. }
  60. const nextNativeContent = nextEditorState.getNativelyRenderedContent();
  61. const wasComposing = prevEditorState.isInCompositionMode();
  62. const nowComposing = nextEditorState.isInCompositionMode(); // If the state is unchanged or we're currently rendering a natively
  63. // rendered state, there's nothing new to be done.
  64. if (prevEditorState === nextEditorState || nextNativeContent !== null && nextEditorState.getCurrentContent() === nextNativeContent || wasComposing && nowComposing) {
  65. return false;
  66. }
  67. const prevContent = prevEditorState.getCurrentContent();
  68. const nextContent = nextEditorState.getCurrentContent();
  69. const prevDecorator = prevEditorState.getDecorator();
  70. const nextDecorator = nextEditorState.getDecorator();
  71. return wasComposing !== nowComposing || prevContent !== nextContent || prevDecorator !== nextDecorator || nextEditorState.mustForceSelection();
  72. }
  73. render(): React.Node {
  74. const {
  75. blockRenderMap,
  76. blockRendererFn,
  77. blockStyleFn,
  78. customStyleMap,
  79. customStyleFn,
  80. editorState,
  81. editorKey,
  82. textDirectionality
  83. } = this.props;
  84. const content = editorState.getCurrentContent();
  85. const selection = editorState.getSelection();
  86. const forceSelection = editorState.mustForceSelection();
  87. const decorator = editorState.getDecorator();
  88. const directionMap = nullthrows(editorState.getDirectionMap());
  89. const blocksAsArray = content.getBlocksAsArray();
  90. const rootBlock = blocksAsArray[0];
  91. const processedBlocks = [];
  92. let nodeBlock = rootBlock;
  93. while (nodeBlock) {
  94. const blockKey = nodeBlock.getKey();
  95. const blockProps = {
  96. blockRenderMap,
  97. blockRendererFn,
  98. blockStyleFn,
  99. contentState: content,
  100. customStyleFn,
  101. customStyleMap,
  102. decorator,
  103. editorKey,
  104. editorState,
  105. forceSelection,
  106. selection,
  107. block: nodeBlock,
  108. direction: textDirectionality ? textDirectionality : directionMap.get(blockKey),
  109. tree: editorState.getBlockTree(blockKey)
  110. };
  111. const configForType = blockRenderMap.get(nodeBlock.getType()) || blockRenderMap.get('unstyled');
  112. const wrapperTemplate = configForType.wrapper;
  113. processedBlocks.push({
  114. /* $FlowFixMe(>=0.112.0 site=www,mobile) This comment suppresses an
  115. * error found when Flow v0.112 was deployed. To see the error delete
  116. * this comment and run Flow. */
  117. block: <DraftEditorBlockNode key={blockKey} {...blockProps} />,
  118. wrapperTemplate,
  119. key: blockKey,
  120. offsetKey: DraftOffsetKey.encode(blockKey, 0, 0)
  121. });
  122. const nextBlockKey = nodeBlock.getNextSiblingKey();
  123. nodeBlock = nextBlockKey ? content.getBlockForKey(nextBlockKey) : null;
  124. } // Group contiguous runs of blocks that have the same wrapperTemplate
  125. const outputBlocks = [];
  126. for (let ii = 0; ii < processedBlocks.length;) {
  127. const info: any = processedBlocks[ii];
  128. if (info.wrapperTemplate) {
  129. const blocks = [];
  130. do {
  131. blocks.push(processedBlocks[ii].block);
  132. ii++;
  133. } while (ii < processedBlocks.length && processedBlocks[ii].wrapperTemplate === info.wrapperTemplate);
  134. const wrapperElement = React.cloneElement(info.wrapperTemplate, {
  135. key: info.key + '-wrap',
  136. 'data-offset-key': info.offsetKey
  137. }, blocks);
  138. outputBlocks.push(wrapperElement);
  139. } else {
  140. outputBlocks.push(info.block);
  141. ii++;
  142. }
  143. }
  144. return <div data-contents="true">{outputBlocks}</div>;
  145. }
  146. }
  147. module.exports = DraftEditorContentsExperimental;