react 0.8.0 → 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 (107) hide show
  1. package/README.md +0 -8
  2. package/addons.js +0 -3
  3. package/lib/AutoFocusMixin.js +30 -0
  4. package/lib/CSSCore.js +22 -21
  5. package/lib/CSSProperty.js +31 -0
  6. package/lib/ChangeEventPlugin.js +26 -4
  7. package/lib/ClientReactRootIndex.js +30 -0
  8. package/lib/CompositionEventPlugin.js +57 -9
  9. package/lib/DOMChildrenOperations.js +32 -2
  10. package/lib/DOMProperty.js +2 -0
  11. package/lib/DOMPropertyOperations.js +14 -1
  12. package/lib/Danger.js +8 -7
  13. package/lib/DefaultDOMPropertyConfig.js +12 -2
  14. package/lib/EnterLeaveEventPlugin.js +37 -4
  15. package/lib/EventConstants.js +3 -0
  16. package/lib/EventListener.js +42 -34
  17. package/lib/EventPluginHub.js +113 -12
  18. package/lib/EventPluginRegistry.js +39 -16
  19. package/lib/EventPluginUtils.js +32 -3
  20. package/lib/EventPropagators.js +6 -42
  21. package/lib/ExecutionEnvironment.js +3 -0
  22. package/lib/LinkedValueUtils.js +161 -0
  23. package/lib/PooledClass.js +6 -0
  24. package/lib/React.js +27 -3
  25. package/lib/ReactCSSTransitionGroup.js +65 -0
  26. package/lib/{ReactTransitionableChild.js → ReactCSSTransitionGroupChild.js} +21 -35
  27. package/lib/ReactComponent.js +87 -52
  28. package/lib/ReactComponentBrowserEnvironment.js +67 -49
  29. package/lib/ReactComponentEnvironment.js +2 -0
  30. package/lib/ReactCompositeComponent.js +547 -112
  31. package/lib/ReactContext.js +67 -0
  32. package/lib/ReactDOM.js +13 -0
  33. package/lib/ReactDOMButton.js +4 -0
  34. package/lib/ReactDOMComponent.js +46 -21
  35. package/lib/ReactDOMForm.js +9 -2
  36. package/lib/ReactDOMIDOperations.js +105 -60
  37. package/lib/ReactDOMImg.js +58 -0
  38. package/lib/ReactDOMInput.js +26 -14
  39. package/lib/ReactDOMOption.js +1 -0
  40. package/lib/ReactDOMSelect.js +36 -17
  41. package/lib/ReactDOMTextarea.js +12 -8
  42. package/lib/ReactDefaultInjection.js +50 -26
  43. package/lib/ReactDefaultPerf.js +207 -370
  44. package/lib/ReactDefaultPerfAnalysis.js +199 -0
  45. package/lib/ReactErrorUtils.js +5 -14
  46. package/lib/ReactEventEmitter.js +141 -145
  47. package/lib/ReactEventEmitterMixin.js +0 -32
  48. package/lib/ReactEventTopLevelCallback.js +32 -12
  49. package/lib/ReactInjection.js +39 -0
  50. package/lib/ReactInstanceHandles.js +35 -19
  51. package/lib/ReactLink.js +1 -1
  52. package/lib/ReactMount.js +127 -103
  53. package/lib/ReactMountReady.js +1 -1
  54. package/lib/ReactMultiChild.js +30 -46
  55. package/lib/ReactMultiChildUpdateTypes.js +2 -0
  56. package/lib/ReactOwner.js +10 -2
  57. package/lib/ReactPerf.js +5 -8
  58. package/lib/ReactPropTransferer.js +40 -21
  59. package/lib/ReactPropTypeLocationNames.js +31 -0
  60. package/lib/ReactPropTypeLocations.js +29 -0
  61. package/lib/ReactPropTypes.js +248 -47
  62. package/lib/ReactPutListenerQueue.js +61 -0
  63. package/lib/ReactReconcileTransaction.js +20 -0
  64. package/lib/ReactRootIndex.js +36 -0
  65. package/lib/ReactServerRendering.js +8 -11
  66. package/lib/ReactTextComponent.js +8 -3
  67. package/lib/{ReactTransitionKeySet.js → ReactTransitionChildMapping.js} +42 -47
  68. package/lib/ReactTransitionGroup.js +132 -57
  69. package/lib/ReactUpdates.js +14 -11
  70. package/lib/ReactWithAddons.js +7 -2
  71. package/lib/SelectEventPlugin.js +22 -39
  72. package/lib/ServerReactRootIndex.js +36 -0
  73. package/lib/SimpleEventPlugin.js +54 -6
  74. package/lib/SyntheticClipboardEvent.js +7 -1
  75. package/lib/SyntheticDragEvent.js +44 -0
  76. package/lib/SyntheticEvent.js +2 -1
  77. package/lib/SyntheticKeyboardEvent.js +4 -2
  78. package/lib/SyntheticWheelEvent.js +10 -7
  79. package/lib/Transaction.js +61 -36
  80. package/lib/cloneWithProps.js +59 -0
  81. package/lib/createArrayFrom.js +10 -13
  82. package/lib/createFullPageComponent.js +63 -0
  83. package/lib/cx.js +2 -2
  84. package/lib/flattenChildren.js +5 -2
  85. package/lib/getActiveElement.js +4 -3
  86. package/lib/getEventKey.js +85 -0
  87. package/lib/getMarkupWrap.js +10 -0
  88. package/lib/getTextContentAccessor.js +5 -3
  89. package/lib/getUnboundedScrollPosition.js +2 -2
  90. package/lib/invariant.js +12 -4
  91. package/lib/isEventSupported.js +7 -11
  92. package/lib/mergeHelpers.js +5 -6
  93. package/lib/onlyChild.js +43 -0
  94. package/lib/shouldUpdateReactComponent.js +58 -0
  95. package/lib/toArray.js +75 -0
  96. package/lib/traverseAllChildren.js +69 -7
  97. package/lib/warning.js +40 -0
  98. package/package.json +2 -3
  99. package/react.js +0 -3
  100. package/ReactJSErrors.js +0 -40
  101. package/lib/$.js +0 -46
  102. package/lib/CallbackRegistry.js +0 -91
  103. package/lib/LinkedValueMixin.js +0 -68
  104. package/lib/ex.js +0 -49
  105. package/lib/filterAttributes.js +0 -45
  106. package/lib/ge.js +0 -76
  107. package/lib/mutateHTMLNodeWithMarkup.js +0 -100
