react 0.6.3 → 0.9.0-rc1

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.
Files changed (218) hide show
  1. package/README.md +10 -222
  2. package/addons.js +1 -0
  3. package/lib/AutoFocusMixin.js +30 -0
  4. package/lib/CSSCore.js +115 -0
  5. package/lib/CSSProperty.js +121 -0
  6. package/lib/CSSPropertyOperations.js +97 -0
  7. package/lib/ChangeEventPlugin.js +387 -0
  8. package/lib/ClientReactRootIndex.js +30 -0
  9. package/lib/CompositionEventPlugin.js +260 -0
  10. package/lib/DOMChildrenOperations.js +165 -0
  11. package/lib/DOMProperty.js +268 -0
  12. package/lib/DOMPropertyOperations.js +181 -0
  13. package/lib/Danger.js +187 -0
  14. package/lib/DefaultDOMPropertyConfig.js +197 -0
  15. package/lib/DefaultEventPluginOrder.js +44 -0
  16. package/lib/EnterLeaveEventPlugin.js +145 -0
  17. package/lib/EventConstants.js +76 -0
  18. package/lib/EventListener.js +69 -0
  19. package/lib/EventPluginHub.js +291 -0
  20. package/lib/EventPluginRegistry.js +260 -0
  21. package/lib/EventPluginUtils.js +214 -0
  22. package/lib/EventPropagators.js +143 -0
  23. package/lib/ExecutionEnvironment.js +44 -0
  24. package/lib/LinkedStateMixin.js +46 -0
  25. package/lib/LinkedValueUtils.js +161 -0
  26. package/lib/MobileSafariClickEventPlugin.js +63 -0
  27. package/lib/PooledClass.js +119 -0
  28. package/lib/React.js +95 -0
  29. package/lib/ReactCSSTransitionGroup.js +65 -0
  30. package/lib/ReactCSSTransitionGroupChild.js +138 -0
  31. package/lib/ReactChildren.js +132 -0
  32. package/lib/ReactComponent.js +550 -0
  33. package/lib/ReactComponentBrowserEnvironment.js +158 -0
  34. package/lib/ReactComponentEnvironment.js +26 -0
  35. package/lib/ReactCompositeComponent.js +1455 -0
  36. package/lib/ReactContext.js +67 -0
  37. package/lib/ReactCurrentOwner.js +39 -0
  38. package/lib/ReactDOM.js +207 -0
  39. package/lib/ReactDOMButton.js +68 -0
  40. package/lib/ReactDOMComponent.js +399 -0
  41. package/lib/ReactDOMForm.js +59 -0
  42. package/lib/ReactDOMIDOperations.js +218 -0
  43. package/lib/ReactDOMImg.js +58 -0
  44. package/lib/ReactDOMInput.js +181 -0
  45. package/lib/ReactDOMOption.js +51 -0
  46. package/lib/ReactDOMSelect.js +179 -0
  47. package/lib/ReactDOMSelection.js +189 -0
  48. package/lib/ReactDOMTextarea.js +140 -0
  49. package/lib/ReactDefaultBatchingStrategy.js +75 -0
  50. package/lib/ReactDefaultInjection.js +115 -0
  51. package/lib/ReactDefaultPerf.js +244 -0
  52. package/lib/ReactDefaultPerfAnalysis.js +199 -0
  53. package/lib/ReactErrorUtils.js +37 -0
  54. package/lib/ReactEventEmitter.js +337 -0
  55. package/lib/ReactEventEmitterMixin.js +57 -0
  56. package/lib/ReactEventTopLevelCallback.js +109 -0
  57. package/lib/ReactInjection.js +39 -0
  58. package/lib/ReactInputSelection.js +140 -0
  59. package/lib/ReactInstanceHandles.js +338 -0
  60. package/lib/ReactLink.js +54 -0
  61. package/lib/ReactMarkupChecksum.js +53 -0
  62. package/lib/ReactMount.js +641 -0
  63. package/lib/ReactMountReady.js +95 -0
  64. package/lib/ReactMultiChild.js +425 -0
  65. package/lib/ReactMultiChildUpdateTypes.js +38 -0
  66. package/lib/ReactOwner.js +154 -0
  67. package/lib/ReactPerf.js +85 -0
  68. package/lib/ReactPropTransferer.js +147 -0
  69. package/lib/ReactPropTypeLocationNames.js +31 -0
  70. package/lib/ReactPropTypeLocations.js +29 -0
  71. package/lib/ReactPropTypes.js +359 -0
  72. package/lib/ReactPutListenerQueue.js +61 -0
  73. package/lib/ReactReconcileTransaction.js +181 -0
  74. package/lib/ReactRootIndex.js +36 -0
  75. package/lib/ReactServerRendering.js +59 -0
  76. package/lib/ReactStateSetters.js +111 -0
  77. package/lib/ReactTextComponent.js +99 -0
  78. package/lib/ReactTransitionChildMapping.js +106 -0
  79. package/lib/ReactTransitionEvents.js +97 -0
  80. package/lib/ReactTransitionGroup.js +187 -0
  81. package/lib/ReactUpdates.js +148 -0
  82. package/lib/ReactWithAddons.js +46 -0
  83. package/lib/SelectEventPlugin.js +200 -0
  84. package/lib/ServerReactRootIndex.js +36 -0
  85. package/lib/SimpleEventPlugin.js +413 -0
  86. package/lib/SyntheticClipboardEvent.js +51 -0
  87. package/lib/SyntheticCompositionEvent.js +51 -0
  88. package/lib/SyntheticDragEvent.js +44 -0
  89. package/lib/SyntheticEvent.js +164 -0
  90. package/lib/SyntheticFocusEvent.js +44 -0
  91. package/lib/SyntheticKeyboardEvent.js +58 -0
  92. package/lib/SyntheticMouseEvent.js +85 -0
  93. package/lib/SyntheticTouchEvent.js +50 -0
  94. package/lib/SyntheticUIEvent.js +45 -0
  95. package/lib/SyntheticWheelEvent.js +66 -0
  96. package/lib/Transaction.js +276 -0
  97. package/lib/ViewportMetrics.js +37 -0
  98. package/lib/accumulate.js +54 -0
  99. package/lib/adler32.js +39 -0
  100. package/lib/cloneWithProps.js +59 -0
  101. package/lib/containsNode.js +49 -0
  102. package/lib/copyProperties.js +54 -0
  103. package/lib/createArrayFrom.js +91 -0
  104. package/lib/createFullPageComponent.js +63 -0
  105. package/lib/createNodesFromMarkup.js +93 -0
  106. package/lib/createObjectFrom.js +61 -0
  107. package/lib/cx.js +44 -0
  108. package/lib/dangerousStyleValue.js +57 -0
  109. package/lib/emptyFunction.js +43 -0
  110. package/lib/escapeTextForBrowser.js +47 -0
  111. package/lib/flattenChildren.js +57 -0
  112. package/lib/forEachAccumulated.js +36 -0
  113. package/lib/getActiveElement.js +34 -0
  114. package/lib/getEventKey.js +85 -0
  115. package/lib/getEventTarget.js +36 -0
  116. package/lib/getMarkupWrap.js +118 -0
  117. package/lib/getNodeForCharacterOffset.js +80 -0
  118. package/lib/getReactRootElementInContainer.js +40 -0
  119. package/lib/getTextContentAccessor.js +42 -0
  120. package/lib/getUnboundedScrollPosition.js +45 -0
  121. package/lib/hyphenate.js +35 -0
  122. package/lib/invariant.js +62 -0
  123. package/lib/isEventSupported.js +70 -0
  124. package/lib/isNode.js +33 -0
  125. package/lib/isTextInputElement.js +49 -0
  126. package/lib/isTextNode.js +30 -0
  127. package/lib/joinClasses.js +44 -0
  128. package/lib/keyMirror.js +58 -0
  129. package/lib/keyOf.js +41 -0
  130. package/lib/memoizeStringOnly.js +39 -0
  131. package/lib/merge.js +37 -0
  132. package/lib/mergeHelpers.js +136 -0
  133. package/lib/mergeInto.js +45 -0
  134. package/lib/mixInto.js +34 -0
  135. package/lib/objMap.js +47 -0
  136. package/lib/objMapKeyVal.js +47 -0
  137. package/lib/onlyChild.js +43 -0
  138. package/lib/performanceNow.js +42 -0
  139. package/lib/shallowEqual.js +49 -0
  140. package/lib/shouldUpdateReactComponent.js +58 -0
  141. package/lib/toArray.js +75 -0
  142. package/lib/traverseAllChildren.js +189 -0
  143. package/lib/warning.js +40 -0
  144. package/package.json +32 -21
  145. package/react.js +1 -0
  146. package/.npmignore +0 -7
  147. package/.travis.yml +0 -5
  148. package/Jakefile.js +0 -39
  149. package/LICENSE +0 -19
  150. package/browser-test/dist.html +0 -90
  151. package/browser-test/index.html +0 -86
  152. package/browser-test/min.html +0 -90
  153. package/dist/react.js +0 -3107
  154. package/dist/react.min.js +0 -22
  155. package/doc/advanced.md +0 -174
  156. package/doc/color-def.graffle +0 -938
  157. package/doc/color-def.png +0 -0
  158. package/doc/simple.dot +0 -25
  159. package/doc/simple.png +0 -0
  160. package/examples/longer-example.js +0 -41
  161. package/examples/simple.js +0 -45
  162. package/examples/using-ast-directly.js +0 -30
  163. package/examples/using-events1.js +0 -79
  164. package/examples/using-log-events.js +0 -43
  165. package/lib/base-task.js +0 -123
  166. package/lib/cb-task.js +0 -84
  167. package/lib/core.js +0 -138
  168. package/lib/dsl.js +0 -138
  169. package/lib/error.js +0 -55
  170. package/lib/event-collector.js +0 -81
  171. package/lib/event-manager.js +0 -89
  172. package/lib/eventemitter.js +0 -20
  173. package/lib/finalcb-first-task.js +0 -68
  174. package/lib/finalcb-task.js +0 -65
  175. package/lib/id.js +0 -22
  176. package/lib/input-parser.js +0 -56
  177. package/lib/log-events.js +0 -101
  178. package/lib/parse.js +0 -41
  179. package/lib/promise-resolve.js +0 -50
  180. package/lib/promise-task.js +0 -93
  181. package/lib/react.js +0 -59
  182. package/lib/ret-task.js +0 -71
  183. package/lib/sprintf.js +0 -18
  184. package/lib/status.js +0 -14
  185. package/lib/task.js +0 -251
  186. package/lib/track-tasks.js +0 -74
  187. package/lib/validate.js +0 -159
  188. package/lib/vcon.js +0 -90
  189. package/lib/when-task.js +0 -85
  190. package/src/dist.build.requirejs +0 -20
  191. package/test/ast.mocha.js +0 -136
  192. package/test/cb-task.mocha.js +0 -220
  193. package/test/core-deferred.mocha.js +0 -143
  194. package/test/core-when.mocha.js +0 -96
  195. package/test/core.mocha.js +0 -589
  196. package/test/dsl.mocha.js +0 -350
  197. package/test/event-manager.mocha.js +0 -119
  198. package/test/exec-options.mocha.js +0 -48
  199. package/test/finalcb-task.mocha.js +0 -58
  200. package/test/input-parser.mocha.js +0 -86
  201. package/test/log-events.mocha.js +0 -88
  202. package/test/mocha.opts +0 -2
  203. package/test/module-use.mocha.js +0 -147
  204. package/test/promise-auto-resolve.mocha.js +0 -68
  205. package/test/ret-task.mocha.js +0 -220
  206. package/test/task.mocha.js +0 -42
  207. package/test/validate-cb-task.mocha.js +0 -100
  208. package/test/validate-ret-task.mocha.js +0 -110
  209. package/test/validate.mocha.js +0 -324
  210. package/test/vcon.mocha.js +0 -193
  211. package/vendor/chai/chai.js +0 -2038
  212. package/vendor/jquery/jquery-1.7.1.js +0 -9266
  213. package/vendor/jquery/jquery-1.7.1.min.js +0 -4
  214. package/vendor/mocha/mocha.css +0 -135
  215. package/vendor/mocha/mocha.js +0 -3589
  216. package/vendor/node/util.js +0 -531
  217. package/vendor/requirejs/require.js +0 -2053
  218. package/vendor/requirejs/require.min.js +0 -33
@@ -0,0 +1,67 @@
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 ReactContext
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var merge = require("./merge");
22
+
23
+ /**
24
+ * Keeps track of the current context.
25
+ *
26
+ * The context is automatically passed down the component ownership hierarchy
27
+ * and is accessible via `this.context` on ReactCompositeComponents.
28
+ */
29
+ var ReactContext = {
30
+
31
+ /**
32
+ * @internal
33
+ * @type {object}
34
+ */
35
+ current: {},
36
+
37
+ /**
38
+ * Temporarily extends the current context while executing scopedCallback.
39
+ *
40
+ * A typical use case might look like
41
+ *
42
+ * render: function() {
43
+ * var children = ReactContext.withContext({foo: 'foo'} () => (
44
+ *
45
+ * ));
46
+ * return <div>{children}</div>;
47
+ * }
48
+ *
49
+ * @param {object} newContext New context to merge into the existing context
50
+ * @param {function} scopedCallback Callback to run with the new context
51
+ * @return {ReactComponent|array<ReactComponent>}
52
+ */
53
+ withContext: function(newContext, scopedCallback) {
54
+ var result;
55
+ var previousContext = ReactContext.current;
56
+ ReactContext.current = merge(previousContext, newContext);
57
+ try {
58
+ result = scopedCallback();
59
+ } finally {
60
+ ReactContext.current = previousContext;
61
+ }
62
+ return result;
63
+ }
64
+
65
+ };
66
+
67
+ module.exports = ReactContext;
@@ -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;
@@ -0,0 +1,207 @@
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
+
54
+ // Expose the constructor on the ConvenienceConstructor and prototype so that
55
+ // it can be easily easily accessed on descriptors.
56
+ // E.g. <div />.type === div.type
57
+ ConvenienceConstructor.type = Constructor;
58
+ Constructor.prototype.type = Constructor;
59
+
60
+ Constructor.ConvenienceConstructor = ConvenienceConstructor;
61
+ ConvenienceConstructor.componentConstructor = Constructor;
62
+ return ConvenienceConstructor;
63
+ }
64
+
65
+ /**
66
+ * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
67
+ * This is also accessible via `React.DOM`.
68
+ *
69
+ * @public
70
+ */
71
+ var ReactDOM = objMapKeyVal({
72
+ a: false,
73
+ abbr: false,
74
+ address: false,
75
+ area: false,
76
+ article: false,
77
+ aside: false,
78
+ audio: false,
79
+ b: false,
80
+ base: false,
81
+ bdi: false,
82
+ bdo: false,
83
+ big: false,
84
+ blockquote: false,
85
+ body: false,
86
+ br: true,
87
+ button: false,
88
+ canvas: false,
89
+ caption: false,
90
+ cite: false,
91
+ code: false,
92
+ col: true,
93
+ colgroup: false,
94
+ data: false,
95
+ datalist: false,
96
+ dd: false,
97
+ del: false,
98
+ details: false,
99
+ dfn: false,
100
+ div: false,
101
+ dl: false,
102
+ dt: false,
103
+ em: false,
104
+ embed: true,
105
+ fieldset: false,
106
+ figcaption: false,
107
+ figure: false,
108
+ footer: false,
109
+ form: false, // NOTE: Injected, see `ReactDOMForm`.
110
+ h1: false,
111
+ h2: false,
112
+ h3: false,
113
+ h4: false,
114
+ h5: false,
115
+ h6: false,
116
+ head: false,
117
+ header: false,
118
+ hr: true,
119
+ html: false,
120
+ i: false,
121
+ iframe: false,
122
+ img: true,
123
+ input: true,
124
+ ins: false,
125
+ kbd: false,
126
+ keygen: true,
127
+ label: false,
128
+ legend: false,
129
+ li: false,
130
+ link: false,
131
+ main: false,
132
+ map: false,
133
+ mark: false,
134
+ menu: false,
135
+ menuitem: false, // NOTE: Close tag should be omitted, but causes problems.
136
+ meta: true,
137
+ meter: false,
138
+ nav: false,
139
+ noscript: false,
140
+ object: false,
141
+ ol: false,
142
+ optgroup: false,
143
+ option: false,
144
+ output: false,
145
+ p: false,
146
+ param: true,
147
+ pre: false,
148
+ progress: false,
149
+ q: false,
150
+ rp: false,
151
+ rt: false,
152
+ ruby: false,
153
+ s: false,
154
+ samp: false,
155
+ script: false,
156
+ section: false,
157
+ select: false,
158
+ small: false,
159
+ source: false,
160
+ span: false,
161
+ strong: false,
162
+ style: false,
163
+ sub: false,
164
+ summary: false,
165
+ sup: false,
166
+ table: false,
167
+ tbody: false,
168
+ td: false,
169
+ textarea: false, // NOTE: Injected, see `ReactDOMTextarea`.
170
+ tfoot: false,
171
+ th: false,
172
+ thead: false,
173
+ time: false,
174
+ title: false,
175
+ tr: false,
176
+ track: true,
177
+ u: false,
178
+ ul: false,
179
+ 'var': false,
180
+ video: false,
181
+ wbr: false,
182
+
183
+ // SVG
184
+ circle: false,
185
+ defs: false,
186
+ g: false,
187
+ line: false,
188
+ linearGradient: false,
189
+ path: false,
190
+ polygon: false,
191
+ polyline: false,
192
+ radialGradient: false,
193
+ rect: false,
194
+ stop: false,
195
+ svg: false,
196
+ text: false
197
+ }, createDOMComponentClass);
198
+
199
+ var injection = {
200
+ injectComponentClasses: function(componentClasses) {
201
+ mergeInto(ReactDOM, componentClasses);
202
+ }
203
+ };
204
+
205
+ ReactDOM.injection = injection;
206
+
207
+ module.exports = ReactDOM;
@@ -0,0 +1,68 @@
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 AutoFocusMixin = require("./AutoFocusMixin");
22
+ var ReactCompositeComponent = require("./ReactCompositeComponent");
23
+ var ReactDOM = require("./ReactDOM");
24
+
25
+ var keyMirror = require("./keyMirror");
26
+
27
+ // Store a reference to the <button> `ReactDOMComponent`.
28
+ var button = ReactDOM.button;
29
+
30
+ var mouseListenerNames = keyMirror({
31
+ onClick: true,
32
+ onDoubleClick: true,
33
+ onMouseDown: true,
34
+ onMouseMove: true,
35
+ onMouseUp: true,
36
+ onClickCapture: true,
37
+ onDoubleClickCapture: true,
38
+ onMouseDownCapture: true,
39
+ onMouseMoveCapture: true,
40
+ onMouseUpCapture: true
41
+ });
42
+
43
+ /**
44
+ * Implements a <button> native component that does not receive mouse events
45
+ * when `disabled` is set.
46
+ */
47
+ var ReactDOMButton = ReactCompositeComponent.createClass({
48
+ displayName: 'ReactDOMButton',
49
+
50
+ mixins: [AutoFocusMixin],
51
+
52
+ render: function() {
53
+ var props = {};
54
+
55
+ // Copy the props; except the mouse listeners if we're disabled
56
+ for (var key in this.props) {
57
+ if (this.props.hasOwnProperty(key) &&
58
+ (!this.props.disabled || !mouseListenerNames[key])) {
59
+ props[key] = this.props[key];
60
+ }
61
+ }
62
+
63
+ return button(props, this.props.children);
64
+ }
65
+
66
+ });
67
+
68
+ module.exports = ReactDOMButton;
@@ -0,0 +1,399 @@
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 ReactMount = require("./ReactMount");
28
+ var ReactMultiChild = require("./ReactMultiChild");
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 deleteListener = ReactEventEmitter.deleteListener;
38
+ var listenTo = ReactEventEmitter.listenTo;
39
+ var registrationNameModules = ReactEventEmitter.registrationNameModules;
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
+ var ELEMENT_NODE_TYPE = 1;
47
+
48
+ /**
49
+ * @param {?object} props
50
+ */
51
+ function assertValidProps(props) {
52
+ if (!props) {
53
+ return;
54
+ }
55
+ // Note the use of `==` which checks for null or undefined.
56
+ ("production" !== process.env.NODE_ENV ? invariant(
57
+ props.children == null || props.dangerouslySetInnerHTML == null,
58
+ 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
59
+ ) : invariant(props.children == null || props.dangerouslySetInnerHTML == null));
60
+ ("production" !== process.env.NODE_ENV ? invariant(
61
+ props.style == null || typeof props.style === 'object',
62
+ 'The `style` prop expects a mapping from style properties to values, ' +
63
+ 'not a string.'
64
+ ) : invariant(props.style == null || typeof props.style === 'object'));
65
+ }
66
+
67
+ function putListener(id, registrationName, listener, transaction) {
68
+ var container = ReactMount.findReactContainerForID(id);
69
+ if (container) {
70
+ var doc = container.nodeType === ELEMENT_NODE_TYPE ?
71
+ container.ownerDocument :
72
+ container;
73
+ listenTo(registrationName, doc);
74
+ }
75
+ transaction.getPutListenerQueue().enqueuePutListener(
76
+ id,
77
+ registrationName,
78
+ listener
79
+ );
80
+ }
81
+
82
+
83
+ /**
84
+ * @constructor ReactDOMComponent
85
+ * @extends ReactComponent
86
+ * @extends ReactMultiChild
87
+ */
88
+ function ReactDOMComponent(tag, omitClose) {
89
+ this._tagOpen = '<' + tag;
90
+ this._tagClose = omitClose ? '' : '</' + tag + '>';
91
+ this.tagName = tag.toUpperCase();
92
+ }
93
+
94
+ ReactDOMComponent.Mixin = {
95
+
96
+ /**
97
+ * Generates root tag markup then recurses. This method has side effects and
98
+ * is not idempotent.
99
+ *
100
+ * @internal
101
+ * @param {string} rootID The root DOM ID for this node.
102
+ * @param {ReactReconcileTransaction} transaction
103
+ * @param {number} mountDepth number of components in the owner hierarchy
104
+ * @return {string} The computed markup.
105
+ */
106
+ mountComponent: ReactPerf.measure(
107
+ 'ReactDOMComponent',
108
+ 'mountComponent',
109
+ function(rootID, transaction, mountDepth) {
110
+ ReactComponent.Mixin.mountComponent.call(
111
+ this,
112
+ rootID,
113
+ transaction,
114
+ mountDepth
115
+ );
116
+ assertValidProps(this.props);
117
+ return (
118
+ this._createOpenTagMarkupAndPutListeners(transaction) +
119
+ this._createContentMarkup(transaction) +
120
+ this._tagClose
121
+ );
122
+ }
123
+ ),
124
+
125
+ /**
126
+ * Creates markup for the open tag and all attributes.
127
+ *
128
+ * This method has side effects because events get registered.
129
+ *
130
+ * Iterating over object properties is faster than iterating over arrays.
131
+ * @see http://jsperf.com/obj-vs-arr-iteration
132
+ *
133
+ * @private
134
+ * @param {ReactReconcileTransaction} transaction
135
+ * @return {string} Markup of opening tag.
136
+ */
137
+ _createOpenTagMarkupAndPutListeners: function(transaction) {
138
+ var props = this.props;
139
+ var ret = this._tagOpen;
140
+
141
+ for (var propKey in props) {
142
+ if (!props.hasOwnProperty(propKey)) {
143
+ continue;
144
+ }
145
+ var propValue = props[propKey];
146
+ if (propValue == null) {
147
+ continue;
148
+ }
149
+ if (registrationNameModules[propKey]) {
150
+ putListener(this._rootNodeID, propKey, propValue, transaction);
151
+ } else {
152
+ if (propKey === STYLE) {
153
+ if (propValue) {
154
+ propValue = props.style = merge(props.style);
155
+ }
156
+ propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
157
+ }
158
+ var markup =
159
+ DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
160
+ if (markup) {
161
+ ret += ' ' + markup;
162
+ }
163
+ }
164
+ }
165
+
166
+ var idMarkup = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
167
+ return ret + ' ' + idMarkup + '>';
168
+ },
169
+
170
+ /**
171
+ * Creates markup for the content between the tags.
172
+ *
173
+ * @private
174
+ * @param {ReactReconcileTransaction} transaction
175
+ * @return {string} Content markup.
176
+ */
177
+ _createContentMarkup: function(transaction) {
178
+ // Intentional use of != to avoid catching zero/false.
179
+ var innerHTML = this.props.dangerouslySetInnerHTML;
180
+ if (innerHTML != null) {
181
+ if (innerHTML.__html != null) {
182
+ return innerHTML.__html;
183
+ }
184
+ } else {
185
+ var contentToUse =
186
+ CONTENT_TYPES[typeof this.props.children] ? this.props.children : null;
187
+ var childrenToUse = contentToUse != null ? null : this.props.children;
188
+ if (contentToUse != null) {
189
+ return escapeTextForBrowser(contentToUse);
190
+ } else if (childrenToUse != null) {
191
+ var mountImages = this.mountChildren(
192
+ childrenToUse,
193
+ transaction
194
+ );
195
+ return mountImages.join('');
196
+ }
197
+ }
198
+ return '';
199
+ },
200
+
201
+ receiveComponent: function(nextComponent, transaction) {
202
+ assertValidProps(nextComponent.props);
203
+ ReactComponent.Mixin.receiveComponent.call(
204
+ this,
205
+ nextComponent,
206
+ transaction
207
+ );
208
+ },
209
+
210
+ /**
211
+ * Updates a native DOM component after it has already been allocated and
212
+ * attached to the DOM. Reconciles the root DOM node, then recurses.
213
+ *
214
+ * @param {ReactReconcileTransaction} transaction
215
+ * @param {object} prevProps
216
+ * @internal
217
+ * @overridable
218
+ */
219
+ updateComponent: ReactPerf.measure(
220
+ 'ReactDOMComponent',
221
+ 'updateComponent',
222
+ function(transaction, prevProps, prevOwner) {
223
+ ReactComponent.Mixin.updateComponent.call(
224
+ this,
225
+ transaction,
226
+ prevProps,
227
+ prevOwner
228
+ );
229
+ this._updateDOMProperties(prevProps, transaction);
230
+ this._updateDOMChildren(prevProps, transaction);
231
+ }
232
+ ),
233
+
234
+ /**
235
+ * Reconciles the properties by detecting differences in property values and
236
+ * updating the DOM as necessary. This function is probably the single most
237
+ * critical path for performance optimization.
238
+ *
239
+ * TODO: Benchmark whether checking for changed values in memory actually
240
+ * improves performance (especially statically positioned elements).
241
+ * TODO: Benchmark the effects of putting this at the top since 99% of props
242
+ * do not change for a given reconciliation.
243
+ * TODO: Benchmark areas that can be improved with caching.
244
+ *
245
+ * @private
246
+ * @param {object} lastProps
247
+ * @param {ReactReconcileTransaction} transaction
248
+ */
249
+ _updateDOMProperties: function(lastProps, transaction) {
250
+ var nextProps = this.props;
251
+ var propKey;
252
+ var styleName;
253
+ var styleUpdates;
254
+ for (propKey in lastProps) {
255
+ if (nextProps.hasOwnProperty(propKey) ||
256
+ !lastProps.hasOwnProperty(propKey)) {
257
+ continue;
258
+ }
259
+ if (propKey === STYLE) {
260
+ var lastStyle = lastProps[propKey];
261
+ for (styleName in lastStyle) {
262
+ if (lastStyle.hasOwnProperty(styleName)) {
263
+ styleUpdates = styleUpdates || {};
264
+ styleUpdates[styleName] = '';
265
+ }
266
+ }
267
+ } else if (registrationNameModules[propKey]) {
268
+ deleteListener(this._rootNodeID, propKey);
269
+ } else if (
270
+ DOMProperty.isStandardName[propKey] ||
271
+ DOMProperty.isCustomAttribute(propKey)) {
272
+ ReactComponent.BackendIDOperations.deletePropertyByID(
273
+ this._rootNodeID,
274
+ propKey
275
+ );
276
+ }
277
+ }
278
+ for (propKey in nextProps) {
279
+ var nextProp = nextProps[propKey];
280
+ var lastProp = lastProps[propKey];
281
+ if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
282
+ continue;
283
+ }
284
+ if (propKey === STYLE) {
285
+ if (nextProp) {
286
+ nextProp = nextProps.style = merge(nextProp);
287
+ }
288
+ if (lastProp) {
289
+ // Unset styles on `lastProp` but not on `nextProp`.
290
+ for (styleName in lastProp) {
291
+ if (lastProp.hasOwnProperty(styleName) &&
292
+ !nextProp.hasOwnProperty(styleName)) {
293
+ styleUpdates = styleUpdates || {};
294
+ styleUpdates[styleName] = '';
295
+ }
296
+ }
297
+ // Update styles that changed since `lastProp`.
298
+ for (styleName in nextProp) {
299
+ if (nextProp.hasOwnProperty(styleName) &&
300
+ lastProp[styleName] !== nextProp[styleName]) {
301
+ styleUpdates = styleUpdates || {};
302
+ styleUpdates[styleName] = nextProp[styleName];
303
+ }
304
+ }
305
+ } else {
306
+ // Relies on `updateStylesByID` not mutating `styleUpdates`.
307
+ styleUpdates = nextProp;
308
+ }
309
+ } else if (registrationNameModules[propKey]) {
310
+ putListener(this._rootNodeID, propKey, nextProp, transaction);
311
+ } else if (
312
+ DOMProperty.isStandardName[propKey] ||
313
+ DOMProperty.isCustomAttribute(propKey)) {
314
+ ReactComponent.BackendIDOperations.updatePropertyByID(
315
+ this._rootNodeID,
316
+ propKey,
317
+ nextProp
318
+ );
319
+ }
320
+ }
321
+ if (styleUpdates) {
322
+ ReactComponent.BackendIDOperations.updateStylesByID(
323
+ this._rootNodeID,
324
+ styleUpdates
325
+ );
326
+ }
327
+ },
328
+
329
+ /**
330
+ * Reconciles the children with the various properties that affect the
331
+ * children content.
332
+ *
333
+ * @param {object} lastProps
334
+ * @param {ReactReconcileTransaction} transaction
335
+ */
336
+ _updateDOMChildren: function(lastProps, transaction) {
337
+ var nextProps = this.props;
338
+
339
+ var lastContent =
340
+ CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
341
+ var nextContent =
342
+ CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
343
+
344
+ var lastHtml =
345
+ lastProps.dangerouslySetInnerHTML &&
346
+ lastProps.dangerouslySetInnerHTML.__html;
347
+ var nextHtml =
348
+ nextProps.dangerouslySetInnerHTML &&
349
+ nextProps.dangerouslySetInnerHTML.__html;
350
+
351
+ // Note the use of `!=` which checks for null or undefined.
352
+ var lastChildren = lastContent != null ? null : lastProps.children;
353
+ var nextChildren = nextContent != null ? null : nextProps.children;
354
+
355
+ // If we're switching from children to content/html or vice versa, remove
356
+ // the old content
357
+ var lastHasContentOrHtml = lastContent != null || lastHtml != null;
358
+ var nextHasContentOrHtml = nextContent != null || nextHtml != null;
359
+ if (lastChildren != null && nextChildren == null) {
360
+ this.updateChildren(null, transaction);
361
+ } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
362
+ this.updateTextContent('');
363
+ }
364
+
365
+ if (nextContent != null) {
366
+ if (lastContent !== nextContent) {
367
+ this.updateTextContent('' + nextContent);
368
+ }
369
+ } else if (nextHtml != null) {
370
+ if (lastHtml !== nextHtml) {
371
+ ReactComponent.BackendIDOperations.updateInnerHTMLByID(
372
+ this._rootNodeID,
373
+ nextHtml
374
+ );
375
+ }
376
+ } else if (nextChildren != null) {
377
+ this.updateChildren(nextChildren, transaction);
378
+ }
379
+ },
380
+
381
+ /**
382
+ * Destroys all event registrations for this instance. Does not remove from
383
+ * the DOM. That must be done by the parent.
384
+ *
385
+ * @internal
386
+ */
387
+ unmountComponent: function() {
388
+ this.unmountChildren();
389
+ ReactEventEmitter.deleteAllListeners(this._rootNodeID);
390
+ ReactComponent.Mixin.unmountComponent.call(this);
391
+ }
392
+
393
+ };
394
+
395
+ mixInto(ReactDOMComponent, ReactComponent.Mixin);
396
+ mixInto(ReactDOMComponent, ReactDOMComponent.Mixin);
397
+ mixInto(ReactDOMComponent, ReactMultiChild.Mixin);
398
+
399
+ module.exports = ReactDOMComponent;