Bug 1294799 - Disable the autoclosing of the bookmark popup if there is any interaction with it such as mousedown or keypress. r?mak
MozReview-Commit-ID: JRo5ZVu0uFD
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -4,29 +4,34 @@
var StarUI = {
_itemId: -1,
uri: null,
_batching: false,
_isNewBookmark: false,
_isComposing: false,
_autoCloseTimer: 0,
+ // The autoclose timer is diasbled if the user interacts with the
+ // popup, such as making a change through typing or clicking on
+ // the popup.
+ _autoCloseTimerEnabled: true,
_element(aID) {
return document.getElementById(aID);
},
// Edit-bookmark panel
get panel() {
delete this.panel;
var element = this._element("editBookmarkPanel");
// initially the panel is hidden
// to avoid impacting startup / new window performance
element.hidden = false;
element.addEventListener("keypress", this);
+ element.addEventListener("mousedown", this);
element.addEventListener("mouseout", this);
element.addEventListener("mousemove", this);
element.addEventListener("compositionstart", this);
element.addEventListener("compositionend", this);
element.addEventListener("input", this);
element.addEventListener("popuphidden", this);
element.addEventListener("popupshown", this);
return this.panel = element;
@@ -61,16 +66,18 @@ var StarUI = {
});
},
// nsIDOMEventListener
handleEvent(aEvent) {
switch (aEvent.type) {
case "mousemove":
clearTimeout(this._autoCloseTimer);
+ // The autoclose timer is not disabled on generic mouseout
+ // because the user may not have actually interacted with the popup.
break;
case "popuphidden":
clearTimeout(this._autoCloseTimer);
if (aEvent.originalTarget == this.panel) {
if (!this._element("editBookmarkPanelContent").hidden)
this.quitEditMode();
if (this._anchorToolbarButton) {
@@ -104,16 +111,17 @@ var StarUI = {
PlacesTransactions.RemoveBookmarksForUrls([this._uriForRemoval])
.transact().catch(Cu.reportError);
}
}
break;
case "keypress":
clearTimeout(this._autoCloseTimer);
+ this._autoCloseTimerEnabled = false;
if (aEvent.defaultPrevented) {
// The event has already been consumed inside of the panel.
break;
}
switch (aEvent.keyCode) {
case KeyEvent.DOM_VK_ESCAPE:
@@ -134,36 +142,42 @@ var StarUI = {
case 0:
let accessKey = document.getElementById("key_close");
if (eventMatchesKey(aEvent, accessKey)) {
this.panel.hidePopup();
}
break;
}
break;
+ case "compositionend":
+ // After composition is committed, "mouseout" or something can set
+ // auto close timer.
+ this._isComposing = false;
+ break;
case "compositionstart":
if (aEvent.defaultPrevented) {
// If the composition was canceled, nothing to do here.
break;
}
- // During composition, panel shouldn't be hidden automatically.
+ this._isComposing = true;
+ // Explicit fall-through, during composition, panel shouldn't be
+ // hidden automatically.
+ case "input":
+ // Might have edited some text without keyboard events nor composition
+ // events. Fall-through to cancel auto close in such case.
+ case "mousedown":
clearTimeout(this._autoCloseTimer);
- this._isComposing = true;
- break;
- case "compositionend":
- // After composition is committed, "mouseout" or something can set
- // auto close timer.
- this._isComposing = false;
- break;
- case "input":
- // Might be edited some text without keyboard events nor composition
- // events. Let's cancel auto close in such case.
- clearTimeout(this._autoCloseTimer);
+ this._autoCloseTimerEnabled = false;
break;
case "mouseout":
+ if (!this._autoCloseTimerEnabled) {
+ // Don't autoclose the popup if the user has made a selection
+ // or keypress and then subsequently mouseout.
+ break;
+ }
// Explicit fall-through
case "popupshown":
// Don't handle events for descendent elements.
if (aEvent.target != aEvent.currentTarget) {
break;
}
// auto-close if new and not interacted with
if (this._isNewBookmark && !this._isComposing) {
@@ -174,16 +188,17 @@ var StarUI = {
delay /= 10;
}
clearTimeout(this._autoCloseTimer);
this._autoCloseTimer = setTimeout(() => {
if (!this.panel.mozMatchesSelector(":hover")) {
this.panel.hidePopup();
}
}, delay);
+ this._autoCloseTimerEnabled = true;
}
break;
}
},
_overlayLoaded: false,
_overlayLoading: false,
showEditBookmarkPopup: Task.async(function* (aNode, aAnchorElement, aPosition, aIsNewBookmark) {
--- a/browser/base/content/test/general/browser_bookmark_popup.js
+++ b/browser/base/content/test/general/browser_bookmark_popup.js
@@ -258,38 +258,33 @@ add_task(function* panel_shown_for_new_b
popupHideFn() {
EventUtils.synthesizeComposition({ type: "compositioncommitasis" });
bookmarkPanel.hidePopup();
},
isBookmarkRemoved: false,
});
});
-add_task(function* panel_shown_for_new_bookmark_compositionend_mouseout_autoclose() {
+add_task(function* panel_shown_for_new_bookmark_compositionend_no_autoclose() {
yield test_bookmarks_popup({
isNewBookmark: true,
popupShowFn() {
bookmarkStar.click();
},
*popupEditFn() {
let mouseMovePromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mousemove");
EventUtils.synthesizeMouseAtCenter(bookmarkPanel, {type: "mousemove"});
info("Waiting for mousemove event");
yield mouseMovePromise;
info("Got mousemove event");
EventUtils.synthesizeComposition({ type: "compositioncommit", data: "committed text" });
},
- *popupHideFn() {
- let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
- EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
- EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
- info("Waiting for mouseout event");
- yield mouseOutPromise;
- info("Got mouseout event, should autoclose now");
+ popupHideFn() {
+ bookmarkPanel.hidePopup();
},
shouldAutoClose: false,
isBookmarkRemoved: false,
});
});
add_task(function* contextmenu_new_bookmark_keypress_no_autoclose() {
yield test_bookmarks_popup({
@@ -393,11 +388,43 @@ add_task(function* mouse_hovering_panel_
shouldAutoClose: false,
popupHideFn() {
document.getElementById("editBookmarkPanelRemoveButton").click();
},
isBookmarkRemoved: true,
});
});
+add_task(function* ctrl_d_new_bookmark_mousedown_mouseout_no_autoclose() {
+ yield test_bookmarks_popup({
+ isNewBookmark: true,
+ popupShowFn(browser) {
+ EventUtils.synthesizeKey("D", {accelKey: true}, window);
+ },
+ *popupEditFn() {
+ let mouseMovePromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mousemove");
+ EventUtils.synthesizeMouseAtCenter(bookmarkPanel, {type: "mousemove"});
+ info("Waiting for mousemove event");
+ yield mouseMovePromise;
+ info("Got mousemove event");
+
+ yield new Promise(resolve => setTimeout(resolve, 400));
+ is(bookmarkPanel.state, "open", "Panel should still be open on mousemove");
+
+ EventUtils.synthesizeMouseAtCenter(bookmarkPanelTitle, {button: 1, type: "mousedown"});
+
+ let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
+ EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
+ EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
+ info("Waiting for mouseout event");
+ yield mouseOutPromise;
+ },
+ shouldAutoClose: false,
+ popupHideFn() {
+ document.getElementById("editBookmarkPanelRemoveButton").click();
+ },
+ isBookmarkRemoved: true,
+ });
+});
+
registerCleanupFunction(function() {
delete StarUI._closePanelQuickForTesting;
-})
+});