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

108 строки
3.2 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. const React = require("react");
  13. const UserAgent = require("fbjs/lib/UserAgent");
  14. const invariant = require("fbjs/lib/invariant");
  15. const isElement = require("./isElement"); // In IE, spans with <br> tags render as two newlines. By rendering a span
  16. // with only a newline character, we can be sure to render a single line.
  17. const useNewlineChar = UserAgent.isBrowser('IE <= 11');
  18. /**
  19. * Check whether the node should be considered a newline.
  20. */
  21. function isNewline(node: Element): boolean {
  22. return useNewlineChar ? node.textContent === '\n' : node.tagName === 'BR';
  23. }
  24. /**
  25. * Placeholder elements for empty text content.
  26. *
  27. * What is this `data-text` attribute, anyway? It turns out that we need to
  28. * put an attribute on the lowest-level text node in order to preserve correct
  29. * spellcheck handling. If the <span> is naked, Chrome and Safari may do
  30. * bizarre things to do the DOM -- split text nodes, create extra spans, etc.
  31. * If the <span> has an attribute, this appears not to happen.
  32. * See http://jsfiddle.net/9khdavod/ for the failure case, and
  33. * http://jsfiddle.net/7pg143f7/ for the fixed case.
  34. */
  35. const NEWLINE_A = ref => useNewlineChar ? <span key="A" data-text="true" ref={ref}>
  36. {'\n'}
  37. </span> : <br key="A" data-text="true" ref={ref} />;
  38. const NEWLINE_B = ref => useNewlineChar ? <span key="B" data-text="true" ref={ref}>
  39. {'\n'}
  40. </span> : <br key="B" data-text="true" ref={ref} />;
  41. type Props = {
  42. children: string,
  43. ...
  44. };
  45. /**
  46. * The lowest-level component in a `DraftEditor`, the text node component
  47. * replaces the default React text node implementation. This allows us to
  48. * perform custom handling of newline behavior and avoid re-rendering text
  49. * nodes with DOM state that already matches the expectations of our immutable
  50. * editor state.
  51. */
  52. class DraftEditorTextNode extends React.Component<Props> {
  53. _forceFlag: boolean;
  54. _node: ?(HTMLSpanElement | HTMLBRElement);
  55. constructor(props: Props) {
  56. super(props); // By flipping this flag, we also keep flipping keys which forces
  57. // React to remount this node every time it rerenders.
  58. this._forceFlag = false;
  59. }
  60. shouldComponentUpdate(nextProps: Props): boolean {
  61. const node = this._node;
  62. const shouldBeNewline = nextProps.children === '';
  63. invariant(isElement(node), 'node is not an Element');
  64. const elementNode: Element = (node: any);
  65. if (shouldBeNewline) {
  66. return !isNewline(elementNode);
  67. }
  68. return elementNode.textContent !== nextProps.children;
  69. }
  70. componentDidMount(): void {
  71. this._forceFlag = !this._forceFlag;
  72. }
  73. componentDidUpdate(): void {
  74. this._forceFlag = !this._forceFlag;
  75. }
  76. render(): React.Node {
  77. if (this.props.children === '') {
  78. return this._forceFlag ? NEWLINE_A(ref => this._node = ref) : NEWLINE_B(ref => this._node = ref);
  79. }
  80. return <span key={this._forceFlag ? 'A' : 'B'} data-text="true" ref={ref => this._node = ref}>
  81. {this.props.children}
  82. </span>;
  83. }
  84. }
  85. module.exports = DraftEditorTextNode;