react 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/README.md +15 -228
  2. package/ReactJSErrors.js +40 -0
  3. package/addons.js +4 -0
  4. package/lib/$.js +46 -0
  5. package/lib/CSSCore.js +114 -0
  6. package/lib/CSSProperty.js +90 -0
  7. package/lib/CSSPropertyOperations.js +97 -0
  8. package/lib/CallbackRegistry.js +91 -0
  9. package/lib/ChangeEventPlugin.js +365 -0
  10. package/lib/CompositionEventPlugin.js +212 -0
  11. package/lib/DOMChildrenOperations.js +135 -0
  12. package/lib/DOMProperty.js +266 -0
  13. package/lib/DOMPropertyOperations.js +168 -0
  14. package/lib/Danger.js +186 -0
  15. package/lib/DefaultDOMPropertyConfig.js +187 -0
  16. package/lib/DefaultEventPluginOrder.js +44 -0
  17. package/lib/EnterLeaveEventPlugin.js +112 -0
  18. package/lib/EventConstants.js +73 -0
  19. package/lib/EventListener.js +61 -0
  20. package/lib/EventPluginHub.js +190 -0
  21. package/lib/EventPluginRegistry.js +237 -0
  22. package/lib/EventPluginUtils.js +185 -0
  23. package/lib/EventPropagators.js +179 -0
  24. package/lib/ExecutionEnvironment.js +41 -0
  25. package/lib/LinkedStateMixin.js +46 -0
  26. package/lib/LinkedValueMixin.js +68 -0
  27. package/lib/MobileSafariClickEventPlugin.js +63 -0
  28. package/lib/PooledClass.js +113 -0
  29. package/lib/React.js +71 -0
  30. package/lib/ReactChildren.js +132 -0
  31. package/lib/ReactComponent.js +515 -0
  32. package/lib/ReactComponentBrowserEnvironment.js +140 -0
  33. package/lib/ReactComponentEnvironment.js +24 -0
  34. package/lib/ReactCompositeComponent.js +1020 -0
  35. package/lib/ReactCurrentOwner.js +39 -0
  36. package/lib/ReactDOM.js +194 -0
  37. package/lib/ReactDOMButton.js +64 -0
  38. package/lib/ReactDOMComponent.js +374 -0
  39. package/lib/ReactDOMForm.js +52 -0
  40. package/lib/ReactDOMIDOperations.js +173 -0
  41. package/lib/ReactDOMInput.js +169 -0
  42. package/lib/ReactDOMOption.js +50 -0
  43. package/lib/ReactDOMSelect.js +160 -0
  44. package/lib/ReactDOMSelection.js +189 -0
  45. package/lib/ReactDOMTextarea.js +136 -0
  46. package/lib/ReactDefaultBatchingStrategy.js +75 -0
  47. package/lib/ReactDefaultInjection.js +91 -0
  48. package/lib/ReactDefaultPerf.js +407 -0
  49. package/lib/ReactErrorUtils.js +46 -0
  50. package/lib/ReactEventEmitter.js +341 -0
  51. package/lib/ReactEventEmitterMixin.js +89 -0
  52. package/lib/ReactEventTopLevelCallback.js +89 -0
  53. package/lib/ReactInputSelection.js +140 -0
  54. package/lib/ReactInstanceHandles.js +322 -0
  55. package/lib/ReactLink.js +54 -0
  56. package/lib/ReactMarkupChecksum.js +53 -0
  57. package/lib/ReactMount.js +617 -0
  58. package/lib/ReactMountReady.js +95 -0
  59. package/lib/ReactMultiChild.js +441 -0
  60. package/lib/ReactMultiChildUpdateTypes.js +36 -0
  61. package/lib/ReactOwner.js +146 -0
  62. package/lib/ReactPerf.js +88 -0
  63. package/lib/ReactPropTransferer.js +128 -0
  64. package/lib/ReactPropTypes.js +158 -0
  65. package/lib/ReactReconcileTransaction.js +161 -0
  66. package/lib/ReactServerRendering.js +62 -0
  67. package/lib/ReactStateSetters.js +111 -0
  68. package/lib/ReactTextComponent.js +94 -0
  69. package/lib/ReactTransitionEvents.js +97 -0
  70. package/lib/ReactTransitionGroup.js +112 -0
  71. package/lib/ReactTransitionKeySet.js +111 -0
  72. package/lib/ReactTransitionableChild.js +152 -0
  73. package/lib/ReactUpdates.js +145 -0
  74. package/lib/ReactWithAddons.js +41 -0
  75. package/lib/SelectEventPlugin.js +217 -0
  76. package/lib/SimpleEventPlugin.js +365 -0
  77. package/lib/SyntheticClipboardEvent.js +45 -0
  78. package/lib/SyntheticCompositionEvent.js +51 -0
  79. package/lib/SyntheticEvent.js +163 -0
  80. package/lib/SyntheticFocusEvent.js +44 -0
  81. package/lib/SyntheticKeyboardEvent.js +56 -0
  82. package/lib/SyntheticMouseEvent.js +85 -0
  83. package/lib/SyntheticTouchEvent.js +50 -0
  84. package/lib/SyntheticUIEvent.js +45 -0
  85. package/lib/SyntheticWheelEvent.js +63 -0
  86. package/lib/Transaction.js +251 -0
  87. package/lib/ViewportMetrics.js +37 -0
  88. package/lib/accumulate.js +54 -0
  89. package/lib/adler32.js +39 -0
  90. package/lib/containsNode.js +49 -0
  91. package/lib/copyProperties.js +54 -0
  92. package/lib/createArrayFrom.js +94 -0
  93. package/lib/createNodesFromMarkup.js +93 -0
  94. package/lib/createObjectFrom.js +61 -0
  95. package/lib/cx.js +44 -0
  96. package/lib/dangerousStyleValue.js +57 -0
  97. package/lib/emptyFunction.js +43 -0
  98. package/lib/escapeTextForBrowser.js +47 -0
  99. package/lib/ex.js +49 -0
  100. package/lib/filterAttributes.js +45 -0
  101. package/lib/flattenChildren.js +54 -0
  102. package/lib/forEachAccumulated.js +36 -0
  103. package/lib/ge.js +76 -0
  104. package/lib/getActiveElement.js +33 -0
  105. package/lib/getEventTarget.js +36 -0
  106. package/lib/getMarkupWrap.js +108 -0
  107. package/lib/getNodeForCharacterOffset.js +80 -0
  108. package/lib/getReactRootElementInContainer.js +40 -0
  109. package/lib/getTextContentAccessor.js +40 -0
  110. package/lib/getUnboundedScrollPosition.js +45 -0
  111. package/lib/hyphenate.js +35 -0
  112. package/lib/invariant.js +54 -0
  113. package/lib/isEventSupported.js +74 -0
  114. package/lib/isNode.js +33 -0
  115. package/lib/isTextInputElement.js +49 -0
  116. package/lib/isTextNode.js +30 -0
  117. package/lib/joinClasses.js +44 -0
  118. package/lib/keyMirror.js +58 -0
  119. package/lib/keyOf.js +41 -0
  120. package/lib/memoizeStringOnly.js +39 -0
  121. package/lib/merge.js +37 -0
  122. package/lib/mergeHelpers.js +137 -0
  123. package/lib/mergeInto.js +45 -0
  124. package/lib/mixInto.js +34 -0
  125. package/lib/mutateHTMLNodeWithMarkup.js +100 -0
  126. package/lib/objMap.js +47 -0
  127. package/lib/objMapKeyVal.js +47 -0
  128. package/lib/performanceNow.js +42 -0
  129. package/lib/shallowEqual.js +49 -0
  130. package/lib/traverseAllChildren.js +127 -0
  131. package/package.json +33 -31
  132. package/react.js +4 -0
  133. package/.npmignore +0 -7
  134. package/.travis.yml +0 -7
  135. package/Jakefile.js +0 -39
  136. package/LICENSE +0 -19
  137. package/browser-test/dist.html +0 -90
  138. package/browser-test/index.html +0 -86
  139. package/browser-test/min.html +0 -90
  140. package/dist/react.js +0 -3141
  141. package/dist/react.min.js +0 -22
  142. package/doc/advanced.md +0 -175
  143. package/doc/color-def.graffle +0 -938
  144. package/doc/color-def.png +0 -0
  145. package/doc/simple.dot +0 -25
  146. package/doc/simple.png +0 -0
  147. package/examples/longer-example.js +0 -41
  148. package/examples/simple.js +0 -45
  149. package/examples/using-ast-directly.js +0 -30
  150. package/examples/using-events1.js +0 -79
  151. package/examples/using-log-events.js +0 -43
  152. package/lib/base-task.js +0 -120
  153. package/lib/cb-task.js +0 -84
  154. package/lib/core.js +0 -138
  155. package/lib/dsl.js +0 -138
  156. package/lib/error.js +0 -55
  157. package/lib/event-collector.js +0 -81
  158. package/lib/event-manager.js +0 -89
  159. package/lib/eventemitter.js +0 -20
  160. package/lib/finalcb-first-task.js +0 -68
  161. package/lib/finalcb-task.js +0 -65
  162. package/lib/id.js +0 -22
  163. package/lib/input-parser.js +0 -56
  164. package/lib/log-events.js +0 -101
  165. package/lib/parse.js +0 -41
  166. package/lib/promise-resolve.js +0 -50
  167. package/lib/promise-task.js +0 -93
  168. package/lib/react.js +0 -59
  169. package/lib/ret-task.js +0 -71
  170. package/lib/sprintf.js +0 -18
  171. package/lib/status.js +0 -14
  172. package/lib/task.js +0 -251
  173. package/lib/track-tasks.js +0 -74
  174. package/lib/validate.js +0 -159
  175. package/lib/vcon.js +0 -113
  176. package/lib/when-task.js +0 -84
  177. package/src/dist.build.requirejs +0 -20
  178. package/test/ast.mocha.js +0 -136
  179. package/test/cb-task.mocha.js +0 -220
  180. package/test/core-deferred.mocha.js +0 -143
  181. package/test/core-when.mocha.js +0 -96
  182. package/test/core.mocha.js +0 -589
  183. package/test/dsl.mocha.js +0 -352
  184. package/test/event-manager.mocha.js +0 -119
  185. package/test/exec-options.mocha.js +0 -48
  186. package/test/finalcb-task.mocha.js +0 -58
  187. package/test/input-parser.mocha.js +0 -86
  188. package/test/log-events.mocha.js +0 -88
  189. package/test/mocha.opts +0 -2
  190. package/test/module-use.mocha.js +0 -164
  191. package/test/promise-auto-resolve.mocha.js +0 -68
  192. package/test/ret-task.mocha.js +0 -220
  193. package/test/task.mocha.js +0 -42
  194. package/test/validate-cb-task.mocha.js +0 -100
  195. package/test/validate-ret-task.mocha.js +0 -110
  196. package/test/validate.mocha.js +0 -324
  197. package/test/vcon.mocha.js +0 -193
  198. package/vendor/chai/chai.js +0 -4251
  199. package/vendor/jquery/jquery-1.7.1.js +0 -9266
  200. package/vendor/jquery/jquery-1.7.1.min.js +0 -4
  201. package/vendor/node/util.js +0 -531
  202. package/vendor/requirejs/require.js +0 -2045
  203. package/vendor/requirejs/require.min.js +0 -36
