mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
react app
This commit is contained in:
506
react-app/node_modules/react/lib/ReactDOMComponent.js
generated
vendored
Normal file
506
react-app/node_modules/react/lib/ReactDOMComponent.js
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
/**
|
||||
* 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 ReactDOMComponent
|
||||
* @typechecks static-only
|
||||
*/
|
||||
|
||||
/* global hasOwnProperty:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var CSSPropertyOperations = require("./CSSPropertyOperations");
|
||||
var DOMProperty = require("./DOMProperty");
|
||||
var DOMPropertyOperations = require("./DOMPropertyOperations");
|
||||
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
|
||||
var ReactComponentBrowserEnvironment =
|
||||
require("./ReactComponentBrowserEnvironment");
|
||||
var ReactMount = require("./ReactMount");
|
||||
var ReactMultiChild = require("./ReactMultiChild");
|
||||
var ReactPerf = require("./ReactPerf");
|
||||
|
||||
var assign = require("./Object.assign");
|
||||
var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
|
||||
var invariant = require("./invariant");
|
||||
var isEventSupported = require("./isEventSupported");
|
||||
var keyOf = require("./keyOf");
|
||||
var warning = require("./warning");
|
||||
|
||||
var deleteListener = ReactBrowserEventEmitter.deleteListener;
|
||||
var listenTo = ReactBrowserEventEmitter.listenTo;
|
||||
var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
|
||||
|
||||
// For quickly matching children type, to test if can be treated as content.
|
||||
var CONTENT_TYPES = {'string': true, 'number': true};
|
||||
|
||||
var STYLE = keyOf({style: null});
|
||||
|
||||
var ELEMENT_NODE_TYPE = 1;
|
||||
|
||||
/**
|
||||
* Optionally injectable operations for mutating the DOM
|
||||
*/
|
||||
var BackendIDOperations = null;
|
||||
|
||||
/**
|
||||
* @param {?object} props
|
||||
*/
|
||||
function assertValidProps(props) {
|
||||
if (!props) {
|
||||
return;
|
||||
}
|
||||
// Note the use of `==` which checks for null or undefined.
|
||||
if (props.dangerouslySetInnerHTML != null) {
|
||||
("production" !== process.env.NODE_ENV ? invariant(
|
||||
props.children == null,
|
||||
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
|
||||
) : invariant(props.children == null));
|
||||
("production" !== process.env.NODE_ENV ? invariant(
|
||||
typeof props.dangerouslySetInnerHTML === 'object' &&
|
||||
'__html' in props.dangerouslySetInnerHTML,
|
||||
'`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
|
||||
'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
|
||||
'for more information.'
|
||||
) : invariant(typeof props.dangerouslySetInnerHTML === 'object' &&
|
||||
'__html' in props.dangerouslySetInnerHTML));
|
||||
}
|
||||
if ("production" !== process.env.NODE_ENV) {
|
||||
("production" !== process.env.NODE_ENV ? warning(
|
||||
props.innerHTML == null,
|
||||
'Directly setting property `innerHTML` is not permitted. ' +
|
||||
'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
|
||||
) : null);
|
||||
("production" !== process.env.NODE_ENV ? warning(
|
||||
!props.contentEditable || props.children == null,
|
||||
'A component is `contentEditable` and contains `children` managed by ' +
|
||||
'React. It is now your responsibility to guarantee that none of ' +
|
||||
'those nodes are unexpectedly modified or duplicated. This is ' +
|
||||
'probably not intentional.'
|
||||
) : null);
|
||||
}
|
||||
("production" !== process.env.NODE_ENV ? invariant(
|
||||
props.style == null || typeof props.style === 'object',
|
||||
'The `style` prop expects a mapping from style properties to values, ' +
|
||||
'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
|
||||
'using JSX.'
|
||||
) : invariant(props.style == null || typeof props.style === 'object'));
|
||||
}
|
||||
|
||||
function putListener(id, registrationName, listener, transaction) {
|
||||
if ("production" !== process.env.NODE_ENV) {
|
||||
// IE8 has no API for event capturing and the `onScroll` event doesn't
|
||||
// bubble.
|
||||
("production" !== process.env.NODE_ENV ? warning(
|
||||
registrationName !== 'onScroll' || isEventSupported('scroll', true),
|
||||
'This browser doesn\'t support the `onScroll` event'
|
||||
) : null);
|
||||
}
|
||||
var container = ReactMount.findReactContainerForID(id);
|
||||
if (container) {
|
||||
var doc = container.nodeType === ELEMENT_NODE_TYPE ?
|
||||
container.ownerDocument :
|
||||
container;
|
||||
listenTo(registrationName, doc);
|
||||
}
|
||||
transaction.getPutListenerQueue().enqueuePutListener(
|
||||
id,
|
||||
registrationName,
|
||||
listener
|
||||
);
|
||||
}
|
||||
|
||||
// For HTML, certain tags should omit their close tag. We keep a whitelist for
|
||||
// those special cased tags.
|
||||
|
||||
var omittedCloseTags = {
|
||||
'area': true,
|
||||
'base': true,
|
||||
'br': true,
|
||||
'col': true,
|
||||
'embed': true,
|
||||
'hr': true,
|
||||
'img': true,
|
||||
'input': true,
|
||||
'keygen': true,
|
||||
'link': true,
|
||||
'meta': true,
|
||||
'param': true,
|
||||
'source': true,
|
||||
'track': true,
|
||||
'wbr': true
|
||||
// NOTE: menuitem's close tag should be omitted, but that causes problems.
|
||||
};
|
||||
|
||||
// We accept any tag to be rendered but since this gets injected into abitrary
|
||||
// HTML, we want to make sure that it's a safe tag.
|
||||
// http://www.w3.org/TR/REC-xml/#NT-Name
|
||||
|
||||
var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
|
||||
var validatedTagCache = {};
|
||||
var hasOwnProperty = {}.hasOwnProperty;
|
||||
|
||||
function validateDangerousTag(tag) {
|
||||
if (!hasOwnProperty.call(validatedTagCache, tag)) {
|
||||
("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
|
||||
validatedTagCache[tag] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new React class that is idempotent and capable of containing other
|
||||
* React components. It accepts event listeners and DOM properties that are
|
||||
* valid according to `DOMProperty`.
|
||||
*
|
||||
* - Event listeners: `onClick`, `onMouseDown`, etc.
|
||||
* - DOM properties: `className`, `name`, `title`, etc.
|
||||
*
|
||||
* The `style` property functions differently from the DOM API. It accepts an
|
||||
* object mapping of style properties to values.
|
||||
*
|
||||
* @constructor ReactDOMComponent
|
||||
* @extends ReactMultiChild
|
||||
*/
|
||||
function ReactDOMComponent(tag) {
|
||||
validateDangerousTag(tag);
|
||||
this._tag = tag;
|
||||
this._renderedChildren = null;
|
||||
this._previousStyleCopy = null;
|
||||
this._rootNodeID = null;
|
||||
}
|
||||
|
||||
ReactDOMComponent.displayName = 'ReactDOMComponent';
|
||||
|
||||
ReactDOMComponent.Mixin = {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates root tag markup then recurses. This method has side effects and
|
||||
* is not idempotent.
|
||||
*
|
||||
* @internal
|
||||
* @param {string} rootID The root DOM ID for this node.
|
||||
* @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
|
||||
* @return {string} The computed markup.
|
||||
*/
|
||||
mountComponent: function(rootID, transaction, context) {
|
||||
this._rootNodeID = rootID;
|
||||
assertValidProps(this._currentElement.props);
|
||||
var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
|
||||
return (
|
||||
this._createOpenTagMarkupAndPutListeners(transaction) +
|
||||
this._createContentMarkup(transaction, context) +
|
||||
closeTag
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates markup for the open tag and all attributes.
|
||||
*
|
||||
* This method has side effects because events get registered.
|
||||
*
|
||||
* Iterating over object properties is faster than iterating over arrays.
|
||||
* @see http://jsperf.com/obj-vs-arr-iteration
|
||||
*
|
||||
* @private
|
||||
* @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
|
||||
* @return {string} Markup of opening tag.
|
||||
*/
|
||||
_createOpenTagMarkupAndPutListeners: function(transaction) {
|
||||
var props = this._currentElement.props;
|
||||
var ret = '<' + this._tag;
|
||||
|
||||
for (var propKey in props) {
|
||||
if (!props.hasOwnProperty(propKey)) {
|
||||
continue;
|
||||
}
|
||||
var propValue = props[propKey];
|
||||
if (propValue == null) {
|
||||
continue;
|
||||
}
|
||||
if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
putListener(this._rootNodeID, propKey, propValue, transaction);
|
||||
} else {
|
||||
if (propKey === STYLE) {
|
||||
if (propValue) {
|
||||
propValue = this._previousStyleCopy = assign({}, props.style);
|
||||
}
|
||||
propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
|
||||
}
|
||||
var markup =
|
||||
DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
|
||||
if (markup) {
|
||||
ret += ' ' + markup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For static pages, no need to put React ID and checksum. Saves lots of
|
||||
// bytes.
|
||||
if (transaction.renderToStaticMarkup) {
|
||||
return ret + '>';
|
||||
}
|
||||
|
||||
var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
|
||||
return ret + ' ' + markupForID + '>';
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates markup for the content between the tags.
|
||||
*
|
||||
* @private
|
||||
* @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
|
||||
* @param {object} context
|
||||
* @return {string} Content markup.
|
||||
*/
|
||||
_createContentMarkup: function(transaction, context) {
|
||||
var prefix = '';
|
||||
if (this._tag === 'listing' ||
|
||||
this._tag === 'pre' ||
|
||||
this._tag === 'textarea') {
|
||||
// Add an initial newline because browsers ignore the first newline in
|
||||
// a <listing>, <pre>, or <textarea> as an "authoring convenience" -- see
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody.
|
||||
prefix = '\n';
|
||||
}
|
||||
|
||||
var props = this._currentElement.props;
|
||||
|
||||
// Intentional use of != to avoid catching zero/false.
|
||||
var innerHTML = props.dangerouslySetInnerHTML;
|
||||
if (innerHTML != null) {
|
||||
if (innerHTML.__html != null) {
|
||||
return prefix + innerHTML.__html;
|
||||
}
|
||||
} else {
|
||||
var contentToUse =
|
||||
CONTENT_TYPES[typeof props.children] ? props.children : null;
|
||||
var childrenToUse = contentToUse != null ? null : props.children;
|
||||
if (contentToUse != null) {
|
||||
return prefix + escapeTextContentForBrowser(contentToUse);
|
||||
} else if (childrenToUse != null) {
|
||||
var mountImages = this.mountChildren(
|
||||
childrenToUse,
|
||||
transaction,
|
||||
context
|
||||
);
|
||||
return prefix + mountImages.join('');
|
||||
}
|
||||
}
|
||||
return prefix;
|
||||
},
|
||||
|
||||
receiveComponent: function(nextElement, transaction, context) {
|
||||
var prevElement = this._currentElement;
|
||||
this._currentElement = nextElement;
|
||||
this.updateComponent(transaction, prevElement, nextElement, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates a native DOM component after it has already been allocated and
|
||||
* attached to the DOM. Reconciles the root DOM node, then recurses.
|
||||
*
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
* @param {ReactElement} prevElement
|
||||
* @param {ReactElement} nextElement
|
||||
* @internal
|
||||
* @overridable
|
||||
*/
|
||||
updateComponent: function(transaction, prevElement, nextElement, context) {
|
||||
assertValidProps(this._currentElement.props);
|
||||
this._updateDOMProperties(prevElement.props, transaction);
|
||||
this._updateDOMChildren(prevElement.props, transaction, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reconciles the properties by detecting differences in property values and
|
||||
* updating the DOM as necessary. This function is probably the single most
|
||||
* critical path for performance optimization.
|
||||
*
|
||||
* TODO: Benchmark whether checking for changed values in memory actually
|
||||
* improves performance (especially statically positioned elements).
|
||||
* TODO: Benchmark the effects of putting this at the top since 99% of props
|
||||
* do not change for a given reconciliation.
|
||||
* TODO: Benchmark areas that can be improved with caching.
|
||||
*
|
||||
* @private
|
||||
* @param {object} lastProps
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
*/
|
||||
_updateDOMProperties: function(lastProps, transaction) {
|
||||
var nextProps = this._currentElement.props;
|
||||
var propKey;
|
||||
var styleName;
|
||||
var styleUpdates;
|
||||
for (propKey in lastProps) {
|
||||
if (nextProps.hasOwnProperty(propKey) ||
|
||||
!lastProps.hasOwnProperty(propKey)) {
|
||||
continue;
|
||||
}
|
||||
if (propKey === STYLE) {
|
||||
var lastStyle = this._previousStyleCopy;
|
||||
for (styleName in lastStyle) {
|
||||
if (lastStyle.hasOwnProperty(styleName)) {
|
||||
styleUpdates = styleUpdates || {};
|
||||
styleUpdates[styleName] = '';
|
||||
}
|
||||
}
|
||||
this._previousStyleCopy = null;
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
deleteListener(this._rootNodeID, propKey);
|
||||
} else if (
|
||||
DOMProperty.isStandardName[propKey] ||
|
||||
DOMProperty.isCustomAttribute(propKey)) {
|
||||
BackendIDOperations.deletePropertyByID(
|
||||
this._rootNodeID,
|
||||
propKey
|
||||
);
|
||||
}
|
||||
}
|
||||
for (propKey in nextProps) {
|
||||
var nextProp = nextProps[propKey];
|
||||
var lastProp = propKey === STYLE ?
|
||||
this._previousStyleCopy :
|
||||
lastProps[propKey];
|
||||
if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
|
||||
continue;
|
||||
}
|
||||
if (propKey === STYLE) {
|
||||
if (nextProp) {
|
||||
nextProp = this._previousStyleCopy = assign({}, nextProp);
|
||||
} else {
|
||||
this._previousStyleCopy = null;
|
||||
}
|
||||
if (lastProp) {
|
||||
// Unset styles on `lastProp` but not on `nextProp`.
|
||||
for (styleName in lastProp) {
|
||||
if (lastProp.hasOwnProperty(styleName) &&
|
||||
(!nextProp || !nextProp.hasOwnProperty(styleName))) {
|
||||
styleUpdates = styleUpdates || {};
|
||||
styleUpdates[styleName] = '';
|
||||
}
|
||||
}
|
||||
// Update styles that changed since `lastProp`.
|
||||
for (styleName in nextProp) {
|
||||
if (nextProp.hasOwnProperty(styleName) &&
|
||||
lastProp[styleName] !== nextProp[styleName]) {
|
||||
styleUpdates = styleUpdates || {};
|
||||
styleUpdates[styleName] = nextProp[styleName];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Relies on `updateStylesByID` not mutating `styleUpdates`.
|
||||
styleUpdates = nextProp;
|
||||
}
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
putListener(this._rootNodeID, propKey, nextProp, transaction);
|
||||
} else if (
|
||||
DOMProperty.isStandardName[propKey] ||
|
||||
DOMProperty.isCustomAttribute(propKey)) {
|
||||
BackendIDOperations.updatePropertyByID(
|
||||
this._rootNodeID,
|
||||
propKey,
|
||||
nextProp
|
||||
);
|
||||
}
|
||||
}
|
||||
if (styleUpdates) {
|
||||
BackendIDOperations.updateStylesByID(
|
||||
this._rootNodeID,
|
||||
styleUpdates
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reconciles the children with the various properties that affect the
|
||||
* children content.
|
||||
*
|
||||
* @param {object} lastProps
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
*/
|
||||
_updateDOMChildren: function(lastProps, transaction, context) {
|
||||
var nextProps = this._currentElement.props;
|
||||
|
||||
var lastContent =
|
||||
CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
|
||||
var nextContent =
|
||||
CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
|
||||
|
||||
var lastHtml =
|
||||
lastProps.dangerouslySetInnerHTML &&
|
||||
lastProps.dangerouslySetInnerHTML.__html;
|
||||
var nextHtml =
|
||||
nextProps.dangerouslySetInnerHTML &&
|
||||
nextProps.dangerouslySetInnerHTML.__html;
|
||||
|
||||
// Note the use of `!=` which checks for null or undefined.
|
||||
var lastChildren = lastContent != null ? null : lastProps.children;
|
||||
var nextChildren = nextContent != null ? null : nextProps.children;
|
||||
|
||||
// If we're switching from children to content/html or vice versa, remove
|
||||
// the old content
|
||||
var lastHasContentOrHtml = lastContent != null || lastHtml != null;
|
||||
var nextHasContentOrHtml = nextContent != null || nextHtml != null;
|
||||
if (lastChildren != null && nextChildren == null) {
|
||||
this.updateChildren(null, transaction, context);
|
||||
} else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
|
||||
this.updateTextContent('');
|
||||
}
|
||||
|
||||
if (nextContent != null) {
|
||||
if (lastContent !== nextContent) {
|
||||
this.updateTextContent('' + nextContent);
|
||||
}
|
||||
} else if (nextHtml != null) {
|
||||
if (lastHtml !== nextHtml) {
|
||||
BackendIDOperations.updateInnerHTMLByID(
|
||||
this._rootNodeID,
|
||||
nextHtml
|
||||
);
|
||||
}
|
||||
} else if (nextChildren != null) {
|
||||
this.updateChildren(nextChildren, transaction, context);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys all event registrations for this instance. Does not remove from
|
||||
* the DOM. That must be done by the parent.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
unmountComponent: function() {
|
||||
this.unmountChildren();
|
||||
ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
|
||||
ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
|
||||
this._rootNodeID = null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
|
||||
mountComponent: 'mountComponent',
|
||||
updateComponent: 'updateComponent'
|
||||
});
|
||||
|
||||
assign(
|
||||
ReactDOMComponent.prototype,
|
||||
ReactDOMComponent.Mixin,
|
||||
ReactMultiChild.Mixin
|
||||
);
|
||||
|
||||
ReactDOMComponent.injection = {
|
||||
injectIDOperations: function(IDOperations) {
|
||||
ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ReactDOMComponent;
|
Reference in New Issue
Block a user