/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @flow * @emails oncall+draft_js */ 'use strict'; const React = require("react"); const UserAgent = require("fbjs/lib/UserAgent"); const invariant = require("fbjs/lib/invariant"); const isElement = require("./isElement"); // In IE, spans with
tags render as two newlines. By rendering a span // with only a newline character, we can be sure to render a single line. const useNewlineChar = UserAgent.isBrowser('IE <= 11'); /** * Check whether the node should be considered a newline. */ function isNewline(node: Element): boolean { return useNewlineChar ? node.textContent === '\n' : node.tagName === 'BR'; } /** * Placeholder elements for empty text content. * * What is this `data-text` attribute, anyway? It turns out that we need to * put an attribute on the lowest-level text node in order to preserve correct * spellcheck handling. If the is naked, Chrome and Safari may do * bizarre things to do the DOM -- split text nodes, create extra spans, etc. * If the has an attribute, this appears not to happen. * See http://jsfiddle.net/9khdavod/ for the failure case, and * http://jsfiddle.net/7pg143f7/ for the fixed case. */ const NEWLINE_A = ref => useNewlineChar ? {'\n'} :
; const NEWLINE_B = ref => useNewlineChar ? {'\n'} :
; type Props = { children: string, ... }; /** * The lowest-level component in a `DraftEditor`, the text node component * replaces the default React text node implementation. This allows us to * perform custom handling of newline behavior and avoid re-rendering text * nodes with DOM state that already matches the expectations of our immutable * editor state. */ class DraftEditorTextNode extends React.Component { _forceFlag: boolean; _node: ?(HTMLSpanElement | HTMLBRElement); constructor(props: Props) { super(props); // By flipping this flag, we also keep flipping keys which forces // React to remount this node every time it rerenders. this._forceFlag = false; } shouldComponentUpdate(nextProps: Props): boolean { const node = this._node; const shouldBeNewline = nextProps.children === ''; invariant(isElement(node), 'node is not an Element'); const elementNode: Element = (node: any); if (shouldBeNewline) { return !isNewline(elementNode); } return elementNode.textContent !== nextProps.children; } componentDidMount(): void { this._forceFlag = !this._forceFlag; } componentDidUpdate(): void { this._forceFlag = !this._forceFlag; } render(): React.Node { if (this.props.children === '') { return this._forceFlag ? NEWLINE_A(ref => this._node = ref) : NEWLINE_B(ref => this._node = ref); } return this._node = ref}> {this.props.children} ; } } module.exports = DraftEditorTextNode;