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

fix(input, textarea): clearOnInput ignores key modifiers #28639

Merged
merged 11 commits into from
Dec 11, 2023
2 changes: 1 addition & 1 deletion core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Change Log
testwq# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
Expand Down
24 changes: 22 additions & 2 deletions core/src/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -545,15 +545,35 @@ export class Input implements ComponentInterface {
if (!this.shouldClearOnEdit()) {
return;
}

/**
* The following keys do not modify the
* contents of the input. As a result, pressing
* them should not edit the input.
*
* We can't check to see if the value of the input
* was changed because we call checkClearOnEdit
* in a keydown listener, and the key has not yet
* been added to the input.
*/
const IGNORED_KEYS = ['Enter', 'Tab', 'Shift', 'Meta', 'Alt', 'Control'];

/**
* Clear the input if the control has not been previously cleared during focus.
* Do not clear if the user hitting enter to submit a form.
*/
if (!this.didInputClearOnEdit && this.hasValue() && ev.key !== 'Enter' && ev.key !== 'Tab') {
if (!this.didInputClearOnEdit && this.hasValue() && !IGNORED_KEYS.includes(ev.key)) {
this.value = '';
this.emitInputChange(ev);

/**
* Only set this flag if we cleared the input.
* Otherwise pressing an IGNORED_KEYS first and
* then an allowed key will cause the input to not
* be cleared.
*/
this.didInputClearOnEdit = true;
}
this.didInputClearOnEdit = true;
}

private onCompositionStart = () => {
Expand Down
34 changes: 25 additions & 9 deletions core/src/components/input/test/clear-on-edit/input.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from '@playwright/test';
import { test, configs } from '@utils/test/playwright';

const IGNORED_KEYS = ['Enter', 'Tab', 'Shift', 'Meta', 'Alt', 'Control'];
liamdebeasi marked this conversation as resolved.
Show resolved Hide resolved

configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('input: clearOnEdit'), () => {
test('should clear when typed into', async ({ page }) => {
Expand All @@ -16,28 +18,42 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await expect(input).toHaveJSProperty('value', 'h');
});

test('should not clear when enter is pressed', async ({ page }) => {
await page.setContent(`<ion-input value="abc" clear-on-edit="true" aria-label="input"></ion-input>`, config);
IGNORED_KEYS.forEach((ignoredKey: string) => {
test(`should not clear when ${ignoredKey} is pressed`, async ({ page }) => {
await page.setContent(`<ion-input value="abc" clear-on-edit="true" aria-label="input"></ion-input>`, config);

const input = page.locator('ion-input');
await input.locator('input').focus();
const input = page.locator('ion-input');
await input.locator('input').focus();

await page.keyboard.press('Enter');
await page.waitForChanges();
await page.keyboard.press(ignoredKey);
await page.waitForChanges();

await expect(input).toHaveJSProperty('value', 'abc');
await expect(input).toHaveJSProperty('value', 'abc');
});
});

test('should not clear when tab is pressed', async ({ page }) => {
test('should clear after when pressing valid key after pressing ignored key', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/28633',
});

await page.setContent(`<ion-input value="abc" clear-on-edit="true" aria-label="input"></ion-input>`, config);

const input = page.locator('ion-input');
await input.locator('input').focus();

await page.keyboard.press('Tab');
// ignored
await page.keyboard.press('Shift');
await page.waitForChanges();

await expect(input).toHaveJSProperty('value', 'abc');

// allowed
await page.keyboard.press('a');
await page.waitForChanges();

await expect(input).toHaveJSProperty('value', 'a');
});
});
});
46 changes: 46 additions & 0 deletions core/src/components/textarea/test/clear-on-edit/textarea.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from '@playwright/test';
import { test, configs } from '@utils/test/playwright';

const IGNORED_KEYS = ['Tab', 'Shift', 'Meta', 'Alt', 'Control'];

configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('textarea: clearOnEdit'), () => {
test('should clear when typed into', async ({ page }) => {
Expand Down Expand Up @@ -33,5 +35,49 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>

await expect(textarea).toHaveJSProperty('value', 'abc');
});

IGNORED_KEYS.forEach((ignoredKey: string) => {
test(`should not clear when ${ignoredKey} is pressed`, async ({ page }) => {
await page.setContent(
`<ion-textarea value="abc" clear-on-edit="true" aria-label="textarea"></ion-textarea>`,
config
);

const textarea = page.locator('ion-textarea');
await textarea.locator('textarea').focus();

await page.keyboard.press(ignoredKey);
await page.waitForChanges();

await expect(textarea).toHaveJSProperty('value', 'abc');
});
});

test('should clear after when pressing valid key after pressing ignored key', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/28633',
});

await page.setContent(
`<ion-textarea value="abc" clear-on-edit="true" aria-label="textarea"></ion-textarea>`,
config
);

const textarea = page.locator('ion-textarea');
await textarea.locator('textarea').focus();

// ignored
await page.keyboard.press('Shift');
await page.waitForChanges();

await expect(textarea).toHaveJSProperty('value', 'abc');

// allowed
await page.keyboard.press('a');
await page.waitForChanges();

await expect(textarea).toHaveJSProperty('value', 'a');
});
});
});
28 changes: 26 additions & 2 deletions core/src/components/textarea/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -455,15 +455,39 @@ export class Textarea implements ComponentInterface {
if (!this.clearOnEdit) {
return;
}

/**
* The following keys do not modify the
* contents of the input. As a result, pressing
* them should not edit the textarea.
*
* We can't check to see if the value of the textarea
* was changed because we call checkClearOnEdit
* in a keydown listener, and the key has not yet
* been added to the textarea.
*
* Unlike ion-input, the "Enter" key does modify the
* textarea by adding a new line, so "Enter" is not
* included in the IGNORED_KEYS array.
*/
const IGNORED_KEYS = ['Tab', 'Shift', 'Meta', 'Alt', 'Control'];

/**
* Clear the textarea if the control has not been previously cleared
* during focus.
*/
if (!this.didTextareaClearOnEdit && this.hasValue() && ev.key !== 'Tab') {
if (!this.didTextareaClearOnEdit && this.hasValue() && !IGNORED_KEYS.includes(ev.key)) {
this.value = '';
this.emitInputChange(ev);

/**
* Only set this flag if we cleared the input.
* Otherwise pressing an IGNORED_KEYS first and
* then an allowed key will cause the input to not
* be cleared.
*/
this.didTextareaClearOnEdit = true;
}
this.didTextareaClearOnEdit = true;
}

private focusChange() {
Expand Down
Loading