зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1311279, when the mouse is released, check if it should be retargetted at the select element in the content process, so that a click event is received, r=mconley
This commit is contained in:
Родитель
03860c9589
Коммит
839f1bb76c
|
@ -11,7 +11,8 @@ const XHTML_DTD = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www
|
|||
|
||||
const PAGECONTENT =
|
||||
"<html xmlns='http://www.w3.org/1999/xhtml'>" +
|
||||
"<body onload='gChangeEvents = 0;gInputEvents = 0; document.body.firstChild.focus()'><select oninput='gInputEvents++' onchange='gChangeEvents++'>" +
|
||||
"<body onload='gChangeEvents = 0;gInputEvents = 0; gClickEvents = 0; document.body.firstChild.focus()'>" +
|
||||
"<select oninput='gInputEvents++' onchange='gChangeEvents++' onclick='if (event.target == this) gClickEvents++'>" +
|
||||
" <optgroup label='First Group'>" +
|
||||
" <option value='One'>One</option>" +
|
||||
" <option value='Two'>Two</option>" +
|
||||
|
@ -127,6 +128,12 @@ function getChangeEvents() {
|
|||
});
|
||||
}
|
||||
|
||||
function getClickEvents() {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
|
||||
return content.wrappedJSObject.gClickEvents;
|
||||
});
|
||||
}
|
||||
|
||||
function* doSelectTests(contentType, dtd) {
|
||||
const pageUrl = "data:" + contentType + "," + escape(dtd + "\n" + PAGECONTENT);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
@ -169,6 +176,7 @@ function* doSelectTests(contentType, dtd) {
|
|||
|
||||
is((yield getInputEvents()), 0, "Before closed - number of input events");
|
||||
is((yield getChangeEvents()), 0, "Before closed - number of change events");
|
||||
is((yield getClickEvents()), 0, "Before closed - number of click events");
|
||||
|
||||
EventUtils.synthesizeKey("a", { accelKey: true });
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { isWindows }, function(args) {
|
||||
|
@ -189,26 +197,31 @@ function* doSelectTests(contentType, dtd) {
|
|||
is(menulist.selectedIndex, 3, "Item 3 still selected");
|
||||
is((yield getInputEvents()), 1, "After closed - number of input events");
|
||||
is((yield getChangeEvents()), 1, "After closed - number of change events");
|
||||
is((yield getClickEvents()), 0, "After closed - number of click events");
|
||||
|
||||
// Opening and closing the popup without changing the value should not fire a change event.
|
||||
yield openSelectPopup(selectPopup, "click");
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
is((yield getInputEvents()), 1, "Open and close with no change - number of input events");
|
||||
is((yield getChangeEvents()), 1, "Open and close with no change - number of change events");
|
||||
is((yield getClickEvents()), 1, "Open and close with no change - number of click events");
|
||||
EventUtils.synthesizeKey("VK_TAB", { });
|
||||
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true });
|
||||
is((yield getInputEvents()), 1, "Tab away from select with no change - number of input events");
|
||||
is((yield getChangeEvents()), 1, "Tab away from select with no change - number of change events");
|
||||
is((yield getClickEvents()), 1, "Tab away from select with no change - number of click events");
|
||||
|
||||
yield openSelectPopup(selectPopup, "click");
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
is((yield getInputEvents()), isWindows ? 2 : 1, "Open and close with change - number of input events");
|
||||
is((yield getChangeEvents()), isWindows ? 2 : 1, "Open and close with change - number of change events");
|
||||
is((yield getClickEvents()), 2, "Open and close with change - number of click events");
|
||||
EventUtils.synthesizeKey("VK_TAB", { });
|
||||
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true });
|
||||
is((yield getInputEvents()), isWindows ? 2 : 1, "Tab away from select with change - number of input events");
|
||||
is((yield getChangeEvents()), isWindows ? 2 : 1, "Tab away from select with change - number of change events");
|
||||
is((yield getClickEvents()), 2, "Tab away from select with change - number of click events");
|
||||
|
||||
is(selectPopup.lastChild.previousSibling.label, "Seven", "Spaces collapsed");
|
||||
is(selectPopup.lastChild.label, "\xA0\xA0Eight\xA0\xA0", "Non-breaking spaces not collapsed");
|
||||
|
|
|
@ -113,6 +113,15 @@ this.SelectContentHelper.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
dispatchMouseEvent(win, target, eventName) {
|
||||
let mouseEvent = new win.MouseEvent(eventName, {
|
||||
view: win,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
target.dispatchEvent(mouseEvent);
|
||||
},
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "Forms:SelectDropDownItem":
|
||||
|
@ -131,15 +140,8 @@ this.SelectContentHelper.prototype = {
|
|||
// to select an element in the dropdown, we only fire input and
|
||||
// change events.
|
||||
if (!this.closedWithEnter) {
|
||||
const MOUSE_EVENTS = ["mousedown", "mouseup"];
|
||||
for (let eventName of MOUSE_EVENTS) {
|
||||
let mouseEvent = new win.MouseEvent(eventName, {
|
||||
view: win,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
selectedOption.dispatchEvent(mouseEvent);
|
||||
}
|
||||
this.dispatchMouseEvent(win, selectedOption, "mousedown");
|
||||
this.dispatchMouseEvent(win, selectedOption, "mouseup");
|
||||
DOMUtils.removeContentState(this.element, kStateActive);
|
||||
}
|
||||
|
||||
|
@ -154,12 +156,7 @@ this.SelectContentHelper.prototype = {
|
|||
this.element.dispatchEvent(changeEvent);
|
||||
|
||||
if (!this.closedWithEnter) {
|
||||
let mouseEvent = new win.MouseEvent("click", {
|
||||
view: win,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
selectedOption.dispatchEvent(mouseEvent);
|
||||
this.dispatchMouseEvent(win, selectedOption, "click");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,9 +172,15 @@ this.SelectContentHelper.prototype = {
|
|||
break;
|
||||
|
||||
case "Forms:MouseUp":
|
||||
let win = this.element.ownerDocument.defaultView;
|
||||
if (message.data.onAnchor) {
|
||||
this.dispatchMouseEvent(win, this.element, "mouseup");
|
||||
}
|
||||
DOMUtils.removeContentState(this.element, kStateActive);
|
||||
if (message.data.onAnchor) {
|
||||
this.dispatchMouseEvent(win, this.element, "click");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ var currentBrowser = null;
|
|||
var currentMenulist = null;
|
||||
var currentZoom = 1;
|
||||
var closedWithEnter = false;
|
||||
var selectRect;
|
||||
|
||||
this.SelectParentHelper = {
|
||||
draggedOverPopup: false,
|
||||
|
@ -42,6 +43,7 @@ this.SelectParentHelper = {
|
|||
menulist.hidden = false;
|
||||
currentBrowser = browser;
|
||||
closedWithEnter = false;
|
||||
selectRect = rect;
|
||||
this._registerListeners(browser, menulist.menupopup);
|
||||
|
||||
let win = browser.ownerDocument.defaultView;
|
||||
|
@ -97,7 +99,15 @@ this.SelectParentHelper = {
|
|||
case "mouseup":
|
||||
this.clearScrollTimer();
|
||||
currentMenulist.menupopup.removeEventListener("mousemove", this);
|
||||
currentBrowser.messageManager.sendAsyncMessage("Forms:MouseUp", {});
|
||||
|
||||
function inRect(rect, x, y) {
|
||||
return x >= rect.left && x <= rect.left + rect.width && y >= rect.top && y <= rect.top + rect.height;
|
||||
}
|
||||
|
||||
let x = event.screenX, y = event.screenY;
|
||||
let onAnchor = !inRect(currentMenulist.menupopup.getOuterScreenRect(), x, y) &&
|
||||
inRect(selectRect, x, y) && currentMenulist.menupopup.state == "open";
|
||||
currentBrowser.messageManager.sendAsyncMessage("Forms:MouseUp", { onAnchor });
|
||||
break;
|
||||
|
||||
case "mouseover":
|
||||
|
@ -110,15 +120,25 @@ this.SelectParentHelper = {
|
|||
|
||||
case "mousemove":
|
||||
let menupopup = currentMenulist.menupopup;
|
||||
let popupRect = menupopup.getOuterScreenRect();
|
||||
|
||||
this.clearScrollTimer();
|
||||
|
||||
// If the user released the mouse before the popup opens, we will
|
||||
// still be capturing, so check that the button is still pressed. If
|
||||
// not, release the capture and do nothing else. This also handles if
|
||||
// the dropdown was opened via the keyboard.
|
||||
if (!(event.buttons & 1)) {
|
||||
currentMenulist.menupopup.removeEventListener("mousemove", this);
|
||||
menupopup.releaseCapture();
|
||||
return;
|
||||
}
|
||||
|
||||
// If dragging outside the top or bottom edge of the popup, but within
|
||||
// the popup area horizontally, scroll the list in that direction. The
|
||||
// draggedOverPopup flag is used to ensure that scrolling does not start
|
||||
// until the mouse has moved over the popup first, preventing scrolling
|
||||
// while over the dropdown button.
|
||||
let popupRect = menupopup.getOuterScreenRect();
|
||||
if (event.screenX >= popupRect.left && event.screenX <= popupRect.right) {
|
||||
if (!this.draggedOverPopup) {
|
||||
if (event.screenY > popupRect.top && event.screenY < popupRect.bottom) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче