Skip to content

Commit

Permalink
fix: wait for editor focusout on Tab to get updated value (#7822) (#7969
Browse files Browse the repository at this point in the history
)
  • Loading branch information
web-padawan authored Oct 15, 2024
1 parent 8017ec1 commit b58a187
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 127 deletions.
137 changes: 137 additions & 0 deletions integration/tests/grid-pro-custom-editor.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { expect } from '@esm-bundle/chai';
import { fixtureSync, nextRender } from '@vaadin/testing-helpers';
import { sendKeys } from '@web/test-runner-commands';
import '@vaadin/combo-box';
import '@vaadin/date-picker';
import '@vaadin/grid-pro';
import '@vaadin/grid-pro/vaadin-grid-pro-edit-column.js';
import '@vaadin/time-picker';
import { flushGrid, getContainerCell } from '@vaadin/grid-pro/test/helpers.js';

describe('grid-pro custom editor', () => {
let grid;

beforeEach(async () => {
grid = fixtureSync(`
<vaadin-grid-pro>
<vaadin-grid-pro-edit-column path="firstName"></vaadin-grid-pro-edit-column>
<vaadin-grid-pro-edit-column path="lastName"></vaadin-grid-pro-edit-column>
<vaadin-grid-pro-edit-column path="birthday" editor-type="custom"></vaadin-grid-pro-edit-column>
<vaadin-grid-pro-edit-column path="status" editor-type="custom"></vaadin-grid-pro-edit-column>
<vaadin-grid-pro-edit-column path="time" editor-type="custom"></vaadin-grid-pro-edit-column>
</vaadin-gri-pro>
`);

grid.items = [
{ firstName: 'Aria', lastName: 'Bailey', birthday: '1984-01-13', status: 'suspended', time: '09:00' },
{ firstName: 'Aaliyah', lastName: 'Butler', birthday: '1977-07-12', status: 'active', time: '09:30' },
{ firstName: 'Eleanor', lastName: 'Price', birthday: '1976-12-14', status: 'suspended', time: '10:00' },
{ firstName: 'Allison', lastName: 'Torres', birthday: '1972-12-04', status: 'active', time: '10:00' },
{ firstName: 'Madeline', lastName: 'Lewis', birthday: '1978-02-03', status: 'active', time: '10:00' },
];

grid.querySelector('[path="birthday"]').editModeRenderer = (root, _, model) => {
root.innerHTML = `
<vaadin-date-picker value="${model.item.birthday}" auto-open-disabled>
</vaadin-date-picker>
`;
};

grid.querySelector('[path="status"]').editModeRenderer = (root, _, model) => {
if (!root.firstChild) {
const comboBox = document.createElement('vaadin-combo-box');
comboBox.autoOpenDisabled = true;
comboBox.items = ['active', 'suspended'];
root.appendChild(comboBox);
}
root.firstChild.value = model.item.status;
};

grid.querySelector('[path="time"]').editModeRenderer = (root, _, model) => {
root.innerHTML = `
<vaadin-time-picker value="${model.item.time}" auto-open-disabled></vaadin-time-picker>
`;
};

flushGrid(grid);
await nextRender();
});

describe('date-picker', () => {
it('should apply the updated date to the cell when exiting on Tab', async () => {
const cell = getContainerCell(grid.$.items, 0, 2);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: '1/12/1984' });
await sendKeys({ press: 'Tab' });

expect(cell._content.textContent).to.equal('1984-01-12');
});

it('should apply the updated date to the cell when exiting on Enter', async () => {
const cell = getContainerCell(grid.$.items, 0, 2);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: '1/12/1984' });
await sendKeys({ press: 'Enter' });

expect(cell._content.textContent).to.equal('1984-01-12');
});
});

describe('combo-box', () => {
it('should apply the updated value to the cell when exiting on Tab', async () => {
const cell = getContainerCell(grid.$.items, 0, 3);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: 'active' });
await sendKeys({ press: 'Tab' });

expect(cell._content.textContent).to.equal('active');
});

it('should apply the updated value to the cell when exiting on Enter', async () => {
const cell = getContainerCell(grid.$.items, 0, 3);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: 'active' });
await sendKeys({ press: 'Enter' });

expect(cell._content.textContent).to.equal('active');
});
});

describe('time-picker', () => {
it('should apply the updated time to the cell when exiting on Tab', async () => {
const cell = getContainerCell(grid.$.items, 0, 4);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: '10:00' });
await sendKeys({ press: 'Tab' });

expect(cell._content.textContent).to.equal('10:00');
});

it('should apply the updated value to the cell when exiting on Enter', async () => {
const cell = getContainerCell(grid.$.items, 0, 4);
cell.focus();

await sendKeys({ press: 'Enter' });

await sendKeys({ type: '10:00' });
await sendKeys({ press: 'Enter' });

expect(cell._content.textContent).to.equal('10:00');
});
});
});
26 changes: 21 additions & 5 deletions packages/grid-pro/src/vaadin-grid-pro-inline-editing-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ export const InlineEditingMixin = (superClass) =>