@@ -0,0 +1,90 @@
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 CSSProperty
17
+ */
18
+
19
+ "use strict";
20
+
21
+ /**
22
+ * CSS properties which accept numbers but are not in units of "px".
23
+ */
24
+ var isUnitlessNumber = {
25
+ fillOpacity: true,
26
+ fontWeight: true,
27
+ lineHeight: true,
28
+ opacity: true,
29
+ orphans: true,
30
+ zIndex: true,
31
+ zoom: true
32
+ };
33
+
34
+ /**
35
+ * Most style properties can be unset by doing .style[prop] = '' but IE8
36
+ * doesn't like doing that with shorthand properties so for the properties that
37
+ * IE8 breaks on, which are listed here, we instead unset each of the
38
+ * individual properties. See http://bugs.jquery.com/ticket/12385.
39
+ * The 4-value 'clock' properties like margin, padding, border-width seem to
40
+ * behave without any problems. Curiously, list-style works too without any
41
+ * special prodding.
42
+ */
43
+ var shorthandPropertyExpansions = {
44
+ background: {
45
+ backgroundImage: true,
46
+ backgroundPosition: true,
47
+ backgroundRepeat: true,
48
+ backgroundColor: true
49
+ },
50
+ border: {
51
+ borderWidth: true,
52
+ borderStyle: true,
53
+ borderColor: true
54
+ },
55
+ borderBottom: {
56
+ borderBottomWidth: true,
57
+ borderBottomStyle: true,
58
+ borderBottomColor: true
59
+ },
60
+ borderLeft: {
61
+ borderLeftWidth: true,
62
+ borderLeftStyle: true,
63
+ borderLeftColor: true
64
+ },
65
+ borderRight: {
66
+ borderRightWidth: true,
67
+ borderRightStyle: true,
68
+ borderRightColor: true
69
+ },
70
+ borderTop: {
71
+ borderTopWidth: true,
72
+ borderTopStyle: true,
73
+ borderTopColor: true
74
+ },
75
+ font: {
76
+ fontStyle: true,
77
+ fontVariant: true,
78
+ fontWeight: true,
79
+ fontSize: true,
80
+ lineHeight: true,
81
+ fontFamily: true
82
+ }
83
+ };
84
+
85
+ var CSSProperty = {
86
+ isUnitlessNumber: isUnitlessNumber,
87
+ shorthandPropertyExpansions: shorthandPropertyExpansions
88
+ };
89
+
90
+ module.exports = CSSProperty;
@@ -0,0 +1,97 @@
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 CSSPropertyOperations
17
+ * @typechecks static-only
18
+ */
19
+
20
+ "use strict";
21
+
22
+ var CSSProperty = require("./CSSProperty");
23
+
24
+ var dangerousStyleValue = require("./dangerousStyleValue");
25
+ var escapeTextForBrowser = require("./escapeTextForBrowser");
26
+ var hyphenate = require("./hyphenate");
27
+ var memoizeStringOnly = require("./memoizeStringOnly");
28
+
29
+ var processStyleName = memoizeStringOnly(function(styleName) {
30
+ return escapeTextForBrowser(hyphenate(styleName));
31
+ });
32
+
33
+ /**
34
+ * Operations for dealing with CSS properties.
35
+ */
36
+ var CSSPropertyOperations = {
37
+
38
+ /**
39
+ * Serializes a mapping of style properties for use as inline styles:
40
+ *
41
+ * > createMarkupForStyles({width: '200px', height: 0})
42
+ * "width:200px;height:0;"
43
+ *
44
+ * Undefined values are ignored so that declarative programming is easier.
45
+ *
46
+ * @param {object} styles
47
+ * @return {?string}
48
+ */
49
+ createMarkupForStyles: function(styles) {
50
+ var serialized = '';
51
+ for (var styleName in styles) {
52
+ if (!styles.hasOwnProperty(styleName)) {
53
+ continue;
54
+ }
55
+ var styleValue = styles[styleName];
56
+ if (styleValue != null) {
57
+ serialized += processStyleName(styleName) + ':';
58
+ serialized += dangerousStyleValue(styleName, styleValue) + ';';
59
+ }
60
+ }
61
+ return serialized || null;
62
+ },
63
+
64
+ /**
65
+ * Sets the value for multiple styles on a node. If a value is specified as
66
+ * '' (empty string), the corresponding style property will be unset.
67
+ *
68
+ * @param {DOMElement} node
69
+ * @param {object} styles
70
+ */
71
+ setValueForStyles: function(node, styles) {
72
+ var style = node.style;
73
+ for (var styleName in styles) {
74
+ if (!styles.hasOwnProperty(styleName)) {
75
+ continue;
76
+ }
77
+ var styleValue = dangerousStyleValue(styleName, styles[styleName]);
78
+ if (styleValue) {
79
+ style[styleName] = styleValue;
80
+ } else {
81
+ var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
82
+ if (expansion) {
83
+ // Shorthand property that IE8 won't like unsetting, so unset each
84
+ // component to placate it
85
+ for (var individualStyleName in expansion) {
86
+ style[individualStyleName] = '';
87
+ }
88
+ } else {
89
+ style[styleName] = '';
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ };
96
+
97
+ module.exports = CSSPropertyOperations;
@@ -0,0 +1,91 @@
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 CallbackRegistry
17
+ * @typechecks static-only
18
+ */
19
+
20
+ "use strict";
21
+
22
+ var listenerBank = {};
23
+
24
+ /**
25
+ * Stores "listeners" by `registrationName`/`id`. There should be at most one
26
+ * "listener" per `registrationName`/`id` in the `listenerBank`.
27
+ *
28
+ * Access listeners via `listenerBank[registrationName][id]`.
29
+ *
30
+ * @class CallbackRegistry
31
+ * @internal
32
+ */
33
+ var CallbackRegistry = {
34
+
35
+ /**
36
+ * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
37
+ *
38
+ * @param {string} id ID of the DOM element.
39
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
40
+ * @param {?function} listener The callback to store.
41
+ */
42
+ putListener: function(id, registrationName, listener) {
43
+ var bankForRegistrationName =
44
+ listenerBank[registrationName] || (listenerBank[registrationName] = {});
45
+ bankForRegistrationName[id] = listener;
46
+ },
47
+
48
+ /**
49
+ * @param {string} id ID of the DOM element.
50
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
51
+ * @return {?function} The stored callback.
52
+ */
53
+ getListener: function(id, registrationName) {
54
+ var bankForRegistrationName = listenerBank[registrationName];
55
+ return bankForRegistrationName && bankForRegistrationName[id];
56
+ },
57
+
58
+ /**
59
+ * Deletes a listener from the registration bank.
60
+ *
61
+ * @param {string} id ID of the DOM element.
62
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
63
+ */
64
+ deleteListener: function(id, registrationName) {
65
+ var bankForRegistrationName = listenerBank[registrationName];
66
+ if (bankForRegistrationName) {
67
+ delete bankForRegistrationName[id];
68
+ }
69
+ },
70
+
71
+ /**
72
+ * Deletes all listeners for the DOM element with the supplied ID.
73
+ *
74
+ * @param {string} id ID of the DOM element.
75
+ */
76
+ deleteAllListeners: function(id) {
77
+ for (var registrationName in listenerBank) {
78
+ delete listenerBank[registrationName][id];
79
+ }
80
+ },
81
+
82
+ /**
83
+ * This is needed for tests only. Do not use!
84
+ */
85
+ __purge: function() {
86
+ listenerBank = {};
87
+ }
88
+
89
+ };
90
+
91
+ module.exports = CallbackRegistry;
@@ -0,0 +1,365 @@
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 ChangeEventPlugin
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var EventConstants = require("./EventConstants");
22
+ var EventPluginHub = require("./EventPluginHub");
23
+ var EventPropagators = require("./EventPropagators");
24
+ var ExecutionEnvironment = require("./ExecutionEnvironment");
25
+ var SyntheticEvent = require("./SyntheticEvent");
26
+
27
+ var isEventSupported = require("./isEventSupported");
28
+ var isTextInputElement = require("./isTextInputElement");
29
+ var keyOf = require("./keyOf");
30
+
31
+ var topLevelTypes = EventConstants.topLevelTypes;
32
+
33
+ var eventTypes = {
34
+ change: {
35
+ phasedRegistrationNames: {
36
+ bubbled: keyOf({onChange: null}),
37
+ captured: keyOf({onChangeCapture: null})
38
+ }
39
+ }
40
+ };
41
+
42
+ /**
43
+ * For IE shims
44
+ */
45
+ var activeElement = null;
46
+ var activeElementID = null;
47
+ var activeElementValue = null;
48
+ var activeElementValueProp = null;
49
+
50
+ /**
51
+ * SECTION: handle `change` event
52
+ */
53
+ function shouldUseChangeEvent(elem) {
54
+ return (
55
+ elem.nodeName === 'SELECT' ||
56
+ (elem.nodeName === 'INPUT' && elem.type === 'file')
57
+ );
58
+ }
59
+
60
+ var doesChangeEventBubble = false;
61
+ if (ExecutionEnvironment.canUseDOM) {
62
+ // See `handleChange` comment below
63
+ doesChangeEventBubble = isEventSupported('change') && (
64
+ !('documentMode' in document) || document.documentMode > 8
65
+ );
66
+ }
67
+
68
+ function manualDispatchChangeEvent(nativeEvent) {
69
+ var event = SyntheticEvent.getPooled(
70
+ eventTypes.change,
71
+ activeElementID,
72
+ nativeEvent
73
+ );
74
+ EventPropagators.accumulateTwoPhaseDispatches(event);
75
+
76
+ // If change bubbled, we'd just bind to it like all the other events
77
+ // and have it go through ReactEventTopLevelCallback. Since it doesn't, we
78
+ // manually listen for the change event and so we have to enqueue and
79
+ // process the abstract event manually.
80
+ EventPluginHub.enqueueEvents(event);
81
+ EventPluginHub.processEventQueue();
82
+ }
83
+
84
+ function startWatchingForChangeEventIE8(target, targetID) {
85
+ activeElement = target;
86
+ activeElementID = targetID;
87
+ activeElement.attachEvent('onchange', manualDispatchChangeEvent);
88
+ }
89
+
90
+ function stopWatchingForChangeEventIE8() {
91
+ if (!activeElement) {
92
+ return;
93
+ }
94
+ activeElement.detachEvent('onchange', manualDispatchChangeEvent);
95
+ activeElement = null;
96
+ activeElementID = null;
97
+ }
98
+
99
+ function getTargetIDForChangeEvent(
100
+ topLevelType,
101
+ topLevelTarget,
102
+ topLevelTargetID) {
103
+ if (topLevelType === topLevelTypes.topChange) {
104
+ return topLevelTargetID;
105
+ }
106
+ }
107
+ function handleEventsForChangeEventIE8(
108
+ topLevelType,
109
+ topLevelTarget,
110
+ topLevelTargetID) {
111
+ if (topLevelType === topLevelTypes.topFocus) {
112
+ // stopWatching() should be a noop here but we call it just in case we
113
+ // missed a blur event somehow.
114
+ stopWatchingForChangeEventIE8();
115
+ startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
116
+ } else if (topLevelType === topLevelTypes.topBlur) {
117
+ stopWatchingForChangeEventIE8();
118
+ }
119
+ }
120
+
121
+
122
+ /**
123
+ * SECTION: handle `input` event
124
+ */
125
+ var isInputEventSupported = false;
126
+ if (ExecutionEnvironment.canUseDOM) {
127
+ // IE9 claims to support the input event but fails to trigger it when
128
+ // deleting text, so we ignore its input events
129
+ isInputEventSupported = isEventSupported('input') && (
130
+ !('documentMode' in document) || document.documentMode > 9
131
+ );
132
+ }
133
+
134
+ /**
135
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
136
+ * set on the active element.
137
+ */
138
+ var newValueProp = {
139
+ get: function() {
140
+ return activeElementValueProp.get.call(this);
141
+ },
142
+ set: function(val) {
143
+ // Cast to a string so we can do equality checks.
144
+ activeElementValue = '' + val;
145
+ activeElementValueProp.set.call(this, val);
146
+ }
147
+ };
148
+
149
+ /**
150
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
151
+ * and override the value property so that we can distinguish user events from
152
+ * value changes in JS.
153
+ */
154
+ function startWatchingForValueChange(target, targetID) {
155
+ activeElement = target;
156
+ activeElementID = targetID;
157
+ activeElementValue = target.value;
158
+ activeElementValueProp = Object.getOwnPropertyDescriptor(
159
+ target.constructor.prototype,
160
+ 'value'
161
+ );
162
+
163
+ Object.defineProperty(activeElement, 'value', newValueProp);
164
+ activeElement.attachEvent('onpropertychange', handlePropertyChange);
165
+ }
166
+
167
+ /**
168
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
169
+ * if any exists.
170
+ */
171
+ function stopWatchingForValueChange() {
172
+ if (!activeElement) {
173
+ return;
174
+ }
175
+
176
+ // delete restores the original property definition
177
+ delete activeElement.value;
178
+ activeElement.detachEvent('onpropertychange', handlePropertyChange);
179
+
180
+ activeElement = null;
181
+ activeElementID = null;
182
+ activeElementValue = null;
183
+ activeElementValueProp = null;
184
+ }
185
+
186
+ /**
187
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
188
+ * the value of the active element has changed.
189
+ */
190
+ function handlePropertyChange(nativeEvent) {
191
+ if (nativeEvent.propertyName !== 'value') {
192
+ return;
193
+ }
194
+ var value = nativeEvent.srcElement.value;
195
+ if (value === activeElementValue) {
196
+ return;
197
+ }
198
+ activeElementValue = value;
199
+
200
+ manualDispatchChangeEvent(nativeEvent);
201
+ }
202
+
203
+ /**
204
+ * If a `change` event should be fired, returns the target's ID.
205
+ */
206
+ function getTargetIDForInputEvent(
207
+ topLevelType,
208
+ topLevelTarget,
209
+ topLevelTargetID) {
210
+ if (topLevelType === topLevelTypes.topInput) {
211
+ // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
212
+ // what we want so fall through here and trigger an abstract event
213
+ return topLevelTargetID;
214
+ }
215
+ }
216
+
217
+ // For IE8 and IE9.
218
+ function handleEventsForInputEventIE(
219
+ topLevelType,
220
+ topLevelTarget,
221
+ topLevelTargetID) {
222
+ if (topLevelType === topLevelTypes.topFocus) {
223
+ // In IE8, we can capture almost all .value changes by adding a
224
+ // propertychange handler and looking for events with propertyName
225
+ // equal to 'value'
226
+ // In IE9, propertychange fires for most input events but is buggy and
227
+ // doesn't fire when text is deleted, but conveniently, selectionchange
228
+ // appears to fire in all of the remaining cases so we catch those and
229
+ // forward the event if the value has changed
230
+ // In either case, we don't want to call the event handler if the value
231
+ // is changed from JS so we redefine a setter for `.value` that updates
232
+ // our activeElementValue variable, allowing us to ignore those changes
233
+ //
234
+ // stopWatching() should be a noop here but we call it just in case we
235
+ // missed a blur event somehow.
236
+ stopWatchingForValueChange();
237
+ startWatchingForValueChange(topLevelTarget, topLevelTargetID);
238
+ } else if (topLevelType === topLevelTypes.topBlur) {
239
+ stopWatchingForValueChange();
240
+ }
241
+ }
242
+
243
+ // For IE8 and IE9.
244
+ function getTargetIDForInputEventIE(
245
+ topLevelType,
246
+ topLevelTarget,
247
+ topLevelTargetID) {
248
+ if (topLevelType === topLevelTypes.topSelectionChange ||
249
+ topLevelType === topLevelTypes.topKeyUp ||
250
+ topLevelType === topLevelTypes.topKeyDown) {
251
+ // On the selectionchange event, the target is just document which isn't
252
+ // helpful for us so just check activeElement instead.
253
+ //
254
+ // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
255
+ // propertychange on the first input event after setting `value` from a
256
+ // script and fires only keydown, keypress, keyup. Catching keyup usually
257
+ // gets it and catching keydown lets us fire an event for the first
258
+ // keystroke if user does a key repeat (it'll be a little delayed: right
259
+ // before the second keystroke). Other input methods (e.g., paste) seem to
260
+ // fire selectionchange normally.
261
+ if (activeElement && activeElement.value !== activeElementValue) {
262
+ activeElementValue = activeElement.value;
263
+ return activeElementID;
264
+ }
265
+ }
266
+ }
267
+
268
+
269
+ /**
270
+ * SECTION: handle `click` event
271
+ */
272
+ function shouldUseClickEvent(elem) {
273
+ // Use the `click` event to detect changes to checkbox and radio inputs.
274
+ // This approach works across all browsers, whereas `change` does not fire
275
+ // until `blur` in IE8.
276
+ return (
277
+ elem.nodeName === 'INPUT' &&
278
+ (elem.type === 'checkbox' || elem.type === 'radio')
279
+ );
280
+ }
281
+
282
+ function getTargetIDForClickEvent(
283
+ topLevelType,
284
+ topLevelTarget,
285
+ topLevelTargetID) {
286
+ if (topLevelType === topLevelTypes.topClick) {
287
+ return topLevelTargetID;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * This plugin creates an `onChange` event that normalizes change events
293
+ * across form elements. This event fires at a time when it's possible to
294
+ * change the element's value without seeing a flicker.
295
+ *
296
+ * Supported elements are:
297
+ * - input (see `isTextInputElement`)
298
+ * - textarea
299
+ * - select
300
+ */
301
+ var ChangeEventPlugin = {
302
+
303
+ eventTypes: eventTypes,
304
+
305
+ /**
306
+ * @param {string} topLevelType Record from `EventConstants`.
307
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
308
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
309
+ * @param {object} nativeEvent Native browser event.
310
+ * @return {*} An accumulation of synthetic events.
311
+ * @see {EventPluginHub.extractEvents}
312
+ */
313
+ extractEvents: function(
314
+ topLevelType,
315
+ topLevelTarget,
316
+ topLevelTargetID,
317
+ nativeEvent) {
318
+
319
+ var getTargetIDFunc, handleEventFunc;
320
+ if (shouldUseChangeEvent(topLevelTarget)) {
321
+ if (doesChangeEventBubble) {
322
+ getTargetIDFunc = getTargetIDForChangeEvent;
323
+ } else {
324
+ handleEventFunc = handleEventsForChangeEventIE8;
325
+ }
326
+ } else if (isTextInputElement(topLevelTarget)) {
327
+ if (isInputEventSupported) {
328
+ getTargetIDFunc = getTargetIDForInputEvent;
329
+ } else {
330
+ getTargetIDFunc = getTargetIDForInputEventIE;
331
+ handleEventFunc = handleEventsForInputEventIE;
332
+ }
333
+ } else if (shouldUseClickEvent(topLevelTarget)) {
334
+ getTargetIDFunc = getTargetIDForClickEvent;
335
+ }
336
+
337
+ if (getTargetIDFunc) {
338
+ var targetID = getTargetIDFunc(
339
+ topLevelType,
340
+ topLevelTarget,
341
+ topLevelTargetID
342
+ );
343
+ if (targetID) {
344
+ var event = SyntheticEvent.getPooled(
345
+ eventTypes.change,
346
+ targetID,
347
+ nativeEvent
348
+ );
349
+ EventPropagators.accumulateTwoPhaseDispatches(event);
350
+ return event;
351
+ }
352
+ }
353
+
354
+ if (handleEventFunc) {
355
+ handleEventFunc(
356
+ topLevelType,
357
+ topLevelTarget,
358
+ topLevelTargetID
359
+ );
360
+ }
361
+ }
362
+
363
+ };
364
+
365
+ module.exports = ChangeEventPlugin;