Merge pull request #7658 from figma/webview-manual-guest-resize

Allow webview guests to be resized manually
This commit is contained in:
Kevin Sawicki 2016-11-15 14:21:56 -08:00 committed by GitHub
commit 0ef6d4631d
9 changed files with 217 additions and 3 deletions

View file

@ -1131,6 +1131,17 @@ win.webContents.on('did-finish-load', () => {
Shows pop-up dictionary that searches the selected word on the page.
#### `contents.setSize(options)`
Set the size of the page. This is only supported for `<webview>` guest contents.
* `options` Object
* `normal` Object (optional) - Normal size of the page. This can be used in
combination with the [`disableguestresize`](web-view-tag.md#disableguestresize)
attribute to manually resize the webview guest contents.
* `width` Integer
* `height` Integer
#### `contents.isOffscreen()`
Returns `Boolean` - Indicates whether *offscreen rendering* is enabled.

View file

@ -243,6 +243,44 @@ webview.
The existing webview will see the `destroy` event and will then create a new
webContents when a new url is loaded.
### `disableguestresize`
```html
<webview src="https://www.github.com/" disableguestresize></webview>
```
Prevents the webview contents from resizing when the webview element itself is
resized.
This can be used in combination with
[`webContents.setSize`](web-contents.md#contentssetsizeoptions) to manually
resize the webview contents in reaction to a window size change. This can
make resizing faster compared to relying on the webview element bounds to
automatically resize the contents.
```javascript
const {webContents} = require('electron')
// We assume that `win` points to a `BrowserWindow` instance containing a
// `<webview>` with `disableguestresize`.
win.on('resize', () => {
const [width, height] = win.getContentSize()
for (let wc of webContents.getAllWebContents()) {
// Check if `wc` belongs to a webview in the `win` window.
if (wc.hostWebContents &&
wc.hostWebContents.id === win.webContents.id) {
wc.setSize({
normal: {
width: width,
height: height
}
})
}
}
})
```
## Methods
The `webview` tag has the following methods:

View file

@ -327,6 +327,7 @@ WebViewImpl.prototype.setupWebViewAttributes = function () {
this.attributes[webViewConstants.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
this.attributes[webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
this.attributes[webViewConstants.ATTRIBUTE_GUESTINSTANCE] = new GuestInstanceAttribute(this)
this.attributes[webViewConstants.ATTRIBUTE_DISABLEGUESTRESIZE] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEGUESTRESIZE, this)
this.attributes[webViewConstants.ATTRIBUTE_WEBPREFERENCES] = new WebPreferencesAttribute(this)
const autosizeAttributes = [webViewConstants.ATTRIBUTE_MAXHEIGHT, webViewConstants.ATTRIBUTE_MAXWIDTH, webViewConstants.ATTRIBUTE_MINHEIGHT, webViewConstants.ATTRIBUTE_MINWIDTH]

View file

@ -18,6 +18,7 @@ module.exports = {
ATTRIBUTE_BLINKFEATURES: 'blinkfeatures',
ATTRIBUTE_DISABLEBLINKFEATURES: 'disableblinkfeatures',
ATTRIBUTE_GUESTINSTANCE: 'guestinstance',
ATTRIBUTE_DISABLEGUESTRESIZE: 'disableguestresize',
ATTRIBUTE_WEBPREFERENCES: 'webpreferences',
// Internal attribute.

View file

@ -172,7 +172,8 @@ class WebViewImpl {
resizeEvent.newWidth = newSize.width
resizeEvent.newHeight = newSize.height
this.dispatchEvent(resizeEvent)
if (this.guestInstanceId) {
if (this.guestInstanceId &&
!this.attributes[webViewConstants.ATTRIBUTE_DISABLEGUESTRESIZE].getValue()) {
guestViewInternal.setSize(this.guestInstanceId, {
normal: newSize
})

9
spec/fixtures/pages/resize.html vendored Normal file
View file

@ -0,0 +1,9 @@
<html>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
window.addEventListener('resize', () => {
ipcRenderer.send('webview-guest-resize', window.innerWidth, window.innerHeight)
}, false);
</script>
</html>

View file

@ -0,0 +1,20 @@
<html>
<style>
* {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<body>
<webview id="webview" nodeintegration src="resize.html"/>
</body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
const webview = document.getElementById('webview')
webview.addEventListener('resize', event => {
ipcRenderer.send('webview-element-resize', event.newWidth, event.newHeight)
}, false)
</script>
</html>

View file

@ -0,0 +1,20 @@
<html>
<style>
* {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<body>
<webview id="webview" nodeintegration disableguestresize src="resize.html"/>
</body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
const webview = document.getElementById('webview')
webview.addEventListener('resize', event => {
ipcRenderer.send('webview-element-resize', event.newWidth, event.newHeight)
}, false)
</script>
</html>

View file

@ -2,11 +2,11 @@ const assert = require('assert')
const path = require('path')
const http = require('http')
const url = require('url')
const {app, session, getGuestWebContents, ipcMain, BrowserWindow} = require('electron').remote
const {app, session, getGuestWebContents, ipcMain, BrowserWindow, webContents} = require('electron').remote
const {closeWindow} = require('./window-helpers')
describe('<webview> tag', function () {
this.timeout(20000)
this.timeout(60000)
var fixtures = path.join(__dirname, 'fixtures')
@ -1346,4 +1346,117 @@ describe('<webview> tag', function () {
document.body.appendChild(div)
})
})
describe('disableguestresize attribute', () => {
it('does not have attribute by default', () => {
document.body.appendChild(webview)
assert(!webview.hasAttribute('disableguestresize'))
})
it('resizes guest when attribute is not present', done => {
w = new BrowserWindow({show: false, width: 200, height: 200})
w.loadURL('file://' + fixtures + '/pages/webview-guest-resize.html')
w.webContents.once('did-finish-load', () => {
const CONTENT_SIZE = 300
const elementResizePromise = new Promise(resolve => {
ipcMain.once('webview-element-resize', (event, width, height) => {
assert.equal(width, CONTENT_SIZE)
assert.equal(height, CONTENT_SIZE)
resolve()
})
})
const guestResizePromise = new Promise(resolve => {
ipcMain.once('webview-guest-resize', (event, width, height) => {
assert.equal(width, CONTENT_SIZE)
assert.equal(height, CONTENT_SIZE)
resolve()
})
})
Promise.all([elementResizePromise, guestResizePromise]).then(() => done())
w.setContentSize(CONTENT_SIZE, CONTENT_SIZE)
})
})
it('does not resize guest when attribute is present', done => {
w = new BrowserWindow({show: false, width: 200, height: 200})
w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html')
w.webContents.once('did-finish-load', () => {
const CONTENT_SIZE = 300
const elementResizePromise = new Promise(resolve => {
ipcMain.once('webview-element-resize', (event, width, height) => {
assert.equal(width, CONTENT_SIZE)
assert.equal(height, CONTENT_SIZE)
resolve()
})
})
const noGuestResizePromise = new Promise(resolve => {
const onGuestResize = (event, width, height) => {
done(new Error('Unexpected guest resize message'))
}
ipcMain.once('webview-guest-resize', onGuestResize)
setTimeout(() => {
ipcMain.removeListener('webview-guest-resize', onGuestResize)
resolve()
}, 500)
})
Promise.all([elementResizePromise, noGuestResizePromise]).then(() => done())
w.setContentSize(CONTENT_SIZE, CONTENT_SIZE)
})
})
it('dispatches element resize event even when attribute is present', done => {
w = new BrowserWindow({show: false, width: 200, height: 200})
w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html')
w.webContents.once('did-finish-load', () => {
const CONTENT_SIZE = 300
ipcMain.once('webview-element-resize', (event, width, height) => {
assert.equal(width, CONTENT_SIZE)
done()
})
w.setContentSize(CONTENT_SIZE, CONTENT_SIZE)
})
})
it('can be manually resized with setSize even when attribute is present', done => {
w = new BrowserWindow({show: false, width: 200, height: 200})
w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html')
w.webContents.once('did-finish-load', () => {
const GUEST_WIDTH = 10
const GUEST_HEIGHT = 20
ipcMain.once('webview-guest-resize', (event, width, height) => {
assert.equal(width, GUEST_WIDTH)
assert.equal(height, GUEST_HEIGHT)
done()
})
for (const wc of webContents.getAllWebContents()) {
if (wc.hostWebContents &&
wc.hostWebContents.id === w.webContents.id) {
wc.setSize({
normal: {
width: GUEST_WIDTH,
height: GUEST_HEIGHT
}
})
}
}
})
})
})
})