@@ -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;
package/lib/ReactDOM.js CHANGED
@@ -50,6 +50,14 @@ function createDOMComponentClass(tag, omitClose) {
50
50
  instance.construct.apply(instance, arguments);
51
51
  return instance;
52
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;
53
61
  ConvenienceConstructor.componentConstructor = Constructor;
54
62
  return ConvenienceConstructor;
55
63
  }
@@ -174,11 +182,16 @@ var ReactDOM = objMapKeyVal({
174
182
 
175
183
  // SVG
176
184
  circle: false,
185
+ defs: false,
177
186
  g: false,
178
187
  line: false,
188
+ linearGradient: false,
179
189
  path: false,
190
+ polygon: false,
180
191
  polyline: false,
192
+ radialGradient: false,
181
193
  rect: false,
194
+ stop: false,
182
195
  svg: false,
183
196
  text: false
184
197
  }, createDOMComponentClass);
@@ -18,6 +18,7 @@
18
18
 
19
19
  "use strict";
20
20
 
21
+ var AutoFocusMixin = require("./AutoFocusMixin");
21
22
  var ReactCompositeComponent = require("./ReactCompositeComponent");
22
23
  var ReactDOM = require("./ReactDOM");
23
24
 
@@ -44,6 +45,9 @@ var mouseListenerNames = keyMirror({
44
45
  * when `disabled` is set.
45
46
  */
46
47
  var ReactDOMButton = ReactCompositeComponent.createClass({
48
+ displayName: 'ReactDOMButton',
49
+
50
+ mixins: [AutoFocusMixin],
47
51
 
48
52
  render: function() {
49
53
  var props = {};
@@ -24,8 +24,8 @@ var DOMProperty = require("./DOMProperty");
24
24
  var DOMPropertyOperations = require("./DOMPropertyOperations");
25
25
  var ReactComponent = require("./ReactComponent");
26
26
  var ReactEventEmitter = require("./ReactEventEmitter");
27
- var ReactMultiChild = require("./ReactMultiChild");
28
27
  var ReactMount = require("./ReactMount");
28
+ var ReactMultiChild = require("./ReactMultiChild");
29
29
  var ReactPerf = require("./ReactPerf");
30
30
 
31
31
  var escapeTextForBrowser = require("./escapeTextForBrowser");
@@ -34,15 +34,17 @@ var keyOf = require("./keyOf");
34
34
  var merge = require("./merge");
35
35
  var mixInto = require("./mixInto");
36
36
 
37
- var putListener = ReactEventEmitter.putListener;
38
37
  var deleteListener = ReactEventEmitter.deleteListener;
39
- var registrationNames = ReactEventEmitter.registrationNames;
38
+ var listenTo = ReactEventEmitter.listenTo;
39
+ var registrationNameModules = ReactEventEmitter.registrationNameModules;
40
40
 
41
41
  // For quickly matching children type, to test if can be treated as content.
42
42
  var CONTENT_TYPES = {'string': true, 'number': true};
43
43
 
44
44
  var STYLE = keyOf({style: null});
45
45
 
46
+ var ELEMENT_NODE_TYPE = 1;
47
+
46
48
  /**
47
49
  * @param {?object} props
48
50
  */
@@ -62,6 +64,22 @@ function assertValidProps(props) {
62
64
  ) : invariant(props.style == null || typeof props.style === 'object'));
63
65
  }
64
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
+
65
83
  /**
66
84
  * @constructor ReactDOMComponent
67
85
  * @extends ReactComponent
@@ -97,7 +115,7 @@ ReactDOMComponent.Mixin = {
97
115
  );
98
116
  assertValidProps(this.props);
99
117
  return (
100
- this._createOpenTagMarkup() +
118
+ this._createOpenTagMarkupAndPutListeners(transaction) +
101
119
  this._createContentMarkup(transaction) +
102
120
  this._tagClose
103
121
  );
@@ -113,9 +131,10 @@ ReactDOMComponent.Mixin = {
113
131
  * @see http://jsperf.com/obj-vs-arr-iteration
114
132
  *
115
133
  * @private
134
+ * @param {ReactReconcileTransaction} transaction
116
135
  * @return {string} Markup of opening tag.
117
136
  */
118
- _createOpenTagMarkup: function() {
137
+ _createOpenTagMarkupAndPutListeners: function(transaction) {
119
138
  var props = this.props;
120
139
  var ret = this._tagOpen;
121
140
 
@@ -127,8 +146,8 @@ ReactDOMComponent.Mixin = {
127
146
  if (propValue == null) {
128
147
  continue;
129
148
  }
130
- if (registrationNames[propKey]) {
131
- putListener(this._rootNodeID, propKey, propValue);
149
+ if (registrationNameModules[propKey]) {
150
+ putListener(this._rootNodeID, propKey, propValue, transaction);
132
151
  } else {
133
152
  if (propKey === STYLE) {
134
153
  if (propValue) {
@@ -144,8 +163,8 @@ ReactDOMComponent.Mixin = {
144
163
  }
145
164
  }
146
165
 
147
- var escapedID = escapeTextForBrowser(this._rootNodeID);
148
- return ret + ' ' + ReactMount.ATTR_NAME + '="' + escapedID + '">';
166
+ var idMarkup = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
167
+ return ret + ' ' + idMarkup + '>';
149
168
  },
150
169
 
151
170
  /**
@@ -200,9 +219,14 @@ ReactDOMComponent.Mixin = {
200
219
  updateComponent: ReactPerf.measure(
201
220
  'ReactDOMComponent',
202
221
  'updateComponent',
203
- function(transaction, prevProps) {
204
- ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
205
- this._updateDOMProperties(prevProps);
222
+ function(transaction, prevProps, prevOwner) {
223
+ ReactComponent.Mixin.updateComponent.call(
224
+ this,
225
+ transaction,
226
+ prevProps,
227
+ prevOwner
228
+ );
229
+ this._updateDOMProperties(prevProps, transaction);
206
230
  this._updateDOMChildren(prevProps, transaction);
207
231
  }
208
232
  ),
@@ -220,8 +244,9 @@ ReactDOMComponent.Mixin = {
220
244
  *
221
245
  * @private
222
246
  * @param {object} lastProps
247
+ * @param {ReactReconcileTransaction} transaction
223
248
  */
224
- _updateDOMProperties: function(lastProps) {
249
+ _updateDOMProperties: function(lastProps, transaction) {
225
250
  var nextProps = this.props;
226
251
  var propKey;
227
252
  var styleName;
@@ -239,12 +264,12 @@ ReactDOMComponent.Mixin = {
239
264
  styleUpdates[styleName] = '';
240
265
  }
241
266
  }
242
- } else if (registrationNames[propKey]) {
267
+ } else if (registrationNameModules[propKey]) {
243
268
  deleteListener(this._rootNodeID, propKey);
244
269
  } else if (
245
270
  DOMProperty.isStandardName[propKey] ||
246
271
  DOMProperty.isCustomAttribute(propKey)) {
247
- ReactComponent.DOMIDOperations.deletePropertyByID(
272
+ ReactComponent.BackendIDOperations.deletePropertyByID(
248
273
  this._rootNodeID,
249
274
  propKey
250
275
  );
@@ -281,12 +306,12 @@ ReactDOMComponent.Mixin = {
281
306
  // Relies on `updateStylesByID` not mutating `styleUpdates`.
282
307
  styleUpdates = nextProp;
283
308
  }
284
- } else if (registrationNames[propKey]) {
285
- putListener(this._rootNodeID, propKey, nextProp);
309
+ } else if (registrationNameModules[propKey]) {
310
+ putListener(this._rootNodeID, propKey, nextProp, transaction);
286
311
  } else if (
287
312
  DOMProperty.isStandardName[propKey] ||
288
313
  DOMProperty.isCustomAttribute(propKey)) {
289
- ReactComponent.DOMIDOperations.updatePropertyByID(
314
+ ReactComponent.BackendIDOperations.updatePropertyByID(
290
315
  this._rootNodeID,
291
316
  propKey,
292
317
  nextProp
@@ -294,7 +319,7 @@ ReactDOMComponent.Mixin = {
294
319
  }
295
320
  }
296
321
  if (styleUpdates) {
297
- ReactComponent.DOMIDOperations.updateStylesByID(
322
+ ReactComponent.BackendIDOperations.updateStylesByID(
298
323
  this._rootNodeID,
299
324
  styleUpdates
300
325
  );
@@ -343,7 +368,7 @@ ReactDOMComponent.Mixin = {
343
368
  }
344
369
  } else if (nextHtml != null) {
345
370
  if (lastHtml !== nextHtml) {
346
- ReactComponent.DOMIDOperations.updateInnerHTMLByID(
371
+ ReactComponent.BackendIDOperations.updateInnerHTMLByID(
347
372
  this._rootNodeID,
348
373
  nextHtml
349
374
  );
@@ -360,9 +385,9 @@ ReactDOMComponent.Mixin = {
360
385
  * @internal
361
386
  */
362
387
  unmountComponent: function() {
388
+ this.unmountChildren();
363
389
  ReactEventEmitter.deleteAllListeners(this._rootNodeID);
364
390
  ReactComponent.Mixin.unmountComponent.call(this);
365
- this.unmountChildren();
366
391
  }
367
392
 
368
393
  };
@@ -33,6 +33,8 @@ var form = ReactDOM.form;
33
33
  * composite component and use `componentDidMount` to attach the event handlers.
34
34
  */
35
35
  var ReactDOMForm = ReactCompositeComponent.createClass({
36
+ displayName: 'ReactDOMForm',
37
+
36
38
  render: function() {
37
39
  // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
38
40
  // `jshint` fails to parse JSX so in order for linting to work in the open
@@ -40,11 +42,16 @@ var ReactDOMForm = ReactCompositeComponent.createClass({
40
42
  return this.transferPropsTo(form(null, this.props.children));
41
43
  },
42
44
 
43
- componentDidMount: function(node) {
45
+ componentDidMount: function() {
46
+ ReactEventEmitter.trapBubbledEvent(
47
+ EventConstants.topLevelTypes.topReset,
48
+ 'reset',
49
+ this.getDOMNode()
50
+ );
44
51
  ReactEventEmitter.trapBubbledEvent(
45
52
  EventConstants.topLevelTypes.topSubmit,
46
53
  'submit',
47
- node
54
+ this.getDOMNode()
48
55
  );
49
56
  }
50
57
  });
@@ -25,8 +25,8 @@ var CSSPropertyOperations = require("./CSSPropertyOperations");
25
25
  var DOMChildrenOperations = require("./DOMChildrenOperations");
26
26
  var DOMPropertyOperations = require("./DOMPropertyOperations");
27
27
  var ReactMount = require("./ReactMount");
28
+ var ReactPerf = require("./ReactPerf");
28
29
 
29
- var getTextContentAccessor = require("./getTextContentAccessor");
30
30
  var invariant = require("./invariant");
31
31
 
32
32
  /**
@@ -41,19 +41,11 @@ var INVALID_PROPERTY_ERRORS = {
41
41
  style: '`style` must be set using `updateStylesByID()`.'
42
42
  };
43
43
 
44
- /**
45
- * The DOM property to use when setting text content.
46
- *
47
- * @type {string}
48
- * @private
49
- */
50
- var textContentAccessor = getTextContentAccessor() || 'NA';
51
-
52
- var LEADING_SPACE = /^ /;
44
+ var useWhitespaceWorkaround;
53
45
 
54
46
  /**
55
47
  * Operations used to process updates to DOM nodes. This is made injectable via
56
- * `ReactComponent.DOMIDOperations`.
48
+ * `ReactComponent.BackendIDOperations`.
57
49
  */
58
50
  var ReactDOMIDOperations = {
59
51
 
@@ -66,23 +58,27 @@ var ReactDOMIDOperations = {
66
58
  * @param {*} value New value of the property.
67
59
  * @internal
68
60
  */
69
- updatePropertyByID: function(id, name, value) {
70
- var node = ReactMount.getNode(id);
71
- ("production" !== process.env.NODE_ENV ? invariant(
72
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
73
- 'updatePropertyByID(...): %s',
74
- INVALID_PROPERTY_ERRORS[name]
75
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
76
-
77
- // If we're updating to null or undefined, we should remove the property
78
- // from the DOM node instead of inadvertantly setting to a string. This
79
- // brings us in line with the same behavior we have on initial render.
80
- if (value != null) {
81
- DOMPropertyOperations.setValueForProperty(node, name, value);
82
- } else {
83
- DOMPropertyOperations.deleteValueForProperty(node, name);
61
+ updatePropertyByID: ReactPerf.measure(
62
+ 'ReactDOMIDOperations',
63
+ 'updatePropertyByID',
64
+ function(id, name, value) {
65
+ var node = ReactMount.getNode(id);
66
+ ("production" !== process.env.NODE_ENV ? invariant(
67
+ !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
68
+ 'updatePropertyByID(...): %s',
69
+ INVALID_PROPERTY_ERRORS[name]
70
+ ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
71
+
72
+ // If we're updating to null or undefined, we should remove the property
73
+ // from the DOM node instead of inadvertantly setting to a string. This
74
+ // brings us in line with the same behavior we have on initial render.
75
+ if (value != null) {
76
+ DOMPropertyOperations.setValueForProperty(node, name, value);
77
+ } else {
78
+ DOMPropertyOperations.deleteValueForProperty(node, name);
79
+ }
84
80
  }
85
- },
81
+ ),
86
82
 
87
83
  /**
88
84
  * Updates a DOM node to remove a property. This should only be used to remove
@@ -92,15 +88,19 @@ var ReactDOMIDOperations = {
92
88
  * @param {string} name A property name to remove, see `DOMProperty`.
93
89
  * @internal
94
90
  */
95
- deletePropertyByID: function(id, name, value) {
96
- var node = ReactMount.getNode(id);
97
- ("production" !== process.env.NODE_ENV ? invariant(
98
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
99
- 'updatePropertyByID(...): %s',
100
- INVALID_PROPERTY_ERRORS[name]
101
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
102
- DOMPropertyOperations.deleteValueForProperty(node, name, value);
103
- },
91
+ deletePropertyByID: ReactPerf.measure(
92
+ 'ReactDOMIDOperations',
93
+ 'deletePropertyByID',
94
+ function(id, name, value) {
95
+ var node = ReactMount.getNode(id);
96
+ ("production" !== process.env.NODE_ENV ? invariant(
97
+ !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
98
+ 'updatePropertyByID(...): %s',
99
+ INVALID_PROPERTY_ERRORS[name]
100
+ ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
101
+ DOMPropertyOperations.deleteValueForProperty(node, name, value);
102
+ }
103
+ ),
104
104
 
105
105
  /**
106
106
  * Updates a DOM node with new style values. If a value is specified as '',
@@ -110,10 +110,14 @@ var ReactDOMIDOperations = {
110
110
  * @param {object} styles Mapping from styles to values.
111
111
  * @internal
112
112
  */
113
- updateStylesByID: function(id, styles) {
114
- var node = ReactMount.getNode(id);
115
- CSSPropertyOperations.setValueForStyles(node, styles);
116
- },
113
+ updateStylesByID: ReactPerf.measure(
114
+ 'ReactDOMIDOperations',
115
+ 'updateStylesByID',
116
+ function(id, styles) {
117
+ var node = ReactMount.getNode(id);
118
+ CSSPropertyOperations.setValueForStyles(node, styles);
119
+ }
120
+ ),
117
121
 
118
122
  /**
119
123
  * Updates a DOM node's innerHTML.
@@ -122,12 +126,42 @@ var ReactDOMIDOperations = {
122
126
  * @param {string} html An HTML string.
123
127
  * @internal
124
128
  */
125
- updateInnerHTMLByID: function(id, html) {
126
- var node = ReactMount.getNode(id);
127
- // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces.
128
- // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
129
- node.innerHTML = html.replace(LEADING_SPACE, '&nbsp;');
130
- },
129
+ updateInnerHTMLByID: ReactPerf.measure(
130
+ 'ReactDOMIDOperations',
131
+ 'updateInnerHTMLByID',
132
+ function(id, html) {
133
+ var node = ReactMount.getNode(id);
134
+
135
+ // IE8: When updating a just created node with innerHTML only leading
136
+ // whitespace is removed. When updating an existing node with innerHTML
137
+ // whitespace in root TextNodes is also collapsed.
138
+ // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
139
+
140
+ if (useWhitespaceWorkaround === undefined) {
141
+ // Feature detection; only IE8 is known to behave improperly like this.
142
+ var temp = document.createElement('div');
143
+ temp.innerHTML = ' ';
144
+ useWhitespaceWorkaround = temp.innerHTML === '';
145
+ }
146
+
147
+ if (useWhitespaceWorkaround) {
148
+ // Magic theory: IE8 supposedly differentiates between added and updated
149
+ // nodes when processing innerHTML, innerHTML on updated nodes suffers
150
+ // from worse whitespace behavior. Re-adding a node like this triggers
151
+ // the initial and more favorable whitespace behavior.
152
+ node.parentNode.replaceChild(node, node);
153
+ }
154
+
155
+ if (useWhitespaceWorkaround && html.match(/^[ \r\n\t\f]/)) {
156
+ // Recover leading whitespace by temporarily prepending any character.
157
+ // \uFEFF has the potential advantage of being zero-width/invisible.
158
+ node.innerHTML = '\uFEFF' + html;
159
+ node.firstChild.deleteData(0, 1);
160
+ } else {
161
+ node.innerHTML = html;
162
+ }
163
+ }
164
+ ),
131
165
 
132
166
  /**
133
167
  * Updates a DOM node's text content set by `props.content`.
@@ -136,10 +170,14 @@ var ReactDOMIDOperations = {
136
170
  * @param {string} content Text content.
137
171
  * @internal
138
172
  */
139
- updateTextContentByID: function(id, content) {
140
- var node = ReactMount.getNode(id);
141
- node[textContentAccessor] = content;
142
- },
173
+ updateTextContentByID: ReactPerf.measure(
174
+ 'ReactDOMIDOperations',
175
+ 'updateTextContentByID',
176
+ function(id, content) {
177
+ var node = ReactMount.getNode(id);
178
+ DOMChildrenOperations.updateTextContent(node, content);
179
+ }
180
+ ),
143
181
 
144
182
  /**
145
183
  * Replaces a DOM node that exists in the document with markup.
@@ -149,10 +187,14 @@ var ReactDOMIDOperations = {
149
187
  * @internal
150
188
  * @see {Danger.dangerouslyReplaceNodeWithMarkup}
151
189
  */
152
- dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
153
- var node = ReactMount.getNode(id);
154
- DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
155
- },
190
+ dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
191
+ 'ReactDOMIDOperations',
192
+ 'dangerouslyReplaceNodeWithMarkupByID',
193
+ function(id, markup) {
194
+ var node = ReactMount.getNode(id);
195
+ DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
196
+ }
197
+ ),
156
198
 
157
199
  /**
158
200
  * Updates a component's children by processing a series of updates.
@@ -161,13 +203,16 @@ var ReactDOMIDOperations = {
161
203
  * @param {array<string>} markup List of markup strings.
162
204
  * @internal
163
205
  */
164
- dangerouslyProcessChildrenUpdates: function(updates, markup) {
165
- for (var i = 0; i < updates.length; i++) {
166
- updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
206
+ dangerouslyProcessChildrenUpdates: ReactPerf.measure(
207
+ 'ReactDOMIDOperations',
208
+ 'dangerouslyProcessChildrenUpdates',
209
+ function(updates, markup) {
210
+ for (var i = 0; i < updates.length; i++) {
211
+ updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
212
+ }
213
+ DOMChildrenOperations.processUpdates(updates, markup);
167
214
  }
168
- DOMChildrenOperations.processUpdates(updates, markup);
169
- }
170
-
215
+ )
171
216
  };
172
217
 
173
218
  module.exports = ReactDOMIDOperations;