The library for web and native user interfaces.
Injectable DOMProperty configs, and add back ID attribute
https://github.com/facebook/react/pull/141
Pete Hunt committed
Jul 2, 2013 at 18:26 UTC
32423a83fc9c9c8dc1eac8f769a581e09a2ba74f
6 files changed
+345
-175
src/core/ReactDefaultInjection.js
+6
-7
@@ -22,6 +22,9 @@ var ReactDOM = require('ReactDOM');
22
var ReactDOMForm = require('ReactDOMForm');
23
var ReactDOMTextarea = require('ReactDOMTextarea');
24
25
+var DefaultDOMPropertyConfig = require('DefaultDOMPropertyConfig');
26
+var DOMProperty = require('DOMProperty');
27
+
28
var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
29
var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
30
var ChangeEventPlugin = require('ChangeEventPlugin');
@@ -37,7 +40,7 @@ function inject() {
40
EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
41
42
/**
40
- * Two important event plugins included by default (without having to require
43
+ * Some important event plugins included by default (without having to require
44
* them).
45
*/
46
EventPluginHub.injection.injectEventPluginsByName({
@@ -46,17 +49,13 @@ function inject() {
49
'ChangeEventPlugin': ChangeEventPlugin
50
});
51
49
- /**
50
- * This is a bit of a hack. We need to override the <form> element to be a
51
- * composite component because IE8 does not bubble or capture submit to the
52
- * top level. In order to make this work with our dependency graph we need to
53
- * inject it here.
54
- */
52
ReactDOM.injection.injectComponentClasses({
53
form: ReactDOMForm,
54
// TODO: Inject `ReactDOMInput`.
55
textarea: ReactDOMTextarea
56
});
57
+
58
+ DOMProperty.injection.injectDOMPropertyConfig(DefaultDOMPropertyConfig);
59
}
60
61
module.exports = {
src/core/__tests__/ReactNativeComponent-test.js
+4
-1
@@ -193,6 +193,9 @@ describe('ReactNativeComponent', function() {
193
beforeEach(function() {
194
require('mock-modules').dumpCache();
195
196
+ var ReactDefaultInjection = require('ReactDefaultInjection');
197
+ ReactDefaultInjection.inject();
198
+
199
var mixInto = require('mixInto');
200
var ReactNativeComponent = require('ReactNativeComponent');
201
@@ -217,7 +220,7 @@ describe('ReactNativeComponent', function() {
220
});
221
});
222
220
- it("should handle className", function() {
223
+ it("should generate the correct markup with className", function() {
224
expect(genMarkup({ className: 'a' })).toHaveAttribute('class', 'a');
225
expect(genMarkup({ className: 'a b' })).toHaveAttribute('class', 'a b');
226
expect(genMarkup({ className: '' })).toHaveAttribute('class', '');
src/dom/DOMProperty.js
+109
-164
@@ -23,6 +23,101 @@
23
24
var invariant = require('invariant');
25
26
+var DOMPropertyInjection = {
27
+ /**
28
+ * Mapping from normalized, camelcased property names to a configuration that
29
+ * specifies how the associated DOM property should be accessed or rendered.
30
+ */
31
+ MUST_USE_ATTRIBUTE: 0x1,
32
+ MUST_USE_PROPERTY: 0x2,
33
+ HAS_BOOLEAN_VALUE: 0x4,
34
+ HAS_SIDE_EFFECTS: 0x8,
35
+
36
+ /**
37
+ * Inject some specialized knowledge about the DOM. This takes a config object
38
+ * with the following properties:
39
+ *
40
+ * isCustomAttribute: function that given an attribute name will return true
41
+ * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
42
+ * attributes where it's impossible to enumerate all of the possible
43
+ * attribute names,
44
+ *
45
+ * Properties: object mapping DOM property name to one of the
46
+ * DOMPropertyInjection constants or null. If your attribute isn't in here,
47
+ * it won't get written to the DOM.
48
+ *
49
+ * DOMAttributeNames: object mapping React attribute name to the DOM
50
+ * attribute name. Attribute names not specified use the **lowercase**
51
+ * normalized name.
52
+ *
53
+ * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
54
+ * Property names not specified use the normalized name.
55
+ *
56
+ * DOMMutationMethods: Properties that require special mutation methods. If
57
+ * `value` is undefined, the mutation method should unset the property.
58
+ *
59
+ * @param {object} domPropertyConfig the config as described above.
60
+ */
61
+ injectDOMPropertyConfig: function(domPropertyConfig) {
62
+ var Properties = domPropertyConfig.Properties || {};
63
+ var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
64
+ var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
65
+ var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
66
+
67
+ if (domPropertyConfig.isCustomAttribute) {
68
+ DOMProperty._isCustomAttributeFunctions.push(
69
+ domPropertyConfig.isCustomAttribute
70
+ );
71
+ }
72
+
73
+ for (var propName in Properties) {
74
+ invariant(
75
+ !DOMProperty.isStandardName[propName],
76
+ 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
77
+ '\'%s\' which has already been injected. You may be accidentally ' +
78
+ 'injecting the same DOM property config twice, or you may be ' +
79
+ 'injecting two configs that have conflicting property names.',
80
+ propName
81
+ );
82
+
83
+ DOMProperty.isStandardName[propName] = true;
84
+
85
+ DOMProperty.getAttributeName[propName] =
86
+ DOMAttributeNames[propName] || propName.toLowerCase();
87
+
88
+ DOMProperty.getPropertyName[propName] =
89
+ DOMPropertyNames[propName] || propName;
90
+
91
+ var mutationMethod = DOMMutationMethods[propName];
92
+ if (mutationMethod) {
93
+ DOMProperty.getMutationMethod[propName] = mutationMethod;
94
+ }
95
+
96
+ var propConfig = Properties[propName];
97
+ DOMProperty.mustUseAttribute[propName] =
98
+ propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE;
99
+ DOMProperty.mustUseProperty[propName] =
100
+ propConfig & DOMPropertyInjection.MUST_USE_PROPERTY;
101
+ DOMProperty.hasBooleanValue[propName] =
102
+ propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE;
103
+ DOMProperty.hasSideEffects[propName] =
104
+ propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS;
105
+
106
+ invariant(
107
+ !DOMProperty.mustUseAttribute[propName] ||
108
+ !DOMProperty.mustUseProperty[propName],
109
+ 'DOMProperty: Cannot use require using both attribute and property: %s',
110
+ propName
111
+ );
112
+ invariant(
113
+ DOMProperty.mustUseProperty[propName] ||
114
+ !DOMProperty.hasSideEffects[propName],
115
+ 'DOMProperty: Properties that have side effects must use property: %s',
116
+ propName
117
+ );
118
+ }
119
+ }
120
+};
121
var defaultValueCache = {};
122
123
/**
@@ -94,13 +189,22 @@ var DOMProperty = {
189
*/
190
hasSideEffects: {},
191
192
+ /**
193
+ * All of the isCustomAttribute() functions that have been injected.
194
+ */
195
+ _isCustomAttributeFunctions: [],
196
+
197
/**
198
* Checks whether a property name is a custom attribute.
199
* @method
200
*/
101
- isCustomAttribute: RegExp.prototype.test.bind(
102
- /^(data|aria)-[a-z_][a-z\d_.\-]*$/
103
- ),
201
+ isCustomAttribute: function(attributeName) {
202
+ return DOMProperty._isCustomAttributeFunctions.some(
203
+ function(isCustomAttributeFn) {
204
+ return isCustomAttributeFn.call(null, attributeName);
205
+ }
206
+ );
207
+ },
208
209
/**
210
* Returns the default property value for a DOM property (i.e., not an
@@ -121,168 +225,9 @@ var DOMProperty = {
225
nodeDefaults[prop] = testElement[prop];
226
}
227
return nodeDefaults[prop];
124
- }
125
-};
126
-
127
-/**
128
- * Mapping from normalized, camelcased property names to a configuration that
129
- * specifies how the associated DOM property should be accessed or rendered.
130
- */
131
-var MustUseAttribute = 0x1;
132
-var MustUseProperty = 0x2;
133
-var HasBooleanValue = 0x4;
134
-var HasSideEffects = 0x8;
228
+ },
229
136
-var Properties = {
137
- /**
138
- * Standard Properties
139
- */
140
- accept: null,
141
- action: null,
142
- ajaxify: MustUseAttribute,
143
- allowFullScreen: MustUseAttribute | HasBooleanValue,
144
- alt: null,
145
- autoComplete: null,
146
- autoplay: HasBooleanValue,
147
- cellPadding: null,
148
- cellSpacing: null,
149
- checked: MustUseProperty | HasBooleanValue,
150
- className: MustUseProperty,
151
- colSpan: null,
152
- contentEditable: null,
153
- controls: MustUseProperty | HasBooleanValue,
154
- data: null, // For `<object />` acts as `src`.
155
- dir: null,
156
- disabled: MustUseProperty | HasBooleanValue,
157
- draggable: null,
158
- enctype: null,
159
- height: MustUseAttribute,
160
- href: null,
161
- htmlFor: null,
162
- max: null,
163
- method: null,
164
- min: null,
165
- multiple: MustUseProperty | HasBooleanValue,
166
- name: null,
167
- poster: null,
168
- preload: null,
169
- placeholder: null,
170
- rel: null,
171
- required: HasBooleanValue,
172
- role: MustUseAttribute,
173
- scrollLeft: MustUseProperty,
174
- scrollTop: MustUseProperty,
175
- selected: MustUseProperty | HasBooleanValue,
176
- spellCheck: null,
177
- src: null,
178
- step: null,
179
- style: null,
180
- tabIndex: null,
181
- target: null,
182
- title: null,
183
- type: null,
184
- value: MustUseProperty | HasSideEffects,
185
- width: MustUseAttribute,
186
- wmode: MustUseAttribute,
187
- /**
188
- * SVG Properties
189
- */
190
- cx: MustUseProperty,
191
- cy: MustUseProperty,
192
- d: MustUseProperty,
193
- fill: MustUseProperty,
194
- fx: MustUseProperty,
195
- fy: MustUseProperty,
196
- points: MustUseProperty,
197
- r: MustUseProperty,
198
- stroke: MustUseProperty,
199
- strokeLinecap: MustUseProperty,
200
- strokeWidth: MustUseProperty,
201
- transform: MustUseProperty,
202
- x: MustUseProperty,
203
- x1: MustUseProperty,
204
- x2: MustUseProperty,
205
- version: MustUseProperty,
206
- viewBox: MustUseProperty,
207
- y: MustUseProperty,
208
- y1: MustUseProperty,
209
- y2: MustUseProperty,
210
- spreadMethod: MustUseProperty,
211
- offset: MustUseProperty,
212
- stopColor: MustUseProperty,
213
- stopOpacity: MustUseProperty,
214
- gradientUnits: MustUseProperty,
215
- gradientTransform: MustUseProperty
230
+ injection: DOMPropertyInjection
231
};
232
218
-/**
219
- * Attribute names not specified use the **lowercase** normalized name.
220
- */
221
-var DOMAttributeNames = {
222
- className: 'class',
223
- htmlFor: 'for',
224
- strokeLinecap: 'stroke-linecap',
225
- strokeWidth: 'stroke-width',
226
- stopColor: 'stop-color',
227
- stopOpacity: 'stop-opacity'
228
-};
229
-
230
-/**
231
- * Property names not specified use the normalized name.
232
- */
233
-var DOMPropertyNames = {
234
- autoComplete: 'autocomplete',
235
- spellCheck: 'spellcheck'
236
-};
237
-
238
-/**
239
- * Properties that require special mutation methods. If `value` is undefined,
240
- * the mutation method should unset the property.
241
- */
242
-var DOMMutationMethods = {
243
- /**
244
- * Setting `className` to null may cause it to be set to the string "null".
245
- *
246
- * @param {DOMElement} node
247
- * @param {*} value
248
- */
249
- className: function(node, value) {
250
- node.className = value || '';
251
- }
252
-};
253
-
254
-for (var propName in Properties) {
255
- DOMProperty.isStandardName[propName] = true;
256
-
257
- DOMProperty.getAttributeName[propName] =
258
- DOMAttributeNames[propName] || propName.toLowerCase();
259
-
260
- DOMProperty.getPropertyName[propName] =
261
- DOMPropertyNames[propName] || propName;
262
-
263
- var mutationMethod = DOMMutationMethods[propName];
264
- if (mutationMethod) {
265
- DOMProperty.getMutationMethod[propName] = mutationMethod;
266
- }
267
-
268
- var propConfig = Properties[propName];
269
- DOMProperty.mustUseAttribute[propName] = propConfig & MustUseAttribute;
270
- DOMProperty.mustUseProperty[propName] = propConfig & MustUseProperty;
271
- DOMProperty.hasBooleanValue[propName] = propConfig & HasBooleanValue;
272
- DOMProperty.hasSideEffects[propName] = propConfig & HasSideEffects;
273
-
274
- invariant(
275
- !DOMProperty.mustUseAttribute[propName] ||
276
- !DOMProperty.mustUseProperty[propName],
277
- 'DOMProperty: Cannot use require using both attribute and property: %s',
278
- propName
279
- );
280
- invariant(
281
- DOMProperty.mustUseProperty[propName] ||
282
- !DOMProperty.hasSideEffects[propName],
283
- 'DOMProperty: Properties that have side effects must use property: %s',
284
- propName
285
- );
286
-}
287
-
233
module.exports = DOMProperty;
src/dom/DefaultDOMPropertyConfig.js
new
+139
@@ -0,0 +1,139 @@
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 DefaultDOMPropertyConfig
17
+ */
18
+
19
+"use strict";
20
+
21
+var DOMProperty = require('DOMProperty');
22
+
23
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
24
+var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
25
+var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
26
+var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
27
+
28
+var DefaultDOMPropertyConfig = {
29
+ isCustomAttribute: RegExp.prototype.test.bind(
30
+ /^(data|aria)-[a-z_][a-z\d_.\-]*$/
31
+ ),
32
+ Properties: {
33
+ /**
34
+ * Standard Properties
35
+ */
36
+ accept: null,
37
+ action: null,
38
+ ajaxify: MUST_USE_ATTRIBUTE,
39
+ allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
40
+ alt: null,
41
+ autoComplete: null,
42
+ autoplay: HAS_BOOLEAN_VALUE,
43
+ cellPadding: null,
44
+ cellSpacing: null,
45
+ checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
46
+ className: MUST_USE_PROPERTY,
47
+ colSpan: null,
48
+ contentEditable: null,
49
+ controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
50
+ data: null, // For `<object />` acts as `src`.
51
+ dir: null,
52
+ disabled: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
53
+ draggable: null,
54
+ enctype: null,
55
+ height: MUST_USE_ATTRIBUTE,
56
+ href: null,
57
+ htmlFor: null,
58
+ id: MUST_USE_PROPERTY,
59
+ max: null,
60
+ method: null,
61
+ min: null,
62
+ multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
63
+ name: null,
64
+ poster: null,
65
+ preload: null,
66
+ placeholder: null,
67
+ rel: null,
68
+ required: HAS_BOOLEAN_VALUE,
69
+ role: MUST_USE_ATTRIBUTE,
70
+ scrollLeft: MUST_USE_PROPERTY,
71
+ scrollTop: MUST_USE_PROPERTY,
72
+ selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
73
+ spellCheck: null,
74
+ src: null,
75
+ step: null,
76
+ style: null,
77
+ tabIndex: null,
78
+ target: null,
79
+ title: null,
80
+ type: null,
81
+ value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
82
+ width: MUST_USE_ATTRIBUTE,
83
+ wmode: MUST_USE_ATTRIBUTE,
84
+ /**
85
+ * SVG Properties
86
+ */
87
+ cx: MUST_USE_PROPERTY,
88
+ cy: MUST_USE_PROPERTY,
89
+ d: MUST_USE_PROPERTY,
90
+ fill: MUST_USE_PROPERTY,
91
+ fx: MUST_USE_PROPERTY,
92
+ fy: MUST_USE_PROPERTY,
93
+ points: MUST_USE_PROPERTY,
94
+ r: MUST_USE_PROPERTY,
95
+ stroke: MUST_USE_PROPERTY,
96
+ strokeLinecap: MUST_USE_PROPERTY,
97
+ strokeWidth: MUST_USE_PROPERTY,
98
+ transform: MUST_USE_PROPERTY,
99
+ x: MUST_USE_PROPERTY,
100
+ x1: MUST_USE_PROPERTY,
101
+ x2: MUST_USE_PROPERTY,
102
+ version: MUST_USE_PROPERTY,
103
+ viewBox: MUST_USE_PROPERTY,
104
+ y: MUST_USE_PROPERTY,
105
+ y1: MUST_USE_PROPERTY,
106
+ y2: MUST_USE_PROPERTY,
107
+ spreadMethod: MUST_USE_PROPERTY,
108
+ offset: MUST_USE_PROPERTY,
109
+ stopColor: MUST_USE_PROPERTY,
110
+ stopOpacity: MUST_USE_PROPERTY,
111
+ gradientUnits: MUST_USE_PROPERTY,
112
+ gradientTransform: MUST_USE_PROPERTY
113
+ },
114
+ DOMAttributeNames: {
115
+ className: 'class',
116
+ htmlFor: 'for',
117
+ strokeLinecap: 'stroke-linecap',
118
+ strokeWidth: 'stroke-width',
119
+ stopColor: 'stop-color',
120
+ stopOpacity: 'stop-opacity'
121
+ },
122
+ DOMPropertyNames: {
123
+ autoComplete: 'autocomplete',
124
+ spellCheck: 'spellcheck'
125
+ },
126
+ DOMMutationMethods: {
127
+ /**
128
+ * Setting `className` to null may cause it to be set to the string "null".
129
+ *
130
+ * @param {DOMElement} node
131
+ * @param {*} value
132
+ */
133
+ className: function(node, value) {
134
+ node.className = value || '';
135
+ }
136
+ }
137
+};
138
+
139
+module.exports = DefaultDOMPropertyConfig;
src/dom/__tests__/DOMPropertyOperations-test.js
+65
@@ -21,10 +21,15 @@
21
22
describe('DOMPropertyOperations', function() {
23
var DOMPropertyOperations;
24
+ var DOMProperty;
25
26
beforeEach(function() {
27
require('mock-modules').dumpCache();
28
+ var ReactDefaultInjection = require('ReactDefaultInjection');
29
+ ReactDefaultInjection.inject();
30
+
31
DOMPropertyOperations = require('DOMPropertyOperations');
32
+ DOMProperty = require('DOMProperty');
33
});
34
35
describe('createMarkupForProperty', function() {
@@ -46,6 +51,13 @@ describe('DOMPropertyOperations', function() {
51
)).toBe('');
52
});
53
54
+ it('should work with the id attribute', function() {
55
+ expect(DOMPropertyOperations.createMarkupForProperty(
56
+ 'id',
57
+ 'simple'
58
+ )).toBe('id="simple"');
59
+ });
60
+
61
it('should create markup for boolean properties', function() {
62
expect(DOMPropertyOperations.createMarkupForProperty(
63
'checked',
@@ -126,4 +138,57 @@ describe('DOMPropertyOperations', function() {
138
});
139
140
});
141
+
142
+ describe('injectDOMPropertyConfig', function() {
143
+ it('should support custom attributes', function() {
144
+ // foobar does not exist yet
145
+ expect(DOMPropertyOperations.createMarkupForProperty(
146
+ 'foobar',
147
+ 'simple'
148
+ )).toBe(null);
149
+
150
+ // foo-* does not exist yet
151
+ expect(DOMPropertyOperations.createMarkupForProperty(
152
+ 'foo-xyz',
153
+ 'simple'
154
+ )).toBe(null);
155
+
156
+ // inject foobar DOM property
157
+ DOMProperty.injection.injectDOMPropertyConfig({
158
+ isCustomAttribute: function(name) {
159
+ return name.indexOf('foo-') === 0;
160
+ },
161
+ Properties: {foobar: null}
162
+ });
163
+
164
+ // Ensure old attributes still work
165
+ expect(DOMPropertyOperations.createMarkupForProperty(
166
+ 'name',
167
+ 'simple'
168
+ )).toBe('name="simple"');
169
+ expect(DOMPropertyOperations.createMarkupForProperty(
170
+ 'data-name',
171
+ 'simple'
172
+ )).toBe('data-name="simple"');
173
+
174
+ // foobar should work
175
+ expect(DOMPropertyOperations.createMarkupForProperty(
176
+ 'foobar',
177
+ 'simple'
178
+ )).toBe('foobar="simple"');
179
+
180
+ // foo-* should work
181
+ expect(DOMPropertyOperations.createMarkupForProperty(
182
+ 'foo-xyz',
183
+ 'simple'
184
+ )).toBe('foo-xyz="simple"');
185
+
186
+ // It should complain about double injections.
187
+ expect(function() {
188
+ DOMProperty.injection.injectDOMPropertyConfig(
189
+ {Properties: {foobar: null}}
190
+ );
191
+ }).toThrow();
192
+ });
193
+ });
194
});
src/eventPlugins/__tests__/AnalyticsEventPlugin-test.js
+22
-3
@@ -26,23 +26,42 @@ describe('AnalyticsEventPlugin', function() {
26
var EventPluginHub;
27
var EventPluginRegistry;
28
var React;
29
- var ReactDefaultInjection;
29
var ReactEventEmitter;
30
var ReactEventTopLevelCallback;
31
var ReactTestUtils;
32
33
+ var DefaultEventPluginOrder;
34
+ var EnterLeaveEventPlugin;
35
+ var ChangeEventPlugin;
36
+ var ReactInstanceHandles;
37
+ var SimpleEventPlugin;
38
+
39
beforeEach(function() {
40
AnalyticsEventPluginFactory = require('AnalyticsEventPluginFactory');
41
EventPluginHub = require('EventPluginHub');
42
EventPluginRegistry = require('EventPluginRegistry');
43
React = require('React');
39
- ReactDefaultInjection = require('ReactDefaultInjection');
44
ReactEventEmitter = require('ReactEventEmitter');
45
ReactEventTopLevelCallback = require('ReactEventTopLevelCallback');
46
ReactTestUtils = require('ReactTestUtils');
47
48
EventPluginRegistry._resetEventPlugins();
45
- ReactDefaultInjection.inject();
49
+
50
+ // Re-inject default events system after resetting.
51
+ DefaultEventPluginOrder = require('DefaultEventPluginOrder');
52
+ EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
53
+ ChangeEventPlugin = require('ChangeEventPlugin');
54
+ ReactInstanceHandles = require('ReactInstanceHandles');
55
+ SimpleEventPlugin = require('SimpleEventPlugin');
56
+
57
+ EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder);
58
+ EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
59
+
60
+ EventPluginHub.injection.injectEventPluginsByName({
61
+ 'SimpleEventPlugin': SimpleEventPlugin,
62
+ 'EnterLeaveEventPlugin': EnterLeaveEventPlugin,
63
+ 'ChangeEventPlugin': ChangeEventPlugin
64
+ });
65
66
ReactEventEmitter.ensureListening(false, ReactEventTopLevelCallback);
67
});