Skip to content

Commit 027d880

Browse files
committed
Stopgap fix for element disabling (#8387)
Fix for #8308. This is a bad hack -- EventPluginHub.getListener isn't even DOM-specific -- but this works for now and lets us release 15.4.1. (cherry picked from commit c7129ce)
1 parent 24ffd57 commit 027d880

File tree

4 files changed

+77
-25
lines changed

4 files changed

+77
-25
lines changed

src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js

+1-16
Original file line numberDiff line numberDiff line change
@@ -156,18 +156,6 @@ function isInteractive(tag) {
156156
);
157157
}
158158

159-
function shouldPreventMouseEvent(inst) {
160-
if (inst) {
161-
var disabled = inst._currentElement && inst._currentElement.props.disabled;
162-
163-
if (disabled) {
164-
return isInteractive(inst._tag);
165-
}
166-
}
167-
168-
return false;
169-
}
170-
171159
var SimpleEventPlugin: PluginModule<MouseEvent> = {
172160

173161
eventTypes: eventTypes,
@@ -243,10 +231,7 @@ var SimpleEventPlugin: PluginModule<MouseEvent> = {
243231
case 'topMouseDown':
244232
case 'topMouseMove':
245233
case 'topMouseUp':
246-
// Disabled elements should not respond to mouse events
247-
if (shouldPreventMouseEvent(targetInst)) {
248-
return null;
249-
}
234+
// TODO: Disabled elements should not respond to mouse events
250235
/* falls through */
251236
case 'topMouseOut':
252237
case 'topMouseOver':

src/renderers/dom/client/eventPlugins/__tests__/SimpleEventPlugin-test.js

+45-8
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@ describe('SimpleEventPlugin', function() {
1717
var ReactDOM;
1818
var ReactTestUtils;
1919

20-
var onClick = jest.fn();
20+
var onClick;
2121

2222
function expectClickThru(element) {
23-
onClick.mockClear();
2423
ReactTestUtils.SimulateNative.click(ReactDOM.findDOMNode(element));
2524
expect(onClick.mock.calls.length).toBe(1);
2625
}
2726

2827
function expectNoClickThru(element) {
29-
onClick.mockClear();
3028
ReactTestUtils.SimulateNative.click(ReactDOM.findDOMNode(element));
3129
expect(onClick.mock.calls.length).toBe(0);
3230
}
@@ -40,6 +38,8 @@ describe('SimpleEventPlugin', function() {
4038
React = require('React');
4139
ReactDOM = require('ReactDOM');
4240
ReactTestUtils = require('ReactTestUtils');
41+
42+
onClick = jest.fn();
4343
});
4444

4545
it('A non-interactive tags click when disabled', function() {
@@ -53,7 +53,48 @@ describe('SimpleEventPlugin', function() {
5353
);
5454
var child = ReactDOM.findDOMNode(element).firstChild;
5555

56-
onClick.mockClear();
56+
ReactTestUtils.SimulateNative.click(child);
57+
expect(onClick.mock.calls.length).toBe(1);
58+
});
59+
60+
it('does not register a click when clicking a child of a disabled element', function() {
61+
var element = ReactTestUtils.renderIntoDocument(
62+
<button onClick={onClick} disabled={true}><span /></button>
63+
);
64+
var child = ReactDOM.findDOMNode(element).querySelector('span');
65+
66+
ReactTestUtils.SimulateNative.click(child);
67+
expect(onClick.mock.calls.length).toBe(0);
68+
});
69+
70+
it('triggers click events for children of disabled elements', function() {
71+
var element = ReactTestUtils.renderIntoDocument(
72+
<button disabled={true}><span onClick={onClick} /></button>
73+
);
74+
var child = ReactDOM.findDOMNode(element).querySelector('span');
75+
76+
ReactTestUtils.SimulateNative.click(child);
77+
expect(onClick.mock.calls.length).toBe(1);
78+
});
79+
80+
it('triggers parent captured click events when target is a child of a disabled elements', function() {
81+
var element = ReactTestUtils.renderIntoDocument(
82+
<div onClickCapture={onClick}>
83+
<button disabled={true}><span /></button>
84+
</div>
85+
);
86+
var child = ReactDOM.findDOMNode(element).querySelector('span');
87+
88+
ReactTestUtils.SimulateNative.click(child);
89+
expect(onClick.mock.calls.length).toBe(1);
90+
});
91+
92+
it('triggers captured click events for children of disabled elements', function() {
93+
var element = ReactTestUtils.renderIntoDocument(
94+
<button disabled={true}><span onClickCapture={onClick} /></button>
95+
);
96+
var child = ReactDOM.findDOMNode(element).querySelector('span');
97+
5798
ReactTestUtils.SimulateNative.click(child);
5899
expect(onClick.mock.calls.length).toBe(1);
59100
});
@@ -124,10 +165,6 @@ describe('SimpleEventPlugin', function() {
124165
describe('iOS bubbling click fix', function() {
125166
// See http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
126167

127-
beforeEach(function() {
128-
onClick.mockClear();
129-
});
130-
131168
it('does not add a local click to interactive elements', function() {
132169
var container = document.createElement('div');
133170

src/renderers/shared/stack/event/EventPluginHub.js

+30
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,31 @@ var getDictionaryKey = function(inst) {
5959
return '.' + inst._rootNodeID;
6060
};
6161

62+
function isInteractive(tag) {
63+
return (
64+
tag === 'button' || tag === 'input' ||
65+
tag === 'select' || tag === 'textarea'
66+
);
67+
}
68+
69+
function shouldPreventMouseEvent(name, type, props) {
70+
switch (name) {
71+
case 'onClick':
72+
case 'onClickCapture':
73+
case 'onDoubleClick':
74+
case 'onDoubleClickCapture':
75+
case 'onMouseDown':
76+
case 'onMouseDownCapture':
77+
case 'onMouseMove':
78+
case 'onMouseMoveCapture':
79+
case 'onMouseUp':
80+
case 'onMouseUpCapture':
81+
return !!(props.disabled && isInteractive(type));
82+
default:
83+
return false;
84+
}
85+
}
86+
6287
/**
6388
* This is a unified interface for event plugins to be installed and configured.
6489
*
@@ -133,7 +158,12 @@ var EventPluginHub = {
133158
* @return {?function} The stored callback.
134159
*/
135160
getListener: function(inst, registrationName) {
161+
// TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
162+
// live here; needs to be moved to a better place soon
136163
var bankForRegistrationName = listenerBank[registrationName];
164+
if (shouldPreventMouseEvent(registrationName, inst._currentElement.type, inst._currentElement.props)) {
165+
return null;
166+
}
137167
var key = getDictionaryKey(inst);
138168
return bankForRegistrationName && bankForRegistrationName[key];
139169
},

src/renderers/shared/stack/event/eventPlugins/__tests__/ResponderEventPlugin-test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ var CHILD_ID2 = '.0.0.1';
311311

312312
var idToInstance = {};
313313
[GRANDPARENT_ID, PARENT_ID, CHILD_ID, CHILD_ID2].forEach(function(id) {
314-
idToInstance[id] = {_rootNodeID: id};
314+
idToInstance[id] = {_rootNodeID: id, _currentElement: {}};
315315
});
316316

317317
var three = {

0 commit comments

Comments
 (0)