Skip to content

Commit

Permalink
Handle composition events in ChangeEventPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
yesmeck committed Nov 28, 2016
1 parent e24ec4a commit dca73a4
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 2 deletions.
34 changes: 32 additions & 2 deletions src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ var eventTypes = {
'topKeyDown',
'topKeyUp',
'topSelectionChange',
'topCompositionStart',
'topCompositionUpdate',
'topCompositionEnd',
],
},
};
Expand All @@ -62,7 +65,10 @@ function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
var activeElement = null;
var activeElementInst = null;


/**
* For composition events
*/
var lastTopLevelType = null;

/**
* SECTION: handle `change` event
Expand Down Expand Up @@ -281,14 +287,37 @@ function getTargetInstForInputOrChangeEvent(
topLevelType,
targetInst
) {
if (
if (inComposition(topLevelType)) {
return;
} else if (
topLevelType === 'topInput' &&
lastTopLevelType === 'topCompositionEnd'
) {
return getInstIfValueChanged(targetInst);
} else if (
// Webkit fires compositionEnd event after input
topLevelType === 'topKeyUp' &&
lastTopLevelType === 'topCompositionEnd'
) {
return getInstIfValueChanged(targetInst);
} else if (
topLevelType === 'topInput' ||
topLevelType === 'topChange'
) {
return getInstIfValueChanged(targetInst);
}
}

var isComposing = false;
function inComposition(topLevelType) {
if (topLevelType === 'topCompositionStart') {
isComposing = true;
} else if (topLevelType === 'topCompositionEnd') {
isComposing = false;
}
return isComposing;
}

/**
* This plugin creates an `onChange` event that normalizes change events
* across form elements. This event fires at a time when it's possible to
Expand Down Expand Up @@ -334,6 +363,7 @@ var ChangeEventPlugin = {

if (getTargetInstFunc) {
var inst = getTargetInstFunc(topLevelType, targetInst);
lastTopLevelType = topLevelType;
if (inst) {
var event = createAndAccumulateChangeEvent(
inst,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,156 @@ describe('ChangeEventPlugin', () => {
ReactTestUtils.SimulateNative.change(input);
expect(called).toBe(2);
});

describe('composition events', () => {
function simulateEvent(inst, event) {
ReactTestUtils.SimulateNative[event](inst);
}

function TestCompositionEvent(Scenario) {
var called = 0;
var value = null;

function cb(e) {
called += 1;
value = e.target.value;
}

var input = ReactTestUtils.renderIntoDocument(
<input type="text" onChange={cb} />
);

Scenario.forEach(el => {
el.run.apply(null, [input].concat(el.args))
});

expect(called).toBe(1);
expect(value).toBe('你');
}

var Scenario = {
Webkit: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'textInput' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
],
Firefox: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
],
IE9: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
],
IE10: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
],
IE11: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'compositionUpdate' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'input' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
],
Edge: [
{ run: setUntrackedValue, args: [ 'n' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionStart' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ 'ni' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'keyUp' ] },
{ run: setUntrackedValue, args: [ '你' ] },
{ run: simulateEvent, args: [ 'keyDown' ] },
{ run: simulateEvent, args: [ 'compositionEnd' ] },
{ run: simulateEvent, args: [ 'input' ] },
],
};

it('should only fire change once on Webkit', () => {
TestCompositionEvent(Scenario.Webkit);
});

it('should only fire change once on Firefox', () => {
TestCompositionEvent(Scenario.Firefox);
});

it('should only fire change once on IE9', () => {
TestCompositionEvent(Scenario.IE9);
});

it('should only fire change once on IE10', () => {
TestCompositionEvent(Scenario.IE10);
});

it('should only fire change once on IE11', () => {
TestCompositionEvent(Scenario.IE11);
});

it('should only fire change once on Edge', () => {
TestCompositionEvent(Scenario.Edge);
});
});
});

0 comments on commit dca73a4

Please sign in to comment.