forked from Gitlink/forgeplus-react
115 lines
4.5 KiB
JavaScript
115 lines
4.5 KiB
JavaScript
|
|
/**
|
||
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
||
|
|
* All rights reserved.
|
||
|
|
*
|
||
|
|
* This source code is licensed under the BSD-style license found in the
|
||
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
|
*
|
||
|
|
* @providesModule DraftEditorTextNode.react
|
||
|
|
* @format
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||
|
|
|
||
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||
|
|
|
||
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||
|
|
|
||
|
|
var React = require('react');
|
||
|
|
var ReactDOM = require('react-dom');
|
||
|
|
var UserAgent = require('fbjs/lib/UserAgent');
|
||
|
|
|
||
|
|
var invariant = require('fbjs/lib/invariant');
|
||
|
|
|
||
|
|
// In IE, spans with <br> tags render as two newlines. By rendering a span
|
||
|
|
// with only a newline character, we can be sure to render a single line.
|
||
|
|
var useNewlineChar = UserAgent.isBrowser('IE <= 11');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check whether the node should be considered a newline.
|
||
|
|
*/
|
||
|
|
function isNewline(node) {
|
||
|
|
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 <span> is naked, Chrome and Safari may do
|
||
|
|
* bizarre things to do the DOM -- split text nodes, create extra spans, etc.
|
||
|
|
* If the <span> 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.
|
||
|
|
*/
|
||
|
|
var NEWLINE_A = useNewlineChar ? React.createElement(
|
||
|
|
'span',
|
||
|
|
{ key: 'A', 'data-text': 'true' },
|
||
|
|
'\n'
|
||
|
|
) : React.createElement('br', { key: 'A', 'data-text': 'true' });
|
||
|
|
|
||
|
|
var NEWLINE_B = useNewlineChar ? React.createElement(
|
||
|
|
'span',
|
||
|
|
{ key: 'B', 'data-text': 'true' },
|
||
|
|
'\n'
|
||
|
|
) : React.createElement('br', { key: 'B', 'data-text': 'true' });
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 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.
|
||
|
|
*/
|
||
|
|
var DraftEditorTextNode = function (_React$Component) {
|
||
|
|
_inherits(DraftEditorTextNode, _React$Component);
|
||
|
|
|
||
|
|
function DraftEditorTextNode(props) {
|
||
|
|
_classCallCheck(this, DraftEditorTextNode);
|
||
|
|
|
||
|
|
// By flipping this flag, we also keep flipping keys which forces
|
||
|
|
// React to remount this node every time it rerenders.
|
||
|
|
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
|
||
|
|
|
||
|
|
_this._forceFlag = false;
|
||
|
|
return _this;
|
||
|
|
}
|
||
|
|
|
||
|
|
DraftEditorTextNode.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
|
||
|
|
var node = ReactDOM.findDOMNode(this);
|
||
|
|
var shouldBeNewline = nextProps.children === '';
|
||
|
|
!(node instanceof Element) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'node is not an Element') : invariant(false) : void 0;
|
||
|
|
if (shouldBeNewline) {
|
||
|
|
return !isNewline(node);
|
||
|
|
}
|
||
|
|
return node.textContent !== nextProps.children;
|
||
|
|
};
|
||
|
|
|
||
|
|
DraftEditorTextNode.prototype.componentDidMount = function componentDidMount() {
|
||
|
|
this._forceFlag = !this._forceFlag;
|
||
|
|
};
|
||
|
|
|
||
|
|
DraftEditorTextNode.prototype.componentDidUpdate = function componentDidUpdate() {
|
||
|
|
this._forceFlag = !this._forceFlag;
|
||
|
|
};
|
||
|
|
|
||
|
|
DraftEditorTextNode.prototype.render = function render() {
|
||
|
|
if (this.props.children === '') {
|
||
|
|
return this._forceFlag ? NEWLINE_A : NEWLINE_B;
|
||
|
|
}
|
||
|
|
return React.createElement(
|
||
|
|
'span',
|
||
|
|
{ key: this._forceFlag ? 'A' : 'B', 'data-text': 'true' },
|
||
|
|
this.props.children
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
return DraftEditorTextNode;
|
||
|
|
}(React.Component);
|
||
|
|
|
||
|
|
module.exports = DraftEditorTextNode;
|