Bug 1279771 - Treat change events triggered by changing <select> element selections as user-initiated in e10s, r=enndeakin

This commit is contained in:
Michael Layzell 2016-06-14 08:11:09 -04:00
parent 8296f93061
commit 197e47c6a7
6 changed files with 115 additions and 21 deletions

View File

@ -3996,6 +3996,20 @@ nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::StartHandlingUserInput()
{
EventStateManager::StartHandlingUserInput();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::StopHandlingUserInput()
{
EventStateManager::StopHandlingUserInput();
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)

View File

@ -1916,6 +1916,19 @@ interface nsIDOMWindowUtils : nsISupports {
* was last provided is what will be used.
*/
void respectDisplayPortSuppression(in boolean aEnabled);
/**
* Start treating code as running within a user-initiated event callback. Must
* be matched by a call to stopHandlingUserInput.
*/
void startHandlingUserInput();
/**
* Stop treating code as running within a user-initiated event callback. Must
* be matched by a call to startHandlingUserInput.
*/
void stopHandlingUserInput();
};
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]

View File

@ -0,0 +1,15 @@
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Components.utils.import("resource://gre/modules/Services.jsm");
// Define these to make EventUtils happy.
let window = this;
let parent = {};
let EventUtils = {};
Services.scriptloader.loadSubScript(
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
EventUtils
);
let label = browserElement.ownerDocument.getElementById(browserElement.getAttribute('selectmenulist')).querySelector("[label=B]");
EventUtils.synthesizeMouseAtCenter(label, {}, browserElement.ownerDocument.defaultView);

View File

@ -141,3 +141,5 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' # Mou
[test_WebKitCSSMatrix.html]
[test_resource_timing_frameset.html]
[test_bug1208217.html]
[test_bug1279771.html]
support-files = file_bug1279771_chromeScript.js

View File

@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1279771
-->
<head>
<title>Test for Bug 1279771</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<script src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<select id="select">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<pre id="test">
<script type="application/javascript">
add_task(function* (){
var select = document.querySelector("#select");
let done = new Promise(resolve => {
select.addEventListener('change', function() {
ok(document.execCommand("copy"), "The copy command is allowed to be executed from this callback");
resolve();
});
})
// Spin the event loop once so that synthesizeMouseAtCenter works...
yield new Promise(resolve => SimpleTest.executeSoon(resolve));
synthesizeMouseAtCenter(select, {});
// Run the chrome script which will close the selectmenulist, firing a change event
SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL("file_bug1279771_chromeScript.js"));
yield done;
});
</script>
</pre>
</body>
</html>

View File

@ -114,29 +114,36 @@ this.SelectContentHelper.prototype = {
case "Forms:DismissedDropDown":
if (this.initialSelection != this.element.item(this.element.selectedIndex)) {
let win = this.element.ownerDocument.defaultView;
let inputEvent = new win.UIEvent("input", {
bubbles: true,
});
this.element.dispatchEvent(inputEvent);
let changeEvent = new win.Event("change", {
bubbles: true,
});
this.element.dispatchEvent(changeEvent);
// Going for mostly-Blink parity here, which (at least on Windows)
// fires a mouseup and click event after each selection -
// even by keyboard. We're firing a mousedown too, since that
// seems to make more sense. Unfortunately, the spec on form
// control behaviours for these events is really not clear.
const MOUSE_EVENTS = ["mousedown", "mouseup", "click"];
for (let eventName of MOUSE_EVENTS) {
let mouseEvent = new win.MouseEvent(eventName, {
view: win,
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
dwu.startHandlingUserInput();
try {
let inputEvent = new win.UIEvent("input", {
bubbles: true,
cancelable: true,
});
this.element.dispatchEvent(mouseEvent);
this.element.dispatchEvent(inputEvent);
let changeEvent = new win.Event("change", {
bubbles: true,
});
this.element.dispatchEvent(changeEvent);
// Going for mostly-Blink parity here, which (at least on Windows)
// fires a mouseup and click event after each selection -
// even by keyboard. We're firing a mousedown too, since that
// seems to make more sense. Unfortunately, the spec on form
// control behaviours for these events is really not clear.
const MOUSE_EVENTS = ["mousedown", "mouseup", "click"];
for (let eventName of MOUSE_EVENTS) {
let mouseEvent = new win.MouseEvent(eventName, {
view: win,
bubbles: true,
cancelable: true,
});
this.element.dispatchEvent(mouseEvent);
}
} finally {
dwu.stopHandlingUserInput();
}
}