Bug 1253486, [e10s only] hide select popups when the select element is removed, r=mconley

This commit is contained in:
Neil Deakin
2016-04-13 13:15:55 -04:00
parent a25f90892d
commit 1d00585fb2
5 changed files with 90 additions and 13 deletions

View File

@@ -26,13 +26,26 @@ const PAGECONTENT =
" </optgroup></select><input />Text" +
"</body></html>";
function openSelectPopup(selectPopup, withMouse)
const PAGECONTENT_SMALL =
"<html>" +
"<body><select id='one'>" +
" <option value='One'>One</option>" +
" <option value='Two'>Two</option>" +
"</select><select id='two'>" +
" <option value='Three'>Three</option>" +
" <option value='Four'>Four</option>" +
"</select><select id='three'>" +
" <option value='Five'>Five</option>" +
" <option value='Six'>Six</option>" +
"</select></body></html>";
function openSelectPopup(selectPopup, withMouse, selector = "select")
{
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
if (withMouse) {
return Promise.all([popupShownPromise,
BrowserTestUtils.synthesizeMouseAtCenter("select", { }, gBrowser.selectedBrowser)]);
BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, gBrowser.selectedBrowser)]);
}
setTimeout(() => EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" }), 1500);
@@ -41,7 +54,7 @@ function openSelectPopup(selectPopup, withMouse)
function hideSelectPopup(selectPopup, withEscape)
{
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
if (withEscape) {
EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" });
@@ -50,7 +63,7 @@ function hideSelectPopup(selectPopup, withEscape)
EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" });
}
return popupShownPromise;
return popupHiddenPromise;
}
function getChangeEvents()
@@ -62,11 +75,8 @@ function getChangeEvents()
function doSelectTests(contentType, dtd)
{
let tab = gBrowser.selectedTab = gBrowser.addTab();
let browser = gBrowser.getBrowserForTab(tab);
yield promiseTabLoadEvent(tab, "data:" + contentType + "," + escape(dtd + "\n" + PAGECONTENT));
yield SimpleTest.promiseFocus(browser.contentWindow);
const pageUrl = "data:" + contentType + "," + escape(dtd + "\n" + PAGECONTENT);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
let menulist = document.getElementById("ContentSelectDropdown");
let selectPopup = menulist.menupopup;
@@ -138,7 +148,7 @@ function doSelectTests(contentType, dtd)
is(selectPopup.lastChild.previousSibling.label, "Seven", "Spaces collapsed");
is(selectPopup.lastChild.label, "\xA0\xA0Eight\xA0\xA0", "Non-breaking spaces not collapsed");
gBrowser.removeCurrentTab();
yield BrowserTestUtils.removeTab(tab);
}
add_task(function*() {
@@ -149,3 +159,46 @@ add_task(function*() {
yield doSelectTests("application/xhtml+xml", XHTML_DTD);
});
// This test opens a select popup and removes the content node of a popup while
// The popup should close if its node is removed.
add_task(function*() {
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
let menulist = document.getElementById("ContentSelectDropdown");
let selectPopup = menulist.menupopup;
// First, try it when a different <select> element than the one that is open is removed
yield openSelectPopup(selectPopup, true, "#one");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.document.body.removeChild(content.document.getElementById("two"));
});
// Wait a bit just to make sure the popup won't close.
yield new Promise(resolve => setTimeout(resolve, 1000));
is(selectPopup.state, "open", "Different popup did not affect open popup");
yield hideSelectPopup(selectPopup);
// Next, try it when the same <select> element than the one that is open is removed
yield openSelectPopup(selectPopup, true, "#three");
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.document.body.removeChild(content.document.getElementById("three"));
});
yield popupHiddenPromise;
ok(true, "Popup hidden when select is removed");
// Finally, try it when the tab is closed while the select popup is open.
yield openSelectPopup(selectPopup, true, "#one");
popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
yield BrowserTestUtils.removeTab(tab);
yield popupHiddenPromise;
ok(true, "Popup hidden when tab is closed");
});

View File

@@ -141,6 +141,14 @@ nsListControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mousemove"),
mEventListener, false);
if (XRE_IsContentProcess() &&
Preferences::GetBool("browser.tabs.remote.desktopbehavior", false)) {
nsContentUtils::AddScriptRunner(
new AsyncEventDispatcher(mContent,
NS_LITERAL_STRING("mozhidedropdown"), true,
true));
}
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
nsHTMLScrollFrame::DestroyFrom(aDestructRoot);
}

View File

@@ -401,6 +401,12 @@
Note: This overrides the destroy() method from browser.xml. -->
<method name="destroy">
<body><![CDATA[
// Make sure that any open select is closed.
if (this._selectParentHelper) {
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
this._selectParentHelper.hide(menulist, this);
}
if (this.mDestroyed)
return;
this.mDestroyed = true;
@@ -483,7 +489,7 @@
case "Forms:HideDropDown": {
if (this._selectParentHelper) {
let menulist = document.getElementById(this.getAttribute("selectmenulist"));
this._selectParentHelper.hide(menulist);
this._selectParentHelper.hide(menulist, this);
}
break;
}

View File

@@ -36,6 +36,7 @@ this.SelectContentHelper.prototype = {
this.global.addMessageListener("Forms:MouseOver", this);
this.global.addMessageListener("Forms:MouseOut", this);
this.global.addEventListener("pagehide", this);
this.global.addEventListener("mozhidedropdown", this);
},
uninit: function() {
@@ -44,6 +45,7 @@ this.SelectContentHelper.prototype = {
this.global.removeMessageListener("Forms:MouseOver", this);
this.global.removeMessageListener("Forms:MouseOut", this);
this.global.removeEventListener("pagehide", this);
this.global.removeEventListener("mozhidedropdown", this);
this.element = null;
this.global = null;
},
@@ -102,6 +104,12 @@ this.SelectContentHelper.prototype = {
this.uninit();
}
break;
case "mozhidedropdown":
if (this.element === event.target) {
this.global.sendAsyncMessage("Forms:HideDropDown", {});
this.uninit();
}
break;
}
}

View File

@@ -26,8 +26,10 @@ this.SelectParentHelper = {
menulist.selectedItem.scrollIntoView();
},
hide: function(menulist) {
menulist.menupopup.hidePopup();
hide: function(menulist, browser) {
if (currentBrowser == browser) {
menulist.menupopup.hidePopup();
}
},
handleEvent: function(event) {