Skip to content

Commit

Permalink
feat(selectAll): allow selecting all in the inputs and in the plain d…
Browse files Browse the repository at this point in the history
…om (#1783)
  • Loading branch information
pavelfeldman committed Apr 15, 2020
1 parent b2c65db commit da683b2
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 21 deletions.
46 changes: 41 additions & 5 deletions docs/api.md
Expand Up @@ -1424,7 +1424,13 @@ The `format` options are:

Focuses the element, and then uses [`keyboard.down`](#keyboarddownkey) and [`keyboard.up`](#keyboardupkey).

`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Note that only those present on a typical full computer keyboard are supported. Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:

`F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrayRight`, `ArrowUp`, etc.

Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.

Holding down `Shift` will type the text that corresponds to the `key` in the upper case.

If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.

Expand Down Expand Up @@ -2242,7 +2248,13 @@ If the name is empty, returns the id attribute instead.
- `timeout` <[number]> Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [browserContext.setDefaultTimeout(timeout)](#browsercontextsetdefaulttimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
- returns: <[Promise]>

`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Note that only those present on a typical full computer keyboard are supported. Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:

`F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrayRight`, `ArrowUp`, etc.

Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.

Holding down `Shift` will type the text that corresponds to the `key` in the upper case.

If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.

Expand Down Expand Up @@ -2517,6 +2529,7 @@ ElementHandle instances can be used as an argument in [`page.$eval()`](#pageeval
- [elementHandle.screenshot([options])](#elementhandlescreenshotoptions)
- [elementHandle.scrollIntoViewIfNeeded()](#elementhandlescrollintoviewifneeded)
- [elementHandle.selectOption(values[, options])](#elementhandleselectoptionvalues-options)
- [elementHandle.selectText()](#elementhandleselecttext)
- [elementHandle.setInputFiles(files[, options])](#elementhandlesetinputfilesfiles-options)
- [elementHandle.textContent()](#elementhandletextcontent)
- [elementHandle.toString()](#elementhandletostring)
Expand Down Expand Up @@ -2736,7 +2749,13 @@ If the element is detached from DOM, the method throws an error.

Focuses the element, and then uses [`keyboard.down`](#keyboarddownkey) and [`keyboard.up`](#keyboardupkey).

`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Note that only those present on a typical full computer keyboard are supported. Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:

`F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrayRight`, `ArrowUp`, etc.

Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.

Holding down `Shift` will type the text that corresponds to the `key` in the upper case.

If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.

Expand Down Expand Up @@ -2793,6 +2812,11 @@ handle.selectOption('red', 'green', 'blue');
handle.selectOption({ value: 'blue' }, { index: 2 }, 'red');
```

#### elementHandle.selectText()
- returns: <[Promise]> Promise which resolves when the element is successfully selected.

This method focuses the element and selects all its text content.

#### elementHandle.setInputFiles(files[, options])
- `files` <[string]|[Array]<[string]>|[Object]|[Array]<[Object]>>
- `name` <[string]> [File] name **required**
Expand Down Expand Up @@ -3125,7 +3149,13 @@ await page.keyboard.press('Shift+A');

Dispatches a `keydown` event.

`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Note that only those present on a typical full computer keyboard are supported. Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:

`F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrayRight`, `ArrowUp`, etc.

Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.

Holding down `Shift` will type the text that corresponds to the `key` in the upper case.

If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.

Expand Down Expand Up @@ -3153,7 +3183,13 @@ page.keyboard.insertText('嗨');
- `delay` <[number]> Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0.
- returns: <[Promise]>

`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Note that only those present on a typical full computer keyboard are supported. Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
`key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to generate the text for. A superset of the `key` values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:

`F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrayRight`, `ArrowUp`, etc.

Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.

Holding down `Shift` will type the text that corresponds to the `key` in the upper case.

If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.

Expand Down
6 changes: 6 additions & 0 deletions src/dom.ts
Expand Up @@ -290,6 +290,12 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
}, deadline, options, true);
}

async selectText(): Promise<void> {
const error = await this._evaluateInUtility(({ injected, node }) => injected.selectText(node), {});
if (typeof error === 'string')
throw new Error(error);
}

async setInputFiles(files: string | types.FilePayload | string[] | types.FilePayload[], options?: types.NavigatingActionWaitOptions) {
const deadline = this._page._timeoutSettings.computeDeadline(options);
const multiple = await this._evaluateInUtility(({ node }) => {
Expand Down
45 changes: 29 additions & 16 deletions src/injected/injected.ts
Expand Up @@ -183,33 +183,46 @@ class Injected {
element.dispatchEvent(new Event('change', { 'bubbles': true }));
return false; // We have already changed the value, no need to input it.
}
} else if (element.nodeName.toLowerCase() === 'textarea') {
const textarea = element as HTMLTextAreaElement;
if (textarea.disabled)
return 'Cannot fill a disabled textarea.';
if (textarea.readOnly)
return 'Cannot fill a readonly textarea.';
} else if (!element.isContentEditable) {
return 'Element is not an <input>, <textarea> or [contenteditable] element.';
}
return this.selectText(node);
}

selectText(node: Node) {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'Node is not of type HTMLElement';
const element = node as HTMLElement;
if (!this.isVisible(element))
return 'Element is not visible';
if (element.nodeName.toLowerCase() === 'input') {
const input = element as HTMLInputElement;
input.select();
input.focus();
return true;
}
if (element.nodeName.toLowerCase() === 'textarea') {
const textarea = element as HTMLTextAreaElement;
if (textarea.disabled)
return 'Cannot fill a disabled textarea.';
if (textarea.readOnly)
return 'Cannot fill a readonly textarea.';
textarea.selectionStart = 0;
textarea.selectionEnd = textarea.value.length;
textarea.focus();
return true;
}
if (element.isContentEditable) {
const range = element.ownerDocument!.createRange();
range.selectNodeContents(element);
const selection = element.ownerDocument!.defaultView!.getSelection();
if (!selection)
return 'Element belongs to invisible iframe.';
selection.removeAllRanges();
selection.addRange(range);
element.focus();
return true;
}
return 'Element is not an <input>, <textarea> or [contenteditable] element.';
const range = element.ownerDocument!.createRange();
range.selectNodeContents(element);
const selection = element.ownerDocument!.defaultView!.getSelection();
if (!selection)
return 'Element belongs to invisible iframe.';
selection.removeAllRanges();
selection.addRange(range);
element.focus();
return true;
}

isCheckboxChecked(node: Node) {
Expand Down
1 change: 1 addition & 0 deletions test/assets/input/textarea.html
Expand Up @@ -7,6 +7,7 @@
<textarea spellcheck="false"></textarea>
<input></input>
<div contenteditable="true"></div>
<div class="plain">Plain div</div>
<script src='mouse-helper.js'></script>
<script>
window.result = '';
Expand Down
24 changes: 24 additions & 0 deletions test/elementhandle.spec.js
Expand Up @@ -327,6 +327,30 @@ describe('ElementHandle.fill', function() {
});
});

describe('ElementHandle.selectText', function() {
it.fail(FFOX)('should select textarea', async({page, server}) => {
await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = await page.$('textarea');
await textarea.evaluate(textarea => textarea.value = 'some value');
await textarea.selectText();
expect(await page.evaluate(() => window.getSelection().toString())).toBe('some value');
});
it.fail(FFOX)('should select input', async({page, server}) => {
await page.goto(server.PREFIX + '/input/textarea.html');
const input = await page.$('input');
await input.evaluate(input => input.value = 'some value');
await input.selectText();
expect(await page.evaluate(() => window.getSelection().toString())).toBe('some value');
});
it('should select plain div', async({page, server}) => {
await page.goto(server.PREFIX + '/input/textarea.html');
const div = await page.$('div.plain');
await div.selectText();
expect(await page.evaluate(() => window.getSelection().toString())).toBe('Plain div');
});
});


describe('ElementHandle convenience API', function() {
it('getAttribute should work', async({page, server}) => {
await page.goto(`${server.PREFIX}/dom.html`);
Expand Down

0 comments on commit da683b2

Please sign in to comment.