diff --git a/browser/components/customizableui/src/CustomizableUI.jsm b/browser/components/customizableui/src/CustomizableUI.jsm index 6dd92bb13bb..1453916ff5a 100644 --- a/browser/components/customizableui/src/CustomizableUI.jsm +++ b/browser/components/customizableui/src/CustomizableUI.jsm @@ -3704,6 +3704,7 @@ function XULWidgetSingleWrapper(aWidgetId, aNode, aDocument) { } const LAZY_RESIZE_INTERVAL_MS = 200; +const OVERFLOW_PANEL_HIDE_DELAY_MS = 500 function OverflowableToolbar(aToolbarNode) { this._toolbar = aToolbarNode; @@ -3747,6 +3748,8 @@ OverflowableToolbar.prototype = { let chevronId = this._toolbar.getAttribute("overflowbutton"); this._chevron = doc.getElementById(chevronId); this._chevron.addEventListener("command", this); + this._chevron.addEventListener("dragover", this); + this._chevron.addEventListener("dragend", this); let panelId = this._toolbar.getAttribute("overflowpanel"); this._panel = doc.getElementById(panelId); @@ -3781,6 +3784,8 @@ OverflowableToolbar.prototype = { window.gNavToolbox.removeEventListener("customizationstarting", this); window.gNavToolbox.removeEventListener("aftercustomization", this); this._chevron.removeEventListener("command", this); + this._chevron.removeEventListener("dragover", this); + this._chevron.removeEventListener("dragend", this); this._panel.removeEventListener("popuphiding", this); CustomizableUI.removeListener(this); CustomizableUIInternal.removePanelCloseListeners(this._panel); @@ -3788,8 +3793,8 @@ OverflowableToolbar.prototype = { handleEvent: function(aEvent) { switch(aEvent.type) { - case "resize": - this._onResize(aEvent); + case "aftercustomization": + this._enable(); break; case "command": if (aEvent.target == this._chevron) { @@ -3798,15 +3803,20 @@ OverflowableToolbar.prototype = { this._panel.hidePopup(); } break; - case "popuphiding": - this._onPanelHiding(aEvent); - break; case "customizationstarting": this._disable(); break; - case "aftercustomization": - this._enable(); + case "dragover": + this._showWithTimeout(); break; + case "dragend": + this._panel.hidePopup(); + break; + case "popuphiding": + this._onPanelHiding(aEvent); + break; + case "resize": + this._onResize(aEvent); } }, @@ -3824,8 +3834,11 @@ OverflowableToolbar.prototype = { this._panel.openPopup(anchor || this._chevron); this._chevron.open = true; - this._panel.addEventListener("popupshown", function onPopupShown() { + let overflowableToolbarInstance = this; + this._panel.addEventListener("popupshown", function onPopupShown(aEvent) { this.removeEventListener("popupshown", onPopupShown); + this.addEventListener("dragover", overflowableToolbarInstance); + this.addEventListener("dragend", overflowableToolbarInstance); deferred.resolve(); }); @@ -3843,6 +3856,8 @@ OverflowableToolbar.prototype = { _onPanelHiding: function(aEvent) { this._chevron.open = false; + this._panel.removeEventListener("dragover", this); + this._panel.removeEventListener("dragend", this); let doc = aEvent.target.ownerDocument; let contextMenu = doc.getElementById(this._panel.getAttribute("context")); gELS.removeSystemEventListener(contextMenu, 'command', this, true); @@ -4077,6 +4092,21 @@ OverflowableToolbar.prototype = { } return this._target; }, + + _hideTimeoutId: null, + _showWithTimeout: function() { + this.show(); + let window = this._toolbar.ownerDocument.defaultView; + if (this._hideTimeoutId) { + window.clearTimeout(this._hideTimeoutId); + this._hideTimeoutId = null; + } + this._hideTimeoutId = window.setTimeout(() => { + if (!this._panel.firstChild.mozMatchesSelector(":hover")) { + this._panel.hidePopup(); + } + }, OVERFLOW_PANEL_HIDE_DELAY_MS); + }, }; CustomizableUIInternal.initialize(); diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini index 93fb73b630d..d6f1cd97902 100644 --- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -69,6 +69,7 @@ skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s f [browser_948985_non_removable_defaultArea.js] [browser_952963_areaType_getter_no_area.js] [browser_956602_remove_special_widget.js] +[browser_962069_drag_to_overflow_chevron.js] [browser_962884_opt_in_disable_hyphens.js] [browser_963639_customizing_attribute_non_customizable_toolbar.js] [browser_967000_button_charEncoding.js] diff --git a/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js b/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js new file mode 100644 index 00000000000..aa64875ad8b --- /dev/null +++ b/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +let originalWindowWidth; + +// Drag to overflow chevron should open the overflow panel. +add_task(function*() { + originalWindowWidth = window.outerWidth; + let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); + ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); + ok(CustomizableUI.inDefaultState, "Should start in default state."); + let oldChildCount = navbar.customizationTarget.childElementCount; + window.resizeTo(400, window.outerHeight); + yield waitForCondition(() => navbar.hasAttribute("overflowing")); + ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); + + let widgetOverflowPanel = document.getElementById("widget-overflow"); + let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel); + let identityBox = document.getElementById("identity-box"); + let overflowChevron = document.getElementById("nav-bar-overflow-button"); + ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null); + yield panelShownPromise; + + ok(true, "Overflow panel is shown."); + + let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel); + EventUtils.synthesizeKey("VK_ESCAPE", {}); + yield panelHiddenPromise; +}); + +add_task(function*() { + window.resizeTo(originalWindowWidth, window.outerHeight); + let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); + yield waitForCondition(() => !navbar.hasAttribute("overflowing")); + ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar."); +});