Implicitly close tabs upon navigation
authorAlexander Ebert <ebert@woltlab.com>
Wed, 15 Dec 2021 14:25:15 +0000 (15:25 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 15 Dec 2021 14:25:15 +0000 (15:25 +0100)
This is required to ensure compatibility with the functionality of legacy user panels.

ts/WoltLabSuite/Core/Ui/Page/Menu/Container.ts
ts/WoltLabSuite/Core/Ui/Page/Menu/Main.ts
ts/WoltLabSuite/Core/Ui/Page/Menu/Provider.ts
ts/WoltLabSuite/Core/Ui/Page/Menu/User.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Container.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/Main.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Menu/User.js

index 776a43f72b20ccad9613d6da4b602af6b8c51589..8e368cbd85a899e1ebeec80a5e25585aab92b612 100644 (file)
@@ -37,7 +37,7 @@ export class PageMenuContainer {
     scrollDisable();
 
     this.container.hidden = false;
-    this.provider.refresh();
+    this.provider.wakeup();
 
     this.getFocusTrap().activate();
   }
@@ -50,6 +50,8 @@ export class PageMenuContainer {
 
     this.container.hidden = true;
     this.getFocusTrap().deactivate();
+
+    this.provider.sleep();
   }
 
   toggle(): void {
index 9e6c7761f3fab7d53461cb560bd0709691feb171..43c023c30de0c47e285420aa0200d5e291df8b2e 100644 (file)
@@ -113,7 +113,11 @@ export class PageMenuMain implements PageMenuProvider {
     return this.mainMenu;
   }
 
-  refresh(): void {
+  sleep(): void {
+    /* Does nothing */
+  }
+
+  wakeup(): void {
     /* Does nothing */
   }
 
index bed52a2feb7e4f2bf803af02641b1d593de85f50..5f2bb0ea0c3c62d98b475e480dfd06e792b717b6 100644 (file)
@@ -7,5 +7,7 @@ export interface PageMenuProvider {
 
   getMenuButton(): HTMLElement;
 
-  refresh(): void;
+  sleep(): void;
+
+  wakeup(): void;
 }
index 01f70c6bc62e9d7eff1fd7f674070944a1550835..a0618508cf71ec17edb8a590d5d356912ff97b51 100644 (file)
@@ -39,6 +39,7 @@ type LegacyUserPanelApi = {
 };
 
 export class PageMenuUser implements PageMenuProvider {
+  private activeTab?: Tab = undefined;
   private readonly callbackOpen: CallbackOpen;
   private readonly container: PageMenuContainer;
   private readonly legacyUserPanels = new Map<Tab, LegacyUserPanelApi>();
@@ -87,15 +88,20 @@ export class PageMenuUser implements PageMenuProvider {
     return this.userMenu;
   }
 
-  refresh(): void {
-    const activeTab = this.tabs.find((element) => element.getAttribute("aria-selected") === "true");
-    if (activeTab === undefined) {
-      this.openNotifications();
-    } else {
+  sleep(): void {
+    if (this.activeTab) {
+      this.closeTab(this.activeTab);
+    }
+  }
+
+  wakeup(): void {
+    if (this.activeTab) {
       // The UI elements in the tab panel are shared and can appear in a different
       // context. The element might have been moved elsewhere while the menu was
       // closed.
-      this.attachViewToPanel(activeTab);
+      this.openTab(this.activeTab);
+    } else {
+      this.openNotifications();
     }
   }
 
@@ -109,18 +115,7 @@ export class PageMenuUser implements PageMenuProvider {
   }
 
   private openTab(tab: Tab): void {
-    if (tab.getAttribute("aria-selected") === "true") {
-      return;
-    }
-
-    const activeTab = this.tabs.find((element) => element.getAttribute("aria-selected") === "true");
-    if (activeTab) {
-      activeTab.setAttribute("aria-selected", "false");
-      activeTab.tabIndex = -1;
-
-      const activePanel = this.tabPanels.get(activeTab)!;
-      activePanel.hidden = true;
-    }
+    this.closeActiveTab();
 
     tab.setAttribute("aria-selected", "true");
     tab.tabIndex = 0;
@@ -133,6 +128,31 @@ export class PageMenuUser implements PageMenuProvider {
     }
 
     this.attachViewToPanel(tab);
+
+    this.activeTab = tab;
+  }
+
+  private closeActiveTab(): void {
+    if (!this.activeTab) {
+      return;
+    }
+
+    this.closeTab(this.activeTab);
+
+    this.activeTab = undefined;
+  }
+
+  private closeTab(tab: Tab): void {
+    tab.setAttribute("aria-selected", "false");
+    tab.tabIndex = -1;
+
+    const tabPanel = this.tabPanels.get(tab)!;
+    tabPanel.hidden = true;
+
+    const legacyPanel = this.legacyUserPanels.get(tab);
+    if (legacyPanel) {
+      legacyPanel.close();
+    }
   }
 
   private attachViewToPanel(tab: Tab): void {
index bfad0f9bb3799ae670cfec89b01a1a3997c77398..2bd8ed3003aef3e31cdeecc5401c0e024df4b502 100644 (file)
@@ -28,7 +28,7 @@ define(["require", "exports", "tslib", "focus-trap", "../../Screen", "../../Clos
             (0, Screen_1.pageOverlayOpen)();
             (0, Screen_1.scrollDisable)();
             this.container.hidden = false;
-            this.provider.refresh();
+            this.provider.wakeup();
             this.getFocusTrap().activate();
         }
         close() {
@@ -37,6 +37,7 @@ define(["require", "exports", "tslib", "focus-trap", "../../Screen", "../../Clos
             (0, Screen_1.scrollEnable)();
             this.container.hidden = true;
             this.getFocusTrap().deactivate();
+            this.provider.sleep();
         }
         toggle() {
             if (this.container.hidden) {
index 28f01c7452b40493b496b9e1ba4687137966c0b5..cfbc2d9d9414a34c9ba1f01dbee0efffbf48df21 100644 (file)
@@ -81,7 +81,10 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../.
         getMenuButton() {
             return this.mainMenu;
         }
-        refresh() {
+        sleep() {
+            /* Does nothing */
+        }
+        wakeup() {
             /* Does nothing */
         }
         buildMainMenu() {
index 041a1f69099e59da0f8c1d6b8d8a33be3582599f..c00c886f7dd79bce2b152d0406bba63abd6d3f82 100644 (file)
@@ -16,6 +16,7 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../.
     EventHandler = (0, tslib_1.__importStar)(EventHandler);
     class PageMenuUser {
         constructor() {
+            this.activeTab = undefined;
             this.legacyUserPanels = new Map();
             this.userMenuProviders = new Map();
             this.tabPanels = new Map();
@@ -49,16 +50,20 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../.
         getMenuButton() {
             return this.userMenu;
         }
-        refresh() {
-            const activeTab = this.tabs.find((element) => element.getAttribute("aria-selected") === "true");
-            if (activeTab === undefined) {
-                this.openNotifications();
+        sleep() {
+            if (this.activeTab) {
+                this.closeTab(this.activeTab);
             }
-            else {
+        }
+        wakeup() {
+            if (this.activeTab) {
                 // The UI elements in the tab panel are shared and can appear in a different
                 // context. The element might have been moved elsewhere while the menu was
                 // closed.
-                this.attachViewToPanel(activeTab);
+                this.openTab(this.activeTab);
+            }
+            else {
+                this.openNotifications();
             }
         }
         openNotifications() {
@@ -69,16 +74,7 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../.
             this.openTab(notifications);
         }
         openTab(tab) {
-            if (tab.getAttribute("aria-selected") === "true") {
-                return;
-            }
-            const activeTab = this.tabs.find((element) => element.getAttribute("aria-selected") === "true");
-            if (activeTab) {
-                activeTab.setAttribute("aria-selected", "false");
-                activeTab.tabIndex = -1;
-                const activePanel = this.tabPanels.get(activeTab);
-                activePanel.hidden = true;
-            }
+            this.closeActiveTab();
             tab.setAttribute("aria-selected", "true");
             tab.tabIndex = 0;
             const tabPanel = this.tabPanels.get(tab);
@@ -87,6 +83,24 @@ define(["require", "exports", "tslib", "./Container", "../../../Language", "../.
                 tab.focus();
             }
             this.attachViewToPanel(tab);
+            this.activeTab = tab;
+        }
+        closeActiveTab() {
+            if (!this.activeTab) {
+                return;
+            }
+            this.closeTab(this.activeTab);
+            this.activeTab = undefined;
+        }
+        closeTab(tab) {
+            tab.setAttribute("aria-selected", "false");
+            tab.tabIndex = -1;
+            const tabPanel = this.tabPanels.get(tab);
+            tabPanel.hidden = true;
+            const legacyPanel = this.legacyUserPanels.get(tab);
+            if (legacyPanel) {
+                legacyPanel.close();
+            }
         }
         attachViewToPanel(tab) {
             const origin = tab.dataset.origin;