/** @private */
_onEditorFocusOut() {
// Ignore focusout from internal tab event
if (this.__cancelCellSwitch) {
return;
}
// Schedule stop on editor component focusout
this._debouncerStopEdit = Debouncer.debounce(this._debouncerStopEdit, animationFrame, this._stopEdit.bind(this));
}
Expand Down Expand Up @@ -413,7 +417,7 @@ export const InlineEditingMixin = (superClass) =>
* @param {!KeyboardEvent} e
* @protected
*/
_switchEditCell(e) {
async _switchEditCell(e) {
if (this.__cancelCellSwitch || (e.defaultPrevented && e.keyCode === 9)) {
return;
}
Expand All @@ -423,6 +427,22 @@ export const InlineEditingMixin = (superClass) =>
const cols = this._getEditColumns();

const { cell, column, model } = this.__edited;

// Prevent vaadin-grid handler from being called
e.stopImmediatePropagation();

const editor = column._getEditorComponent(cell);

// Do not prevent Tab to allow native input blur and wait for it,
// unless the keydown event is from the edit cell select overlay.
if (e.key === 'Tab' && editor && editor.contains(e.target)) {
await new Promise((resolve) => {
editor.addEventListener('focusout', () => resolve(), { once: true });
});
} else {
e.preventDefault();
}

const colIndex = cols.indexOf(column);
const { index } = model;

Expand Down Expand Up @@ -462,10 +482,6 @@ export const InlineEditingMixin = (superClass) =>

if (nextRow && nextCol) {
const nextCell = Array.from(nextRow.children).find((cell) => cell._column === nextCol);
e.preventDefault();

// Prevent vaadin-grid handler from being called
e.stopImmediatePropagation();

if (!this.singleCellEdit && nextCell !== cell) {
this._startEdit(nextCell, nextCol);
Expand Down
46 changes: 25 additions & 21 deletions packages/grid-pro/test/edit-column.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from '@esm-bundle/chai';
import { enter, fixtureSync, focusin, focusout, isIOS, tab } from '@vaadin/testing-helpers';
import { enter, fixtureSync, focusin, focusout, nextFrame } from '@vaadin/testing-helpers';
import { sendKeys } from '@web/test-runner-commands';
import sinon from 'sinon';
import '@vaadin/polymer-legacy-adapter/template-renderer.js';
Expand All @@ -20,10 +20,10 @@ import {
const isMac = navigator.platform.includes('Mac');

describe('edit column', () => {
(isIOS ? describe.skip : describe)('select column', () => {
let grid, textCell, selectCell, checkboxCell;
describe('select column', () => {
let grid, textCell, selectCell, ageCell;

beforeEach(() => {
beforeEach(async () => {
grid = fixtureSync(`
<vaadin-grid-pro>
<vaadin-grid-pro-edit-column path="name"></vaadin-grid-pro-edit-column>
Expand All @@ -37,31 +37,36 @@ describe('edit column', () => {
flushGrid(grid);
textCell = getContainerCell(grid.$.items, 1, 0);
selectCell = getContainerCell(grid.$.items, 1, 1);
checkboxCell = getContainerCell(grid.$.items, 1, 2);
ageCell = getContainerCell(grid.$.items, 1, 2);
await nextFrame();
});

it('should focus cell next available for editing in edit mode on Tab', async () => {
dblclick(textCell._content);
expect(getCellEditor(textCell)).to.be.ok;
await nextFrame();

// Press Tab to edit the select cell
await sendKeys({ press: 'Tab' });
expect(getCellEditor(selectCell)).to.be.ok;
await nextFrame();

// Press Tab to edit the checkbox cell
// Press Tab to edit the age cell
await sendKeys({ press: 'Tab' });
expect(getCellEditor(checkboxCell)).to.be.ok;
expect(getCellEditor(ageCell)).to.be.ok;
});

it('should focus previous cell available for editing in edit mode on Shift Tab', async () => {
dblclick(checkboxCell._content);
expect(getCellEditor(checkboxCell)).to.be.ok;
dblclick(ageCell._content);
expect(getCellEditor(ageCell)).to.be.ok;
await nextFrame();

// Press Shift + Tab to edit the select cell
await sendKeys({ down: 'Shift' });
await sendKeys({ press: 'Tab' });
await sendKeys({ up: 'Shift' });
expect(getCellEditor(selectCell)).to.be.ok;
await nextFrame();

// Press Shift + Tab to edit the text cell
await sendKeys({ down: 'Shift' });
Expand Down Expand Up @@ -111,7 +116,7 @@ describe('edit column', () => {
});

describe('horizontal scrolling to cell', () => {
let grid, input;
let grid;

beforeEach(() => {
grid = fixtureSync(`
Expand All @@ -130,26 +135,24 @@ describe('edit column', () => {
flushGrid(grid);
});

it('should scroll to the right on tab when editable cell is outside the viewport', () => {
it('should scroll to the right on tab when editable cell is outside the viewport', async () => {
const firstCell = getContainerCell(grid.$.items, 1, 0);
dblclick(firstCell._content);
input = getCellEditor(firstCell);
tab(input);

await sendKeys({ press: 'Tab' });

expect(grid.$.table.scrollLeft).to.be.at.least(100);
});

it('should scroll to the left on tab when editable cell is outside the viewport', (done) => {
it('should scroll to the left on tab when editable cell is outside the viewport', async () => {
const firstCell = getContainerCell(grid.$.items, 1, 1);
dblclick(firstCell._content);

setTimeout(() => {
input = getCellEditor(firstCell);
tab(input, ['shift']);
await sendKeys({ down: 'Shift' });
await sendKeys({ press: 'Tab' });
await sendKeys({ up: 'Shift' });

expect(grid.$.table.scrollLeft).to.closeTo(1, 1);
done();
});
expect(grid.$.table.scrollLeft).to.closeTo(1, 1);
});
});

Expand Down Expand Up @@ -250,11 +253,12 @@ describe('edit column', () => {
expect(input).to.be.not.ok;
});

it('should cancel editing when disabled is set to true', () => {
it('should cancel editing when disabled is set to true', async () => {
const cell = getContainerCell(grid.$.items, 1, 0);
const oldContent = cell._content.textContent;
enter(cell);
grid.disabled = true;
await nextFrame();
expect(cell._content.textContent).to.equal(oldContent);
});
});
Expand Down
Loading

0 comments on commit b58a187

Please sign in to comment.