From a84a433271a0c6aba501ee774aac172663780754 Mon Sep 17 00:00:00 2001 From: Jim Date: Mon, 21 Mar 2016 13:29:01 -0700 Subject: [PATCH 1/2] Fix event handling when input name='nodeName' - Add test coverage for nodeName fix - Add defaultValue to test to avoid log --- .../components/fixtures/text-inputs/index.js | 16 ++++++++++++++ .../dom/shared/ReactInputSelection.js | 8 +++---- .../shared/eventPlugins/ChangeEventPlugin.js | 8 ++++++- .../wrappers/__tests__/ReactDOMInput-test.js | 22 +++++++++++++++++++ .../shared/utils/isTextInputElement.js | 6 ++--- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/fixtures/dom/src/components/fixtures/text-inputs/index.js b/fixtures/dom/src/components/fixtures/text-inputs/index.js index 61600b8ca1eb..9f98a00a9be1 100644 --- a/fixtures/dom/src/components/fixtures/text-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/text-inputs/index.js @@ -70,6 +70,22 @@ class TextInputFixtures extends React.Component { + + +
  • Type any character
  • +
    + + + There should be no errors in the console. + + +
    +
    + +
    +
    +
    + diff --git a/src/renderers/dom/shared/ReactInputSelection.js b/src/renderers/dom/shared/ReactInputSelection.js index 427e71f88a79..0cf18ea5d3d6 100644 --- a/src/renderers/dom/shared/ReactInputSelection.js +++ b/src/renderers/dom/shared/ReactInputSelection.js @@ -30,12 +30,10 @@ function isInDocument(node) { */ var ReactInputSelection = { hasSelectionCapabilities: function(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); return ( - nodeName && - ((nodeName === 'input' && elem.type === 'text') || - nodeName === 'textarea' || - elem.contentEditable === 'true') + (elem instanceof HTMLInputElement && elem.type === 'text') || + elem instanceof HTMLTextAreaElement || + elem.contentEditable === 'true' ); }, diff --git a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js index 6381eb54eded..4cb8bb0db5ca 100644 --- a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js +++ b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js @@ -40,8 +40,14 @@ var eventTypes = { }, }; +var nodeNameGetter = Object.getOwnPropertyDescriptor( + Node.prototype, + 'nodeName' +).get; + function shouldUseChangeEvent(elem) { - var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); + var nodeName = nodeNameGetter.call(element); + return ( nodeName === 'select' || (nodeName === 'input' && elem.type === 'file') ); diff --git a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js index b90923c77213..d08c6459aaf1 100644 --- a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js @@ -1346,4 +1346,26 @@ describe('ReactDOMInput', () => { expect(node.getAttribute('value')).toBe('1'); }); }); + + it('an input with an id of `nodeName` works as intended', () => { + var spy = jest.fn(); + + class Test extends React.Component { + render() { + return ( +
    + + +
    + ); + } + } + + var stub = ReactTestUtils.renderIntoDocument(); + var node = ReactDOM.findDOMNode(stub); + + ReactTestUtils.Simulate.submit(node); + + expect(spy).toHaveBeenCalled(); + }); }); diff --git a/src/renderers/shared/utils/isTextInputElement.js b/src/renderers/shared/utils/isTextInputElement.js index 633c19ce33af..61f5ba03819e 100644 --- a/src/renderers/shared/utils/isTextInputElement.js +++ b/src/renderers/shared/utils/isTextInputElement.js @@ -34,13 +34,11 @@ var supportedInputTypes: {[key: string]: true | void} = { }; function isTextInputElement(elem: ?HTMLElement): boolean { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - - if (nodeName === 'input') { + if (elem instanceof HTMLInputElement) { return !!supportedInputTypes[((elem: any): HTMLInputElement).type]; } - if (nodeName === 'textarea') { + if (elem instanceof HTMLTextAreaElement) { return true; } From 1810b5a876c1b3bc3543e7efccc5d36094449fb0 Mon Sep 17 00:00:00 2001 From: Nathan Hunzaker Date: Wed, 9 Aug 2017 18:59:56 -0400 Subject: [PATCH 2/2] Use nodeName getter instead of instanceof --- src/renderers/dom/shared/ReactInputSelection.js | 13 +++++++++++-- .../dom/shared/eventPlugins/ChangeEventPlugin.js | 15 ++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/renderers/dom/shared/ReactInputSelection.js b/src/renderers/dom/shared/ReactInputSelection.js index 0cf18ea5d3d6..7d172c979e0a 100644 --- a/src/renderers/dom/shared/ReactInputSelection.js +++ b/src/renderers/dom/shared/ReactInputSelection.js @@ -22,6 +22,9 @@ function isInDocument(node) { return containsNode(document.documentElement, node); } +var nodeNameGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'nodeName') + .get; + /** * @ReactInputSelection: React input selection module. Based on Selection.js, * but modified to be suitable for react and has a couple of bug fixes (doesn't @@ -30,9 +33,15 @@ function isInDocument(node) { */ var ReactInputSelection = { hasSelectionCapabilities: function(elem) { + if (elem === window) { + return false; + } + + var nodeName = nodeNameGetter.call(elem); + return ( - (elem instanceof HTMLInputElement && elem.type === 'text') || - elem instanceof HTMLTextAreaElement || + (nodeName === 'INPUT' && elem.type === 'text') || + nodeName === 'TEXTAREA' || elem.contentEditable === 'true' ); }, diff --git a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js index 4cb8bb0db5ca..567148764d35 100644 --- a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js +++ b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js @@ -40,16 +40,18 @@ var eventTypes = { }, }; -var nodeNameGetter = Object.getOwnPropertyDescriptor( - Node.prototype, - 'nodeName' -).get; +var nodeNameGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'nodeName') + .get; function shouldUseChangeEvent(elem) { - var nodeName = nodeNameGetter.call(element); + if (elem === window) { + return false; + } + + var nodeName = nodeNameGetter.call(elem); return ( - nodeName === 'select' || (nodeName === 'input' && elem.type === 'file') + nodeName === 'SELECT' || (nodeName === 'INPUT' && elem.type === 'FILE') ); } @@ -165,7 +167,6 @@ var ChangeEventPlugin = { } var getTargetInstFunc, handleEventFunc; - if (shouldUseChangeEvent(targetNode)) { getTargetInstFunc = getTargetInstForChangeEvent; } else if (isTextInputElement(targetNode) && !isTextInputEventSupported) {