react 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -217
- package/ReactJSErrors.js +40 -0
- package/addons.js +4 -0
- package/lib/$.js +46 -0
- package/lib/CSSCore.js +114 -0
- package/lib/CSSProperty.js +90 -0
- package/lib/CSSPropertyOperations.js +97 -0
- package/lib/CallbackRegistry.js +91 -0
- package/lib/ChangeEventPlugin.js +365 -0
- package/lib/CompositionEventPlugin.js +212 -0
- package/lib/DOMChildrenOperations.js +135 -0
- package/lib/DOMProperty.js +266 -0
- package/lib/DOMPropertyOperations.js +168 -0
- package/lib/Danger.js +186 -0
- package/lib/DefaultDOMPropertyConfig.js +187 -0
- package/lib/DefaultEventPluginOrder.js +44 -0
- package/lib/EnterLeaveEventPlugin.js +112 -0
- package/lib/EventConstants.js +73 -0
- package/lib/EventListener.js +61 -0
- package/lib/EventPluginHub.js +190 -0
- package/lib/EventPluginRegistry.js +237 -0
- package/lib/EventPluginUtils.js +185 -0
- package/lib/EventPropagators.js +179 -0
- package/lib/ExecutionEnvironment.js +41 -0
- package/lib/LinkedStateMixin.js +46 -0
- package/lib/LinkedValueMixin.js +68 -0
- package/lib/MobileSafariClickEventPlugin.js +63 -0
- package/lib/PooledClass.js +113 -0
- package/lib/React.js +71 -0
- package/lib/ReactChildren.js +132 -0
- package/lib/ReactComponent.js +515 -0
- package/lib/ReactComponentBrowserEnvironment.js +140 -0
- package/lib/ReactComponentEnvironment.js +24 -0
- package/lib/ReactCompositeComponent.js +1020 -0
- package/lib/ReactCurrentOwner.js +39 -0
- package/lib/ReactDOM.js +194 -0
- package/lib/ReactDOMButton.js +64 -0
- package/lib/ReactDOMComponent.js +374 -0
- package/lib/ReactDOMForm.js +52 -0
- package/lib/ReactDOMIDOperations.js +173 -0
- package/lib/ReactDOMInput.js +169 -0
- package/lib/ReactDOMOption.js +50 -0
- package/lib/ReactDOMSelect.js +160 -0
- package/lib/ReactDOMSelection.js +189 -0
- package/lib/ReactDOMTextarea.js +136 -0
- package/lib/ReactDefaultBatchingStrategy.js +75 -0
- package/lib/ReactDefaultInjection.js +91 -0
- package/lib/ReactDefaultPerf.js +407 -0
- package/lib/ReactErrorUtils.js +46 -0
- package/lib/ReactEventEmitter.js +341 -0
- package/lib/ReactEventEmitterMixin.js +89 -0
- package/lib/ReactEventTopLevelCallback.js +89 -0
- package/lib/ReactInputSelection.js +140 -0
- package/lib/ReactInstanceHandles.js +322 -0
- package/lib/ReactLink.js +54 -0
- package/lib/ReactMarkupChecksum.js +53 -0
- package/lib/ReactMount.js +617 -0
- package/lib/ReactMountReady.js +95 -0
- package/lib/ReactMultiChild.js +441 -0
- package/lib/ReactMultiChildUpdateTypes.js +36 -0
- package/lib/ReactOwner.js +146 -0
- package/lib/ReactPerf.js +88 -0
- package/lib/ReactPropTransferer.js +128 -0
- package/lib/ReactPropTypes.js +158 -0
- package/lib/ReactReconcileTransaction.js +161 -0
- package/lib/ReactServerRendering.js +62 -0
- package/lib/ReactStateSetters.js +111 -0
- package/lib/ReactTextComponent.js +94 -0
- package/lib/ReactTransitionEvents.js +97 -0
- package/lib/ReactTransitionGroup.js +112 -0
- package/lib/ReactTransitionKeySet.js +111 -0
- package/lib/ReactTransitionableChild.js +152 -0
- package/lib/ReactUpdates.js +145 -0
- package/lib/ReactWithAddons.js +41 -0
- package/lib/SelectEventPlugin.js +217 -0
- package/lib/SimpleEventPlugin.js +365 -0
- package/lib/SyntheticClipboardEvent.js +45 -0
- package/lib/SyntheticCompositionEvent.js +51 -0
- package/lib/SyntheticEvent.js +163 -0
- package/lib/SyntheticFocusEvent.js +44 -0
- package/lib/SyntheticKeyboardEvent.js +56 -0
- package/lib/SyntheticMouseEvent.js +85 -0
- package/lib/SyntheticTouchEvent.js +50 -0
- package/lib/SyntheticUIEvent.js +45 -0
- package/lib/SyntheticWheelEvent.js +63 -0
- package/lib/Transaction.js +251 -0
- package/lib/ViewportMetrics.js +37 -0
- package/lib/accumulate.js +54 -0
- package/lib/adler32.js +39 -0
- package/lib/containsNode.js +49 -0
- package/lib/copyProperties.js +54 -0
- package/lib/createArrayFrom.js +94 -0
- package/lib/createNodesFromMarkup.js +93 -0
- package/lib/createObjectFrom.js +61 -0
- package/lib/cx.js +44 -0
- package/lib/dangerousStyleValue.js +57 -0
- package/lib/emptyFunction.js +43 -0
- package/lib/escapeTextForBrowser.js +47 -0
- package/lib/ex.js +49 -0
- package/lib/filterAttributes.js +45 -0
- package/lib/flattenChildren.js +54 -0
- package/lib/forEachAccumulated.js +36 -0
- package/lib/ge.js +76 -0
- package/lib/getActiveElement.js +33 -0
- package/lib/getEventTarget.js +36 -0
- package/lib/getMarkupWrap.js +108 -0
- package/lib/getNodeForCharacterOffset.js +80 -0
- package/lib/getReactRootElementInContainer.js +40 -0
- package/lib/getTextContentAccessor.js +40 -0
- package/lib/getUnboundedScrollPosition.js +45 -0
- package/lib/hyphenate.js +35 -0
- package/lib/invariant.js +54 -0
- package/lib/isEventSupported.js +74 -0
- package/lib/isNode.js +33 -0
- package/lib/isTextInputElement.js +49 -0
- package/lib/isTextNode.js +30 -0
- package/lib/joinClasses.js +44 -0
- package/lib/keyMirror.js +58 -0
- package/lib/keyOf.js +41 -0
- package/lib/memoizeStringOnly.js +39 -0
- package/lib/merge.js +37 -0
- package/lib/mergeHelpers.js +137 -0
- package/lib/mergeInto.js +45 -0
- package/lib/mixInto.js +34 -0
- package/lib/mutateHTMLNodeWithMarkup.js +100 -0
- package/lib/objMap.js +47 -0
- package/lib/objMapKeyVal.js +47 -0
- package/lib/performanceNow.js +42 -0
- package/lib/shallowEqual.js +49 -0
- package/lib/traverseAllChildren.js +127 -0
- package/package.json +33 -21
- package/react.js +4 -0
- package/.npmignore +0 -7
- package/.travis.yml +0 -5
- package/Jakefile.js +0 -39
- package/LICENSE +0 -19
- package/browser-test/dist.html +0 -89
- package/browser-test/index.html +0 -85
- package/browser-test/min.html +0 -89
- package/dist/react.js +0 -3094
- package/dist/react.min.js +0 -22
- package/doc/advanced.md +0 -166
- package/doc/color-def.graffle +0 -938
- package/doc/color-def.png +0 -0
- package/doc/simple.dot +0 -25
- package/doc/simple.png +0 -0
- package/examples/longer-example.js +0 -41
- package/examples/simple.js +0 -45
- package/examples/using-ast-directly.js +0 -30
- package/examples/using-events1.js +0 -79
- package/examples/using-log-events.js +0 -43
- package/lib/base-task.js +0 -123
- package/lib/cb-task.js +0 -84
- package/lib/core.js +0 -138
- package/lib/dsl.js +0 -138
- package/lib/error.js +0 -55
- package/lib/event-collector.js +0 -81
- package/lib/event-manager.js +0 -85
- package/lib/eventemitter.js +0 -20
- package/lib/finalcb-first-task.js +0 -68
- package/lib/finalcb-task.js +0 -65
- package/lib/id.js +0 -22
- package/lib/input-parser.js +0 -56
- package/lib/log-events.js +0 -92
- package/lib/parse.js +0 -41
- package/lib/promise-resolve.js +0 -50
- package/lib/promise-task.js +0 -93
- package/lib/react.js +0 -59
- package/lib/ret-task.js +0 -71
- package/lib/sprintf.js +0 -18
- package/lib/status.js +0 -14
- package/lib/task.js +0 -251
- package/lib/track-tasks.js +0 -74
- package/lib/validate.js +0 -159
- package/lib/vcon.js +0 -90
- package/lib/when-task.js +0 -85
- package/src/dist.build.requirejs +0 -20
- package/test/ast.mocha.js +0 -136
- package/test/cb-task.mocha.js +0 -220
- package/test/core-deferred.mocha.js +0 -143
- package/test/core-when.mocha.js +0 -96
- package/test/core.mocha.js +0 -589
- package/test/dsl.mocha.js +0 -350
- package/test/event-manager.mocha.js +0 -119
- package/test/exec-options.mocha.js +0 -48
- package/test/finalcb-task.mocha.js +0 -58
- package/test/input-parser.mocha.js +0 -86
- package/test/mocha.opts +0 -2
- package/test/module-use.mocha.js +0 -147
- package/test/promise-auto-resolve.mocha.js +0 -68
- package/test/ret-task.mocha.js +0 -220
- package/test/task.mocha.js +0 -42
- package/test/validate-cb-task.mocha.js +0 -100
- package/test/validate-ret-task.mocha.js +0 -110
- package/test/validate.mocha.js +0 -324
- package/test/vcon.mocha.js +0 -193
- package/vendor/chai/chai.js +0 -2038
- package/vendor/jquery/jquery-1.7.1.js +0 -9266
- package/vendor/jquery/jquery-1.7.1.min.js +0 -4
- package/vendor/mocha/mocha.css +0 -135
- package/vendor/mocha/mocha.js +0 -3589
- package/vendor/node/util.js +0 -531
- package/vendor/requirejs/require.js +0 -2053
- package/vendor/requirejs/require.min.js +0 -33
package/lib/ReactLink.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactLink
|
|
17
|
+
* @typechecks static-only
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
"use strict";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* ReactLink encapsulates a common pattern in which a component wants to modify
|
|
24
|
+
* a prop received from its parent. ReactLink allows the parent to pass down a
|
|
25
|
+
* value coupled with a callback that, when invoked, expresses an intent to
|
|
26
|
+
* modify that value. For example:
|
|
27
|
+
*
|
|
28
|
+
* React.createClass({
|
|
29
|
+
* getInitialState: function() {
|
|
30
|
+
* return {value: ''};
|
|
31
|
+
* },
|
|
32
|
+
* render: function() {
|
|
33
|
+
* var valueLink = new ReactLink(this.state.value, this._handleValueChange);
|
|
34
|
+
* return <input valueLink={valueLink} />;
|
|
35
|
+
* },
|
|
36
|
+
* this._handleValueChange: function(newValue) {
|
|
37
|
+
* this.setState({value: newValue});
|
|
38
|
+
* }
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* We have provided some sugary mixins to make the creation and
|
|
42
|
+
* consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {*} value current value of the link
|
|
47
|
+
* @param {function} requestChange callback to request a change
|
|
48
|
+
*/
|
|
49
|
+
function ReactLink(value, requestChange) {
|
|
50
|
+
this.value = value;
|
|
51
|
+
this.requestChange = requestChange;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = ReactLink;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactMarkupChecksum
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
var adler32 = require("./adler32");
|
|
22
|
+
|
|
23
|
+
var ReactMarkupChecksum = {
|
|
24
|
+
CHECKSUM_ATTR_NAME: 'data-react-checksum',
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} markup Markup string
|
|
28
|
+
* @return {string} Markup string with checksum attribute attached
|
|
29
|
+
*/
|
|
30
|
+
addChecksumToMarkup: function(markup) {
|
|
31
|
+
var checksum = adler32(markup);
|
|
32
|
+
return markup.replace(
|
|
33
|
+
'>',
|
|
34
|
+
' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} markup to use
|
|
40
|
+
* @param {DOMElement} element root React element
|
|
41
|
+
* @returns {boolean} whether or not the markup is the same
|
|
42
|
+
*/
|
|
43
|
+
canReuseMarkup: function(markup, element) {
|
|
44
|
+
var existingChecksum = element.getAttribute(
|
|
45
|
+
ReactMarkupChecksum.CHECKSUM_ATTR_NAME
|
|
46
|
+
);
|
|
47
|
+
existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
|
|
48
|
+
var markupChecksum = adler32(markup);
|
|
49
|
+
return markupChecksum === existingChecksum;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = ReactMarkupChecksum;
|
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactMount
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
var ReactEventEmitter = require("./ReactEventEmitter");
|
|
22
|
+
var ReactInstanceHandles = require("./ReactInstanceHandles");
|
|
23
|
+
|
|
24
|
+
var $ = require("./$");
|
|
25
|
+
var containsNode = require("./containsNode");
|
|
26
|
+
var getReactRootElementInContainer = require("./getReactRootElementInContainer");
|
|
27
|
+
var invariant = require("./invariant");
|
|
28
|
+
|
|
29
|
+
var SEPARATOR = ReactInstanceHandles.SEPARATOR;
|
|
30
|
+
|
|
31
|
+
var ATTR_NAME = 'data-reactid';
|
|
32
|
+
var nodeCache = {};
|
|
33
|
+
|
|
34
|
+
var ELEMENT_NODE_TYPE = 1;
|
|
35
|
+
var DOC_NODE_TYPE = 9;
|
|
36
|
+
|
|
37
|
+
/** Mapping from reactRootID to React component instance. */
|
|
38
|
+
var instancesByReactRootID = {};
|
|
39
|
+
|
|
40
|
+
/** Mapping from reactRootID to `container` nodes. */
|
|
41
|
+
var containersByReactRootID = {};
|
|
42
|
+
|
|
43
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
44
|
+
/** __DEV__-only mapping from reactRootID to root elements. */
|
|
45
|
+
var rootElementsByReactRootID = {};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {DOMElement} container DOM element that may contain a React component.
|
|
50
|
+
* @return {?string} A "reactRoot" ID, if a React component is rendered.
|
|
51
|
+
*/
|
|
52
|
+
function getReactRootID(container) {
|
|
53
|
+
var rootElement = getReactRootElementInContainer(container);
|
|
54
|
+
return rootElement && ReactMount.getID(rootElement);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
|
|
59
|
+
* element can return its control whose name or ID equals ATTR_NAME. All
|
|
60
|
+
* DOM nodes support `getAttributeNode` but this can also get called on
|
|
61
|
+
* other objects so just return '' if we're given something other than a
|
|
62
|
+
* DOM node (such as window).
|
|
63
|
+
*
|
|
64
|
+
* @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
|
|
65
|
+
* @return {string} ID of the supplied `domNode`.
|
|
66
|
+
*/
|
|
67
|
+
function getID(node) {
|
|
68
|
+
var id = internalGetID(node);
|
|
69
|
+
if (id) {
|
|
70
|
+
if (nodeCache.hasOwnProperty(id)) {
|
|
71
|
+
var cached = nodeCache[id];
|
|
72
|
+
if (cached !== node) {
|
|
73
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
74
|
+
!isValid(cached, id),
|
|
75
|
+
'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
|
|
76
|
+
ATTR_NAME, id
|
|
77
|
+
) : invariant(!isValid(cached, id)));
|
|
78
|
+
|
|
79
|
+
nodeCache[id] = node;
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
nodeCache[id] = node;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return id;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function internalGetID(node) {
|
|
90
|
+
// If node is something like a window, document, or text node, none of
|
|
91
|
+
// which support attributes or a .getAttribute method, gracefully return
|
|
92
|
+
// the empty string, as if the attribute were missing.
|
|
93
|
+
return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sets the React-specific ID of the given node.
|
|
98
|
+
*
|
|
99
|
+
* @param {DOMElement} node The DOM node whose ID will be set.
|
|
100
|
+
* @param {string} id The value of the ID attribute.
|
|
101
|
+
*/
|
|
102
|
+
function setID(node, id) {
|
|
103
|
+
var oldID = internalGetID(node);
|
|
104
|
+
if (oldID !== id) {
|
|
105
|
+
delete nodeCache[oldID];
|
|
106
|
+
}
|
|
107
|
+
node.setAttribute(ATTR_NAME, id);
|
|
108
|
+
nodeCache[id] = node;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Finds the node with the supplied React-generated DOM ID.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} id A React-generated DOM ID.
|
|
115
|
+
* @return {DOMElement} DOM node with the suppled `id`.
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
function getNode(id) {
|
|
119
|
+
if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
|
|
120
|
+
nodeCache[id] = ReactMount.findReactNodeByID(id);
|
|
121
|
+
}
|
|
122
|
+
return nodeCache[id];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A node is "valid" if it is contained by a currently mounted container.
|
|
127
|
+
*
|
|
128
|
+
* This means that the node does not have to be contained by a document in
|
|
129
|
+
* order to be considered valid.
|
|
130
|
+
*
|
|
131
|
+
* @param {?DOMElement} node The candidate DOM node.
|
|
132
|
+
* @param {string} id The expected ID of the node.
|
|
133
|
+
* @return {boolean} Whether the node is contained by a mounted container.
|
|
134
|
+
*/
|
|
135
|
+
function isValid(node, id) {
|
|
136
|
+
if (node) {
|
|
137
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
138
|
+
internalGetID(node) === id,
|
|
139
|
+
'ReactMount: Unexpected modification of `%s`',
|
|
140
|
+
ATTR_NAME
|
|
141
|
+
) : invariant(internalGetID(node) === id));
|
|
142
|
+
|
|
143
|
+
var container = ReactMount.findReactContainerForID(id);
|
|
144
|
+
if (container && containsNode(container, node)) {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Causes the cache to forget about one React-specific ID.
|
|
154
|
+
*
|
|
155
|
+
* @param {string} id The ID to forget.
|
|
156
|
+
*/
|
|
157
|
+
function purgeID(id) {
|
|
158
|
+
delete nodeCache[id];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Mounting is the process of initializing a React component by creatings its
|
|
163
|
+
* representative DOM elements and inserting them into a supplied `container`.
|
|
164
|
+
* Any prior content inside `container` is destroyed in the process.
|
|
165
|
+
*
|
|
166
|
+
* ReactMount.renderComponent(component, $('container'));
|
|
167
|
+
*
|
|
168
|
+
* <div id="container"> <-- Supplied `container`.
|
|
169
|
+
* <div data-reactid=".r[3]"> <-- Rendered reactRoot of React
|
|
170
|
+
* // ... component.
|
|
171
|
+
* </div>
|
|
172
|
+
* </div>
|
|
173
|
+
*
|
|
174
|
+
* Inside of `container`, the first element rendered is the "reactRoot".
|
|
175
|
+
*/
|
|
176
|
+
var ReactMount = {
|
|
177
|
+
/**
|
|
178
|
+
* Safety guard to prevent accidentally rendering over the entire HTML tree.
|
|
179
|
+
*/
|
|
180
|
+
allowFullPageRender: false,
|
|
181
|
+
|
|
182
|
+
/** Time spent generating markup. */
|
|
183
|
+
totalInstantiationTime: 0,
|
|
184
|
+
|
|
185
|
+
/** Time spent inserting markup into the DOM. */
|
|
186
|
+
totalInjectionTime: 0,
|
|
187
|
+
|
|
188
|
+
/** Whether support for touch events should be initialized. */
|
|
189
|
+
useTouchEvents: false,
|
|
190
|
+
|
|
191
|
+
/** Exposed for debugging purposes **/
|
|
192
|
+
_instancesByReactRootID: instancesByReactRootID,
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* This is a hook provided to support rendering React components while
|
|
196
|
+
* ensuring that the apparent scroll position of its `container` does not
|
|
197
|
+
* change.
|
|
198
|
+
*
|
|
199
|
+
* @param {DOMElement} container The `container` being rendered into.
|
|
200
|
+
* @param {function} renderCallback This must be called once to do the render.
|
|
201
|
+
*/
|
|
202
|
+
scrollMonitor: function(container, renderCallback) {
|
|
203
|
+
renderCallback();
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Ensures that the top-level event delegation listener is set up. This will
|
|
208
|
+
* be invoked some time before the first time any React component is rendered.
|
|
209
|
+
* @param {DOMElement} container container we're rendering into
|
|
210
|
+
*
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
prepareEnvironmentForDOM: function(container) {
|
|
214
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
215
|
+
container && (
|
|
216
|
+
container.nodeType === ELEMENT_NODE_TYPE ||
|
|
217
|
+
container.nodeType === DOC_NODE_TYPE
|
|
218
|
+
),
|
|
219
|
+
'prepareEnvironmentForDOM(...): Target container is not a DOM element.'
|
|
220
|
+
) : invariant(container && (
|
|
221
|
+
container.nodeType === ELEMENT_NODE_TYPE ||
|
|
222
|
+
container.nodeType === DOC_NODE_TYPE
|
|
223
|
+
)));
|
|
224
|
+
var doc = container.nodeType === ELEMENT_NODE_TYPE ?
|
|
225
|
+
container.ownerDocument :
|
|
226
|
+
container;
|
|
227
|
+
ReactEventEmitter.ensureListening(ReactMount.useTouchEvents, doc);
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Take a component that's already mounted into the DOM and replace its props
|
|
232
|
+
* @param {ReactComponent} prevComponent component instance already in the DOM
|
|
233
|
+
* @param {ReactComponent} nextComponent component instance to render
|
|
234
|
+
* @param {DOMElement} container container to render into
|
|
235
|
+
* @param {?function} callback function triggered on completion
|
|
236
|
+
*/
|
|
237
|
+
_updateRootComponent: function(
|
|
238
|
+
prevComponent,
|
|
239
|
+
nextComponent,
|
|
240
|
+
container,
|
|
241
|
+
callback) {
|
|
242
|
+
var nextProps = nextComponent.props;
|
|
243
|
+
ReactMount.scrollMonitor(container, function() {
|
|
244
|
+
prevComponent.replaceProps(nextProps, callback);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
248
|
+
// Record the root element in case it later gets transplanted.
|
|
249
|
+
rootElementsByReactRootID[getReactRootID(container)] =
|
|
250
|
+
getReactRootElementInContainer(container);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return prevComponent;
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Register a component into the instance map and start the events system.
|
|
258
|
+
* @param {ReactComponent} nextComponent component instance to render
|
|
259
|
+
* @param {DOMElement} container container to render into
|
|
260
|
+
* @return {string} reactRoot ID prefix
|
|
261
|
+
*/
|
|
262
|
+
_registerComponent: function(nextComponent, container) {
|
|
263
|
+
ReactMount.prepareEnvironmentForDOM(container);
|
|
264
|
+
|
|
265
|
+
var reactRootID = ReactMount.registerContainer(container);
|
|
266
|
+
instancesByReactRootID[reactRootID] = nextComponent;
|
|
267
|
+
return reactRootID;
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Render a new component into the DOM.
|
|
272
|
+
* @param {ReactComponent} nextComponent component instance to render
|
|
273
|
+
* @param {DOMElement} container container to render into
|
|
274
|
+
* @param {boolean} shouldReuseMarkup if we should skip the markup insertion
|
|
275
|
+
* @return {ReactComponent} nextComponent
|
|
276
|
+
*/
|
|
277
|
+
_renderNewRootComponent: function(
|
|
278
|
+
nextComponent,
|
|
279
|
+
container,
|
|
280
|
+
shouldReuseMarkup) {
|
|
281
|
+
var reactRootID = ReactMount._registerComponent(nextComponent, container);
|
|
282
|
+
nextComponent.mountComponentIntoNode(
|
|
283
|
+
reactRootID,
|
|
284
|
+
container,
|
|
285
|
+
shouldReuseMarkup
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
289
|
+
// Record the root element in case it later gets transplanted.
|
|
290
|
+
rootElementsByReactRootID[reactRootID] =
|
|
291
|
+
getReactRootElementInContainer(container);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return nextComponent;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Renders a React component into the DOM in the supplied `container`.
|
|
299
|
+
*
|
|
300
|
+
* If the React component was previously rendered into `container`, this will
|
|
301
|
+
* perform an update on it and only mutate the DOM as necessary to reflect the
|
|
302
|
+
* latest React component.
|
|
303
|
+
*
|
|
304
|
+
* @param {ReactComponent} nextComponent Component instance to render.
|
|
305
|
+
* @param {DOMElement} container DOM element to render into.
|
|
306
|
+
* @param {?function} callback function triggered on completion
|
|
307
|
+
* @return {ReactComponent} Component instance rendered in `container`.
|
|
308
|
+
*/
|
|
309
|
+
renderComponent: function(nextComponent, container, callback) {
|
|
310
|
+
var registeredComponent = instancesByReactRootID[getReactRootID(container)];
|
|
311
|
+
|
|
312
|
+
if (registeredComponent) {
|
|
313
|
+
if (registeredComponent.constructor === nextComponent.constructor) {
|
|
314
|
+
return ReactMount._updateRootComponent(
|
|
315
|
+
registeredComponent,
|
|
316
|
+
nextComponent,
|
|
317
|
+
container,
|
|
318
|
+
callback
|
|
319
|
+
);
|
|
320
|
+
} else {
|
|
321
|
+
ReactMount.unmountComponentAtNode(container);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
var reactRootElement = getReactRootElementInContainer(container);
|
|
326
|
+
var containerHasReactMarkup =
|
|
327
|
+
reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
|
|
328
|
+
|
|
329
|
+
var shouldReuseMarkup = containerHasReactMarkup && !registeredComponent;
|
|
330
|
+
|
|
331
|
+
var component = ReactMount._renderNewRootComponent(
|
|
332
|
+
nextComponent,
|
|
333
|
+
container,
|
|
334
|
+
shouldReuseMarkup
|
|
335
|
+
);
|
|
336
|
+
callback && callback();
|
|
337
|
+
return component;
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Constructs a component instance of `constructor` with `initialProps` and
|
|
342
|
+
* renders it into the supplied `container`.
|
|
343
|
+
*
|
|
344
|
+
* @param {function} constructor React component constructor.
|
|
345
|
+
* @param {?object} props Initial props of the component instance.
|
|
346
|
+
* @param {DOMElement} container DOM element to render into.
|
|
347
|
+
* @return {ReactComponent} Component instance rendered in `container`.
|
|
348
|
+
*/
|
|
349
|
+
constructAndRenderComponent: function(constructor, props, container) {
|
|
350
|
+
return ReactMount.renderComponent(constructor(props), container);
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Constructs a component instance of `constructor` with `initialProps` and
|
|
355
|
+
* renders it into a container node identified by supplied `id`.
|
|
356
|
+
*
|
|
357
|
+
* @param {function} componentConstructor React component constructor
|
|
358
|
+
* @param {?object} props Initial props of the component instance.
|
|
359
|
+
* @param {string} id ID of the DOM element to render into.
|
|
360
|
+
* @return {ReactComponent} Component instance rendered in the container node.
|
|
361
|
+
*/
|
|
362
|
+
constructAndRenderComponentByID: function(constructor, props, id) {
|
|
363
|
+
return ReactMount.constructAndRenderComponent(constructor, props, $(id));
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Registers a container node into which React components will be rendered.
|
|
368
|
+
* This also creates the "reatRoot" ID that will be assigned to the element
|
|
369
|
+
* rendered within.
|
|
370
|
+
*
|
|
371
|
+
* @param {DOMElement} container DOM element to register as a container.
|
|
372
|
+
* @return {string} The "reactRoot" ID of elements rendered within.
|
|
373
|
+
*/
|
|
374
|
+
registerContainer: function(container) {
|
|
375
|
+
var reactRootID = getReactRootID(container);
|
|
376
|
+
if (reactRootID) {
|
|
377
|
+
// If one exists, make sure it is a valid "reactRoot" ID.
|
|
378
|
+
reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
|
|
379
|
+
}
|
|
380
|
+
if (!reactRootID) {
|
|
381
|
+
// No valid "reactRoot" ID found, create one.
|
|
382
|
+
reactRootID = ReactInstanceHandles.createReactRootID();
|
|
383
|
+
}
|
|
384
|
+
containersByReactRootID[reactRootID] = container;
|
|
385
|
+
return reactRootID;
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Unmounts and destroys the React component rendered in the `container`.
|
|
390
|
+
*
|
|
391
|
+
* @param {DOMElement} container DOM element containing a React component.
|
|
392
|
+
* @return {boolean} True if a component was found in and unmounted from
|
|
393
|
+
* `container`
|
|
394
|
+
*/
|
|
395
|
+
unmountComponentAtNode: function(container) {
|
|
396
|
+
var reactRootID = getReactRootID(container);
|
|
397
|
+
var component = instancesByReactRootID[reactRootID];
|
|
398
|
+
if (!component) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
ReactMount.unmountComponentFromNode(component, container);
|
|
402
|
+
delete instancesByReactRootID[reactRootID];
|
|
403
|
+
delete containersByReactRootID[reactRootID];
|
|
404
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
405
|
+
delete rootElementsByReactRootID[reactRootID];
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @deprecated
|
|
412
|
+
*/
|
|
413
|
+
unmountAndReleaseReactRootNode: function() {
|
|
414
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
415
|
+
console.warn(
|
|
416
|
+
'unmountAndReleaseReactRootNode() has been renamed to ' +
|
|
417
|
+
'unmountComponentAtNode() and will be removed in the next ' +
|
|
418
|
+
'version of React.'
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
return ReactMount.unmountComponentAtNode.apply(this, arguments);
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Unmounts a component and removes it from the DOM.
|
|
426
|
+
*
|
|
427
|
+
* @param {ReactComponent} instance React component instance.
|
|
428
|
+
* @param {DOMElement} container DOM element to unmount from.
|
|
429
|
+
* @final
|
|
430
|
+
* @internal
|
|
431
|
+
* @see {ReactMount.unmountComponentAtNode}
|
|
432
|
+
*/
|
|
433
|
+
unmountComponentFromNode: function(instance, container) {
|
|
434
|
+
instance.unmountComponent();
|
|
435
|
+
|
|
436
|
+
if (container.nodeType === DOC_NODE_TYPE) {
|
|
437
|
+
container = container.documentElement;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// http://jsperf.com/emptying-a-node
|
|
441
|
+
while (container.lastChild) {
|
|
442
|
+
container.removeChild(container.lastChild);
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Finds the container DOM element that contains React component to which the
|
|
448
|
+
* supplied DOM `id` belongs.
|
|
449
|
+
*
|
|
450
|
+
* @param {string} id The ID of an element rendered by a React component.
|
|
451
|
+
* @return {?DOMElement} DOM element that contains the `id`.
|
|
452
|
+
*/
|
|
453
|
+
findReactContainerForID: function(id) {
|
|
454
|
+
var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
|
|
455
|
+
var container = containersByReactRootID[reactRootID];
|
|
456
|
+
|
|
457
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
458
|
+
var rootElement = rootElementsByReactRootID[reactRootID];
|
|
459
|
+
if (rootElement && rootElement.parentNode !== container) {
|
|
460
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
461
|
+
// Call internalGetID here because getID calls isValid which calls
|
|
462
|
+
// findReactContainerForID (this function).
|
|
463
|
+
internalGetID(rootElement) === reactRootID,
|
|
464
|
+
'ReactMount: Root element ID differed from reactRootID.'
|
|
465
|
+
) : invariant(// Call internalGetID here because getID calls isValid which calls
|
|
466
|
+
// findReactContainerForID (this function).
|
|
467
|
+
internalGetID(rootElement) === reactRootID));
|
|
468
|
+
|
|
469
|
+
var containerChild = container.firstChild;
|
|
470
|
+
if (containerChild &&
|
|
471
|
+
reactRootID === internalGetID(containerChild)) {
|
|
472
|
+
// If the container has a new child with the same ID as the old
|
|
473
|
+
// root element, then rootElementsByReactRootID[reactRootID] is
|
|
474
|
+
// just stale and needs to be updated. The case that deserves a
|
|
475
|
+
// warning is when the container is empty.
|
|
476
|
+
rootElementsByReactRootID[reactRootID] = containerChild;
|
|
477
|
+
} else {
|
|
478
|
+
console.warn(
|
|
479
|
+
'ReactMount: Root element has been removed from its original ' +
|
|
480
|
+
'container. New container:', rootElement.parentNode
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return container;
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Finds an element rendered by React with the supplied ID.
|
|
491
|
+
*
|
|
492
|
+
* @param {string} id ID of a DOM node in the React component.
|
|
493
|
+
* @return {DOMElement} Root DOM node of the React component.
|
|
494
|
+
*/
|
|
495
|
+
findReactNodeByID: function(id) {
|
|
496
|
+
var reactRoot = ReactMount.findReactContainerForID(id);
|
|
497
|
+
return ReactMount.findComponentRoot(reactRoot, id);
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* True if the supplied `node` is rendered by React.
|
|
502
|
+
*
|
|
503
|
+
* @param {*} node DOM Element to check.
|
|
504
|
+
* @return {boolean} True if the DOM Element appears to be rendered by React.
|
|
505
|
+
* @internal
|
|
506
|
+
*/
|
|
507
|
+
isRenderedByReact: function(node) {
|
|
508
|
+
if (node.nodeType !== 1) {
|
|
509
|
+
// Not a DOMElement, therefore not a React component
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
var id = ReactMount.getID(node);
|
|
513
|
+
return id ? id.charAt(0) === SEPARATOR : false;
|
|
514
|
+
},
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Traverses up the ancestors of the supplied node to find a node that is a
|
|
518
|
+
* DOM representation of a React component.
|
|
519
|
+
*
|
|
520
|
+
* @param {*} node
|
|
521
|
+
* @return {?DOMEventTarget}
|
|
522
|
+
* @internal
|
|
523
|
+
*/
|
|
524
|
+
getFirstReactDOM: function(node) {
|
|
525
|
+
var current = node;
|
|
526
|
+
while (current && current.parentNode !== current) {
|
|
527
|
+
if (ReactMount.isRenderedByReact(current)) {
|
|
528
|
+
return current;
|
|
529
|
+
}
|
|
530
|
+
current = current.parentNode;
|
|
531
|
+
}
|
|
532
|
+
return null;
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Finds a node with the supplied `id` inside of the supplied `ancestorNode`.
|
|
537
|
+
* Exploits the ID naming scheme to perform the search quickly.
|
|
538
|
+
*
|
|
539
|
+
* @param {DOMEventTarget} ancestorNode Search from this root.
|
|
540
|
+
* @pararm {string} id ID of the DOM representation of the component.
|
|
541
|
+
* @return {DOMEventTarget} DOM node with the supplied `id`.
|
|
542
|
+
* @internal
|
|
543
|
+
*/
|
|
544
|
+
findComponentRoot: function(ancestorNode, id) {
|
|
545
|
+
var firstChildren = [ancestorNode.firstChild];
|
|
546
|
+
var childIndex = 0;
|
|
547
|
+
|
|
548
|
+
while (childIndex < firstChildren.length) {
|
|
549
|
+
var child = firstChildren[childIndex++];
|
|
550
|
+
while (child) {
|
|
551
|
+
var childID = ReactMount.getID(child);
|
|
552
|
+
if (childID) {
|
|
553
|
+
if (id === childID) {
|
|
554
|
+
return child;
|
|
555
|
+
} else if (ReactInstanceHandles.isAncestorIDOf(childID, id)) {
|
|
556
|
+
// If we find a child whose ID is an ancestor of the given ID,
|
|
557
|
+
// then we can be sure that we only want to search the subtree
|
|
558
|
+
// rooted at this child, so we can throw out the rest of the
|
|
559
|
+
// search state.
|
|
560
|
+
firstChildren.length = childIndex = 0;
|
|
561
|
+
firstChildren.push(child.firstChild);
|
|
562
|
+
break;
|
|
563
|
+
} else {
|
|
564
|
+
// TODO This should not be necessary if the ID hierarchy is
|
|
565
|
+
// correct, but is occasionally necessary if the DOM has been
|
|
566
|
+
// modified in unexpected ways.
|
|
567
|
+
firstChildren.push(child.firstChild);
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
// If this child had no ID, then there's a chance that it was
|
|
571
|
+
// injected automatically by the browser, as when a `<table>`
|
|
572
|
+
// element sprouts an extra `<tbody>` child as a side effect of
|
|
573
|
+
// `.innerHTML` parsing. Optimistically continue down this
|
|
574
|
+
// branch, but not before examining the other siblings.
|
|
575
|
+
firstChildren.push(child.firstChild);
|
|
576
|
+
}
|
|
577
|
+
child = child.nextSibling;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
582
|
+
console.error(
|
|
583
|
+
'Error while invoking `findComponentRoot` with the following ' +
|
|
584
|
+
'ancestor node:',
|
|
585
|
+
ancestorNode
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
589
|
+
false,
|
|
590
|
+
'findComponentRoot(..., %s): Unable to find element. This probably ' +
|
|
591
|
+
'means the DOM was unexpectedly mutated (e.g. by the browser).',
|
|
592
|
+
id,
|
|
593
|
+
ReactMount.getID(ancestorNode)
|
|
594
|
+
) : invariant(false));
|
|
595
|
+
},
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* React ID utilities.
|
|
600
|
+
*/
|
|
601
|
+
|
|
602
|
+
ATTR_NAME: ATTR_NAME,
|
|
603
|
+
|
|
604
|
+
getReactRootID: getReactRootID,
|
|
605
|
+
|
|
606
|
+
getID: getID,
|
|
607
|
+
|
|
608
|
+
setID: setID,
|
|
609
|
+
|
|
610
|
+
getNode: getNode,
|
|
611
|
+
|
|
612
|
+
purgeID: purgeID,
|
|
613
|
+
|
|
614
|
+
injection: {}
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
module.exports = ReactMount;
|