fix: emit focus/blur events for webview (backport: 3-0-x) (#14359)
* fix: emit focus/blur events for webview * test: webview can emit focus event
This commit is contained in:
parent
873f39b159
commit
b1c22ba531
5 changed files with 53 additions and 21 deletions
|
@ -26,6 +26,7 @@ const supportedWebViewEvents = [
|
|||
'did-navigate',
|
||||
'did-frame-navigate',
|
||||
'did-navigate-in-page',
|
||||
'focus-change',
|
||||
'close',
|
||||
'crashed',
|
||||
'gpu-crashed',
|
||||
|
@ -322,6 +323,10 @@ ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedder
|
|||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
|
||||
event.sender.emit('focus-change', {}, focus, guestInstanceId)
|
||||
})
|
||||
|
||||
// Returns WebContents from its guest id.
|
||||
const getGuest = function (guestInstanceId) {
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
|
|
|
@ -25,6 +25,7 @@ var v8Util = process.atomBinding('v8_util')
|
|||
v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter())
|
||||
|
||||
// Use electron module after everything is ready.
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const {
|
||||
warnAboutNodeWithRemoteContent,
|
||||
|
@ -184,3 +185,15 @@ window.addEventListener('load', function loadHandler () {
|
|||
|
||||
window.removeEventListener('load', loadHandler)
|
||||
})
|
||||
|
||||
// Report focus/blur events of webview to browser.
|
||||
// Note that while Chromium content APIs have observer for focus/blur, they
|
||||
// unfortunately do not work for webview.
|
||||
if (process.guestInstanceId) {
|
||||
window.addEventListener('focus', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', true, process.guestInstanceId)
|
||||
})
|
||||
window.addEventListener('blur', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', false, process.guestInstanceId)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ const WEB_VIEW_EVENTS = {
|
|||
'did-navigate': ['url', 'httpResponseCode', 'httpStatusText'],
|
||||
'did-frame-navigate': ['url', 'httpResponseCode', 'httpStatusText', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||
'did-navigate-in-page': ['url', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||
'focus-change': ['focus', 'guestInstanceId'],
|
||||
'close': [],
|
||||
'crashed': [],
|
||||
'gpu-crashed': [],
|
||||
|
@ -55,6 +56,8 @@ const dispatchEvent = function (webView, eventName, eventKey, ...args) {
|
|||
webView.dispatchEvent(domEvent)
|
||||
if (eventName === 'load-commit') {
|
||||
webView.onLoadCommit(domEvent)
|
||||
} else if (eventName === 'focus-change') {
|
||||
webView.onFocusChange(domEvent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ class WebViewImpl {
|
|||
v8Util.setHiddenValue(this.webviewNode, 'internal', this)
|
||||
this.elementAttached = false
|
||||
this.beforeFirstNavigation = true
|
||||
this.hasFocus = false
|
||||
|
||||
// Check for removed attributes.
|
||||
for (const attributeName of removedAttributes) {
|
||||
|
@ -41,13 +42,21 @@ class WebViewImpl {
|
|||
// on* Event handlers.
|
||||
this.on = {}
|
||||
|
||||
// Create internal iframe element.
|
||||
this.internalElement = this.createInternalElement()
|
||||
const shadowRoot = this.webviewNode.attachShadow({mode: 'open'})
|
||||
shadowRoot.innerHTML = '<!DOCTYPE html><style type="text/css">:host { display: flex; }</style>'
|
||||
this.setupWebViewAttributes()
|
||||
this.setupFocusPropagation()
|
||||
this.viewInstanceId = getNextId()
|
||||
shadowRoot.appendChild(this.internalElement)
|
||||
|
||||
// Provide access to contentWindow.
|
||||
Object.defineProperty(this.webviewNode, 'contentWindow', {
|
||||
get: () => {
|
||||
return this.internalElement.contentWindow
|
||||
},
|
||||
enumerable: true
|
||||
})
|
||||
}
|
||||
|
||||
createInternalElement () {
|
||||
|
@ -91,26 +100,6 @@ class WebViewImpl {
|
|||
})
|
||||
}
|
||||
|
||||
setupFocusPropagation () {
|
||||
if (!this.webviewNode.hasAttribute('tabIndex')) {
|
||||
// <webview> needs a tabIndex in order to be focusable.
|
||||
// TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
||||
// to allow <webview> to be focusable.
|
||||
// See http://crbug.com/231664.
|
||||
this.webviewNode.setAttribute('tabIndex', -1)
|
||||
}
|
||||
|
||||
// Focus the BrowserPlugin when the <webview> takes focus.
|
||||
this.webviewNode.addEventListener('focus', () => {
|
||||
this.internalElement.focus()
|
||||
})
|
||||
|
||||
// Blur the BrowserPlugin when the <webview> loses focus.
|
||||
this.webviewNode.addEventListener('blur', () => {
|
||||
this.internalElement.blur()
|
||||
})
|
||||
}
|
||||
|
||||
// This observer monitors mutations to attributes of the <webview> and
|
||||
// updates the BrowserPlugin properties accordingly. In turn, updating
|
||||
// a BrowserPlugin property will update the corresponding BrowserPlugin
|
||||
|
@ -185,6 +174,15 @@ class WebViewImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// Emits focus/blur events.
|
||||
onFocusChange () {
|
||||
const hasFocus = document.activeElement === this.webviewNode
|
||||
if (hasFocus !== this.hasFocus) {
|
||||
this.hasFocus = hasFocus
|
||||
this.dispatchEvent(new Event(hasFocus ? 'focus' : 'blur'))
|
||||
}
|
||||
}
|
||||
|
||||
onAttach (storagePartitionId) {
|
||||
return this.attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue(storagePartitionId)
|
||||
}
|
||||
|
|
|
@ -1283,6 +1283,19 @@ describe('<webview> tag', function () {
|
|||
expect(secondResizeEvent.newWidth).to.equal(newWidth)
|
||||
expect(secondResizeEvent.newHeight).to.equal(newHeight)
|
||||
})
|
||||
|
||||
it('emits focus event', async () => {
|
||||
const domReadySignal = waitForEvent(webview, 'dom-ready')
|
||||
webview.src = `file://${fixtures}/pages/a.html`
|
||||
document.body.appendChild(webview)
|
||||
|
||||
await domReadySignal
|
||||
|
||||
const focusSignal = waitForEvent(webview, 'focus')
|
||||
webview.contentWindow.focus()
|
||||
|
||||
await focusSignal
|
||||
})
|
||||
})
|
||||
|
||||
describe('zoom behavior', () => {
|
||||
|
|
Loading…
Add table
Reference in a new issue