mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
165 lines
4.9 KiB
JavaScript
165 lines
4.9 KiB
JavaScript
/**
|
|
* 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 (
|
|
'<span ' + DOMPropertyOperations.createMarkupForID(domID) + '>' +
|
|
escapedText +
|
|
'</span>'
|
|
);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 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;
|