react 0.7.1 → 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 -228
- 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 -31
- package/react.js +4 -0
- package/.npmignore +0 -7
- package/.travis.yml +0 -7
- package/Jakefile.js +0 -39
- package/LICENSE +0 -19
- package/browser-test/dist.html +0 -90
- package/browser-test/index.html +0 -86
- package/browser-test/min.html +0 -90
- package/dist/react.js +0 -3141
- package/dist/react.min.js +0 -22
- package/doc/advanced.md +0 -175
- 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 -120
- 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 -89
- 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 -101
- 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 -113
- package/lib/when-task.js +0 -84
- 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 -352
- 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/log-events.mocha.js +0 -88
- package/test/mocha.opts +0 -2
- package/test/module-use.mocha.js +0 -164
- 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 -4251
- package/vendor/jquery/jquery-1.7.1.js +0 -9266
- package/vendor/jquery/jquery-1.7.1.min.js +0 -4
- package/vendor/node/util.js +0 -531
- package/vendor/requirejs/require.js +0 -2045
- package/vendor/requirejs/require.min.js +0 -36
|
@@ -0,0 +1,39 @@
|
|
|
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 ReactCurrentOwner
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Keeps track of the current owner.
|
|
23
|
+
*
|
|
24
|
+
* The current owner is the component who should own any components that are
|
|
25
|
+
* currently being constructed.
|
|
26
|
+
*
|
|
27
|
+
* The depth indicate how many composite components are above this render level.
|
|
28
|
+
*/
|
|
29
|
+
var ReactCurrentOwner = {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @internal
|
|
33
|
+
* @type {ReactComponent}
|
|
34
|
+
*/
|
|
35
|
+
current: null
|
|
36
|
+
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
module.exports = ReactCurrentOwner;
|
package/lib/ReactDOM.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
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 ReactDOM
|
|
17
|
+
* @typechecks static-only
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
"use strict";
|
|
21
|
+
|
|
22
|
+
var ReactDOMComponent = require("./ReactDOMComponent");
|
|
23
|
+
|
|
24
|
+
var mergeInto = require("./mergeInto");
|
|
25
|
+
var objMapKeyVal = require("./objMapKeyVal");
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new React class that is idempotent and capable of containing other
|
|
29
|
+
* React components. It accepts event listeners and DOM properties that are
|
|
30
|
+
* valid according to `DOMProperty`.
|
|
31
|
+
*
|
|
32
|
+
* - Event listeners: `onClick`, `onMouseDown`, etc.
|
|
33
|
+
* - DOM properties: `className`, `name`, `title`, etc.
|
|
34
|
+
*
|
|
35
|
+
* The `style` property functions differently from the DOM API. It accepts an
|
|
36
|
+
* object mapping of style properties to values.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} tag Tag name (e.g. `div`).
|
|
39
|
+
* @param {boolean} omitClose True if the close tag should be omitted.
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
function createDOMComponentClass(tag, omitClose) {
|
|
43
|
+
var Constructor = function() {};
|
|
44
|
+
Constructor.prototype = new ReactDOMComponent(tag, omitClose);
|
|
45
|
+
Constructor.prototype.constructor = Constructor;
|
|
46
|
+
Constructor.displayName = tag;
|
|
47
|
+
|
|
48
|
+
var ConvenienceConstructor = function(props, children) {
|
|
49
|
+
var instance = new Constructor();
|
|
50
|
+
instance.construct.apply(instance, arguments);
|
|
51
|
+
return instance;
|
|
52
|
+
};
|
|
53
|
+
ConvenienceConstructor.componentConstructor = Constructor;
|
|
54
|
+
return ConvenienceConstructor;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
|
|
59
|
+
* This is also accessible via `React.DOM`.
|
|
60
|
+
*
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
var ReactDOM = objMapKeyVal({
|
|
64
|
+
a: false,
|
|
65
|
+
abbr: false,
|
|
66
|
+
address: false,
|
|
67
|
+
area: false,
|
|
68
|
+
article: false,
|
|
69
|
+
aside: false,
|
|
70
|
+
audio: false,
|
|
71
|
+
b: false,
|
|
72
|
+
base: false,
|
|
73
|
+
bdi: false,
|
|
74
|
+
bdo: false,
|
|
75
|
+
big: false,
|
|
76
|
+
blockquote: false,
|
|
77
|
+
body: false,
|
|
78
|
+
br: true,
|
|
79
|
+
button: false,
|
|
80
|
+
canvas: false,
|
|
81
|
+
caption: false,
|
|
82
|
+
cite: false,
|
|
83
|
+
code: false,
|
|
84
|
+
col: true,
|
|
85
|
+
colgroup: false,
|
|
86
|
+
data: false,
|
|
87
|
+
datalist: false,
|
|
88
|
+
dd: false,
|
|
89
|
+
del: false,
|
|
90
|
+
details: false,
|
|
91
|
+
dfn: false,
|
|
92
|
+
div: false,
|
|
93
|
+
dl: false,
|
|
94
|
+
dt: false,
|
|
95
|
+
em: false,
|
|
96
|
+
embed: true,
|
|
97
|
+
fieldset: false,
|
|
98
|
+
figcaption: false,
|
|
99
|
+
figure: false,
|
|
100
|
+
footer: false,
|
|
101
|
+
form: false, // NOTE: Injected, see `ReactDOMForm`.
|
|
102
|
+
h1: false,
|
|
103
|
+
h2: false,
|
|
104
|
+
h3: false,
|
|
105
|
+
h4: false,
|
|
106
|
+
h5: false,
|
|
107
|
+
h6: false,
|
|
108
|
+
head: false,
|
|
109
|
+
header: false,
|
|
110
|
+
hr: true,
|
|
111
|
+
html: false,
|
|
112
|
+
i: false,
|
|
113
|
+
iframe: false,
|
|
114
|
+
img: true,
|
|
115
|
+
input: true,
|
|
116
|
+
ins: false,
|
|
117
|
+
kbd: false,
|
|
118
|
+
keygen: true,
|
|
119
|
+
label: false,
|
|
120
|
+
legend: false,
|
|
121
|
+
li: false,
|
|
122
|
+
link: false,
|
|
123
|
+
main: false,
|
|
124
|
+
map: false,
|
|
125
|
+
mark: false,
|
|
126
|
+
menu: false,
|
|
127
|
+
menuitem: false, // NOTE: Close tag should be omitted, but causes problems.
|
|
128
|
+
meta: true,
|
|
129
|
+
meter: false,
|
|
130
|
+
nav: false,
|
|
131
|
+
noscript: false,
|
|
132
|
+
object: false,
|
|
133
|
+
ol: false,
|
|
134
|
+
optgroup: false,
|
|
135
|
+
option: false,
|
|
136
|
+
output: false,
|
|
137
|
+
p: false,
|
|
138
|
+
param: true,
|
|
139
|
+
pre: false,
|
|
140
|
+
progress: false,
|
|
141
|
+
q: false,
|
|
142
|
+
rp: false,
|
|
143
|
+
rt: false,
|
|
144
|
+
ruby: false,
|
|
145
|
+
s: false,
|
|
146
|
+
samp: false,
|
|
147
|
+
script: false,
|
|
148
|
+
section: false,
|
|
149
|
+
select: false,
|
|
150
|
+
small: false,
|
|
151
|
+
source: false,
|
|
152
|
+
span: false,
|
|
153
|
+
strong: false,
|
|
154
|
+
style: false,
|
|
155
|
+
sub: false,
|
|
156
|
+
summary: false,
|
|
157
|
+
sup: false,
|
|
158
|
+
table: false,
|
|
159
|
+
tbody: false,
|
|
160
|
+
td: false,
|
|
161
|
+
textarea: false, // NOTE: Injected, see `ReactDOMTextarea`.
|
|
162
|
+
tfoot: false,
|
|
163
|
+
th: false,
|
|
164
|
+
thead: false,
|
|
165
|
+
time: false,
|
|
166
|
+
title: false,
|
|
167
|
+
tr: false,
|
|
168
|
+
track: true,
|
|
169
|
+
u: false,
|
|
170
|
+
ul: false,
|
|
171
|
+
'var': false,
|
|
172
|
+
video: false,
|
|
173
|
+
wbr: false,
|
|
174
|
+
|
|
175
|
+
// SVG
|
|
176
|
+
circle: false,
|
|
177
|
+
g: false,
|
|
178
|
+
line: false,
|
|
179
|
+
path: false,
|
|
180
|
+
polyline: false,
|
|
181
|
+
rect: false,
|
|
182
|
+
svg: false,
|
|
183
|
+
text: false
|
|
184
|
+
}, createDOMComponentClass);
|
|
185
|
+
|
|
186
|
+
var injection = {
|
|
187
|
+
injectComponentClasses: function(componentClasses) {
|
|
188
|
+
mergeInto(ReactDOM, componentClasses);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
ReactDOM.injection = injection;
|
|
193
|
+
|
|
194
|
+
module.exports = ReactDOM;
|
|
@@ -0,0 +1,64 @@
|
|
|
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 ReactDOMButton
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
var ReactCompositeComponent = require("./ReactCompositeComponent");
|
|
22
|
+
var ReactDOM = require("./ReactDOM");
|
|
23
|
+
|
|
24
|
+
var keyMirror = require("./keyMirror");
|
|
25
|
+
|
|
26
|
+
// Store a reference to the <button> `ReactDOMComponent`.
|
|
27
|
+
var button = ReactDOM.button;
|
|
28
|
+
|
|
29
|
+
var mouseListenerNames = keyMirror({
|
|
30
|
+
onClick: true,
|
|
31
|
+
onDoubleClick: true,
|
|
32
|
+
onMouseDown: true,
|
|
33
|
+
onMouseMove: true,
|
|
34
|
+
onMouseUp: true,
|
|
35
|
+
onClickCapture: true,
|
|
36
|
+
onDoubleClickCapture: true,
|
|
37
|
+
onMouseDownCapture: true,
|
|
38
|
+
onMouseMoveCapture: true,
|
|
39
|
+
onMouseUpCapture: true
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Implements a <button> native component that does not receive mouse events
|
|
44
|
+
* when `disabled` is set.
|
|
45
|
+
*/
|
|
46
|
+
var ReactDOMButton = ReactCompositeComponent.createClass({
|
|
47
|
+
|
|
48
|
+
render: function() {
|
|
49
|
+
var props = {};
|
|
50
|
+
|
|
51
|
+
// Copy the props; except the mouse listeners if we're disabled
|
|
52
|
+
for (var key in this.props) {
|
|
53
|
+
if (this.props.hasOwnProperty(key) &&
|
|
54
|
+
(!this.props.disabled || !mouseListenerNames[key])) {
|
|
55
|
+
props[key] = this.props[key];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return button(props, this.props.children);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
module.exports = ReactDOMButton;
|
|
@@ -0,0 +1,374 @@
|
|
|
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 ReactDOMComponent
|
|
17
|
+
* @typechecks static-only
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
"use strict";
|
|
21
|
+
|
|
22
|
+
var CSSPropertyOperations = require("./CSSPropertyOperations");
|
|
23
|
+
var DOMProperty = require("./DOMProperty");
|
|
24
|
+
var DOMPropertyOperations = require("./DOMPropertyOperations");
|
|
25
|
+
var ReactComponent = require("./ReactComponent");
|
|
26
|
+
var ReactEventEmitter = require("./ReactEventEmitter");
|
|
27
|
+
var ReactMultiChild = require("./ReactMultiChild");
|
|
28
|
+
var ReactMount = require("./ReactMount");
|
|
29
|
+
var ReactPerf = require("./ReactPerf");
|
|
30
|
+
|
|
31
|
+
var escapeTextForBrowser = require("./escapeTextForBrowser");
|
|
32
|
+
var invariant = require("./invariant");
|
|
33
|
+
var keyOf = require("./keyOf");
|
|
34
|
+
var merge = require("./merge");
|
|
35
|
+
var mixInto = require("./mixInto");
|
|
36
|
+
|
|
37
|
+
var putListener = ReactEventEmitter.putListener;
|
|
38
|
+
var deleteListener = ReactEventEmitter.deleteListener;
|
|
39
|
+
var registrationNames = ReactEventEmitter.registrationNames;
|
|
40
|
+
|
|
41
|
+
// For quickly matching children type, to test if can be treated as content.
|
|
42
|
+
var CONTENT_TYPES = {'string': true, 'number': true};
|
|
43
|
+
|
|
44
|
+
var STYLE = keyOf({style: null});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {?object} props
|
|
48
|
+
*/
|
|
49
|
+
function assertValidProps(props) {
|
|
50
|
+
if (!props) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Note the use of `==` which checks for null or undefined.
|
|
54
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
55
|
+
props.children == null || props.dangerouslySetInnerHTML == null,
|
|
56
|
+
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
|
|
57
|
+
) : invariant(props.children == null || props.dangerouslySetInnerHTML == null));
|
|
58
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
59
|
+
props.style == null || typeof props.style === 'object',
|
|
60
|
+
'The `style` prop expects a mapping from style properties to values, ' +
|
|
61
|
+
'not a string.'
|
|
62
|
+
) : invariant(props.style == null || typeof props.style === 'object'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @constructor ReactDOMComponent
|
|
67
|
+
* @extends ReactComponent
|
|
68
|
+
* @extends ReactMultiChild
|
|
69
|
+
*/
|
|
70
|
+
function ReactDOMComponent(tag, omitClose) {
|
|
71
|
+
this._tagOpen = '<' + tag;
|
|
72
|
+
this._tagClose = omitClose ? '' : '</' + tag + '>';
|
|
73
|
+
this.tagName = tag.toUpperCase();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
ReactDOMComponent.Mixin = {
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Generates root tag markup then recurses. This method has side effects and
|
|
80
|
+
* is not idempotent.
|
|
81
|
+
*
|
|
82
|
+
* @internal
|
|
83
|
+
* @param {string} rootID The root DOM ID for this node.
|
|
84
|
+
* @param {ReactReconcileTransaction} transaction
|
|
85
|
+
* @param {number} mountDepth number of components in the owner hierarchy
|
|
86
|
+
* @return {string} The computed markup.
|
|
87
|
+
*/
|
|
88
|
+
mountComponent: ReactPerf.measure(
|
|
89
|
+
'ReactDOMComponent',
|
|
90
|
+
'mountComponent',
|
|
91
|
+
function(rootID, transaction, mountDepth) {
|
|
92
|
+
ReactComponent.Mixin.mountComponent.call(
|
|
93
|
+
this,
|
|
94
|
+
rootID,
|
|
95
|
+
transaction,
|
|
96
|
+
mountDepth
|
|
97
|
+
);
|
|
98
|
+
assertValidProps(this.props);
|
|
99
|
+
return (
|
|
100
|
+
this._createOpenTagMarkup() +
|
|
101
|
+
this._createContentMarkup(transaction) +
|
|
102
|
+
this._tagClose
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
),
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates markup for the open tag and all attributes.
|
|
109
|
+
*
|
|
110
|
+
* This method has side effects because events get registered.
|
|
111
|
+
*
|
|
112
|
+
* Iterating over object properties is faster than iterating over arrays.
|
|
113
|
+
* @see http://jsperf.com/obj-vs-arr-iteration
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
* @return {string} Markup of opening tag.
|
|
117
|
+
*/
|
|
118
|
+
_createOpenTagMarkup: function() {
|
|
119
|
+
var props = this.props;
|
|
120
|
+
var ret = this._tagOpen;
|
|
121
|
+
|
|
122
|
+
for (var propKey in props) {
|
|
123
|
+
if (!props.hasOwnProperty(propKey)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
var propValue = props[propKey];
|
|
127
|
+
if (propValue == null) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (registrationNames[propKey]) {
|
|
131
|
+
putListener(this._rootNodeID, propKey, propValue);
|
|
132
|
+
} else {
|
|
133
|
+
if (propKey === STYLE) {
|
|
134
|
+
if (propValue) {
|
|
135
|
+
propValue = props.style = merge(props.style);
|
|
136
|
+
}
|
|
137
|
+
propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
|
|
138
|
+
}
|
|
139
|
+
var markup =
|
|
140
|
+
DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
|
|
141
|
+
if (markup) {
|
|
142
|
+
ret += ' ' + markup;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
var escapedID = escapeTextForBrowser(this._rootNodeID);
|
|
148
|
+
return ret + ' ' + ReactMount.ATTR_NAME + '="' + escapedID + '">';
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates markup for the content between the tags.
|
|
153
|
+
*
|
|
154
|
+
* @private
|
|
155
|
+
* @param {ReactReconcileTransaction} transaction
|
|
156
|
+
* @return {string} Content markup.
|
|
157
|
+
*/
|
|
158
|
+
_createContentMarkup: function(transaction) {
|
|
159
|
+
// Intentional use of != to avoid catching zero/false.
|
|
160
|
+
var innerHTML = this.props.dangerouslySetInnerHTML;
|
|
161
|
+
if (innerHTML != null) {
|
|
162
|
+
if (innerHTML.__html != null) {
|
|
163
|
+
return innerHTML.__html;
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
var contentToUse =
|
|
167
|
+
CONTENT_TYPES[typeof this.props.children] ? this.props.children : null;
|
|
168
|
+
var childrenToUse = contentToUse != null ? null : this.props.children;
|
|
169
|
+
if (contentToUse != null) {
|
|
170
|
+
return escapeTextForBrowser(contentToUse);
|
|
171
|
+
} else if (childrenToUse != null) {
|
|
172
|
+
var mountImages = this.mountChildren(
|
|
173
|
+
childrenToUse,
|
|
174
|
+
transaction
|
|
175
|
+
);
|
|
176
|
+
return mountImages.join('');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return '';
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
receiveComponent: function(nextComponent, transaction) {
|
|
183
|
+
assertValidProps(nextComponent.props);
|
|
184
|
+
ReactComponent.Mixin.receiveComponent.call(
|
|
185
|
+
this,
|
|
186
|
+
nextComponent,
|
|
187
|
+
transaction
|
|
188
|
+
);
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Updates a native DOM component after it has already been allocated and
|
|
193
|
+
* attached to the DOM. Reconciles the root DOM node, then recurses.
|
|
194
|
+
*
|
|
195
|
+
* @param {ReactReconcileTransaction} transaction
|
|
196
|
+
* @param {object} prevProps
|
|
197
|
+
* @internal
|
|
198
|
+
* @overridable
|
|
199
|
+
*/
|
|
200
|
+
updateComponent: ReactPerf.measure(
|
|
201
|
+
'ReactDOMComponent',
|
|
202
|
+
'updateComponent',
|
|
203
|
+
function(transaction, prevProps) {
|
|
204
|
+
ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
|
|
205
|
+
this._updateDOMProperties(prevProps);
|
|
206
|
+
this._updateDOMChildren(prevProps, transaction);
|
|
207
|
+
}
|
|
208
|
+
),
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Reconciles the properties by detecting differences in property values and
|
|
212
|
+
* updating the DOM as necessary. This function is probably the single most
|
|
213
|
+
* critical path for performance optimization.
|
|
214
|
+
*
|
|
215
|
+
* TODO: Benchmark whether checking for changed values in memory actually
|
|
216
|
+
* improves performance (especially statically positioned elements).
|
|
217
|
+
* TODO: Benchmark the effects of putting this at the top since 99% of props
|
|
218
|
+
* do not change for a given reconciliation.
|
|
219
|
+
* TODO: Benchmark areas that can be improved with caching.
|
|
220
|
+
*
|
|
221
|
+
* @private
|
|
222
|
+
* @param {object} lastProps
|
|
223
|
+
*/
|
|
224
|
+
_updateDOMProperties: function(lastProps) {
|
|
225
|
+
var nextProps = this.props;
|
|
226
|
+
var propKey;
|
|
227
|
+
var styleName;
|
|
228
|
+
var styleUpdates;
|
|
229
|
+
for (propKey in lastProps) {
|
|
230
|
+
if (nextProps.hasOwnProperty(propKey) ||
|
|
231
|
+
!lastProps.hasOwnProperty(propKey)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (propKey === STYLE) {
|
|
235
|
+
var lastStyle = lastProps[propKey];
|
|
236
|
+
for (styleName in lastStyle) {
|
|
237
|
+
if (lastStyle.hasOwnProperty(styleName)) {
|
|
238
|
+
styleUpdates = styleUpdates || {};
|
|
239
|
+
styleUpdates[styleName] = '';
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} else if (registrationNames[propKey]) {
|
|
243
|
+
deleteListener(this._rootNodeID, propKey);
|
|
244
|
+
} else if (
|
|
245
|
+
DOMProperty.isStandardName[propKey] ||
|
|
246
|
+
DOMProperty.isCustomAttribute(propKey)) {
|
|
247
|
+
ReactComponent.DOMIDOperations.deletePropertyByID(
|
|
248
|
+
this._rootNodeID,
|
|
249
|
+
propKey
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
for (propKey in nextProps) {
|
|
254
|
+
var nextProp = nextProps[propKey];
|
|
255
|
+
var lastProp = lastProps[propKey];
|
|
256
|
+
if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (propKey === STYLE) {
|
|
260
|
+
if (nextProp) {
|
|
261
|
+
nextProp = nextProps.style = merge(nextProp);
|
|
262
|
+
}
|
|
263
|
+
if (lastProp) {
|
|
264
|
+
// Unset styles on `lastProp` but not on `nextProp`.
|
|
265
|
+
for (styleName in lastProp) {
|
|
266
|
+
if (lastProp.hasOwnProperty(styleName) &&
|
|
267
|
+
!nextProp.hasOwnProperty(styleName)) {
|
|
268
|
+
styleUpdates = styleUpdates || {};
|
|
269
|
+
styleUpdates[styleName] = '';
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Update styles that changed since `lastProp`.
|
|
273
|
+
for (styleName in nextProp) {
|
|
274
|
+
if (nextProp.hasOwnProperty(styleName) &&
|
|
275
|
+
lastProp[styleName] !== nextProp[styleName]) {
|
|
276
|
+
styleUpdates = styleUpdates || {};
|
|
277
|
+
styleUpdates[styleName] = nextProp[styleName];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// Relies on `updateStylesByID` not mutating `styleUpdates`.
|
|
282
|
+
styleUpdates = nextProp;
|
|
283
|
+
}
|
|
284
|
+
} else if (registrationNames[propKey]) {
|
|
285
|
+
putListener(this._rootNodeID, propKey, nextProp);
|
|
286
|
+
} else if (
|
|
287
|
+
DOMProperty.isStandardName[propKey] ||
|
|
288
|
+
DOMProperty.isCustomAttribute(propKey)) {
|
|
289
|
+
ReactComponent.DOMIDOperations.updatePropertyByID(
|
|
290
|
+
this._rootNodeID,
|
|
291
|
+
propKey,
|
|
292
|
+
nextProp
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (styleUpdates) {
|
|
297
|
+
ReactComponent.DOMIDOperations.updateStylesByID(
|
|
298
|
+
this._rootNodeID,
|
|
299
|
+
styleUpdates
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Reconciles the children with the various properties that affect the
|
|
306
|
+
* children content.
|
|
307
|
+
*
|
|
308
|
+
* @param {object} lastProps
|
|
309
|
+
* @param {ReactReconcileTransaction} transaction
|
|
310
|
+
*/
|
|
311
|
+
_updateDOMChildren: function(lastProps, transaction) {
|
|
312
|
+
var nextProps = this.props;
|
|
313
|
+
|
|
314
|
+
var lastContent =
|
|
315
|
+
CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
|
|
316
|
+
var nextContent =
|
|
317
|
+
CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
|
|
318
|
+
|
|
319
|
+
var lastHtml =
|
|
320
|
+
lastProps.dangerouslySetInnerHTML &&
|
|
321
|
+
lastProps.dangerouslySetInnerHTML.__html;
|
|
322
|
+
var nextHtml =
|
|
323
|
+
nextProps.dangerouslySetInnerHTML &&
|
|
324
|
+
nextProps.dangerouslySetInnerHTML.__html;
|
|
325
|
+
|
|
326
|
+
// Note the use of `!=` which checks for null or undefined.
|
|
327
|
+
var lastChildren = lastContent != null ? null : lastProps.children;
|
|
328
|
+
var nextChildren = nextContent != null ? null : nextProps.children;
|
|
329
|
+
|
|
330
|
+
// If we're switching from children to content/html or vice versa, remove
|
|
331
|
+
// the old content
|
|
332
|
+
var lastHasContentOrHtml = lastContent != null || lastHtml != null;
|
|
333
|
+
var nextHasContentOrHtml = nextContent != null || nextHtml != null;
|
|
334
|
+
if (lastChildren != null && nextChildren == null) {
|
|
335
|
+
this.updateChildren(null, transaction);
|
|
336
|
+
} else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
|
|
337
|
+
this.updateTextContent('');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (nextContent != null) {
|
|
341
|
+
if (lastContent !== nextContent) {
|
|
342
|
+
this.updateTextContent('' + nextContent);
|
|
343
|
+
}
|
|
344
|
+
} else if (nextHtml != null) {
|
|
345
|
+
if (lastHtml !== nextHtml) {
|
|
346
|
+
ReactComponent.DOMIDOperations.updateInnerHTMLByID(
|
|
347
|
+
this._rootNodeID,
|
|
348
|
+
nextHtml
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
} else if (nextChildren != null) {
|
|
352
|
+
this.updateChildren(nextChildren, transaction);
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Destroys all event registrations for this instance. Does not remove from
|
|
358
|
+
* the DOM. That must be done by the parent.
|
|
359
|
+
*
|
|
360
|
+
* @internal
|
|
361
|
+
*/
|
|
362
|
+
unmountComponent: function() {
|
|
363
|
+
ReactEventEmitter.deleteAllListeners(this._rootNodeID);
|
|
364
|
+
ReactComponent.Mixin.unmountComponent.call(this);
|
|
365
|
+
this.unmountChildren();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
mixInto(ReactDOMComponent, ReactComponent.Mixin);
|
|
371
|
+
mixInto(ReactDOMComponent, ReactDOMComponent.Mixin);
|
|
372
|
+
mixInto(ReactDOMComponent, ReactMultiChild.Mixin);
|
|
373
|
+
|
|
374
|
+
module.exports = ReactDOMComponent;
|