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,75 @@
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 ReactDefaultBatchingStrategy
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var ReactUpdates = require("./ReactUpdates");
22
+ var Transaction = require("./Transaction");
23
+
24
+ var emptyFunction = require("./emptyFunction");
25
+ var mixInto = require("./mixInto");
26
+
27
+ var RESET_BATCHED_UPDATES = {
28
+ initialize: emptyFunction,
29
+ close: function() {
30
+ ReactDefaultBatchingStrategy.isBatchingUpdates = false;
31
+ }
32
+ };
33
+
34
+ var FLUSH_BATCHED_UPDATES = {
35
+ initialize: emptyFunction,
36
+ close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
37
+ };
38
+
39
+ var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
40
+
41
+ function ReactDefaultBatchingStrategyTransaction() {
42
+ this.reinitializeTransaction();
43
+ }
44
+
45
+ mixInto(ReactDefaultBatchingStrategyTransaction, Transaction.Mixin);
46
+ mixInto(ReactDefaultBatchingStrategyTransaction, {
47
+ getTransactionWrappers: function() {
48
+ return TRANSACTION_WRAPPERS;
49
+ }
50
+ });
51
+
52
+ var transaction = new ReactDefaultBatchingStrategyTransaction();
53
+
54
+ var ReactDefaultBatchingStrategy = {
55
+ isBatchingUpdates: false,
56
+
57
+ /**
58
+ * Call the provided function in a context within which calls to `setState`
59
+ * and friends are batched such that components aren't updated unnecessarily.
60
+ */
61
+ batchedUpdates: function(callback, param) {
62
+ var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
63
+
64
+ ReactDefaultBatchingStrategy.isBatchingUpdates = true;
65
+
66
+ // The code is written this way to avoid extra allocations
67
+ if (alreadyBatchingUpdates) {
68
+ callback(param);
69
+ } else {
70
+ transaction.perform(callback, null, param);
71
+ }
72
+ }
73
+ };
74
+
75
+ module.exports = ReactDefaultBatchingStrategy;
@@ -0,0 +1,115 @@
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 ReactDefaultInjection
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var ReactInjection = require("./ReactInjection");
22
+
23
+ var ExecutionEnvironment = require("./ExecutionEnvironment");
24
+
25
+ var DefaultDOMPropertyConfig = require("./DefaultDOMPropertyConfig");
26
+
27
+ var ChangeEventPlugin = require("./ChangeEventPlugin");
28
+ var ClientReactRootIndex = require("./ClientReactRootIndex");
29
+ var CompositionEventPlugin = require("./CompositionEventPlugin");
30
+ var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
31
+ var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
32
+ var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin");
33
+ var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback");
34
+ var ReactDOM = require("./ReactDOM");
35
+ var ReactDOMButton = require("./ReactDOMButton");
36
+ var ReactDOMForm = require("./ReactDOMForm");
37
+ var ReactDOMImg = require("./ReactDOMImg");
38
+ var ReactDOMInput = require("./ReactDOMInput");
39
+ var ReactDOMOption = require("./ReactDOMOption");
40
+ var ReactDOMSelect = require("./ReactDOMSelect");
41
+ var ReactDOMTextarea = require("./ReactDOMTextarea");
42
+ var ReactInstanceHandles = require("./ReactInstanceHandles");
43
+ var ReactMount = require("./ReactMount");
44
+ var SelectEventPlugin = require("./SelectEventPlugin");
45
+ var ServerReactRootIndex = require("./ServerReactRootIndex");
46
+ var SimpleEventPlugin = require("./SimpleEventPlugin");
47
+
48
+ var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy");
49
+
50
+ var createFullPageComponent = require("./createFullPageComponent");
51
+
52
+ function inject() {
53
+ ReactInjection.EventEmitter.injectTopLevelCallbackCreator(
54
+ ReactEventTopLevelCallback
55
+ );
56
+
57
+ /**
58
+ * Inject modules for resolving DOM hierarchy and plugin ordering.
59
+ */
60
+ ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
61
+ ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
62
+ ReactInjection.EventPluginHub.injectMount(ReactMount);
63
+
64
+ /**
65
+ * Some important event plugins included by default (without having to require
66
+ * them).
67
+ */
68
+ ReactInjection.EventPluginHub.injectEventPluginsByName({
69
+ SimpleEventPlugin: SimpleEventPlugin,
70
+ EnterLeaveEventPlugin: EnterLeaveEventPlugin,
71
+ ChangeEventPlugin: ChangeEventPlugin,
72
+ CompositionEventPlugin: CompositionEventPlugin,
73
+ MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
74
+ SelectEventPlugin: SelectEventPlugin
75
+ });
76
+
77
+ ReactInjection.DOM.injectComponentClasses({
78
+ button: ReactDOMButton,
79
+ form: ReactDOMForm,
80
+ img: ReactDOMImg,
81
+ input: ReactDOMInput,
82
+ option: ReactDOMOption,
83
+ select: ReactDOMSelect,
84
+ textarea: ReactDOMTextarea,
85
+
86
+ html: createFullPageComponent(ReactDOM.html),
87
+ head: createFullPageComponent(ReactDOM.head),
88
+ title: createFullPageComponent(ReactDOM.title),
89
+ body: createFullPageComponent(ReactDOM.body)
90
+ });
91
+
92
+ ReactInjection.DOMProperty.injectDOMPropertyConfig(DefaultDOMPropertyConfig);
93
+
94
+ ReactInjection.Updates.injectBatchingStrategy(
95
+ ReactDefaultBatchingStrategy
96
+ );
97
+
98
+ ReactInjection.RootIndex.injectCreateReactRootIndex(
99
+ ExecutionEnvironment.canUseDOM ?
100
+ ClientReactRootIndex.createReactRootIndex :
101
+ ServerReactRootIndex.createReactRootIndex
102
+ );
103
+
104
+ if ("production" !== process.env.NODE_ENV) {
105
+ var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
106
+ if ((/[?&]react_perf\b/).test(url)) {
107
+ var ReactDefaultPerf = require("./ReactDefaultPerf");
108
+ ReactDefaultPerf.start();
109
+ }
110
+ }
111
+ }
112
+
113
+ module.exports = {
114
+ inject: inject
115
+ };
@@ -0,0 +1,244 @@
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 ReactDefaultPerf
17
+ * @typechecks static-only
18
+ */
19
+
20
+ "use strict";
21
+
22
+ var DOMProperty = require("./DOMProperty");
23
+ var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
24
+ var ReactMount = require("./ReactMount");
25
+ var ReactPerf = require("./ReactPerf");
26
+
27
+ var performanceNow = require("./performanceNow");
28
+
29
+ function roundFloat(val) {
30
+ return Math.floor(val * 100) / 100;
31
+ }
32
+
33
+ var ReactDefaultPerf = {
34
+ _allMeasurements: [], // last item in the list is the current one
35
+ _injected: false,
36
+
37
+ start: function() {
38
+ if (!ReactDefaultPerf._injected) {
39
+ ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
40
+ }
41
+
42
+ ReactDefaultPerf._allMeasurements.length = 0;
43
+ ReactPerf.enableMeasure = true;
44
+ },
45
+
46
+ stop: function() {
47
+ ReactPerf.enableMeasure = false;
48
+ },
49
+
50
+ getLastMeasurements: function() {
51
+ return ReactDefaultPerf._allMeasurements;
52
+ },
53
+
54
+ printExclusive: function(measurements) {
55
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
56
+ var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
57
+ console.table(summary.map(function(item) {
58
+ return {
59
+ 'Component class name': item.componentName,
60
+ 'Total inclusive time (ms)': roundFloat(item.inclusive),
61
+ 'Total exclusive time (ms)': roundFloat(item.exclusive),
62
+ 'Exclusive time per instance (ms)': roundFloat(item.exclusive / item.count),
63
+ 'Instances': item.count
64
+ };
65
+ }));
66
+ console.log(
67
+ 'Total time:',
68
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
69
+ );
70
+ },
71
+
72
+ printInclusive: function(measurements) {
73
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
74
+ var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
75
+ console.table(summary.map(function(item) {
76
+ return {
77
+ 'Owner > component': item.componentName,
78
+ 'Inclusive time (ms)': roundFloat(item.time),
79
+ 'Instances': item.count
80
+ };
81
+ }));
82
+ console.log(
83
+ 'Total time:',
84
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
85
+ );
86
+ },
87
+
88
+ printWasted: function(measurements) {
89
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
90
+ var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
91
+ measurements,
92
+ true
93
+ );
94
+ console.table(summary.map(function(item) {
95
+ return {
96
+ 'Owner > component': item.componentName,
97
+ 'Wasted time (ms)': item.time,
98
+ 'Instances': item.count
99
+ };
100
+ }));
101
+ console.log(
102
+ 'Total time:',
103
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
104
+ );
105
+ },
106
+
107
+ printDOM: function(measurements) {
108
+ measurements = measurements || ReactDefaultPerf._allMeasurements;
109
+ var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
110
+ console.table(summary.map(function(item) {
111
+ var result = {};
112
+ result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
113
+ result['type'] = item.type;
114
+ result['args'] = JSON.stringify(item.args);
115
+ return result;
116
+ }));
117
+ console.log(
118
+ 'Total time:',
119
+ ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
120
+ );
121
+ },
122
+
123
+ _recordWrite: function(id, fnName, totalTime, args) {
124
+ // TODO: totalTime isn't that useful since it doesn't count paints/reflows
125
+ var writes =
126
+ ReactDefaultPerf
127
+ ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
128
+ .writes;
129
+ writes[id] = writes[id] || [];
130
+ writes[id].push({
131
+ type: fnName,
132
+ time: totalTime,
133
+ args: args
134
+ });
135
+ },
136
+
137
+ measure: function(moduleName, fnName, func) {
138
+ return function() {var args=Array.prototype.slice.call(arguments,0);
139
+ var totalTime;
140
+ var rv;
141
+ var start;
142
+
143
+ if (fnName === '_renderNewRootComponent' ||
144
+ fnName === 'flushBatchedUpdates') {
145
+ // A "measurement" is a set of metrics recorded for each flush. We want
146
+ // to group the metrics for a given flush together so we can look at the
147
+ // components that rendered and the DOM operations that actually
148
+ // happened to determine the amount of "wasted work" performed.
149
+ ReactDefaultPerf._allMeasurements.push({
150
+ exclusive: {},
151
+ inclusive: {},
152
+ counts: {},
153
+ writes: {},
154
+ displayNames: {},
155
+ totalTime: 0
156
+ });
157
+ start = performanceNow();
158
+ rv = func.apply(this, args);
159
+ ReactDefaultPerf._allMeasurements[
160
+ ReactDefaultPerf._allMeasurements.length - 1
161
+ ].totalTime = performanceNow() - start;
162
+ return rv;
163
+ } else if (moduleName === 'ReactDOMIDOperations' ||
164
+ moduleName === 'ReactComponentBrowserEnvironment') {
165
+ start = performanceNow();
166
+ rv = func.apply(this, args);
167
+ totalTime = performanceNow() - start;
168
+
169
+ if (fnName === 'mountImageIntoNode') {
170
+ var mountID = ReactMount.getID(args[1]);
171
+ ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
172
+ } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
173
+ // special format
174
+ args[0].forEach(function(update) {
175
+ var writeArgs = {};
176
+ if (update.fromIndex !== null) {
177
+ writeArgs.fromIndex = update.fromIndex;
178
+ }
179
+ if (update.toIndex !== null) {
180
+ writeArgs.toIndex = update.toIndex;
181
+ }
182
+ if (update.textContent !== null) {
183
+ writeArgs.textContent = update.textContent;
184
+ }
185
+ if (update.markupIndex !== null) {
186
+ writeArgs.markup = args[1][update.markupIndex];
187
+ }
188
+ ReactDefaultPerf._recordWrite(
189
+ update.parentID,
190
+ update.type,
191
+ totalTime,
192
+ writeArgs
193
+ );
194
+ });
195
+ } else {
196
+ // basic format
197
+ ReactDefaultPerf._recordWrite(
198
+ args[0],
199
+ fnName,
200
+ totalTime,
201
+ Array.prototype.slice.call(args, 1)
202
+ );
203
+ }
204
+ return rv;
205
+ } else if (moduleName === 'ReactCompositeComponent' && (
206
+ fnName === 'mountComponent' ||
207
+ fnName === 'updateComponent' || // TODO: receiveComponent()?
208
+ fnName === '_renderValidatedComponent')) {
209
+
210
+ var rootNodeID = fnName === 'mountComponent' ?
211
+ args[0] :
212
+ this._rootNodeID;
213
+ var isRender = fnName === '_renderValidatedComponent';
214
+ var entry = ReactDefaultPerf._allMeasurements[
215
+ ReactDefaultPerf._allMeasurements.length - 1
216
+ ];
217
+
218
+ if (isRender) {
219
+ entry.counts[rootNodeID] = entry.counts[rootNodeID] || 0;
220
+ entry.counts[rootNodeID] += 1;
221
+ }
222
+
223
+ start = performanceNow();
224
+ rv = func.apply(this, args);
225
+ totalTime = performanceNow() - start;
226
+
227
+ var typeOfLog = isRender ? entry.exclusive : entry.inclusive;
228
+ typeOfLog[rootNodeID] = typeOfLog[rootNodeID] || 0;
229
+ typeOfLog[rootNodeID] += totalTime;
230
+
231
+ entry.displayNames[rootNodeID] = {
232
+ current: this.constructor.displayName,
233
+ owner: this._owner ? this._owner.constructor.displayName : '<root>'
234
+ };
235
+
236
+ return rv;
237
+ } else {
238
+ return func.apply(this, args);
239
+ }
240
+ };
241
+ }
242
+ };
243
+
244
+ module.exports = ReactDefaultPerf;
@@ -0,0 +1,199 @@
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 ReactDefaultPerfAnalysis
17
+ */
18
+
19
+ var merge = require("./merge");
20
+
21
+ // Don't try to save users less than 1.2ms (a number I made up)
22
+ var DONT_CARE_THRESHOLD = 1.2;
23
+ var DOM_OPERATION_TYPES = {
24
+ 'mountImageIntoNode': 'set innerHTML',
25
+ INSERT_MARKUP: 'set innerHTML',
26
+ MOVE_EXISTING: 'move',
27
+ REMOVE_NODE: 'remove',
28
+ TEXT_CONTENT: 'set textContent',
29
+ 'updatePropertyByID': 'update attribute',
30
+ 'deletePropertyByID': 'delete attribute',
31
+ 'updateStylesByID': 'update styles',
32
+ 'updateInnerHTMLByID': 'set innerHTML',
33
+ 'dangerouslyReplaceNodeWithMarkupByID': 'replace'
34
+ };
35
+
36
+ function getTotalTime(measurements) {
37
+ // TODO: return number of DOM ops? could be misleading.
38
+ // TODO: measure dropped frames after reconcile?
39
+ // TODO: log total time of each reconcile and the top-level component
40
+ // class that triggered it.
41
+ var totalTime = 0;
42
+ for (var i = 0; i < measurements.length; i++) {
43
+ var measurement = measurements[i];
44
+ totalTime += measurement.totalTime;
45
+ }
46
+ return totalTime;
47
+ }
48
+
49
+ function getDOMSummary(measurements) {
50
+ var items = [];
51
+ for (var i = 0; i < measurements.length; i++) {
52
+ var measurement = measurements[i];
53
+ var id;
54
+
55
+ for (id in measurement.writes) {
56
+ measurement.writes[id].forEach(function(write) {
57
+ items.push({
58
+ id: id,
59
+ type: DOM_OPERATION_TYPES[write.type] || write.type,
60
+ args: write.args
61
+ });
62
+ });
63
+ }
64
+ }
65
+ return items;
66
+ }
67
+
68
+ function getExclusiveSummary(measurements) {
69
+ var candidates = {};
70
+ var displayName;
71
+
72
+ for (var i = 0; i < measurements.length; i++) {
73
+ var measurement = measurements[i];
74
+ var allIDs = merge(measurement.exclusive, measurement.inclusive);
75
+
76
+ for (var id in allIDs) {
77
+ displayName = measurement.displayNames[id].current;
78
+
79
+ candidates[displayName] = candidates[displayName] || {
80
+ componentName: displayName,
81
+ inclusive: 0,
82
+ exclusive: 0,
83
+ count: 0
84
+ };
85
+ if (measurement.exclusive[id]) {
86
+ candidates[displayName].exclusive += measurement.exclusive[id];
87
+ }
88
+ if (measurement.inclusive[id]) {
89
+ candidates[displayName].inclusive += measurement.inclusive[id];
90
+ }
91
+ if (measurement.counts[id]) {
92
+ candidates[displayName].count += measurement.counts[id];
93
+ }
94
+ }
95
+ }
96
+
97
+ // Now make a sorted array with the results.
98
+ var arr = [];
99
+ for (displayName in candidates) {
100
+ if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
101
+ arr.push(candidates[displayName]);
102
+ }
103
+ }
104
+
105
+ arr.sort(function(a, b) {
106
+ return b.exclusive - a.exclusive;
107
+ });
108
+
109
+ return arr;
110
+ }
111
+
112
+ function getInclusiveSummary(measurements, onlyClean) {
113
+ var candidates = {};
114
+ var inclusiveKey;
115
+
116
+ for (var i = 0; i < measurements.length; i++) {
117
+ var measurement = measurements[i];
118
+ var allIDs = merge(measurement.exclusive, measurement.inclusive);
119
+ var cleanComponents;
120
+
121
+ if (onlyClean) {
122
+ cleanComponents = getUnchangedComponents(measurement);
123
+ }
124
+
125
+ for (var id in allIDs) {
126
+ if (onlyClean && !cleanComponents[id]) {
127
+ continue;
128
+ }
129
+
130
+ var displayName = measurement.displayNames[id];
131
+
132
+ // Inclusive time is not useful for many components without knowing where
133
+ // they are instantiated. So we aggregate inclusive time with both the
134
+ // owner and current displayName as the key.
135
+ inclusiveKey = displayName.owner + ' > ' + displayName.current;
136
+
137
+ candidates[inclusiveKey] = candidates[inclusiveKey] || {
138
+ componentName: inclusiveKey,
139
+ time: 0,
140
+ count: 0
141
+ };
142
+
143
+ if (measurement.inclusive[id]) {
144
+ candidates[inclusiveKey].time += measurement.inclusive[id];
145
+ }
146
+ if (measurement.counts[id]) {
147
+ candidates[inclusiveKey].count += measurement.counts[id];
148
+ }
149
+ }
150
+ }
151
+
152
+ // Now make a sorted array with the results.
153
+ var arr = [];
154
+ for (inclusiveKey in candidates) {
155
+ if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
156
+ arr.push(candidates[inclusiveKey]);
157
+ }
158
+ }
159
+
160
+ arr.sort(function(a, b) {
161
+ return b.time - a.time;
162
+ });
163
+
164
+ return arr;
165
+ }
166
+
167
+ function getUnchangedComponents(measurement) {
168
+ // For a given reconcile, look at which components did not actually
169
+ // render anything to the DOM and return a mapping of their ID to
170
+ // the amount of time it took to render the entire subtree.
171
+ var cleanComponents = {};
172
+ var dirtyLeafIDs = Object.keys(measurement.writes);
173
+ var allIDs = merge(measurement.exclusive, measurement.inclusive);
174
+
175
+ for (var id in allIDs) {
176
+ var isDirty = false;
177
+ // For each component that rendered, see if a component that triggerd
178
+ // a DOM op is in its subtree.
179
+ for (var i = 0; i < dirtyLeafIDs.length; i++) {
180
+ if (dirtyLeafIDs[i].indexOf(id) === 0) {
181
+ isDirty = true;
182
+ break;
183
+ }
184
+ }
185
+ if (!isDirty && measurement.counts[id] > 0) {
186
+ cleanComponents[id] = true;
187
+ }
188
+ }
189
+ return cleanComponents;
190
+ }
191
+
192
+ var ReactDefaultPerfAnalysis = {
193
+ getExclusiveSummary: getExclusiveSummary,
194
+ getInclusiveSummary: getInclusiveSummary,
195
+ getDOMSummary: getDOMSummary,
196
+ getTotalTime: getTotalTime
197
+ };
198
+
199
+ module.exports = ReactDefaultPerfAnalysis;