diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index 4fbe8b0a55f4..372d107c5cf8 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -9,6 +9,10 @@ var StarUI = { _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); @@ -22,6 +26,7 @@ var StarUI = { // 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); @@ -66,6 +71,8 @@ var StarUI = { 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); @@ -109,6 +116,7 @@ var StarUI = { break; case "keypress": clearTimeout(this._autoCloseTimer); + this._autoCloseTimerEnabled = false; if (aEvent.defaultPrevented) { // The event has already been consumed inside of the panel. @@ -139,26 +147,32 @@ var StarUI = { break; } break; - case "compositionstart": - if (aEvent.defaultPrevented) { - // If the composition was canceled, nothing to do here. - break; - } - // During composition, panel shouldn't be hidden automatically. - 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 "compositionstart": + if (aEvent.defaultPrevented) { + // If the composition was canceled, nothing to do here. + break; + } + this._isComposing = true; + // Explicit fall-through, during composition, panel shouldn't be + // hidden automatically. case "input": - // Might be edited some text without keyboard events nor composition - // events. Let's cancel auto close in such case. + // 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._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. @@ -179,6 +193,7 @@ var StarUI = { this.panel.hidePopup(); } }, delay); + this._autoCloseTimerEnabled = true; } break; } diff --git a/browser/base/content/test/general/browser_bookmark_popup.js b/browser/base/content/test/general/browser_bookmark_popup.js index 11496b578513..e792b24c31f4 100644 --- a/browser/base/content/test/general/browser_bookmark_popup.js +++ b/browser/base/content/test/general/browser_bookmark_popup.js @@ -263,7 +263,7 @@ add_task(function* panel_shown_for_new_bookmark_compositionstart_mouseout_no_aut }); }); -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() { @@ -278,13 +278,8 @@ add_task(function* panel_shown_for_new_bookmark_compositionend_mouseout_autoclos 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, @@ -398,6 +393,38 @@ add_task(function* mouse_hovering_panel_should_prevent_autoclose() { }); }); +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; -}) +});