chore: remove non-input related stuff from input (#369)
This commit is contained in:
parent
310d4b193b
commit
f1d6fe6bd8
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
import { Page } from './page';
|
||||
import * as input from './input';
|
||||
import * as network from './network';
|
||||
import * as types from './types';
|
||||
|
||||
|
|
@ -40,8 +39,8 @@ export type BrowserContextOptions = {
|
|||
ignoreHTTPSErrors?: boolean,
|
||||
javaScriptEnabled?: boolean,
|
||||
bypassCSP?: boolean,
|
||||
mediaType?: input.MediaType,
|
||||
colorScheme?: input.ColorScheme,
|
||||
mediaType?: types.MediaType,
|
||||
colorScheme?: types.ColorScheme,
|
||||
userAgent?: string,
|
||||
timezoneId?: string,
|
||||
geolocation?: types.Geolocation
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import { CRWorkers, CRWorker } from './features/crWorkers';
|
|||
import { CRBrowser } from './crBrowser';
|
||||
import { BrowserContext } from '../browserContext';
|
||||
import * as types from '../types';
|
||||
import * as input from '../input';
|
||||
import { ConsoleMessage } from '../console';
|
||||
import * as accessibility from '../accessibility';
|
||||
|
||||
|
|
@ -309,8 +308,8 @@ export class CRPage implements PageDelegate {
|
|||
]);
|
||||
}
|
||||
|
||||
async setEmulateMedia(mediaType: input.MediaType | null, mediaColorScheme: input.ColorScheme | null): Promise<void> {
|
||||
const features = mediaColorScheme ? [{ name: 'prefers-color-scheme', value: mediaColorScheme }] : [];
|
||||
async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
|
||||
const features = colorScheme ? [{ name: 'prefers-color-scheme', value: colorScheme }] : [];
|
||||
await this._client.send('Emulation.setEmulatedMedia', { media: mediaType || '', features });
|
||||
}
|
||||
|
||||
|
|
@ -459,8 +458,8 @@ export class CRPage implements PageDelegate {
|
|||
return { width: layoutMetrics.layoutViewport.clientWidth, height: layoutMetrics.layoutViewport.clientHeight };
|
||||
}
|
||||
|
||||
async setInputFiles(handle: dom.ElementHandle, files: input.FilePayload[]): Promise<void> {
|
||||
await handle.evaluate(input.setFileInputFunction, files);
|
||||
async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise<void> {
|
||||
await handle.evaluate(dom.setFileInputFunction, files);
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
|
||||
|
|
|
|||
111
src/dom.ts
111
src/dom.ts
|
|
@ -10,6 +10,10 @@ import * as zsSelectorEngineSource from './generated/zsSelectorEngineSource';
|
|||
import { assert, helper, debugError } from './helper';
|
||||
import Injected from './injected/injected';
|
||||
import { Page } from './page';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const readFileAsync = helper.promisify(fs.readFile);
|
||||
|
||||
export class FrameExecutionContext extends js.ExecutionContext {
|
||||
readonly frame: frames.Frame;
|
||||
|
|
@ -284,7 +288,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
return this._performPointerAction(point => this._page.mouse.tripleclick(point.x, point.y, options), options);
|
||||
}
|
||||
|
||||
async select(...values: (string | ElementHandle | input.SelectOption)[]): Promise<string[]> {
|
||||
async select(...values: (string | ElementHandle | types.SelectOption)[]): Promise<string[]> {
|
||||
const options = values.map(value => typeof value === 'object' ? value : { value });
|
||||
for (const option of options) {
|
||||
if (option instanceof ElementHandle)
|
||||
|
|
@ -296,18 +300,92 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
if (option.index !== undefined)
|
||||
assert(helper.isNumber(option.index), 'Indices must be numbers. Found index "' + option.index + '" of type "' + (typeof option.index) + '"');
|
||||
}
|
||||
return this._evaluateInUtility(input.selectFunction, ...options);
|
||||
return this._evaluateInUtility((node: Node, ...optionsToSelect: (Node | types.SelectOption)[]) => {
|
||||
if (node.nodeName.toLowerCase() !== 'select')
|
||||
throw new Error('Element is not a <select> element.');
|
||||
const element = node as HTMLSelectElement;
|
||||
|
||||
const options = Array.from(element.options);
|
||||
element.value = undefined;
|
||||
for (let index = 0; index < options.length; index++) {
|
||||
const option = options[index];
|
||||
option.selected = optionsToSelect.some(optionToSelect => {
|
||||
if (optionToSelect instanceof Node)
|
||||
return option === optionToSelect;
|
||||
let matches = true;
|
||||
if (optionToSelect.value !== undefined)
|
||||
matches = matches && optionToSelect.value === option.value;
|
||||
if (optionToSelect.label !== undefined)
|
||||
matches = matches && optionToSelect.label === option.label;
|
||||
if (optionToSelect.index !== undefined)
|
||||
matches = matches && optionToSelect.index === index;
|
||||
return matches;
|
||||
});
|
||||
if (option.selected && !element.multiple)
|
||||
break;
|
||||
}
|
||||
element.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
element.dispatchEvent(new Event('change', { 'bubbles': true }));
|
||||
return options.filter(option => option.selected).map(option => option.value);
|
||||
}, ...options);
|
||||
}
|
||||
|
||||
async fill(value: string): Promise<void> {
|
||||
assert(helper.isString(value), 'Value must be string. Found value "' + value + '" of type "' + (typeof value) + '"');
|
||||
const error = await this._evaluateInUtility(input.fillFunction);
|
||||
const error = await this._evaluateInUtility((node: Node) => {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE)
|
||||
return 'Node is not of type HTMLElement';
|
||||
const element = node as HTMLElement;
|
||||
if (!element.isConnected)
|
||||
return 'Element is not attached to the DOM';
|
||||
if (!element.ownerDocument || !element.ownerDocument.defaultView)
|
||||
return 'Element does not belong to a window';
|
||||
|
||||
const style = element.ownerDocument.defaultView.getComputedStyle(element);
|
||||
if (!style || style.visibility === 'hidden')
|
||||
return 'Element is hidden';
|
||||
if (!element.offsetParent && element.tagName !== 'BODY')
|
||||
return 'Element is not visible';
|
||||
if (element.nodeName.toLowerCase() === 'input') {
|
||||
const input = element as HTMLInputElement;
|
||||
const type = input.getAttribute('type') || '';
|
||||
const kTextInputTypes = new Set(['', 'email', 'password', 'search', 'tel', 'text', 'url']);
|
||||
if (!kTextInputTypes.has(type.toLowerCase()))
|
||||
return 'Cannot fill input of type "' + type + '".';
|
||||
if (input.disabled)
|
||||
return 'Cannot fill a disabled input.';
|
||||
if (input.readOnly)
|
||||
return 'Cannot fill a readonly input.';
|
||||
input.selectionStart = 0;
|
||||
input.selectionEnd = input.value.length;
|
||||
input.focus();
|
||||
} 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.';
|
||||
textarea.selectionStart = 0;
|
||||
textarea.selectionEnd = textarea.value.length;
|
||||
textarea.focus();
|
||||
} else if (element.isContentEditable) {
|
||||
const range = element.ownerDocument.createRange();
|
||||
range.selectNodeContents(element);
|
||||
const selection = element.ownerDocument.defaultView.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
element.focus();
|
||||
} else {
|
||||
return 'Element is not an <input>, <textarea> or [contenteditable] element.';
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (error)
|
||||
throw new Error(error);
|
||||
await this._page.keyboard.sendCharacters(value);
|
||||
}
|
||||
|
||||
async setInputFiles(...files: (string | input.FilePayload)[]) {
|
||||
async setInputFiles(...files: (string | types.FilePayload)[]) {
|
||||
const multiple = await this._evaluateInUtility((node: Node) => {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE || (node as Element).tagName !== 'INPUT')
|
||||
throw new Error('Node is not an HTMLInputElement');
|
||||
|
|
@ -315,7 +393,18 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
|||
return input.multiple;
|
||||
});
|
||||
assert(multiple || files.length <= 1, 'Non-multiple file input can only accept single file!');
|
||||
await this._page._delegate.setInputFiles(this, await input.loadFiles(files));
|
||||
const filePayloads = await Promise.all(files.map(async item => {
|
||||
if (typeof item === 'string') {
|
||||
const file: types.FilePayload = {
|
||||
name: path.basename(item),
|
||||
type: 'application/octet-stream',
|
||||
data: (await readFileAsync(item)).toString('base64')
|
||||
};
|
||||
return file;
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
await this._page._delegate.setInputFiles(this, filePayloads);
|
||||
}
|
||||
|
||||
async focus() {
|
||||
|
|
@ -454,3 +543,15 @@ export function waitForSelectorTask(selector: string, visibility: types.Visibili
|
|||
}, await context._injected(), selector, visibility, timeout);
|
||||
};
|
||||
}
|
||||
|
||||
export const setFileInputFunction = async (element: HTMLInputElement, payloads: types.FilePayload[]) => {
|
||||
const files = await Promise.all(payloads.map(async (file: types.FilePayload) => {
|
||||
const result = await fetch(`data:${file.type};base64,${file.data}`);
|
||||
return new File([await result.blob()], file.name);
|
||||
}));
|
||||
const dt = new DataTransfer();
|
||||
for (const file of files)
|
||||
dt.items.add(file);
|
||||
element.files = dt.files;
|
||||
element.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import { FFNetworkManager } from './ffNetworkManager';
|
|||
import { Events } from '../events';
|
||||
import * as dialog from '../dialog';
|
||||
import { Protocol } from './protocol';
|
||||
import * as input from '../input';
|
||||
import { RawMouseImpl, RawKeyboardImpl } from './ffInput';
|
||||
import { BrowserContext } from '../browserContext';
|
||||
import { getAccessibilityTree } from './ffAccessibility';
|
||||
|
|
@ -213,10 +212,10 @@ export class FFPage implements PageDelegate {
|
|||
});
|
||||
}
|
||||
|
||||
async setEmulateMedia(mediaType: input.MediaType | null, mediaColorScheme: input.ColorScheme | null): Promise<void> {
|
||||
async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
|
||||
await this._session.send('Page.setEmulatedMedia', {
|
||||
type: mediaType === null ? undefined : mediaType,
|
||||
colorScheme: mediaColorScheme === null ? undefined : mediaColorScheme
|
||||
colorScheme: colorScheme === null ? undefined : colorScheme
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -339,8 +338,8 @@ export class FFPage implements PageDelegate {
|
|||
return this._page.evaluate(() => ({ width: innerWidth, height: innerHeight }));
|
||||
}
|
||||
|
||||
async setInputFiles(handle: dom.ElementHandle, files: input.FilePayload[]): Promise<void> {
|
||||
await handle.evaluate(input.setFileInputFunction, files);
|
||||
async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise<void> {
|
||||
await handle.evaluate(dom.setFileInputFunction, files);
|
||||
}
|
||||
|
||||
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import * as js from './javascript';
|
|||
import * as dom from './dom';
|
||||
import * as network from './network';
|
||||
import { helper, assert, RegisteredListener } from './helper';
|
||||
import { ClickOptions, MultiClickOptions, PointerActionOptions, SelectOption } from './input';
|
||||
import { ClickOptions, MultiClickOptions, PointerActionOptions } from './input';
|
||||
import { TimeoutError } from './errors';
|
||||
import { Events } from './events';
|
||||
import { Page } from './page';
|
||||
|
|
@ -646,7 +646,7 @@ export class Frame {
|
|||
await handle.dispose();
|
||||
}
|
||||
|
||||
async select(selector: string, value: string | dom.ElementHandle | SelectOption | string[] | dom.ElementHandle[] | SelectOption[] | undefined, options?: WaitForOptions): Promise<string[]> {
|
||||
async select(selector: string, value: string | dom.ElementHandle | types.SelectOption | string[] | dom.ElementHandle[] | types.SelectOption[] | undefined, options?: WaitForOptions): Promise<string[]> {
|
||||
const handle = await this._optionallyWaitForSelectorInUtilityContext(selector, options);
|
||||
const values = value === undefined ? [] : Array.isArray(value) ? value : [value];
|
||||
const result = await handle.select(...values);
|
||||
|
|
|
|||
128
src/input.ts
128
src/input.ts
|
|
@ -1,14 +1,10 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { assert, helper } from './helper';
|
||||
import { assert } from './helper';
|
||||
import * as types from './types';
|
||||
import * as keyboardLayout from './usKeyboardLayout';
|
||||
|
||||
const readFileAsync = helper.promisify(fs.readFile);
|
||||
|
||||
export type Modifier = 'Alt' | 'Control' | 'Meta' | 'Shift';
|
||||
export type Button = 'left' | 'right' | 'middle';
|
||||
|
||||
|
|
@ -28,12 +24,6 @@ export type MultiClickOptions = PointerActionOptions & {
|
|||
button?: Button;
|
||||
};
|
||||
|
||||
export type SelectOption = {
|
||||
value?: string;
|
||||
label?: string;
|
||||
index?: number;
|
||||
};
|
||||
|
||||
export const keypadLocation = keyboardLayout.keypadLocation;
|
||||
|
||||
type KeyDescription = {
|
||||
|
|
@ -292,119 +282,3 @@ export class Mouse {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const selectFunction = (node: Node, ...optionsToSelect: (Node | SelectOption)[]) => {
|
||||
if (node.nodeName.toLowerCase() !== 'select')
|
||||
throw new Error('Element is not a <select> element.');
|
||||
const element = node as HTMLSelectElement;
|
||||
|
||||
const options = Array.from(element.options);
|
||||
element.value = undefined;
|
||||
for (let index = 0; index < options.length; index++) {
|
||||
const option = options[index];
|
||||
option.selected = optionsToSelect.some(optionToSelect => {
|
||||
if (optionToSelect instanceof Node)
|
||||
return option === optionToSelect;
|
||||
let matches = true;
|
||||
if (optionToSelect.value !== undefined)
|
||||
matches = matches && optionToSelect.value === option.value;
|
||||
if (optionToSelect.label !== undefined)
|
||||
matches = matches && optionToSelect.label === option.label;
|
||||
if (optionToSelect.index !== undefined)
|
||||
matches = matches && optionToSelect.index === index;
|
||||
return matches;
|
||||
});
|
||||
if (option.selected && !element.multiple)
|
||||
break;
|
||||
}
|
||||
element.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
element.dispatchEvent(new Event('change', { 'bubbles': true }));
|
||||
return options.filter(option => option.selected).map(option => option.value);
|
||||
};
|
||||
|
||||
export const fillFunction = (node: Node) => {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE)
|
||||
return 'Node is not of type HTMLElement';
|
||||
const element = node as HTMLElement;
|
||||
if (!element.isConnected)
|
||||
return 'Element is not attached to the DOM';
|
||||
if (!element.ownerDocument || !element.ownerDocument.defaultView)
|
||||
return 'Element does not belong to a window';
|
||||
|
||||
const style = element.ownerDocument.defaultView.getComputedStyle(element);
|
||||
if (!style || style.visibility === 'hidden')
|
||||
return 'Element is hidden';
|
||||
if (!element.offsetParent && element.tagName !== 'BODY')
|
||||
return 'Element is not visible';
|
||||
if (element.nodeName.toLowerCase() === 'input') {
|
||||
const input = element as HTMLInputElement;
|
||||
const type = input.getAttribute('type') || '';
|
||||
const kTextInputTypes = new Set(['', 'email', 'password', 'search', 'tel', 'text', 'url']);
|
||||
if (!kTextInputTypes.has(type.toLowerCase()))
|
||||
return 'Cannot fill input of type "' + type + '".';
|
||||
if (input.disabled)
|
||||
return 'Cannot fill a disabled input.';
|
||||
if (input.readOnly)
|
||||
return 'Cannot fill a readonly input.';
|
||||
input.selectionStart = 0;
|
||||
input.selectionEnd = input.value.length;
|
||||
input.focus();
|
||||
} 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.';
|
||||
textarea.selectionStart = 0;
|
||||
textarea.selectionEnd = textarea.value.length;
|
||||
textarea.focus();
|
||||
} else if (element.isContentEditable) {
|
||||
const range = element.ownerDocument.createRange();
|
||||
range.selectNodeContents(element);
|
||||
const selection = element.ownerDocument.defaultView.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
element.focus();
|
||||
} else {
|
||||
return 'Element is not an <input>, <textarea> or [contenteditable] element.';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const loadFiles = async (items: (string|FilePayload)[]): Promise<FilePayload[]> => {
|
||||
return Promise.all(items.map(async item => {
|
||||
if (typeof item === 'string') {
|
||||
const file: FilePayload = {
|
||||
name: path.basename(item),
|
||||
type: 'application/octet-stream',
|
||||
data: (await readFileAsync(item)).toString('base64')
|
||||
};
|
||||
return file;
|
||||
} else {
|
||||
return item as FilePayload;
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
export const setFileInputFunction = async (element: HTMLInputElement, payloads: FilePayload[]) => {
|
||||
const files = await Promise.all(payloads.map(async (file: FilePayload) => {
|
||||
const result = await fetch(`data:${file.type};base64,${file.data}`);
|
||||
return new File([await result.blob()], file.name);
|
||||
}));
|
||||
const dt = new DataTransfer();
|
||||
for (const file of files)
|
||||
dt.items.add(file);
|
||||
element.files = dt.files;
|
||||
element.dispatchEvent(new Event('input', { 'bubbles': true }));
|
||||
};
|
||||
|
||||
export type FilePayload = {
|
||||
name: string,
|
||||
type: string,
|
||||
data: string
|
||||
};
|
||||
|
||||
export type MediaType = 'screen' | 'print';
|
||||
export const mediaTypes: Set<MediaType> = new Set(['screen', 'print']);
|
||||
export type ColorScheme = 'dark' | 'light' | 'no-preference';
|
||||
export const mediaColorSchemes: Set<ColorScheme> = new Set(['dark', 'light', 'no-preference']);
|
||||
|
|
|
|||
16
src/page.ts
16
src/page.ts
|
|
@ -47,7 +47,7 @@ export interface PageDelegate {
|
|||
|
||||
setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise<void>;
|
||||
setViewport(viewport: types.Viewport): Promise<void>;
|
||||
setEmulateMedia(mediaType: input.MediaType | null, colorScheme: input.ColorScheme | null): Promise<void>;
|
||||
setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void>;
|
||||
setCacheEnabled(enabled: boolean): Promise<void>;
|
||||
setRequestInterception(enabled: boolean): Promise<void>;
|
||||
setOfflineMode(enabled: boolean): Promise<void>;
|
||||
|
|
@ -65,7 +65,7 @@ export interface PageDelegate {
|
|||
getOwnerFrame(handle: dom.ElementHandle): Promise<frames.Frame | null>;
|
||||
getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null>;
|
||||
layoutViewport(): Promise<{ width: number, height: number }>;
|
||||
setInputFiles(handle: dom.ElementHandle, files: input.FilePayload[]): Promise<void>;
|
||||
setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise<void>;
|
||||
getBoundingBox(handle: dom.ElementHandle): Promise<types.Rect | null>;
|
||||
|
||||
getAccessibilityTree(): Promise<accessibility.AXNode>;
|
||||
|
|
@ -73,8 +73,8 @@ export interface PageDelegate {
|
|||
|
||||
type PageState = {
|
||||
viewport: types.Viewport | null;
|
||||
mediaType: input.MediaType | null;
|
||||
colorScheme: input.ColorScheme | null;
|
||||
mediaType: types.MediaType | null;
|
||||
colorScheme: types.ColorScheme | null;
|
||||
extraHTTPHeaders: network.Headers | null;
|
||||
cacheEnabled: boolean | null;
|
||||
interceptNetwork: boolean | null;
|
||||
|
|
@ -370,9 +370,9 @@ export class Page extends EventEmitter {
|
|||
return waitPromise;
|
||||
}
|
||||
|
||||
async emulateMedia(options: { type?: input.MediaType, colorScheme?: input.ColorScheme }) {
|
||||
assert(!options.type || input.mediaTypes.has(options.type), 'Unsupported media type: ' + options.type);
|
||||
assert(!options.colorScheme || input.mediaColorSchemes.has(options.colorScheme), 'Unsupported color scheme: ' + options.colorScheme);
|
||||
async emulateMedia(options: { type?: types.MediaType, colorScheme?: types.ColorScheme }) {
|
||||
assert(!options.type || types.mediaTypes.has(options.type), 'Unsupported media type: ' + options.type);
|
||||
assert(!options.colorScheme || types.colorSchemes.has(options.colorScheme), 'Unsupported color scheme: ' + options.colorScheme);
|
||||
if (options.type !== undefined)
|
||||
this._state.mediaType = options.type;
|
||||
if (options.colorScheme !== undefined)
|
||||
|
|
@ -476,7 +476,7 @@ export class Page extends EventEmitter {
|
|||
return this.mainFrame().hover(selector, options);
|
||||
}
|
||||
|
||||
async select(selector: string, value: string | dom.ElementHandle | input.SelectOption | string[] | dom.ElementHandle[] | input.SelectOption[] | undefined, options?: frames.WaitForOptions): Promise<string[]> {
|
||||
async select(selector: string, value: string | dom.ElementHandle | types.SelectOption | string[] | dom.ElementHandle[] | types.SelectOption[] | undefined, options?: frames.WaitForOptions): Promise<string[]> {
|
||||
return this.mainFrame().select(selector, value, options);
|
||||
}
|
||||
|
||||
|
|
|
|||
22
src/types.ts
22
src/types.ts
|
|
@ -55,10 +55,28 @@ export type URLMatch = string | RegExp | ((url: kurl.URL) => boolean);
|
|||
export type Credentials = {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type Geolocation = {
|
||||
longitude?: number;
|
||||
latitude?: number;
|
||||
accuracy?: number | undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export type SelectOption = {
|
||||
value?: string;
|
||||
label?: string;
|
||||
index?: number;
|
||||
};
|
||||
|
||||
export type FilePayload = {
|
||||
name: string,
|
||||
type: string,
|
||||
data: string,
|
||||
};
|
||||
|
||||
export type MediaType = 'screen' | 'print';
|
||||
export const mediaTypes: Set<MediaType> = new Set(['screen', 'print']);
|
||||
|
||||
export type ColorScheme = 'dark' | 'light' | 'no-preference';
|
||||
export const colorSchemes: Set<ColorScheme> = new Set(['dark', 'light', 'no-preference']);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import * as dialog from '../dialog';
|
|||
import { WKBrowser } from './wkBrowser';
|
||||
import { BrowserContext } from '../browserContext';
|
||||
import { RawMouseImpl, RawKeyboardImpl } from './wkInput';
|
||||
import * as input from '../input';
|
||||
import * as types from '../types';
|
||||
import * as jpeg from 'jpeg-js';
|
||||
import { PNG } from 'pngjs';
|
||||
|
|
@ -288,12 +287,12 @@ export class WKPage implements PageDelegate {
|
|||
await session.send('Network.setExtraHTTPHeaders', { headers });
|
||||
}
|
||||
|
||||
private async _setEmulateMedia(session: WKTargetSession, mediaType: input.MediaType | null, mediaColorScheme: input.ColorScheme | null): Promise<void> {
|
||||
private async _setEmulateMedia(session: WKTargetSession, mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
|
||||
const promises = [];
|
||||
promises.push(session.send('Page.setEmulatedMedia', { media: mediaType || '' }));
|
||||
if (mediaColorScheme !== null) {
|
||||
if (colorScheme !== null) {
|
||||
let appearance: any = '';
|
||||
switch (mediaColorScheme) {
|
||||
switch (colorScheme) {
|
||||
case 'light': appearance = 'Light'; break;
|
||||
case 'dark': appearance = 'Dark'; break;
|
||||
}
|
||||
|
|
@ -306,8 +305,8 @@ export class WKPage implements PageDelegate {
|
|||
await this._setExtraHTTPHeaders(this._session, headers);
|
||||
}
|
||||
|
||||
async setEmulateMedia(mediaType: input.MediaType | null, mediaColorScheme: input.ColorScheme | null): Promise<void> {
|
||||
await this._setEmulateMedia(this._session, mediaType, mediaColorScheme);
|
||||
async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise<void> {
|
||||
await this._setEmulateMedia(this._session, mediaType, colorScheme);
|
||||
}
|
||||
|
||||
async setViewport(viewport: types.Viewport): Promise<void> {
|
||||
|
|
@ -468,7 +467,7 @@ export class WKPage implements PageDelegate {
|
|||
return this._page.evaluate(() => ({ width: innerWidth, height: innerHeight }));
|
||||
}
|
||||
|
||||
async setInputFiles(handle: dom.ElementHandle, files: input.FilePayload[]): Promise<void> {
|
||||
async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise<void> {
|
||||
const objectId = toRemoteObject(handle).objectId;
|
||||
await this._session.send('DOM.setInputFiles', { objectId, files });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue