fix(filechooser): intercept file choosers lazily (#776)

Fixes #764
This commit is contained in:
Pavel Feldman 2020-01-30 17:43:06 -08:00 committed by GitHub
parent 985faebd12
commit b289bb790b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 9 deletions

View File

@ -94,7 +94,6 @@ export class CRPage implements PageDelegate {
this._handleFrameTree(frameTree); this._handleFrameTree(frameTree);
const promises: Promise<any>[] = [ const promises: Promise<any>[] = [
this._client.send('Log.enable', {}), this._client.send('Log.enable', {}),
this._client.send('Page.setInterceptFileChooserDialog', {enabled: true}),
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }), this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
this._client.send('Runtime.enable', {}).then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)), this._client.send('Runtime.enable', {}).then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._networkManager.initialize(), this._networkManager.initialize(),
@ -346,6 +345,10 @@ export class CRPage implements PageDelegate {
await this._networkManager.authenticate(credentials); await this._networkManager.authenticate(credentials);
} }
async setFileChooserIntercepted(enabled: boolean) {
await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
}
async reload(): Promise<void> { async reload(): Promise<void> {
await this._client.send('Page.reload'); await this._client.send('Page.reload');
} }

View File

@ -79,7 +79,6 @@ export class FFPage implements PageDelegate {
this._session.send('Runtime.enable').then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)), this._session.send('Runtime.enable').then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._session.send('Network.enable'), this._session.send('Network.enable'),
this._session.send('Page.enable'), this._session.send('Page.enable'),
this._session.send('Page.setInterceptFileChooserDialog', { enabled: true })
]; ];
const options = this._page.browserContext()._options; const options = this._page.browserContext()._options;
if (options.viewport) if (options.viewport)
@ -306,6 +305,10 @@ export class FFPage implements PageDelegate {
await this._session.send('Network.setAuthCredentials', credentials || { username: null, password: null }); await this._session.send('Network.setAuthCredentials', credentials || { username: null, password: null });
} }
async setFileChooserIntercepted(enabled: boolean) {
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
}
async reload(): Promise<void> { async reload(): Promise<void> {
await this._session.send('Page.reload', { frameId: this._page.mainFrame()._id }); await this._session.send('Page.reload', { frameId: this._page.mainFrame()._id });
} }

View File

@ -50,6 +50,7 @@ export interface PageDelegate {
setRequestInterception(enabled: boolean): Promise<void>; setRequestInterception(enabled: boolean): Promise<void>;
setOfflineMode(enabled: boolean): Promise<void>; setOfflineMode(enabled: boolean): Promise<void>;
authenticate(credentials: types.Credentials | null): Promise<void>; authenticate(credentials: types.Credentials | null): Promise<void>;
setFileChooserIntercepted(enabled: boolean): Promise<void>;
getBoundingBoxForScreenshot(handle: dom.ElementHandle<Node>): Promise<types.Rect | null>; getBoundingBoxForScreenshot(handle: dom.ElementHandle<Node>): Promise<types.Rect | null>;
canScreenshotOutsideViewport(): boolean; canScreenshotOutsideViewport(): boolean;
@ -120,7 +121,7 @@ export class Page extends platform.EventEmitter {
colorScheme: null, colorScheme: null,
extraHTTPHeaders: null, extraHTTPHeaders: null,
credentials: null, credentials: null,
hasTouch: null hasTouch: null,
}; };
this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate)); this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate));
this.keyboard = new input.Keyboard(delegate.rawKeyboard); this.keyboard = new input.Keyboard(delegate.rawKeyboard);
@ -490,6 +491,22 @@ export class Page extends platform.EventEmitter {
this._workers.delete(workerId); this._workers.delete(workerId);
} }
} }
on(event: string | symbol, listener: platform.Listener): this {
if (event === Events.Page.FileChooser) {
if (!this.listenerCount(event))
this._delegate.setFileChooserIntercepted(true);
}
super.on(event, listener);
return this;
}
removeListener(event: string | symbol, listener: platform.Listener): this {
super.removeListener(event, listener);
if (event === Events.Page.FileChooser && !this.listenerCount(event))
this._delegate.setFileChooserIntercepted(false);
return this;
}
} }
export class Worker { export class Worker {

View File

@ -51,13 +51,13 @@ export function promisify(nodeFunction: Function): Function {
return promisified; return promisified;
} }
type Listener = (...args: any[]) => void; export type Listener = (...args: any[]) => void;
export const EventEmitter: typeof nodeEvents.EventEmitter = isNode ? nodeEvents.EventEmitter : ( export const EventEmitter: typeof nodeEvents.EventEmitter = isNode ? nodeEvents.EventEmitter : (
class EventEmitterImpl { class EventEmitterImpl {
private _deliveryQueue?: {listener: Listener, args: any[]}[]; private _deliveryQueue?: {listener: Listener, args: any[]}[];
private _listeners = new Map<string | symbol, Set<Listener>>(); private _listeners = new Map<string | symbol, Set<Listener>>();
addListener(event: string | symbol, listener: Listener): this { on(event: string | symbol, listener: Listener): this {
let set = this._listeners.get(event); let set = this._listeners.get(event);
if (!set) { if (!set) {
set = new Set(); set = new Set();
@ -67,8 +67,8 @@ export const EventEmitter: typeof nodeEvents.EventEmitter = isNode ? nodeEvents.
return this; return this;
} }
on(event: string | symbol, listener: Listener): this { addListener(event: string | symbol, listener: Listener): this {
return this.addListener(event, listener); return this.on(event, listener);
} }
once(event: string | symbol, listener: Listener): this { once(event: string | symbol, listener: Listener): this {
@ -76,7 +76,7 @@ export const EventEmitter: typeof nodeEvents.EventEmitter = isNode ? nodeEvents.
this.removeListener(event, wrapped); this.removeListener(event, wrapped);
listener(...args); listener(...args);
}; };
return this.on(event, wrapped); return this.addListener(event, wrapped);
} }
removeListener(event: string | symbol, listener: Listener): this { removeListener(event: string | symbol, listener: Listener): this {

View File

@ -117,7 +117,6 @@ export class WKPage implements PageDelegate {
session.send('Runtime.enable'), session.send('Runtime.enable'),
session.send('Page.createUserWorld', { name: UTILITY_WORLD_NAME }).catch(_ => {}), // Worlds are per-process session.send('Page.createUserWorld', { name: UTILITY_WORLD_NAME }).catch(_ => {}), // Worlds are per-process
session.send('Console.enable'), session.send('Console.enable'),
session.send('Page.setInterceptFileChooserDialog', { enabled: true }),
session.send('Network.enable'), session.send('Network.enable'),
this._workers.initializeSession(session) this._workers.initializeSession(session)
]; ];
@ -423,6 +422,10 @@ export class WKPage implements PageDelegate {
await this._pageProxySession.send('Emulation.setAuthCredentials', { ...(credentials || { username: '', password: '' }) }); await this._pageProxySession.send('Emulation.setAuthCredentials', { ...(credentials || { username: '', password: '' }) });
} }
async setFileChooserIntercepted(enabled: boolean) {
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
}
async reload(): Promise<void> { async reload(): Promise<void> {
await this._session.send('Page.reload'); await this._session.send('Page.reload');
} }