/* 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"; var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); var overflowList = document.getElementById( navbar.getAttribute("default-overflowtarget") ); const kTestBtn1 = "test-addWidgetToArea-overflow"; const kTestBtn2 = "test-removeWidgetFromArea-overflow"; const kTestBtn3 = "test-createWidget-overflow"; const kTestBtn4 = "test-createWidget-overflow-first-item"; const kTestBtn5 = "test-addWidgetToArea-overflow-first-item"; const kSidebarBtn = "sidebar-button"; const kLibraryButton = "library-button"; const kDownloadsBtn = "downloads-button"; const kSearchBox = "search-container"; var originalWindowWidth; // Adding a widget should add it next to the widget it's being inserted next to. add_task(async function subsequent_widget() { originalWindowWidth = window.outerWidth; createDummyXULButton(kTestBtn1, "Test"); ok( !navbar.hasAttribute("overflowing"), "Should start subsequent_widget with a non-overflowing toolbar." ); ok( CustomizableUI.inDefaultState, "Should start subsequent_widget in default state." ); CustomizableUI.addWidgetToArea(kSidebarBtn, "nav-bar"); await waitForElementShown(document.getElementById(kSidebarBtn)); window.resizeTo(kForceOverflowWidthPx, window.outerHeight); await TestUtils.waitForCondition(() => { return ( navbar.hasAttribute("overflowing") && document.getElementById(kSidebarBtn).getAttribute("overflowedItem") == "true" ); }); ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); ok( !navbar.querySelector("#" + kSidebarBtn), "Sidebar button should no longer be in the navbar" ); let sidebarBtnNode = overflowList.querySelector("#" + kSidebarBtn); ok(sidebarBtnNode, "Sidebar button should be overflowing"); ok( sidebarBtnNode && sidebarBtnNode.getAttribute("overflowedItem") == "true", "Sidebar button should have overflowedItem attribute" ); let placementOfSidebarButton = CustomizableUI.getWidgetIdsInArea( navbar.id ).indexOf(kSidebarBtn); CustomizableUI.addWidgetToArea( kTestBtn1, navbar.id, placementOfSidebarButton ); ok( !navbar.querySelector("#" + kTestBtn1), "New button should not be in the navbar" ); let newButtonNode = overflowList.querySelector("#" + kTestBtn1); ok(newButtonNode, "New button should be overflowing"); ok( newButtonNode && newButtonNode.getAttribute("overflowedItem") == "true", "New button should have overflowedItem attribute" ); let nextEl = newButtonNode && newButtonNode.nextElementSibling; is( nextEl && nextEl.id, kSidebarBtn, "Test button should be next to sidebar button." ); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); ok( !navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar." ); ok( navbar.querySelector("#" + kSidebarBtn), "Sidebar button should be in the navbar" ); ok( sidebarBtnNode && sidebarBtnNode.getAttribute("overflowedItem") != "true", "Sidebar button should no longer have overflowedItem attribute" ); ok( !overflowList.querySelector("#" + kSidebarBtn), "Sidebar button should no longer be overflowing" ); ok( navbar.querySelector("#" + kTestBtn1), "Test button should be in the navbar" ); ok( !overflowList.querySelector("#" + kTestBtn1), "Test button should no longer be overflowing" ); ok( newButtonNode && newButtonNode.getAttribute("overflowedItem") != "true", "New button should no longer have overflowedItem attribute" ); let el = document.getElementById(kTestBtn1); if (el) { CustomizableUI.removeWidgetFromArea(kTestBtn1); el.remove(); } CustomizableUI.removeWidgetFromArea(kSidebarBtn); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); }); // Removing a widget should remove it from the overflow list if that is where it is, and update it accordingly. add_task(async function remove_widget() { createDummyXULButton(kTestBtn2, "Test"); ok( !navbar.hasAttribute("overflowing"), "Should start remove_widget with a non-overflowing toolbar." ); ok( CustomizableUI.inDefaultState, "Should start remove_widget in default state." ); CustomizableUI.addWidgetToArea(kTestBtn2, navbar.id); ok( !navbar.hasAttribute("overflowing"), "Should still have a non-overflowing toolbar." ); window.resizeTo(kForceOverflowWidthPx, window.outerHeight); await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing")); ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); ok( !navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar" ); ok( overflowList.querySelector("#" + kTestBtn2), "Test button should be overflowing" ); CustomizableUI.removeWidgetFromArea(kTestBtn2); ok( !overflowList.querySelector("#" + kTestBtn2), "Test button should not be overflowing." ); ok( !navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar" ); ok( gNavToolbox.palette.querySelector("#" + kTestBtn2), "Test button should be in the palette" ); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); ok( !navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar." ); let el = document.getElementById(kTestBtn2); if (el) { CustomizableUI.removeWidgetFromArea(kTestBtn2); el.remove(); } window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); }); // Constructing a widget while overflown should set the right class on it. add_task(async function construct_widget() { originalWindowWidth = window.outerWidth; ok( !navbar.hasAttribute("overflowing"), "Should start construct_widget with a non-overflowing toolbar." ); ok( CustomizableUI.inDefaultState, "Should start construct_widget in default state." ); CustomizableUI.addWidgetToArea(kSidebarBtn, "nav-bar"); await waitForElementShown(document.getElementById(kSidebarBtn)); window.resizeTo(kForceOverflowWidthPx, window.outerHeight); await TestUtils.waitForCondition(() => { return ( navbar.hasAttribute("overflowing") && document.getElementById(kSidebarBtn).getAttribute("overflowedItem") == "true" ); }); ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); ok( !navbar.querySelector("#" + kSidebarBtn), "Sidebar button should no longer be in the navbar" ); let sidebarBtnNode = overflowList.querySelector("#" + kSidebarBtn); ok(sidebarBtnNode, "Sidebar button should be overflowing"); ok( sidebarBtnNode && sidebarBtnNode.getAttribute("overflowedItem") == "true", "Sidebar button should have overflowedItem class" ); let testBtnSpec = { id: kTestBtn3, label: "Overflowable widget test", defaultArea: "nav-bar", }; CustomizableUI.createWidget(testBtnSpec); let testNode = overflowList.querySelector("#" + kTestBtn3); ok(testNode, "Test button should be overflowing"); ok( testNode && testNode.getAttribute("overflowedItem") == "true", "Test button should have overflowedItem class" ); CustomizableUI.destroyWidget(kTestBtn3); testNode = document.getElementById(kTestBtn3); ok(!testNode, "Test button should be gone"); CustomizableUI.createWidget(testBtnSpec); testNode = overflowList.querySelector("#" + kTestBtn3); ok(testNode, "Test button should be overflowing"); ok( testNode && testNode.getAttribute("overflowedItem") == "true", "Test button should have overflowedItem class" ); CustomizableUI.removeWidgetFromArea(kTestBtn3); testNode = document.getElementById(kTestBtn3); ok(!testNode, "Test button should be gone"); CustomizableUI.destroyWidget(kTestBtn3); CustomizableUI.removeWidgetFromArea(kSidebarBtn); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); }); add_task(async function insertBeforeFirstItemInOverflow() { originalWindowWidth = window.outerWidth; ok( !navbar.hasAttribute("overflowing"), "Should start insertBeforeFirstItemInOverflow with a non-overflowing toolbar." ); ok( CustomizableUI.inDefaultState, "Should start insertBeforeFirstItemInOverflow in default state." ); CustomizableUI.addWidgetToArea( kLibraryButton, "nav-bar", CustomizableUI.getWidgetIdsInArea("nav-bar").indexOf( "save-to-pocket-button" ) ); let libraryButton = document.getElementById(kLibraryButton); await waitForElementShown(libraryButton); // Ensure nothing flexes to make the resize predictable: navbar .querySelectorAll("toolbarspring") .forEach(s => CustomizableUI.removeWidgetFromArea(s.id)); let urlbar = document.getElementById("urlbar-container"); urlbar.style.minWidth = urlbar.getBoundingClientRect().width + "px"; // Negative number to make the window smaller by the difference between the left side of // the item next to the library button and left side of the hamburger one. // The width of the overflow button that needs to appear will then be enough to // also hide the library button. let resizeWidthToMakeLibraryLast = libraryButton.nextElementSibling.getBoundingClientRect().left - PanelUI.menuButton.parentNode.getBoundingClientRect().left + 10; // Leave some margin for the margins between buttons etc.; info( "Resizing to " + resizeWidthToMakeLibraryLast + " , waiting for library to overflow." ); window.resizeBy(resizeWidthToMakeLibraryLast, 0); await TestUtils.waitForCondition(() => { return ( libraryButton.getAttribute("overflowedItem") == "true" && !libraryButton.previousElementSibling ); }); let testBtnSpec = { id: kTestBtn4, label: "Overflowable widget test" }; let placementOfLibraryButton = CustomizableUI.getWidgetIdsInArea( navbar.id ).indexOf(kLibraryButton); CustomizableUI.createWidget(testBtnSpec); CustomizableUI.addWidgetToArea( kTestBtn4, "nav-bar", placementOfLibraryButton ); let testNode = overflowList.querySelector("#" + kTestBtn4); ok(testNode, "Test button should be overflowing"); ok( testNode && testNode.getAttribute("overflowedItem") == "true", "Test button should have overflowedItem class" ); CustomizableUI.destroyWidget(kTestBtn4); testNode = document.getElementById(kTestBtn4); ok(!testNode, "Test button should be gone"); createDummyXULButton(kTestBtn5, "Test"); CustomizableUI.addWidgetToArea( kTestBtn5, "nav-bar", placementOfLibraryButton ); testNode = overflowList.querySelector("#" + kTestBtn5); ok(testNode, "Test button should be overflowing"); ok( testNode && testNode.getAttribute("overflowedItem") == "true", "Test button should have overflowedItem class" ); CustomizableUI.removeWidgetFromArea(kTestBtn5); testNode && testNode.remove(); urlbar.style.removeProperty("min-width"); CustomizableUI.removeWidgetFromArea(kLibraryButton); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); await resetCustomization(); }); registerCleanupFunction(async function asyncCleanup() { document.getElementById("urlbar-container").style.removeProperty("min-width"); window.resizeTo(originalWindowWidth, window.outerHeight); await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); await resetCustomization(); });