Bug 757486 - Allow browser frames to bubble some whitelisted key events. r=jlebar

--HG--
extra : rebase_source : 5d8e8c2a4899f37bd01f4eab69238f48b0a2ddeb
This commit is contained in:
Mounir Lamouri 2012-05-23 16:15:31 +02:00
Родитель b565b9e429
Коммит 81fb734285
6 изменённых файлов: 179 добавлений и 1 удалений

Просмотреть файл

@ -9,6 +9,15 @@ let Ci = Components.interfaces;
let Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// Event whitelisted for bubbling.
let whitelistedEvents = [
Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button.
Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU,
Ci.nsIDOMKeyEvent.DOM_VK_F5, // Search button.
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP, // Volume up.
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN // Volume down.
];
function debug(msg) {
//dump("BrowserElementChild - " + msg + "\n");
}
@ -32,6 +41,8 @@ function sendSyncMsg(msg, data) {
* the parent process.
*/
var global = this;
function BrowserElementChild() {
this._init();
};
@ -57,7 +68,7 @@ BrowserElementChild.prototype = {
// Get the app manifest from the parent, if our frame has one.
let appManifestURL = sendSyncMsg('get-mozapp-manifest-url')[0];
let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
.getInterface(Ci.nsIDOMWindowUtils);
if (!!appManifestURL) {
windowUtils.setIsApp(true);
@ -78,6 +89,21 @@ BrowserElementChild.prototype = {
addMessageListener("browser-element-api:get-screenshot",
this._recvGetScreenshot.bind(this));
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
// We are using the system group for those events so if something in the
// content called .stopPropagation() this will still be called.
els.addSystemEventListener(global, 'keydown',
this._keyEventHandler.bind(this),
/* useCapture = */ true);
els.addSystemEventListener(global, 'keypress',
this._keyEventHandler.bind(this),
/* useCapture = */ true);
els.addSystemEventListener(global, 'keyup',
this._keyEventHandler.bind(this),
/* useCapture = */ true);
},
_titleChangedHandler: function(e) {
@ -129,6 +155,16 @@ BrowserElementChild.prototype = {
});
},
_keyEventHandler: function(e) {
if (whitelistedEvents.indexOf(e.keyCode) != -1 && !e.defaultPrevented) {
sendAsyncMsg('keyevent', {
type: e.type,
code: e.keyCode,
charCode: e.charCode,
});
}
},
// The docShell keeps a weak reference to the progress listener, so we need
// to keep a strong ref to it ourselves.
_progressListener: {

Просмотреть файл

@ -106,6 +106,7 @@ BrowserElementParent.prototype = {
addMessageListener("titlechange", this._fireEventFromMsg);
addMessageListener("iconchange", this._fireEventFromMsg);
addMessageListener("get-mozapp-manifest-url", this._sendMozAppManifestURL);
addMessageListener("keyevent", this._fireKeyEvent);
mm.addMessageListener('browser-element-api:got-screenshot',
this._recvGotScreenshot.bind(this));
@ -164,6 +165,18 @@ BrowserElementParent.prototype = {
return req;
},
_fireKeyEvent: function(frameElement, data) {
let win = frameElement.ownerDocument.defaultView;
let evt = frameElement.ownerDocument.createEvent("KeyboardEvent");
evt.initKeyEvent(data.json.type, true, true, win,
false, false, false, false, // modifiers
data.json.keyCode,
data.json.charCode);
frameElement.dispatchEvent(evt);
},
observe: function(subject, topic, data) {
switch(topic) {
case 'app-startup':

Просмотреть файл

@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
file_empty.html \
file_focus.html \
browserFrameHelpers.js \
test_browserFrame1.html \
test_browserFrame2.html \
@ -24,6 +25,7 @@ _TEST_FILES = \
test_browserFrame7.html \
test_browserFrame8.html \
test_browserFrame9.html \
test_browserFrame_keyEvents.html \
$(NULL)
libs:: $(_TEST_FILES)

Просмотреть файл

@ -106,6 +106,9 @@ const browserFrameHelpers = {
'emptyPage2': 'http://example.org' +
window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
'/file_empty.html',
'focusPage': 'http://example.org' +
window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) +
'/file_focus.html',
};
browserFrameHelpers.origEnabledPref = browserFrameHelpers.getEnabledPref();

Просмотреть файл

@ -0,0 +1,25 @@
<html>
<body>
Aloha! My URL is <span id='url'></span>.
<script>
document.getElementById('url').innerHTML = window.location;
</script>
<script>
// The input element is getting synthesized key events and will prevent
// default on the first ESC keydown event.
var alreadyBlocked = false;
addEventListener('keydown', function(e) {
if (e.keyCode == Components.interfaces.nsIDOMKeyEvent.DOM_VK_ESCAPE &&
alreadyBlocked == false) {
alreadyBlocked = true;
e.preventDefault();
}
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=757486
-->
<head>
<title>Test for Bug 757486</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="browserFrameHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757486">Mozilla Bug 757486</a>
<!--
Test that an iframe with the |mozbrowser| attribute does bubble some
whitelisted key events.
-->
<script type="application/javascript;version=1.7">
"use strict";
let Ci = Components.interfaces;
let whitelistedEvents = [
Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button.
Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU,
Ci.nsIDOMKeyEvent.DOM_VK_F5, // Search button.
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP, // Volume up.
Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN // Volume down.
];
SimpleTest.waitForExplicitFinish();
browserFrameHelpers.setEnabledPref(true);
browserFrameHelpers.addToWhitelist();
browserFrameHelpers.setOOPDisabledPref(true); // this is breaking the autofocus.
var iframe = document.createElement('iframe');
iframe.mozbrowser = true;
iframe.src = browserFrameHelpers.focusPage;
document.body.appendChild(iframe);
// Number of expected events at which point we will consider the test as done.
var nbEvents = 15;
function eventHandler(e) {
ok(((e.type == 'keydown' || e.type == 'keypress' || e.type == 'keyup') &&
!e.defaultPrevented &&
whitelistedEvents.indexOf(e.keyCode)),
"[ " + e.type + "] Handled event should be a non prevented key event in the white list.");
nbEvents--;
if (nbEvents == 0) {
browserFrameHelpers.restoreOriginalPrefs();
SimpleTest.finish();
return;
}
if (nbEvents < 0) {
ok(false, "got an unexpected event! " + e.type + " " + e.keyCode);
SimpleTest.finish();
return;
}
}
function runTest() {
is(document.activeElement, iframe, "iframe should be focused");
addEventListener('keydown', eventHandler);
addEventListener('keypress', eventHandler);
addEventListener('keyup', eventHandler);
// Those event should not be received because not whitelisted.
synthesizeKey("VK_A", {});
synthesizeKey("VK_B", {});
// Those events should not be received because prevent default is called.
synthesizeKey("VK_ESCAPE", {});
// Those events should be received.
synthesizeKey("VK_F5", {}); // F5 key is going to be canceled by ESC key.
synthesizeKey("VK_ESCAPE", {});
synthesizeKey("VK_PAGE_UP", {}); // keypress is ignored because .preventDefault() will be called.
synthesizeKey("VK_PAGE_DOWN", {}); // keypress is ignored because .preventDefault() will be called.
synthesizeKey("VK_CONTEXT_MENU", {});
}
SimpleTest.waitForFocus(function() {
iframe.focus();
SimpleTest.executeSoon(runTest);
});
</script>
</body>
</html>