Commit bf6e5f5a authored by fsamuel@chromium.org's avatar fsamuel@chromium.org

<webview>: Focusing <webview> should propagate to BrowserPlugin.


This patch does two things:

1. It gives <webview> a tabIndex if it doesn't already have one so that it can
   participate in tab order and keyboard focus.
2. When <webview> gets keyboard focus then we pass the focus to BrowserPlugin.
   When <webview> loses keyboard focus then BrowserPlugin loses focus.

BUG=231633
Test=WebViewTest.Focus

Review URL: https://chromiumcodereview.appspot.com/14272003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195294 0039d316-1c4b-4281-b951-d872f2087c98
parent 9595fd84
...@@ -201,3 +201,10 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) { ...@@ -201,3 +201,10 @@ IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) {
} }
#endif // (defined(OS_WIN) || defined(OS_LINUX)) #endif // (defined(OS_WIN) || defined(OS_LINUX))
// Tests that setting focus on the <webview> sets focus on the guest.
IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Focus) {
ASSERT_TRUE(StartTestServer()); // For serving guest pages.
ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/focus"))
<< message_;
}
...@@ -63,11 +63,27 @@ function WebView(node) { ...@@ -63,11 +63,27 @@ function WebView(node) {
} }
}, this); }, this);
if (!this.node_.hasAttribute('tabIndex')) {
// <webview> needs a tabIndex in order to respond to keyboard focus.
// TODO(fsamuel): This introduces unexpected tab ordering. We need to find
// a way to take keyboard focus without messing with tab ordering.
// See http://crbug.com/231664.
this.node_.setAttribute('tabIndex', 0);
}
var self = this;
this.node_.addEventListener('focus', function(e) {
// Focus the BrowserPlugin when the <webview> takes focus.
self.objectNode_.focus();
});
this.node_.addEventListener('blur', function(e) {
// Blur the BrowserPlugin when the <webview> loses focus.
self.objectNode_.blur();
});
shadowRoot.appendChild(this.objectNode_); shadowRoot.appendChild(this.objectNode_);
// this.objectNode_[apiMethod] are not necessarily defined immediately after // this.objectNode_[apiMethod] are not necessarily defined immediately after
// the shadow object is appended to the shadow root. // the shadow object is appended to the shadow root.
var self = this;
forEach(WEB_VIEW_API_METHODS, function(i, apiMethod) { forEach(WEB_VIEW_API_METHODS, function(i, apiMethod) {
node[apiMethod] = function(var_args) { node[apiMethod] = function(var_args) {
return self.objectNode_[apiMethod].apply(self.objectNode_, arguments); return self.objectNode_[apiMethod].apply(self.objectNode_, arguments);
......
<!--
* Copyright 2013 The Chromium Authors. All rights reserved. Use of this
* source code is governed by a BSD-style license that can be found in the
* LICENSE file.
-->
<html>
<body>
<div id="webview-tag-container"></div>
<script src="embedder.js"></script>
</body>
</html>
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var embedder = {};
embedder.tests = {};
embedder.baseGuestURL = '';
embedder.guestURL = '';
embedder.setUp = function(config) {
embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
embedder.guestURL = embedder.baseGuestURL +
'/files/extensions/platform_apps/web_view/focus' +
'/guest.html';
chrome.test.log('Guest url is: ' + embedder.guestURL);
};
/** @private */
embedder.setUpGuest_ = function() {
document.querySelector('#webview-tag-container').innerHTML =
'<webview style="width: 100px; height: 100px;"></webview>';
var webview = document.querySelector('webview');
if (!webview) {
chrome.test.fail('No <webview> element created');
}
return webview;
};
/** @private */
embedder.waitForResponseFromGuest_ =
function(webview,
testName,
channelCreationCallback,
expectedResponse,
responseCallback) {
var onPostMessageReceived = function(e) {
var data = JSON.parse(e.data);
var response = data[0];
if (response == 'channel-created') {
channelCreationCallback(webview);
return;
}
var name = data[1];
if ((response != expectedResponse) || (name != testName)) {
chrome.test.log('Unexpected response from guest.');
return;
}
responseCallback();
};
window.addEventListener('message', onPostMessageReceived);
var onWebViewLoadStop = function(e) {
// This creates a communication channel with the guest.
webview.contentWindow.postMessage(
JSON.stringify(['create-channel', testName]), '*');
};
webview.addEventListener('loadstop', onWebViewLoadStop);
webview.setAttribute('src', embedder.guestURL);
};
// Tests begin.
// The embedder has to initiate a post message so that the guest can get a
// reference to embedder to send the reply back.
embedder.testFocus_ = function(testName,
channelCreationCallback,
expectedResponse,
responseCallback) {
var webview = embedder.setUpGuest_();
embedder.waitForResponseFromGuest_(webview,
testName,
channelCreationCallback,
expectedResponse,
responseCallback);
};
embedder.tests.testFocusEvent = function testFocusEvent() {
var seenResponse = false;
embedder.testFocus_('testFocusEvent', function(webview) {
webview.focus();
}, 'focused', function() {
// The focus event fires three times on first focus. We only care about
// the first focus.
if (seenResponse)
return;
seenResponse = true;
chrome.test.succeed();
});
}
embedder.tests.testBlurEvent = function testBlurEvent() {
var seenResponse = false;
embedder.testFocus_('testFocusEvent', function(webview) {
webview.focus();
}, 'blurred', function() {
chrome.test.succeed();
});
}
onload = function() {
chrome.test.getConfig(function(config) {
embedder.setUp(config);
chrome.test.runTests([
embedder.tests.testFocusEvent,
embedder.tests.testBlurEvent
]);
});
};
<!--
* Copyright 2013 The Chromium Authors. All rights reserved. Use of this
* source code is governed by a BSD-style license that can be found in the
* LICENSE file.
-->
<html>
<head>
<script type="text/javascript">
// A guest that monitors focus.
// Notifies the embedder about changes in focus via postMessage.
// Note that the embedder has to initiate a postMessage first so that
// the guest has a reference to the embedder's window.
// The window reference of the embedder to send post message reply.
var embedderWindowChannel = null;
var embedderTestName = '';
var notifyEmbedder = function(msg_array) {
embedderWindowChannel.postMessage(JSON.stringify(msg_array), '*');
};
var onPostMessageReceived = function(e) {
embedderWindowChannel = e.source;
var data = JSON.parse(e.data);
if (data[0] == 'create-channel') {
embedderTestName = data[1];
notifyEmbedder(['channel-created']);
}
};
window.addEventListener('message', onPostMessageReceived, false);
window.addEventListener('focus', function(e) {
notifyEmbedder(['focused', embedderTestName]);
});
window.addEventListener('blur', function(e) {
notifyEmbedder(['blurred', embedderTestName]);
});
</script>
</head>
<body>
<div>This is a guest that monitors focus.</div>
</body>
</html>
{
"name": "Packaged App Test: <webview> Focus",
"description": "Loads a guest which monitors focus",
"version": "1",
"permissions": [
"webview"
],
"app": {
"background": {
"scripts": ["test.js"]
}
}
}
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('embedder.html', {}, function () {});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment