/** * Copyright 2013-2015, 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 ReactDOMTextComponent * @typechecks static-only */ 'use strict'; var DOMChildrenOperations = require('DOMChildrenOperations'); var DOMLazyTree = require('DOMLazyTree'); var DOMPropertyOperations = require('DOMPropertyOperations'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactPerf = require('ReactPerf'); var assign = require('Object.assign'); var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); var validateDOMNesting = require('validateDOMNesting'); var getNode = ReactDOMComponentTree.getNodeFromInstance; /** * Text nodes violate a couple assumptions that React makes about components: * * - When mounting text into the DOM, adjacent text nodes are merged. * - Text nodes cannot be assigned a React root ID. * * This component is used to wrap strings in elements so that they can undergo * the same reconciliation that is applied to elements. * * TODO: Investigate representing React components in the DOM with text nodes. * * @class ReactDOMTextComponent * @extends ReactComponent * @internal */ var ReactDOMTextComponent = function(props) { // This constructor and its argument is currently used by mocks. }; assign(ReactDOMTextComponent.prototype, { /** * @param {ReactText} text * @internal */ construct: function(text) { // TODO: This is really a ReactText (ReactNode), not a ReactElement this._currentElement = text; this._stringText = '' + text; this._nativeNode = null; // ReactDOMComponentTree uses this: this._nativeParent = null; // Properties this._domID = null; this._mountIndex = 0; }, /** * Creates the markup for this text node. This node is not intended to have * any features besides containing text content. * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction * @return {string} Markup for this text node. * @internal */ mountComponent: function( rootID, transaction, nativeParent, nativeContainerInfo, context ) { if (__DEV__) { var parentInfo; if (nativeParent != null) { parentInfo = nativeParent._ancestorInfo; } else if (nativeContainerInfo != null) { parentInfo = nativeContainerInfo._ancestorInfo; } if (parentInfo) { // parentInfo should always be present except for the top-level // component when server rendering validateDOMNesting('span', this, parentInfo); } } var domID = nativeContainerInfo._idCounter++; this._domID = domID; this._nativeParent = nativeParent; if (transaction.useCreateElement) { var ownerDocument = nativeContainerInfo._ownerDocument; var el = ownerDocument.createElement('span'); ReactDOMComponentTree.precacheNode(this, el); DOMPropertyOperations.setAttributeForID(el, domID); var lazyTree = DOMLazyTree(el); DOMLazyTree.queueText(lazyTree, this._stringText); return lazyTree; } else { var escapedText = escapeTextContentForBrowser(this._stringText); if (transaction.renderToStaticMarkup) { // Normally we'd wrap this in a `span` for the reasons stated above, but // since this is a situation where React won't take over (static pages), // we can simply return the text as it is. return escapedText; } return ( '' + escapedText + '' ); } }, /** * Updates this component by updating the text content. * * @param {ReactText} nextText The next text content * @param {ReactReconcileTransaction} transaction * @internal */ receiveComponent: function(nextText, transaction) { if (nextText !== this._currentElement) { this._currentElement = nextText; var nextStringText = '' + nextText; if (nextStringText !== this._stringText) { // TODO: Save this as pending props and use performUpdateIfNecessary // and/or updateComponent to do the actual update for consistency with // other component types? this._stringText = nextStringText; DOMChildrenOperations.updateTextContent(getNode(this), nextStringText); } } }, getNativeNode: function() { return getNode(this); }, unmountComponent: function() { ReactDOMComponentTree.uncacheNode(this); }, }); ReactPerf.measureMethods( ReactDOMTextComponent.prototype, 'ReactDOMTextComponent', { mountComponent: 'mountComponent', receiveComponent: 'receiveComponent', } ); module.exports = ReactDOMTextComponent;