browser_914138_widget_API_overflowable_toolbar.js (13906B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); 8 var overflowList = document.getElementById( 9 navbar.getAttribute("default-overflowtarget") 10 ); 11 12 const kTestBtn1 = "test-addWidgetToArea-overflow"; 13 const kTestBtn2 = "test-removeWidgetFromArea-overflow"; 14 const kTestBtn3 = "test-createWidget-overflow"; 15 const kTestBtn4 = "test-createWidget-overflow-first-item"; 16 const kTestBtn5 = "test-addWidgetToArea-overflow-first-item"; 17 const kSidebarBtn = "sidebar-button"; 18 const kLibraryButton = "library-button"; 19 const kDownloadsBtn = "downloads-button"; 20 const kSearchBox = "search-container"; 21 22 var originalWindowWidth; 23 24 // Adding a widget should add it next to the widget it's being inserted next to. 25 add_task(async function subsequent_widget() { 26 let sidebarRevampEnabled = Services.prefs.getBoolPref( 27 "sidebar.revamp", 28 false 29 ); 30 createDummyXULButton(kTestBtn1, "Test"); 31 if (sidebarRevampEnabled) { 32 createDummyXULButton(kTestBtn2, "Test2"); 33 } 34 ok( 35 !navbar.hasAttribute("overflowing"), 36 "Should start subsequent_widget with a non-overflowing toolbar." 37 ); 38 ok( 39 CustomizableUI.inDefaultState, 40 "Should start subsequent_widget in default state." 41 ); 42 CustomizableUI.addWidgetToArea( 43 !sidebarRevampEnabled ? kSidebarBtn : kTestBtn2, 44 "nav-bar" 45 ); 46 await waitForElementShown( 47 document.getElementById(!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2) 48 ); 49 50 originalWindowWidth = ensureToolbarOverflow(window, false); 51 await TestUtils.waitForCondition(() => { 52 return ( 53 navbar.hasAttribute("overflowing") && 54 document 55 .getElementById(!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2) 56 .getAttribute("overflowedItem") == "true" 57 ); 58 }); 59 ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); 60 ok( 61 !navbar.querySelector( 62 `#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}` 63 ), 64 `${ 65 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 66 } button should no longer be in the navbar` 67 ); 68 69 let overflowBtnNode = overflowList.querySelector( 70 `#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}` 71 ); 72 ok( 73 overflowBtnNode, 74 `${ 75 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 76 } button should be overflowing` 77 ); 78 ok( 79 overflowBtnNode && overflowBtnNode.getAttribute("overflowedItem") == "true", 80 `${ 81 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 82 } button should have overflowedItem attribute` 83 ); 84 85 let placementOfOverflowButton = CustomizableUI.getWidgetIdsInArea( 86 navbar.id 87 ).indexOf(!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2); 88 CustomizableUI.addWidgetToArea( 89 kTestBtn1, 90 navbar.id, 91 placementOfOverflowButton 92 ); 93 ok( 94 !navbar.querySelector("#" + kTestBtn1), 95 "New button should not be in the navbar" 96 ); 97 let newButtonNode = overflowList.querySelector("#" + kTestBtn1); 98 ok(newButtonNode, "New button should be overflowing"); 99 ok( 100 newButtonNode && newButtonNode.getAttribute("overflowedItem") == "true", 101 "New button should have overflowedItem attribute" 102 ); 103 let nextEl = newButtonNode && newButtonNode.nextElementSibling; 104 is( 105 nextEl && nextEl.id, 106 !sidebarRevampEnabled ? kSidebarBtn : kTestBtn2, 107 `Test button should be next to ${ 108 !sidebarRevampEnabled ? "sidebar" : "test 2" 109 } button.` 110 ); 111 112 unensureToolbarOverflow(window, originalWindowWidth); 113 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 114 ok( 115 !navbar.hasAttribute("overflowing"), 116 "Should not have an overflowing toolbar." 117 ); 118 ok( 119 navbar.querySelector(`#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}`), 120 `${ 121 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 122 } button should be in the navbar` 123 ); 124 ok( 125 overflowBtnNode && overflowBtnNode.getAttribute("overflowedItem") != "true", 126 `${ 127 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 128 } button should no longer have overflowedItem attribute` 129 ); 130 ok( 131 !overflowList.querySelector( 132 `#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}` 133 ), 134 `${ 135 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 136 } button should no longer be overflowing` 137 ); 138 ok( 139 navbar.querySelector("#" + kTestBtn1), 140 "Test button should be in the navbar" 141 ); 142 ok( 143 !overflowList.querySelector("#" + kTestBtn1), 144 "Test button should no longer be overflowing" 145 ); 146 ok( 147 newButtonNode && newButtonNode.getAttribute("overflowedItem") != "true", 148 "New button should no longer have overflowedItem attribute" 149 ); 150 let el = document.getElementById(kTestBtn1); 151 if (el) { 152 CustomizableUI.removeWidgetFromArea(kTestBtn1); 153 el.remove(); 154 } 155 CustomizableUI.removeWidgetFromArea( 156 !sidebarRevampEnabled ? kSidebarBtn : kTestBtn2 157 ); 158 unensureToolbarOverflow(window, originalWindowWidth); 159 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 160 }); 161 162 // Removing a widget should remove it from the overflow list if that is where it is, and update it accordingly. 163 add_task(async function remove_widget() { 164 createDummyXULButton(kTestBtn2, "Test"); 165 ok( 166 !navbar.hasAttribute("overflowing"), 167 "Should start remove_widget with a non-overflowing toolbar." 168 ); 169 ok( 170 CustomizableUI.inDefaultState, 171 "Should start remove_widget in default state." 172 ); 173 CustomizableUI.addWidgetToArea(kTestBtn2, navbar.id); 174 ok( 175 !navbar.hasAttribute("overflowing"), 176 "Should still have a non-overflowing toolbar." 177 ); 178 179 originalWindowWidth = ensureToolbarOverflow(window, false); 180 await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing")); 181 ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); 182 ok( 183 !navbar.querySelector("#" + kTestBtn2), 184 "Test button should not be in the navbar" 185 ); 186 ok( 187 overflowList.querySelector("#" + kTestBtn2), 188 "Test button should be overflowing" 189 ); 190 191 CustomizableUI.removeWidgetFromArea(kTestBtn2); 192 193 ok( 194 !overflowList.querySelector("#" + kTestBtn2), 195 "Test button should not be overflowing." 196 ); 197 ok( 198 !navbar.querySelector("#" + kTestBtn2), 199 "Test button should not be in the navbar" 200 ); 201 ok( 202 gNavToolbox.palette.querySelector("#" + kTestBtn2), 203 "Test button should be in the palette" 204 ); 205 206 unensureToolbarOverflow(window, originalWindowWidth); 207 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 208 ok( 209 !navbar.hasAttribute("overflowing"), 210 "Should not have an overflowing toolbar." 211 ); 212 let el = document.getElementById(kTestBtn2); 213 if (el) { 214 CustomizableUI.removeWidgetFromArea(kTestBtn2); 215 el.remove(); 216 } 217 unensureToolbarOverflow(window, originalWindowWidth); 218 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 219 }); 220 221 // Constructing a widget while overflown should set the right class on it. 222 add_task(async function construct_widget() { 223 let sidebarRevampEnabled = Services.prefs.getBoolPref( 224 "sidebar.revamp", 225 false 226 ); 227 ok( 228 !navbar.hasAttribute("overflowing"), 229 "Should start construct_widget with a non-overflowing toolbar." 230 ); 231 ok( 232 CustomizableUI.inDefaultState, 233 "Should start construct_widget in default state." 234 ); 235 236 CustomizableUI.addWidgetToArea( 237 !sidebarRevampEnabled ? kSidebarBtn : kTestBtn2, 238 "nav-bar" 239 ); 240 await waitForElementShown( 241 document.getElementById(!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2) 242 ); 243 244 originalWindowWidth = ensureToolbarOverflow(window, false); 245 await TestUtils.waitForCondition(() => { 246 return ( 247 navbar.hasAttribute("overflowing") && 248 document 249 .getElementById(!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2) 250 .getAttribute("overflowedItem") == "true" 251 ); 252 }); 253 ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); 254 ok( 255 !navbar.querySelector( 256 `#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}` 257 ), 258 `${ 259 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 260 } button should no longer be in the navbar` 261 ); 262 let overflowBtnNode = overflowList.querySelector( 263 `#${!sidebarRevampEnabled ? kSidebarBtn : kTestBtn2}` 264 ); 265 ok( 266 overflowBtnNode, 267 `${ 268 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 269 } button should be overflowing` 270 ); 271 ok( 272 overflowBtnNode && overflowBtnNode.getAttribute("overflowedItem") == "true", 273 `${ 274 !sidebarRevampEnabled ? "Sidebar" : "Test 2" 275 } button should have overflowedItem class` 276 ); 277 278 let testBtnSpec = { 279 id: kTestBtn3, 280 label: "Overflowable widget test", 281 defaultArea: "nav-bar", 282 }; 283 CustomizableUI.createWidget(testBtnSpec); 284 let testNode = overflowList.querySelector("#" + kTestBtn3); 285 ok(testNode, "Test button should be overflowing"); 286 ok( 287 testNode && testNode.getAttribute("overflowedItem") == "true", 288 "Test button should have overflowedItem class" 289 ); 290 291 CustomizableUI.destroyWidget(kTestBtn3); 292 testNode = document.getElementById(kTestBtn3); 293 ok(!testNode, "Test button should be gone"); 294 295 CustomizableUI.createWidget(testBtnSpec); 296 testNode = overflowList.querySelector("#" + kTestBtn3); 297 ok(testNode, "Test button should be overflowing"); 298 ok( 299 testNode && testNode.getAttribute("overflowedItem") == "true", 300 "Test button should have overflowedItem class" 301 ); 302 303 CustomizableUI.removeWidgetFromArea(kTestBtn3); 304 testNode = document.getElementById(kTestBtn3); 305 ok(!testNode, "Test button should be gone"); 306 CustomizableUI.destroyWidget(kTestBtn3); 307 CustomizableUI.removeWidgetFromArea( 308 !sidebarRevampEnabled ? kSidebarBtn : kTestBtn2 309 ); 310 unensureToolbarOverflow(window, originalWindowWidth); 311 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 312 }); 313 314 add_task(async function insertBeforeFirstItemInOverflow() { 315 originalWindowWidth = window.outerWidth; 316 ok( 317 !navbar.hasAttribute("overflowing"), 318 "Should start insertBeforeFirstItemInOverflow with a non-overflowing toolbar." 319 ); 320 ok( 321 CustomizableUI.inDefaultState, 322 "Should start insertBeforeFirstItemInOverflow in default state." 323 ); 324 325 // Remove sidebar button if present 326 CustomizableUI.removeWidgetFromArea("sidebar-button"); 327 328 CustomizableUI.addWidgetToArea( 329 "fullscreen-button", 330 "nav-bar", 331 CustomizableUI.getWidgetIdsInArea("nav-bar").indexOf( 332 "fxa-toolbar-menu-button" 333 ) 334 ); 335 let fullscreenButton = document.getElementById("fullscreen-button"); 336 await waitForElementShown(fullscreenButton); 337 338 CustomizableUI.addWidgetToArea( 339 kLibraryButton, 340 "nav-bar", 341 CustomizableUI.getWidgetIdsInArea("nav-bar").indexOf("fullscreen-button") 342 ); 343 let libraryButton = document.getElementById(kLibraryButton); 344 await waitForElementShown(libraryButton); 345 // Ensure nothing flexes to make the resize predictable: 346 navbar 347 .querySelectorAll("toolbarspring") 348 .forEach(s => CustomizableUI.removeWidgetFromArea(s.id)); 349 let urlbar = document.getElementById("urlbar-container"); 350 urlbar.style.minWidth = urlbar.getBoundingClientRect().width + "px"; 351 // Negative number to make the window smaller by the difference between the left side of 352 // the item next to the library button and left side of the hamburger one. 353 // The width of the overflow button that needs to appear will then be enough to 354 // also hide the library button. 355 let resizeWidthToMakeLibraryLast = 356 libraryButton.nextElementSibling.getBoundingClientRect().left - 357 PanelUI.menuButton.parentNode.getBoundingClientRect().left + 358 10; // Leave some margin for the margins between buttons etc.; 359 info( 360 "Resizing to " + 361 resizeWidthToMakeLibraryLast + 362 " , waiting for library to overflow." 363 ); 364 window.resizeBy(resizeWidthToMakeLibraryLast, 0); 365 await TestUtils.waitForCondition(() => { 366 return ( 367 libraryButton.getAttribute("overflowedItem") == "true" && 368 !libraryButton.previousElementSibling 369 ); 370 }, "Library button is overflowed"); 371 372 let testBtnSpec = { id: kTestBtn4, label: "Overflowable widget test" }; 373 let placementOfLibraryButton = CustomizableUI.getWidgetIdsInArea( 374 navbar.id 375 ).indexOf(kLibraryButton); 376 CustomizableUI.createWidget(testBtnSpec); 377 CustomizableUI.addWidgetToArea( 378 kTestBtn4, 379 "nav-bar", 380 placementOfLibraryButton 381 ); 382 let testNode = overflowList.querySelector("#" + kTestBtn4); 383 ok(testNode, "Test button should be overflowing"); 384 ok( 385 testNode && testNode.getAttribute("overflowedItem") == "true", 386 "Test button should have overflowedItem class" 387 ); 388 CustomizableUI.destroyWidget(kTestBtn4); 389 testNode = document.getElementById(kTestBtn4); 390 ok(!testNode, "Test button should be gone"); 391 392 createDummyXULButton(kTestBtn5, "Test"); 393 CustomizableUI.addWidgetToArea( 394 kTestBtn5, 395 "nav-bar", 396 placementOfLibraryButton 397 ); 398 testNode = overflowList.querySelector("#" + kTestBtn5); 399 ok(testNode, "Test button should be overflowing"); 400 ok( 401 testNode && testNode.getAttribute("overflowedItem") == "true", 402 "Test button should have overflowedItem class" 403 ); 404 CustomizableUI.removeWidgetFromArea(kTestBtn5); 405 testNode && testNode.remove(); 406 407 urlbar.style.removeProperty("min-width"); 408 CustomizableUI.removeWidgetFromArea(kLibraryButton); 409 unensureToolbarOverflow(window, originalWindowWidth); 410 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 411 await resetCustomization(); 412 }); 413 414 registerCleanupFunction(async function asyncCleanup() { 415 document.getElementById("urlbar-container").style.removeProperty("min-width"); 416 window.resizeTo(originalWindowWidth, window.outerHeight); 417 await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing")); 418 await resetCustomization(); 419 });