mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #6215 from nhunzaker/nh-fix-disabled-inputs
Disabled inputs should not respond to clicks in IE
(cherry picked from commit 36e4fe54a8)
This commit is contained in:
committed by
Paul O’Shannessy
parent
112a400662
commit
3655e30adb
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule DisabledInputUtils
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var disableableMouseListenerNames = {
|
||||
onClick: true,
|
||||
onDoubleClick: true,
|
||||
onMouseDown: true,
|
||||
onMouseMove: true,
|
||||
onMouseUp: true,
|
||||
|
||||
onClickCapture: true,
|
||||
onDoubleClickCapture: true,
|
||||
onMouseDownCapture: true,
|
||||
onMouseMoveCapture: true,
|
||||
onMouseUpCapture: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a native component that does not receive mouse events
|
||||
* when `disabled` is set.
|
||||
*/
|
||||
var DisabledInputUtils = {
|
||||
getNativeProps: function(inst, props) {
|
||||
if (!props.disabled) {
|
||||
return props;
|
||||
}
|
||||
|
||||
// Copy the props, except the mouse listeners
|
||||
var nativeProps = {};
|
||||
for (var key in props) {
|
||||
if (!disableableMouseListenerNames[key] && props.hasOwnProperty(key)) {
|
||||
nativeProps[key] = props[key];
|
||||
}
|
||||
}
|
||||
|
||||
return nativeProps;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = DisabledInputUtils;
|
||||
@@ -11,40 +11,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var mouseListenerNames = {
|
||||
onClick: true,
|
||||
onDoubleClick: true,
|
||||
onMouseDown: true,
|
||||
onMouseMove: true,
|
||||
onMouseUp: true,
|
||||
|
||||
onClickCapture: true,
|
||||
onDoubleClickCapture: true,
|
||||
onMouseDownCapture: true,
|
||||
onMouseMoveCapture: true,
|
||||
onMouseUpCapture: true,
|
||||
};
|
||||
var DisabledInputUtils = require('DisabledInputUtils');
|
||||
|
||||
/**
|
||||
* Implements a <button> native component that does not receive mouse events
|
||||
* when `disabled` is set.
|
||||
*/
|
||||
var ReactDOMButton = {
|
||||
getNativeProps: function(inst, props) {
|
||||
if (!props.disabled) {
|
||||
return props;
|
||||
}
|
||||
|
||||
// Copy the props, except the mouse listeners
|
||||
var nativeProps = {};
|
||||
for (var key in props) {
|
||||
if (props.hasOwnProperty(key) && !mouseListenerNames[key]) {
|
||||
nativeProps[key] = props[key];
|
||||
}
|
||||
}
|
||||
|
||||
return nativeProps;
|
||||
},
|
||||
getNativeProps: DisabledInputUtils.getNativeProps,
|
||||
};
|
||||
|
||||
module.exports = ReactDOMButton;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var DisabledInputUtils = require('DisabledInputUtils');
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var LinkedValueUtils = require('LinkedValueUtils');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
@@ -72,7 +73,7 @@ var ReactDOMInput = {
|
||||
// Make sure we set .type before any other properties (setting .value
|
||||
// before .type means .value is lost in IE11 and below)
|
||||
type: undefined,
|
||||
}, props, {
|
||||
}, DisabledInputUtils.getNativeProps(inst, props), {
|
||||
defaultChecked: undefined,
|
||||
defaultValue: undefined,
|
||||
value: value != null ? value : inst._wrapperState.initialValue,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var DisabledInputUtils = require('DisabledInputUtils');
|
||||
var LinkedValueUtils = require('LinkedValueUtils');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
@@ -158,7 +159,7 @@ function updateOptions(inst, multiple, propValue) {
|
||||
*/
|
||||
var ReactDOMSelect = {
|
||||
getNativeProps: function(inst, props) {
|
||||
return Object.assign({}, props, {
|
||||
return Object.assign({}, DisabledInputUtils.getNativeProps(inst, props), {
|
||||
onChange: inst._wrapperState.onChange,
|
||||
value: undefined,
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var DisabledInputUtils = require('DisabledInputUtils');
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var LinkedValueUtils = require('LinkedValueUtils');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
@@ -67,7 +68,7 @@ var ReactDOMTextarea = {
|
||||
|
||||
// Always set children to the same thing. In IE9, the selection range will
|
||||
// get reset if `textContent` is mutated.
|
||||
var nativeProps = Object.assign({}, props, {
|
||||
var nativeProps = Object.assign({}, DisabledInputUtils.getNativeProps(inst, props), {
|
||||
defaultValue: undefined,
|
||||
value: undefined,
|
||||
children: inst._wrapperState.initialValue,
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
describe('DisabledInputUtils', function() {
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
|
||||
var elements = ['button', 'input', 'select', 'textarea'];
|
||||
|
||||
function expectClickThru(element) {
|
||||
onClick.mockClear();
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(element));
|
||||
expect(onClick.mock.calls.length).toBe(1);
|
||||
}
|
||||
|
||||
function expectNoClickThru(element) {
|
||||
onClick.mockClear();
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(element));
|
||||
expect(onClick.mock.calls.length).toBe(0);
|
||||
}
|
||||
|
||||
function mounted(element) {
|
||||
element = ReactTestUtils.renderIntoDocument(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
var onClick = jest.genMockFn();
|
||||
|
||||
elements.forEach(function(tagName) {
|
||||
|
||||
describe(tagName, function() {
|
||||
|
||||
beforeEach(function() {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
});
|
||||
|
||||
it('should forward clicks when it starts out not disabled', function() {
|
||||
var element = React.createElement(tagName, {
|
||||
onClick: onClick,
|
||||
});
|
||||
|
||||
expectClickThru(mounted(element));
|
||||
});
|
||||
|
||||
it('should not forward clicks when it starts out disabled', function() {
|
||||
var element = React.createElement(tagName, {
|
||||
onClick: onClick,
|
||||
disabled: true,
|
||||
});
|
||||
|
||||
expectNoClickThru(mounted(element));
|
||||
});
|
||||
|
||||
it('should forward clicks when it becomes not disabled', function() {
|
||||
var container = document.createElement('div');
|
||||
var element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick, disabled: true }),
|
||||
container
|
||||
);
|
||||
element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick }),
|
||||
container
|
||||
);
|
||||
expectClickThru(element);
|
||||
});
|
||||
|
||||
it('should not forward clicks when it becomes disabled', function() {
|
||||
var container = document.createElement('div');
|
||||
var element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick }),
|
||||
container
|
||||
);
|
||||
element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick, disabled: true }),
|
||||
container
|
||||
);
|
||||
expectNoClickThru(element);
|
||||
});
|
||||
|
||||
it('should work correctly if the listener is changed', function() {
|
||||
var container = document.createElement('div');
|
||||
var element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick, disabled: true }),
|
||||
container
|
||||
);
|
||||
element = ReactDOM.render(
|
||||
React.createElement(tagName, { onClick: onClick, disabled: false }),
|
||||
container
|
||||
);
|
||||
expectClickThru(element);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
describe('ReactDOMButton', function() {
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
|
||||
var onClick = jest.genMockFn();
|
||||
|
||||
function expectClickThru(button) {
|
||||
onClick.mockClear();
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(button));
|
||||
expect(onClick.mock.calls.length).toBe(1);
|
||||
}
|
||||
|
||||
function expectNoClickThru(button) {
|
||||
onClick.mockClear();
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(button));
|
||||
expect(onClick.mock.calls.length).toBe(0);
|
||||
}
|
||||
|
||||
function mounted(button) {
|
||||
button = ReactTestUtils.renderIntoDocument(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
});
|
||||
|
||||
it('should forward clicks when it starts out not disabled', function() {
|
||||
expectClickThru(mounted(<button onClick={onClick} />));
|
||||
});
|
||||
|
||||
it('should not forward clicks when it starts out disabled', function() {
|
||||
expectNoClickThru(
|
||||
mounted(<button disabled={true} onClick={onClick} />)
|
||||
);
|
||||
});
|
||||
|
||||
it('should forward clicks when it becomes not disabled', function() {
|
||||
var container = document.createElement('div');
|
||||
var btn = ReactDOM.render(
|
||||
<button disabled={true} onClick={onClick} />,
|
||||
container
|
||||
);
|
||||
btn = ReactDOM.render(
|
||||
<button onClick={onClick} />,
|
||||
container
|
||||
);
|
||||
expectClickThru(btn);
|
||||
});
|
||||
|
||||
it('should not forward clicks when it becomes disabled', function() {
|
||||
var container = document.createElement('div');
|
||||
var btn = ReactDOM.render(
|
||||
<button onClick={onClick} />,
|
||||
container
|
||||
);
|
||||
btn = ReactDOM.render(
|
||||
<button disabled={true} onClick={onClick} />,
|
||||
container
|
||||
);
|
||||
expectNoClickThru(btn);
|
||||
});
|
||||
|
||||
it('should work correctly if the listener is changed', function() {
|
||||
var container = document.createElement('div');
|
||||
var btn = ReactDOM.render(
|
||||
<button disabled={true} onClick={function() {}} />,
|
||||
container
|
||||
);
|
||||
btn = ReactDOM.render(
|
||||
<button disabled={false} onClick={onClick} />,
|
||||
container
|
||||
);
|
||||
expectClickThru(btn);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user