Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disabled inputs should not respond to clicks in IE #6215

Merged
merged 4 commits into from
Apr 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/renderers/dom/client/wrappers/DisabledInputUtils.js
Original file line number Diff line number Diff line change
@@ -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;
30 changes: 2 additions & 28 deletions src/renderers/dom/client/wrappers/ReactDOMButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
3 changes: 2 additions & 1 deletion src/renderers/dom/client/wrappers/ReactDOMInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

'use strict';

var DisabledInputUtils = require('DisabledInputUtils');
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/renderers/dom/client/wrappers/ReactDOMSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

'use strict';

var DisabledInputUtils = require('DisabledInputUtils');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactUpdates = require('ReactUpdates');
Expand Down Expand Up @@ -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,
});
Expand Down
3 changes: 2 additions & 1 deletion src/renderers/dom/client/wrappers/ReactDOMTextarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

'use strict';

var DisabledInputUtils = require('DisabledInputUtils');
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
Expand Down Expand Up @@ -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,
Expand Down
108 changes: 108 additions & 0 deletions src/renderers/dom/client/wrappers/__tests__/DisabledInputUtil-test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
});
93 changes: 0 additions & 93 deletions src/renderers/dom/client/wrappers/__tests__/ReactDOMButton-test.js

This file was deleted.