1 | /**
|
2 | * @license
|
3 | * Copyright 2020 Google Inc.
|
4 | * SPDX-License-Identifier: Apache-2.0
|
5 | */
|
6 |
|
7 | import type {Protocol} from 'devtools-protocol';
|
8 |
|
9 | import type {ElementHandle} from '../api/ElementHandle.js';
|
10 | import {assert} from '../util/assert.js';
|
11 |
|
12 | /**
|
13 | * File choosers let you react to the page requesting for a file.
|
14 | *
|
15 | * @remarks
|
16 | * `FileChooser` instances are returned via the {@link Page.waitForFileChooser} method.
|
17 | *
|
18 | * In browsers, only one file chooser can be opened at a time.
|
19 | * All file choosers must be accepted or canceled. Not doing so will prevent
|
20 | * subsequent file choosers from appearing.
|
21 | *
|
22 | * @example
|
23 | *
|
24 | * ```ts
|
25 | * const [fileChooser] = await Promise.all([
|
26 | * page.waitForFileChooser(),
|
27 | * page.click('#upload-file-button'), // some button that triggers file selection
|
28 | * ]);
|
29 | * await fileChooser.accept(['/tmp/myfile.pdf']);
|
30 | * ```
|
31 | *
|
32 | * @public
|
33 | */
|
34 | export class FileChooser {
|
35 | #element: ElementHandle<HTMLInputElement>;
|
36 | #multiple: boolean;
|
37 | #handled = false;
|
38 |
|
39 | /**
|
40 | * @internal
|
41 | */
|
42 | constructor(
|
43 | element: ElementHandle<HTMLInputElement>,
|
44 | event: Protocol.Page.FileChooserOpenedEvent,
|
45 | ) {
|
46 | this.#element = element;
|
47 | this.#multiple = event.mode !== 'selectSingle';
|
48 | }
|
49 |
|
50 | /**
|
51 | * Whether file chooser allow for
|
52 | * {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple | multiple}
|
53 | * file selection.
|
54 | */
|
55 | isMultiple(): boolean {
|
56 | return this.#multiple;
|
57 | }
|
58 |
|
59 | /**
|
60 | * Accept the file chooser request with the given file paths.
|
61 | *
|
62 | * @remarks This will not validate whether the file paths exists. Also, if a
|
63 | * path is relative, then it is resolved against the
|
64 | * {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
|
65 | * For locals script connecting to remote chrome environments, paths must be
|
66 | * absolute.
|
67 | */
|
68 | async accept(paths: string[]): Promise<void> {
|
69 | assert(
|
70 | !this.#handled,
|
71 | 'Cannot accept FileChooser which is already handled!',
|
72 | );
|
73 | this.#handled = true;
|
74 | await this.#element.uploadFile(...paths);
|
75 | }
|
76 |
|
77 | /**
|
78 | * Closes the file chooser without selecting any files.
|
79 | */
|
80 | async cancel(): Promise<void> {
|
81 | assert(
|
82 | !this.#handled,
|
83 | 'Cannot cancel FileChooser which is already handled!',
|
84 | );
|
85 | this.#handled = true;
|
86 | // XXX: These events should converted to trusted events. Perhaps do this
|
87 | // in `DOM.setFileInputFiles`?
|
88 | await this.#element.evaluate(element => {
|
89 | element.dispatchEvent(new Event('cancel', {bubbles: true}));
|
90 | });
|
91 | }
|
92 | }
|