Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit d689a44

Browse files
Goamandmo-odoo
authored andcommitted
[FIX] EventNormalizer: Concurency issue with pointer
1 parent 8323a5a commit d689a44

File tree

7 files changed

+442
-200
lines changed

7 files changed

+442
-200
lines changed

packages/plugin-dom-editable/src/DomEditable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,6 @@ export class DomEditable<T extends JWPluginConfig = JWPluginConfig> extends JWPl
202202
* observation to make chain of event properly.
203203
*/
204204
private _onPreKeydownCommand(): void {
205-
this.eventNormalizer.initNextObservation();
205+
this.eventNormalizer.processEventTimeouts();
206206
}
207207
}

packages/plugin-dom-editable/src/EventNormalizer.ts

Lines changed: 275 additions & 177 deletions
Large diffs are not rendered by default.

packages/plugin-dom-editable/src/MutationNormalizer.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ export class MutationNormalizer {
4242
* @param charMutations
4343
* @returns { previous, current }
4444
*/
45-
getCharactersMapping(): {
45+
getCharactersMapping(
46+
mutations: MutationRecord[],
47+
): {
4648
insert: string;
4749
remove: string;
4850
index: number;
@@ -64,7 +66,7 @@ export class MutationNormalizer {
6466
function isTextNode(target: Node): boolean {
6567
return target.nodeType === Node.TEXT_NODE || nodeName(target) === 'BR';
6668
}
67-
this._mutations.forEach(record => {
69+
mutations.forEach(record => {
6870
const targetMutation = record.target;
6971
const targetIsAdded = add.has(targetMutation);
7072
if (!targetIsAdded) {
@@ -285,9 +287,9 @@ export class MutationNormalizer {
285287
current: currentLinked,
286288
};
287289
}
288-
getMutatedElements(): Set<Node> {
290+
getMutatedElements(mutations: MutationRecord[]): Set<Node> {
289291
const elements: Set<Node> = new Set();
290-
this._mutations.forEach(MutationRecord => {
292+
mutations.forEach(MutationRecord => {
291293
if (MutationRecord.type === 'characterData') {
292294
elements.add(MutationRecord.target);
293295
} else {

packages/plugin-dom-editable/test/DomEditable.test.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ describe('DomEditable', () => {
737737
contentBefore: '<div>[]</div>',
738738
stepFunction: async editor => {
739739
const domEngine = editor.plugins.get(Layout).engines.dom as DomLayoutEngine;
740+
const domEditable = editor.plugins.get(DomEditable);
740741
const editable = domEngine.components.editable[0];
741742
const editableDom = domEngine.getDomNodes(editable)[0] as HTMLElement;
742743
const textNode = editableDom.childNodes[0];
@@ -748,6 +749,19 @@ describe('DomEditable', () => {
748749
textNode.textContent = 'ab';
749750
triggerEvent(editableDom, 'keyup', { key: 'b', code: 'KeyB' });
750751
triggerEvent(editableDom, 'input', { data: 'b', inputType: 'insertText' });
752+
domEditable.eventNormalizer.currentStackObservation.mutations = [
753+
{
754+
addedNodes: editableDom.childNodes,
755+
attributeName: null,
756+
attributeNamespace: null,
757+
nextSibling: null,
758+
oldValue: null,
759+
previousSibling: null,
760+
removedNodes: editableDom.childNodes,
761+
target: editableDom,
762+
type: 'childList',
763+
},
764+
];
751765
triggerEvent(editableDom, 'keydown', { key: 'Tab', code: 'Tab' });
752766
triggerEvent(editableDom, 'keyup', { key: 'Tab', code: 'Tab' });
753767
triggerEvent(editableDom, 'keydown', { key: 'c', code: 'KeyC' });
@@ -804,7 +818,7 @@ describe('DomEditable', () => {
804818
const params = {
805819
context: editor.contextManager.defaultContext,
806820
};
807-
expect(execSpy.args).to.eql([['command-b', params]]);
821+
expect(execSpy.args).to.eql([['@focus'], ['command-b', params]]);
808822
});
809823
it('should trigger a select all, with an other editor which have a shortcut', async () => {
810824
editor = new JWEditor();
@@ -873,13 +887,16 @@ describe('DomEditable', () => {
873887
context: editor.contextManager.defaultContext,
874888
};
875889
expect(execSpy.args).to.eql([
890+
['@focus'],
876891
['command-b', params],
892+
['@blur'],
877893
// todo: There should not be a select all in the first editor.
878894
// Correct this bug when having two editor at the same time
879895
// becomes critical.
880896
['selectAll', {}],
897+
['@focus'],
881898
]);
882-
expect(execSpy2.args).to.eql([['selectAll', {}]]);
899+
expect(execSpy2.args).to.eql([['@focus'], ['@blur'], ['selectAll', {}]]);
883900

884901
await editor.stop();
885902
await editor2.stop();

packages/plugin-dom-editable/test/EventNormalizerPointer.test.ts

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ describe('utils', () => {
249249
ctx.editable.innerHTML = '<div>abc def</div>';
250250
const p = ctx.editable.firstChild;
251251
const text = p.firstChild;
252+
setDomSelection(p, 0, p, 0);
252253
await nextTick();
253254
ctx.eventBatches.splice(0);
254255
triggerEvent(p, 'touchstart', {
@@ -306,6 +307,21 @@ describe('utils', () => {
306307
];
307308

308309
const batchEvents: EventBatch[] = [
310+
{
311+
actions: [
312+
{
313+
type: 'setSelection',
314+
domSelection: {
315+
anchorNode: p,
316+
anchorOffset: 0,
317+
focusNode: p,
318+
focusOffset: 0,
319+
direction: Direction.FORWARD,
320+
},
321+
},
322+
],
323+
mutatedElements: new Set([]),
324+
},
309325
{
310326
actions: normalizedActions,
311327
mutatedElements: new Set([]),
@@ -373,6 +389,21 @@ describe('utils', () => {
373389
];
374390

375391
const batchEvents: EventBatch[] = [
392+
{
393+
actions: [
394+
{
395+
type: 'setSelection',
396+
domSelection: {
397+
anchorNode: text,
398+
anchorOffset: 3,
399+
focusNode: text,
400+
focusOffset: 3,
401+
direction: Direction.FORWARD,
402+
},
403+
},
404+
],
405+
mutatedElements: new Set([]),
406+
},
376407
{
377408
actions: normalizedActions,
378409
mutatedElements: new Set([]),
@@ -584,7 +615,7 @@ describe('utils', () => {
584615
const firstText = div.firstChild;
585616
const textB = b.firstChild;
586617
const text = div.childNodes[2];
587-
setDomSelection(text, 2, text, 2);
618+
setDomSelection(text, 0, text, 2);
588619

589620
await nextTick();
590621
ctx.eventBatches.splice(0);
@@ -1514,6 +1545,21 @@ describe('utils', () => {
15141545
},
15151546
];
15161547
const batchEvents: EventBatch[] = [
1548+
{
1549+
actions: [
1550+
{
1551+
type: 'setSelection',
1552+
domSelection: {
1553+
anchorNode: text1,
1554+
anchorOffset: 0,
1555+
focusNode: text1,
1556+
focusOffset: 0,
1557+
direction: Direction.FORWARD,
1558+
},
1559+
},
1560+
],
1561+
mutatedElements: new Set([]),
1562+
},
15171563
{
15181564
actions: pointerActions1,
15191565
mutatedElements: new Set([]),
@@ -1650,6 +1696,21 @@ describe('utils', () => {
16501696
];
16511697

16521698
const batchEvents: EventBatch[] = [
1699+
{
1700+
actions: [
1701+
{
1702+
type: 'setSelection',
1703+
domSelection: {
1704+
anchorNode: text,
1705+
anchorOffset: 1,
1706+
focusNode: text,
1707+
focusOffset: 1,
1708+
direction: Direction.FORWARD,
1709+
},
1710+
},
1711+
],
1712+
mutatedElements: new Set([]),
1713+
},
16531714
{
16541715
actions: normalizedActions,
16551716
mutatedElements: new Set([]),
@@ -1709,6 +1770,21 @@ describe('utils', () => {
17091770
];
17101771

17111772
const batchEvents: EventBatch[] = [
1773+
{
1774+
actions: [
1775+
{
1776+
type: 'setSelection',
1777+
domSelection: {
1778+
anchorNode: firstDiv.firstChild,
1779+
anchorOffset: 1,
1780+
focusNode: firstDiv.firstChild,
1781+
focusOffset: 1,
1782+
direction: Direction.FORWARD,
1783+
},
1784+
},
1785+
],
1786+
mutatedElements: new Set([]),
1787+
},
17121788
{
17131789
actions: normalizedActions,
17141790
mutatedElements: new Set([]),
@@ -1764,6 +1840,21 @@ describe('utils', () => {
17641840
];
17651841

17661842
const batchEvents: EventBatch[] = [
1843+
{
1844+
actions: [
1845+
{
1846+
type: 'setSelection',
1847+
domSelection: {
1848+
anchorNode: p.firstChild,
1849+
anchorOffset: 1,
1850+
focusNode: p.firstChild,
1851+
focusOffset: 2,
1852+
direction: Direction.FORWARD,
1853+
},
1854+
},
1855+
],
1856+
mutatedElements: new Set([]),
1857+
},
17671858
{
17681859
actions: normalizedActions,
17691860
mutatedElements: new Set([]),
@@ -1819,6 +1910,21 @@ describe('utils', () => {
18191910
];
18201911

18211912
const batchEvents: EventBatch[] = [
1913+
{
1914+
actions: [
1915+
{
1916+
type: 'setSelection',
1917+
domSelection: {
1918+
anchorNode: a,
1919+
anchorOffset: 0,
1920+
focusNode: a,
1921+
focusOffset: 0,
1922+
direction: Direction.FORWARD,
1923+
},
1924+
},
1925+
],
1926+
mutatedElements: new Set([]),
1927+
},
18221928
{
18231929
actions: normalizedActions,
18241930
mutatedElements: new Set([]),
@@ -1890,6 +1996,21 @@ describe('utils', () => {
18901996
];
18911997

18921998
const batchEvents: EventBatch[] = [
1999+
{
2000+
actions: [
2001+
{
2002+
type: 'setSelection',
2003+
domSelection: {
2004+
anchorNode: svg,
2005+
anchorOffset: 0,
2006+
focusNode: svg,
2007+
focusOffset: 0,
2008+
direction: Direction.FORWARD,
2009+
},
2010+
},
2011+
],
2012+
mutatedElements: new Set([]),
2013+
},
18932014
{
18942015
actions: normalizedActions,
18952016
mutatedElements: new Set([]),

0 commit comments

Comments
 (0)