feat(ElementHandle): add ElementHandle.boxModel method (#2256)
This patch introduces ElementHandle.boxModel to get element's box model. Fixes #1357
This commit is contained in:
parent
d4f24f1ec5
commit
41d5838297
12
docs/api.md
12
docs/api.md
@ -186,6 +186,7 @@
|
|||||||
* [elementHandle.$x(expression)](#elementhandlexexpression)
|
* [elementHandle.$x(expression)](#elementhandlexexpression)
|
||||||
* [elementHandle.asElement()](#elementhandleaselement)
|
* [elementHandle.asElement()](#elementhandleaselement)
|
||||||
* [elementHandle.boundingBox()](#elementhandleboundingbox)
|
* [elementHandle.boundingBox()](#elementhandleboundingbox)
|
||||||
|
* [elementHandle.boxModel()](#elementhandleboxmodel)
|
||||||
* [elementHandle.click([options])](#elementhandleclickoptions)
|
* [elementHandle.click([options])](#elementhandleclickoptions)
|
||||||
* [elementHandle.contentFrame()](#elementhandlecontentframe)
|
* [elementHandle.contentFrame()](#elementhandlecontentframe)
|
||||||
* [elementHandle.dispose()](#elementhandledispose)
|
* [elementHandle.dispose()](#elementhandledispose)
|
||||||
@ -2197,6 +2198,17 @@ The method evaluates the XPath expression relative to the elementHandle. If ther
|
|||||||
|
|
||||||
This method returns the bounding box of the element (relative to the main frame), or `null` if the element is not visible.
|
This method returns the bounding box of the element (relative to the main frame), or `null` if the element is not visible.
|
||||||
|
|
||||||
|
#### elementHandle.boxModel()
|
||||||
|
- returns: <[Promise]<?[Object]>>
|
||||||
|
- content <[Array]<[Object]>> Content box, represented as an array of {x, y} points.
|
||||||
|
- padding <[Array]<[Object]>> Padding box, represented as an array of {x, y} points.
|
||||||
|
- border <[Array]<[Object]>> Border box, represented as an array of {x, y} points.
|
||||||
|
- margin <[Array]<[Object]>> Margin box, represented as an array of {x, y} points.
|
||||||
|
- width <[number]> Element's width.
|
||||||
|
- height <[number]> Element's height.
|
||||||
|
|
||||||
|
This method returns boxes of the element, or `null` if the element is not visible. Boxes are represented as an array of objects, {x, y} for each point, points clock-wise. See [getBoxModel](https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getBoxModel) for more details.
|
||||||
|
|
||||||
#### elementHandle.click([options])
|
#### elementHandle.click([options])
|
||||||
- `options` <[Object]>
|
- `options` <[Object]>
|
||||||
- `button` <[string]> `left`, `right`, or `middle`, defaults to `left`.
|
- `button` <[string]> `left`, `right`, or `middle`, defaults to `left`.
|
||||||
|
@ -79,6 +79,28 @@ class ElementHandle extends JSHandle {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {!Promise<?{model: object}>}
|
||||||
|
*/
|
||||||
|
_getBoxModel() {
|
||||||
|
return this._client.send('DOM.getBoxModel', {
|
||||||
|
objectId: this._remoteObject.objectId
|
||||||
|
}).catch(error => debugError(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Array<number>} quad
|
||||||
|
* @return {!Array<object>}
|
||||||
|
*/
|
||||||
|
_fromProtocolQuad(quad) {
|
||||||
|
return [
|
||||||
|
{x: quad[0], y: quad[1]},
|
||||||
|
{x: quad[2], y: quad[3]},
|
||||||
|
{x: quad[4], y: quad[5]},
|
||||||
|
{x: quad[6], y: quad[7]}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
async hover() {
|
async hover() {
|
||||||
const {x, y} = await this._visibleCenter();
|
const {x, y} = await this._visibleCenter();
|
||||||
await this._page.mouse.move(x, y);
|
await this._page.mouse.move(x, y);
|
||||||
@ -133,9 +155,7 @@ class ElementHandle extends JSHandle {
|
|||||||
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
||||||
*/
|
*/
|
||||||
async boundingBox() {
|
async boundingBox() {
|
||||||
const result = await this._client.send('DOM.getBoxModel', {
|
const result = await this._getBoxModel();
|
||||||
objectId: this._remoteObject.objectId
|
|
||||||
}).catch(error => void debugError(error));
|
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
return null;
|
return null;
|
||||||
@ -149,6 +169,26 @@ class ElementHandle extends JSHandle {
|
|||||||
return {x, y, width, height};
|
return {x, y, width, height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {!Promise<?object>}
|
||||||
|
*/
|
||||||
|
async boxModel() {
|
||||||
|
const result = await this._getBoxModel();
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
const {content, padding, border, margin, width, height} = result.model;
|
||||||
|
return {
|
||||||
|
content: this._fromProtocolQuad(content),
|
||||||
|
padding: this._fromProtocolQuad(padding),
|
||||||
|
border: this._fromProtocolQuad(border),
|
||||||
|
margin: this._fromProtocolQuad(margin),
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +52,33 @@ module.exports.addTests = function({testRunner, expect}) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ElementHandle.boxModel', function() {
|
||||||
|
it('should work', async({page, server}) => {
|
||||||
|
const leftTop = {x: 28, y: 260};
|
||||||
|
const rightTop = {x: 292, y: 260};
|
||||||
|
const rightBottom = {x: 292, y: 278};
|
||||||
|
const leftBottom = {x: 28, y: 278};
|
||||||
|
|
||||||
|
await page.setViewport({width: 500, height: 500});
|
||||||
|
await page.goto(server.PREFIX + '/frames/nested-frames.html');
|
||||||
|
const nestedFrame = page.frames()[1].childFrames()[1];
|
||||||
|
const elementHandle = await nestedFrame.$('div');
|
||||||
|
const box = await elementHandle.boxModel();
|
||||||
|
expect(box.content).toEqual([leftTop, rightTop, rightBottom, leftBottom]);
|
||||||
|
expect(box.padding).toEqual([leftTop, rightTop, rightBottom, leftBottom]);
|
||||||
|
expect(box.border).toEqual([leftTop, rightTop, rightBottom, leftBottom]);
|
||||||
|
expect(box.margin).toEqual([leftTop, rightTop, rightBottom, leftBottom]);
|
||||||
|
expect(box.height).toBe(18);
|
||||||
|
expect(box.width).toBe(264);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null for invisible elements', async({page, server}) => {
|
||||||
|
await page.setContent('<div style="display:none">hi</div>');
|
||||||
|
const element = await page.$('div');
|
||||||
|
expect(await element.boxModel()).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('ElementHandle.contentFrame', function() {
|
describe('ElementHandle.contentFrame', function() {
|
||||||
it('should work', async({page,server}) => {
|
it('should work', async({page,server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
Loading…
Reference in New Issue
Block a user