mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: introduce Page.viewportSizeChanged
event (#35994)
This commit is contained in:
parent
6e8c67a3ce
commit
2a5d83a623
@ -84,7 +84,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
_workers = new Set<Worker>();
|
_workers = new Set<Worker>();
|
||||||
private _closed = false;
|
private _closed = false;
|
||||||
readonly _closedOrCrashedScope = new LongStandingScope();
|
readonly _closedOrCrashedScope = new LongStandingScope();
|
||||||
private _viewportSize: Size | null;
|
private _viewportSize: Size | undefined;
|
||||||
_routes: RouteHandler[] = [];
|
_routes: RouteHandler[] = [];
|
||||||
_webSocketRoutes: WebSocketRouteHandler[] = [];
|
_webSocketRoutes: WebSocketRouteHandler[] = [];
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
this._mainFrame = Frame.from(initializer.mainFrame);
|
this._mainFrame = Frame.from(initializer.mainFrame);
|
||||||
this._mainFrame._page = this;
|
this._mainFrame._page = this;
|
||||||
this._frames.add(this._mainFrame);
|
this._frames.add(this._mainFrame);
|
||||||
this._viewportSize = initializer.viewportSize || null;
|
this._viewportSize = initializer.viewportSize;
|
||||||
this._closed = initializer.isClosed;
|
this._closed = initializer.isClosed;
|
||||||
this._opener = Page.fromNullable(initializer.opener);
|
this._opener = Page.fromNullable(initializer.opener);
|
||||||
|
|
||||||
@ -151,6 +151,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
const artifactObject = Artifact.from(artifact);
|
const artifactObject = Artifact.from(artifact);
|
||||||
this._forceVideo()._artifactReady(artifactObject);
|
this._forceVideo()._artifactReady(artifactObject);
|
||||||
});
|
});
|
||||||
|
this._channel.on('viewportSizeChanged', ({ viewportSize }) => this._viewportSize = viewportSize);
|
||||||
this._channel.on('webSocket', ({ webSocket }) => this.emit(Events.Page.WebSocket, WebSocket.from(webSocket)));
|
this._channel.on('webSocket', ({ webSocket }) => this.emit(Events.Page.WebSocket, WebSocket.from(webSocket)));
|
||||||
this._channel.on('worker', ({ worker }) => this._onWorker(Worker.from(worker)));
|
this._channel.on('worker', ({ worker }) => this._onWorker(Worker.from(worker)));
|
||||||
|
|
||||||
@ -506,7 +507,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewportSize(): Size | null {
|
viewportSize(): Size | null {
|
||||||
return this._viewportSize;
|
return this._viewportSize || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
|
async evaluate<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
|
||||||
|
@ -1122,6 +1122,12 @@ scheme.PageDownloadEvent = tObject({
|
|||||||
suggestedFilename: tString,
|
suggestedFilename: tString,
|
||||||
artifact: tChannel(['Artifact']),
|
artifact: tChannel(['Artifact']),
|
||||||
});
|
});
|
||||||
|
scheme.PageViewportSizeChangedEvent = tObject({
|
||||||
|
viewportSize: tOptional(tObject({
|
||||||
|
width: tNumber,
|
||||||
|
height: tNumber,
|
||||||
|
})),
|
||||||
|
});
|
||||||
scheme.PageFileChooserEvent = tObject({
|
scheme.PageFileChooserEvent = tObject({
|
||||||
element: tChannel(['ElementHandle']),
|
element: tChannel(['ElementHandle']),
|
||||||
isMultiple: tBoolean,
|
isMultiple: tBoolean,
|
||||||
|
@ -268,10 +268,10 @@ export class BidiPage implements PageDelegate {
|
|||||||
|
|
||||||
async updateEmulatedViewportSize(): Promise<void> {
|
async updateEmulatedViewportSize(): Promise<void> {
|
||||||
const options = this._browserContext._options;
|
const options = this._browserContext._options;
|
||||||
const deviceSize = this._page.emulatedSize();
|
const emulatedSize = this._page.emulatedSize();
|
||||||
if (deviceSize === null)
|
if (!emulatedSize)
|
||||||
return;
|
return;
|
||||||
const viewportSize = deviceSize.viewport;
|
const viewportSize = emulatedSize.viewport;
|
||||||
await this._session.send('browsingContext.setViewport', {
|
await this._session.send('browsingContext.setViewport', {
|
||||||
context: this._session.sessionId,
|
context: this._session.sessionId,
|
||||||
viewport: {
|
viewport: {
|
||||||
|
@ -108,7 +108,7 @@ export class CRPage implements PageDelegate {
|
|||||||
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
|
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
|
||||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
|
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
|
||||||
if (viewportSize)
|
if (viewportSize)
|
||||||
this._page.setEmulatedSize({ viewport: viewportSize, screen: viewportSize });
|
this._page.setEmulatedSizeFromWindowOpen({ viewport: viewportSize, screen: viewportSize });
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdEvent = this._isBackgroundPage ? CRBrowserContext.CREvents.BackgroundPage : BrowserContext.Events.Page;
|
const createdEvent = this._isBackgroundPage ? CRBrowserContext.CREvents.BackgroundPage : BrowserContext.Events.Page;
|
||||||
@ -953,7 +953,7 @@ class FrameSession {
|
|||||||
assert(this._isMainFrame());
|
assert(this._isMainFrame());
|
||||||
const options = this._crPage._browserContext._options;
|
const options = this._crPage._browserContext._options;
|
||||||
const emulatedSize = this._page.emulatedSize();
|
const emulatedSize = this._page.emulatedSize();
|
||||||
if (emulatedSize === null)
|
if (!emulatedSize)
|
||||||
return;
|
return;
|
||||||
const viewportSize = emulatedSize.viewport;
|
const viewportSize = emulatedSize.viewport;
|
||||||
const screenSize = emulatedSize.screen;
|
const screenSize = emulatedSize.screen;
|
||||||
|
@ -66,7 +66,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||||||
|
|
||||||
super(parentScope, page, 'Page', {
|
super(parentScope, page, 'Page', {
|
||||||
mainFrame,
|
mainFrame,
|
||||||
viewportSize: page.viewportSize() || undefined,
|
viewportSize: page.emulatedSize()?.viewport,
|
||||||
isClosed: page.isClosed(),
|
isClosed: page.isClosed(),
|
||||||
opener: PageDispatcher.fromNullable(parentScope, page.opener())
|
opener: PageDispatcher.fromNullable(parentScope, page.opener())
|
||||||
});
|
});
|
||||||
@ -83,6 +83,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||||||
// Artifact can outlive the page, so bind to the context scope.
|
// Artifact can outlive the page, so bind to the context scope.
|
||||||
this._dispatchEvent('download', { url: download.url, suggestedFilename: download.suggestedFilename(), artifact: ArtifactDispatcher.from(parentScope, download.artifact) });
|
this._dispatchEvent('download', { url: download.url, suggestedFilename: download.suggestedFilename(), artifact: ArtifactDispatcher.from(parentScope, download.artifact) });
|
||||||
});
|
});
|
||||||
|
this.addObjectListener(Page.Events.EmulatedSizeChanged, () => this._dispatchEvent('viewportSizeChanged', { viewportSize: page.emulatedSize()?.viewport }));
|
||||||
this.addObjectListener(Page.Events.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', {
|
this.addObjectListener(Page.Events.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', {
|
||||||
element: ElementHandleDispatcher.from(mainFrame, fileChooser.element()),
|
element: ElementHandleDispatcher.from(mainFrame, fileChooser.element()),
|
||||||
isMultiple: fileChooser.isMultiple()
|
isMultiple: fileChooser.isMultiple()
|
||||||
|
@ -334,7 +334,7 @@ export class FFPage implements PageDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateEmulatedViewportSize(): Promise<void> {
|
async updateEmulatedViewportSize(): Promise<void> {
|
||||||
const viewportSize = this._page.viewportSize();
|
const viewportSize = this._page.emulatedSize()?.viewport ?? null;
|
||||||
await this._session.send('Page.setViewportSize', { viewportSize });
|
await this._session.send('Page.setViewportSize', { viewportSize });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,7 @@ export class Page extends SdkObject {
|
|||||||
Close: 'close',
|
Close: 'close',
|
||||||
Crash: 'crash',
|
Crash: 'crash',
|
||||||
Download: 'download',
|
Download: 'download',
|
||||||
|
EmulatedSizeChanged: 'emulatedsizechanged',
|
||||||
FileChooser: 'filechooser',
|
FileChooser: 'filechooser',
|
||||||
FrameAttached: 'frameattached',
|
FrameAttached: 'frameattached',
|
||||||
FrameDetached: 'framedetached',
|
FrameDetached: 'framedetached',
|
||||||
@ -546,23 +547,24 @@ export class Page extends SdkObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size) {
|
async setViewportSize(viewportSize: types.Size) {
|
||||||
this._emulatedSize = { viewport: { ...viewportSize }, screen: { ...viewportSize } };
|
this._setEmulatedSize({ viewport: { ...viewportSize }, screen: { ...viewportSize } });
|
||||||
await this.delegate.updateEmulatedViewportSize();
|
await this.delegate.updateEmulatedViewportSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportSize(): types.Size | null {
|
setEmulatedSizeFromWindowOpen(emulatedSize: EmulatedSize) {
|
||||||
return this.emulatedSize()?.viewport || null;
|
this._setEmulatedSize(emulatedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
setEmulatedSize(emulatedSize: EmulatedSize) {
|
private _setEmulatedSize(emulatedSize: EmulatedSize) {
|
||||||
this._emulatedSize = emulatedSize;
|
this._emulatedSize = emulatedSize;
|
||||||
|
this.emit(Page.Events.EmulatedSizeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
emulatedSize(): EmulatedSize | null {
|
emulatedSize(): EmulatedSize | undefined {
|
||||||
if (this._emulatedSize)
|
if (this._emulatedSize)
|
||||||
return this._emulatedSize;
|
return this._emulatedSize;
|
||||||
const contextOptions = this.browserContext._options;
|
const contextOptions = this.browserContext._options;
|
||||||
return contextOptions.viewport ? { viewport: contextOptions.viewport, screen: contextOptions.screen || contextOptions.viewport } : null;
|
return contextOptions.viewport ? { viewport: contextOptions.viewport, screen: contextOptions.screen || contextOptions.viewport } : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async bringToFront(): Promise<void> {
|
async bringToFront(): Promise<void> {
|
||||||
|
@ -173,12 +173,11 @@ export class Screenshotter {
|
|||||||
this._queue = new TaskQueue();
|
this._queue = new TaskQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _originalViewportSize(progress: Progress): Promise<{ viewportSize: types.Size, originalViewportSize: types.Size | null }> {
|
private async _originalViewportSize(progress: Progress): Promise<types.Size> {
|
||||||
const originalViewportSize = this._page.viewportSize();
|
let viewportSize = this._page.emulatedSize()?.viewport;
|
||||||
let viewportSize = originalViewportSize;
|
|
||||||
if (!viewportSize)
|
if (!viewportSize)
|
||||||
viewportSize = await this._page.mainFrame().waitForFunctionValueInUtility(progress, () => ({ width: window.innerWidth, height: window.innerHeight }));
|
viewportSize = await this._page.mainFrame().waitForFunctionValueInUtility(progress, () => ({ width: window.innerWidth, height: window.innerHeight }));
|
||||||
return { viewportSize, originalViewportSize };
|
return viewportSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fullPageSize(progress: Progress): Promise<types.Size> {
|
private async _fullPageSize(progress: Progress): Promise<types.Size> {
|
||||||
@ -205,7 +204,7 @@ export class Screenshotter {
|
|||||||
const format = validateScreenshotOptions(options);
|
const format = validateScreenshotOptions(options);
|
||||||
return this._queue.postTask(async () => {
|
return this._queue.postTask(async () => {
|
||||||
progress.log('taking page screenshot');
|
progress.log('taking page screenshot');
|
||||||
const { viewportSize } = await this._originalViewportSize(progress);
|
const viewportSize = await this._originalViewportSize(progress);
|
||||||
await this._preparePageForScreenshot(progress, this._page.mainFrame(), options.style, options.caret !== 'initial', options.animations === 'disabled');
|
await this._preparePageForScreenshot(progress, this._page.mainFrame(), options.style, options.caret !== 'initial', options.animations === 'disabled');
|
||||||
progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup.
|
progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup.
|
||||||
|
|
||||||
@ -233,7 +232,7 @@ export class Screenshotter {
|
|||||||
const format = validateScreenshotOptions(options);
|
const format = validateScreenshotOptions(options);
|
||||||
return this._queue.postTask(async () => {
|
return this._queue.postTask(async () => {
|
||||||
progress.log('taking element screenshot');
|
progress.log('taking element screenshot');
|
||||||
const { viewportSize } = await this._originalViewportSize(progress);
|
const viewportSize = await this._originalViewportSize(progress);
|
||||||
|
|
||||||
await this._preparePageForScreenshot(progress, handle._frame, options.style, options.caret !== 'initial', options.animations === 'disabled');
|
await this._preparePageForScreenshot(progress, handle._frame, options.style, options.caret !== 'initial', options.animations === 'disabled');
|
||||||
progress.throwIfAborted(); // Do not do extra work.
|
progress.throwIfAborted(); // Do not do extra work.
|
||||||
|
@ -358,7 +358,7 @@ export class WKBrowserContext extends BrowserContext {
|
|||||||
await this._browser._browserSession.send('Playwright.cancelDownload', { uuid });
|
await this._browser._browserSession.send('Playwright.cancelDownload', { uuid });
|
||||||
}
|
}
|
||||||
|
|
||||||
_validateEmulatedViewport(viewportSize?: types.Size | null) {
|
_validateEmulatedViewport(viewportSize: types.Size | undefined) {
|
||||||
if (!viewportSize)
|
if (!viewportSize)
|
||||||
return;
|
return;
|
||||||
if (process.platform === 'win32' && this._browser.options.headful && (viewportSize.width < 250 || viewportSize.height < 240))
|
if (process.platform === 'win32' && this._browser.options.headful && (viewportSize.width < 250 || viewportSize.height < 240))
|
||||||
|
@ -109,7 +109,7 @@ export class WKPage implements PageDelegate {
|
|||||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
|
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
|
||||||
opener._nextWindowOpenPopupFeatures = undefined;
|
opener._nextWindowOpenPopupFeatures = undefined;
|
||||||
if (viewportSize)
|
if (viewportSize)
|
||||||
this._page.setEmulatedSize({ viewport: viewportSize, screen: viewportSize });
|
this._page.setEmulatedSizeFromWindowOpen({ viewport: viewportSize, screen: viewportSize });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +677,7 @@ export class WKPage implements PageDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateEmulatedViewportSize(): Promise<void> {
|
async updateEmulatedViewportSize(): Promise<void> {
|
||||||
this._browserContext._validateEmulatedViewport(this._page.viewportSize());
|
this._browserContext._validateEmulatedViewport(this._page.emulatedSize()?.viewport);
|
||||||
await this._updateViewport();
|
await this._updateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,11 +694,11 @@ export class WKPage implements PageDelegate {
|
|||||||
|
|
||||||
async _updateViewport(): Promise<void> {
|
async _updateViewport(): Promise<void> {
|
||||||
const options = this._browserContext._options;
|
const options = this._browserContext._options;
|
||||||
const deviceSize = this._page.emulatedSize();
|
const emulatedSize = this._page.emulatedSize();
|
||||||
if (deviceSize === null)
|
if (!emulatedSize)
|
||||||
return;
|
return;
|
||||||
const viewportSize = deviceSize.viewport;
|
const viewportSize = emulatedSize.viewport;
|
||||||
const screenSize = deviceSize.screen;
|
const screenSize = emulatedSize.screen;
|
||||||
const promises: Promise<any>[] = [
|
const promises: Promise<any>[] = [
|
||||||
this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {
|
this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {
|
||||||
width: viewportSize.width,
|
width: viewportSize.width,
|
||||||
|
8
packages/protocol/src/channels.d.ts
vendored
8
packages/protocol/src/channels.d.ts
vendored
@ -2013,6 +2013,7 @@ export interface PageEventTarget {
|
|||||||
on(event: 'close', callback: (params: PageCloseEvent) => void): this;
|
on(event: 'close', callback: (params: PageCloseEvent) => void): this;
|
||||||
on(event: 'crash', callback: (params: PageCrashEvent) => void): this;
|
on(event: 'crash', callback: (params: PageCrashEvent) => void): this;
|
||||||
on(event: 'download', callback: (params: PageDownloadEvent) => void): this;
|
on(event: 'download', callback: (params: PageDownloadEvent) => void): this;
|
||||||
|
on(event: 'viewportSizeChanged', callback: (params: PageViewportSizeChangedEvent) => void): this;
|
||||||
on(event: 'fileChooser', callback: (params: PageFileChooserEvent) => void): this;
|
on(event: 'fileChooser', callback: (params: PageFileChooserEvent) => void): this;
|
||||||
on(event: 'frameAttached', callback: (params: PageFrameAttachedEvent) => void): this;
|
on(event: 'frameAttached', callback: (params: PageFrameAttachedEvent) => void): this;
|
||||||
on(event: 'frameDetached', callback: (params: PageFrameDetachedEvent) => void): this;
|
on(event: 'frameDetached', callback: (params: PageFrameDetachedEvent) => void): this;
|
||||||
@ -2075,6 +2076,12 @@ export type PageDownloadEvent = {
|
|||||||
suggestedFilename: string,
|
suggestedFilename: string,
|
||||||
artifact: ArtifactChannel,
|
artifact: ArtifactChannel,
|
||||||
};
|
};
|
||||||
|
export type PageViewportSizeChangedEvent = {
|
||||||
|
viewportSize?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
|
};
|
||||||
export type PageFileChooserEvent = {
|
export type PageFileChooserEvent = {
|
||||||
element: ElementHandleChannel,
|
element: ElementHandleChannel,
|
||||||
isMultiple: boolean,
|
isMultiple: boolean,
|
||||||
@ -2566,6 +2573,7 @@ export interface PageEvents {
|
|||||||
'close': PageCloseEvent;
|
'close': PageCloseEvent;
|
||||||
'crash': PageCrashEvent;
|
'crash': PageCrashEvent;
|
||||||
'download': PageDownloadEvent;
|
'download': PageDownloadEvent;
|
||||||
|
'viewportSizeChanged': PageViewportSizeChangedEvent;
|
||||||
'fileChooser': PageFileChooserEvent;
|
'fileChooser': PageFileChooserEvent;
|
||||||
'frameAttached': PageFrameAttachedEvent;
|
'frameAttached': PageFrameAttachedEvent;
|
||||||
'frameDetached': PageFrameDetachedEvent;
|
'frameDetached': PageFrameDetachedEvent;
|
||||||
|
@ -2001,6 +2001,14 @@ Page:
|
|||||||
suggestedFilename: string
|
suggestedFilename: string
|
||||||
artifact: Artifact
|
artifact: Artifact
|
||||||
|
|
||||||
|
viewportSizeChanged:
|
||||||
|
parameters:
|
||||||
|
viewportSize:
|
||||||
|
type: object?
|
||||||
|
properties:
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
|
||||||
fileChooser:
|
fileChooser:
|
||||||
parameters:
|
parameters:
|
||||||
element: ElementHandle
|
element: ElementHandle
|
||||||
|
Loading…
x
Reference in New Issue
Block a user