UNPKG

2.97 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2013-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 */
8
9'use strict';
10
11var ReactDOMComponentTree = require('./ReactDOMComponentTree');
12
13function isCheckable(elem) {
14 var type = elem.type;
15 var nodeName = elem.nodeName;
16 return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio');
17}
18
19function getTracker(inst) {
20 return inst._wrapperState.valueTracker;
21}
22
23function attachTracker(inst, tracker) {
24 inst._wrapperState.valueTracker = tracker;
25}
26
27function detachTracker(inst) {
28 inst._wrapperState.valueTracker = null;
29}
30
31function getValueFromNode(node) {
32 var value;
33 if (node) {
34 value = isCheckable(node) ? '' + node.checked : node.value;
35 }
36 return value;
37}
38
39var inputValueTracking = {
40 // exposed for testing
41 _getTrackerFromNode: function (node) {
42 return getTracker(ReactDOMComponentTree.getInstanceFromNode(node));
43 },
44
45
46 track: function (inst) {
47 if (getTracker(inst)) {
48 return;
49 }
50
51 var node = ReactDOMComponentTree.getNodeFromInstance(inst);
52 var valueField = isCheckable(node) ? 'checked' : 'value';
53 var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField);
54
55 var currentValue = '' + node[valueField];
56
57 // if someone has already defined a value or Safari, then bail
58 // and don't track value will cause over reporting of changes,
59 // but it's better then a hard failure
60 // (needed for certain tests that spyOn input values and Safari)
61 if (node.hasOwnProperty(valueField) || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') {
62 return;
63 }
64
65 Object.defineProperty(node, valueField, {
66 enumerable: descriptor.enumerable,
67 configurable: true,
68 get: function () {
69 return descriptor.get.call(this);
70 },
71 set: function (value) {
72 currentValue = '' + value;
73 descriptor.set.call(this, value);
74 }
75 });
76
77 attachTracker(inst, {
78 getValue: function () {
79 return currentValue;
80 },
81 setValue: function (value) {
82 currentValue = '' + value;
83 },
84 stopTracking: function () {
85 detachTracker(inst);
86 delete node[valueField];
87 }
88 });
89 },
90
91 updateValueIfChanged: function (inst) {
92 if (!inst) {
93 return false;
94 }
95 var tracker = getTracker(inst);
96
97 if (!tracker) {
98 inputValueTracking.track(inst);
99 return true;
100 }
101
102 var lastValue = tracker.getValue();
103 var nextValue = getValueFromNode(ReactDOMComponentTree.getNodeFromInstance(inst));
104
105 if (nextValue !== lastValue) {
106 tracker.setValue(nextValue);
107 return true;
108 }
109
110 return false;
111 },
112 stopTracking: function (inst) {
113 var tracker = getTracker(inst);
114 if (tracker) {
115 tracker.stopTracking();
116 }
117 }
118};
119
120module.exports = inputValueTracking;
\No newline at end of file