Integrate the search bar into the mobile header
authorAlexander Ebert <ebert@woltlab.com>
Mon, 20 Dec 2021 10:54:52 +0000 (11:54 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 20 Dec 2021 10:54:52 +0000 (11:54 +0100)
ts/WoltLabSuite/Core/Ui/Mobile.ts
ts/WoltLabSuite/Core/Ui/Page/Header/Fixed.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Mobile.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Page/Header/Fixed.js
wcfsetup/install/files/style/layout/pageHeader.scss

index d366b0bb507aada48b1fea8b097780ef907fc384..642dc7db035a3097f0a5070bfb77d82239ffe1c0 100644 (file)
 import * as Core from "../Core";
 import DomChangeListener from "../Dom/Change/Listener";
 import * as Environment from "../Environment";
-import * as EventHandler from "../Event/Handler";
 import * as UiAlignment from "./Alignment";
 import UiCloseOverlay from "./CloseOverlay";
 import * as UiDropdownReusable from "./Dropdown/Reusable";
+import { closeSearchBar, openSearchBar } from "./Page/Header/Fixed";
 import { PageMenuMain } from "./Page/Menu/Main";
 import { hasValidUserMenu, PageMenuUser } from "./Page/Menu/User";
 import * as UiScreen from "./Screen";
 
-interface MainMenuMorePayload {
-  identifier: string;
-  handler: any; //UiPageMenuMain;
-}
-
 let _dropdownMenu: HTMLUListElement | null = null;
 let _dropdownMenuMessage: HTMLElement | null = null;
 let _enabled = false;
@@ -38,7 +33,7 @@ const _sidebars: HTMLElement[] = [];
 function init(): void {
   _enabled = true;
 
-  initSearchBar();
+  initSearchButton();
   initButtonGroupNavigation();
   initMessages();
   initMobileMenu();
@@ -50,20 +45,29 @@ function init(): void {
   });
 }
 
-function initSearchBar(): void {
+function initSearchButton(): void {
   const searchBar = document.getElementById("pageHeaderSearch")!;
   const searchInput = document.getElementById("pageHeaderSearchInput")!;
 
   let scrollTop: number | null = null;
-  EventHandler.add("com.woltlab.wcf.MainMenuMobile", "more", (data: MainMenuMorePayload) => {
-    if (data.identifier === "com.woltlab.wcf.search") {
-      data.handler.close();
+  const searchButton = document.getElementById("pageHeaderSearchMobile")!;
+  searchButton.addEventListener("click", (event) => {
+    event.preventDefault();
+    event.stopPropagation();
+
+    if (searchButton.getAttribute("aria-expanded") === "true") {
+      closeSearch(searchBar, scrollTop);
+      closeSearchBar();
 
+      searchButton.setAttribute("aria-expanded", "false");
+    } else {
       if (Environment.platform() === "ios") {
         scrollTop = document.body.scrollTop;
         UiScreen.scrollDisable();
       }
 
+      openSearchBar();
+
       const pageHeader = document.getElementById("pageHeader")!;
       searchBar.style.setProperty("top", `${pageHeader.offsetHeight}px`, "");
       searchBar.classList.add("open");
@@ -72,20 +76,40 @@ function initSearchBar(): void {
       if (Environment.platform() === "ios") {
         document.body.scrollTop = 0;
       }
+
+      searchButton.setAttribute("aria-expanded", "true");
     }
   });
 
-  document.getElementById("main")!.addEventListener("click", () => {
-    if (searchBar) {
-      searchBar.classList.remove("open");
-    }
+  searchBar.addEventListener("click", (event) => {
+    if (event.target === searchBar) {
+      event.preventDefault();
+
+      closeSearch(searchBar, scrollTop);
+      closeSearchBar();
 
-    if (Environment.platform() === "ios" && scrollTop) {
-      UiScreen.scrollEnable();
-      document.body.scrollTop = scrollTop;
-      scrollTop = null;
+      searchButton.setAttribute("aria-expanded", "false");
     }
   });
+
+  UiCloseOverlay.add("WoltLabSuite/Core/Ui/MobileSearch", () => {
+    closeSearch(searchBar, scrollTop);
+    closeSearchBar();
+
+    searchButton.setAttribute("aria-expanded", "false");
+  });
+}
+
+function closeSearch(searchBar: HTMLElement, scrollTop: number | null): void {
+  if (searchBar) {
+    searchBar.classList.remove("open");
+  }
+
+  if (Environment.platform() === "ios" && scrollTop) {
+    UiScreen.scrollEnable();
+    document.body.scrollTop = scrollTop;
+    scrollTop = null;
+  }
 }
 
 function initButtonGroupNavigation(): void {
index 69e36484be4937ea4bbb01a44db87d6eec6322df..1295f3396d5a3f1ccf8a23af9b0c9e86d3a792ef 100644 (file)
@@ -65,7 +65,7 @@ function initSearchBar(): void {
 /**
  * Opens the search bar.
  */
-function openSearchBar(): void {
+export function openSearchBar(): void {
   UiCloseOverlay.execute();
 
   _pageHeader.classList.add("searchBarOpen");
@@ -89,7 +89,7 @@ function openSearchBar(): void {
 /**
  * Closes the search bar.
  */
-function closeSearchBar(): void {
+export function closeSearchBar(): void {
   _pageHeader.classList.remove("searchBarOpen");
   _userPanelSearchButton.parentElement!.classList.remove("open");
 
index 7b6e0f7b841aad3e92b1dea3b90bdce37269e600..32bb9478f522fb2a8c745e6cb5090ccce22d9dd5 100644 (file)
@@ -6,14 +6,13 @@
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module  WoltLabSuite/Core/Ui/Mobile
  */
-define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "../Environment", "../Event/Handler", "./Alignment", "./CloseOverlay", "./Dropdown/Reusable", "./Page/Menu/Main", "./Page/Menu/User", "./Screen"], function (require, exports, tslib_1, Core, Listener_1, Environment, EventHandler, UiAlignment, CloseOverlay_1, UiDropdownReusable, Main_1, User_1, UiScreen) {
+define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "../Environment", "./Alignment", "./CloseOverlay", "./Dropdown/Reusable", "./Page/Header/Fixed", "./Page/Menu/Main", "./Page/Menu/User", "./Screen"], function (require, exports, tslib_1, Core, Listener_1, Environment, UiAlignment, CloseOverlay_1, UiDropdownReusable, Fixed_1, Main_1, User_1, UiScreen) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.removeShadow = exports.rebuildShadow = exports.disableShadow = exports.disable = exports.enableShadow = exports.enable = exports.setup = void 0;
     Core = (0, tslib_1.__importStar)(Core);
     Listener_1 = (0, tslib_1.__importDefault)(Listener_1);
     Environment = (0, tslib_1.__importStar)(Environment);
-    EventHandler = (0, tslib_1.__importStar)(EventHandler);
     UiAlignment = (0, tslib_1.__importStar)(UiAlignment);
     CloseOverlay_1 = (0, tslib_1.__importDefault)(CloseOverlay_1);
     UiDropdownReusable = (0, tslib_1.__importStar)(UiDropdownReusable);
@@ -31,7 +30,7 @@ define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "../
     const _sidebars = [];
     function init() {
         _enabled = true;
-        initSearchBar();
+        initSearchButton();
         initButtonGroupNavigation();
         initMessages();
         initMobileMenu();
@@ -41,17 +40,25 @@ define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "../
             initMessages();
         });
     }
-    function initSearchBar() {
+    function initSearchButton() {
         const searchBar = document.getElementById("pageHeaderSearch");
         const searchInput = document.getElementById("pageHeaderSearchInput");
         let scrollTop = null;
-        EventHandler.add("com.woltlab.wcf.MainMenuMobile", "more", (data) => {
-            if (data.identifier === "com.woltlab.wcf.search") {
-                data.handler.close();
+        const searchButton = document.getElementById("pageHeaderSearchMobile");
+        searchButton.addEventListener("click", (event) => {
+            event.preventDefault();
+            event.stopPropagation();
+            if (searchButton.getAttribute("aria-expanded") === "true") {
+                closeSearch(searchBar, scrollTop);
+                (0, Fixed_1.closeSearchBar)();
+                searchButton.setAttribute("aria-expanded", "false");
+            }
+            else {
                 if (Environment.platform() === "ios") {
                     scrollTop = document.body.scrollTop;
                     UiScreen.scrollDisable();
                 }
+                (0, Fixed_1.openSearchBar)();
                 const pageHeader = document.getElementById("pageHeader");
                 searchBar.style.setProperty("top", `${pageHeader.offsetHeight}px`, "");
                 searchBar.classList.add("open");
@@ -59,18 +66,32 @@ define(["require", "exports", "tslib", "../Core", "../Dom/Change/Listener", "../
                 if (Environment.platform() === "ios") {
                     document.body.scrollTop = 0;
                 }
+                searchButton.setAttribute("aria-expanded", "true");
             }
         });
-        document.getElementById("main").addEventListener("click", () => {
-            if (searchBar) {
-                searchBar.classList.remove("open");
-            }
-            if (Environment.platform() === "ios" && scrollTop) {
-                UiScreen.scrollEnable();
-                document.body.scrollTop = scrollTop;
-                scrollTop = null;
+        searchBar.addEventListener("click", (event) => {
+            if (event.target === searchBar) {
+                event.preventDefault();
+                closeSearch(searchBar, scrollTop);
+                (0, Fixed_1.closeSearchBar)();
+                searchButton.setAttribute("aria-expanded", "false");
             }
         });
+        CloseOverlay_1.default.add("WoltLabSuite/Core/Ui/MobileSearch", () => {
+            closeSearch(searchBar, scrollTop);
+            (0, Fixed_1.closeSearchBar)();
+            searchButton.setAttribute("aria-expanded", "false");
+        });
+    }
+    function closeSearch(searchBar, scrollTop) {
+        if (searchBar) {
+            searchBar.classList.remove("open");
+        }
+        if (Environment.platform() === "ios" && scrollTop) {
+            UiScreen.scrollEnable();
+            document.body.scrollTop = scrollTop;
+            scrollTop = null;
+        }
     }
     function initButtonGroupNavigation() {
         document.querySelectorAll(".buttonGroupNavigation").forEach((navigation) => {
index 53328fa3f327f5b704b802adf8a6a3cbdb41ae27..b55cdeff55f52c2bab210ba1351370d83ddd727d 100644 (file)
@@ -9,7 +9,7 @@
 define(["require", "exports", "tslib", "../../../Event/Handler", "../../Alignment", "../../CloseOverlay", "../../Dropdown/Simple", "../../Screen"], function (require, exports, tslib_1, EventHandler, UiAlignment, CloseOverlay_1, Simple_1, UiScreen) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
-    exports.init = void 0;
+    exports.init = exports.closeSearchBar = exports.openSearchBar = void 0;
     EventHandler = (0, tslib_1.__importStar)(EventHandler);
     UiAlignment = (0, tslib_1.__importStar)(UiAlignment);
     CloseOverlay_1 = (0, tslib_1.__importDefault)(CloseOverlay_1);
@@ -74,6 +74,7 @@ define(["require", "exports", "tslib", "../../../Event/Handler", "../../Alignmen
             _searchInput.selectionStart = _searchInput.selectionEnd = _searchInput.value.length;
         }, 1);
     }
+    exports.openSearchBar = openSearchBar;
     /**
      * Closes the search bar.
      */
@@ -88,6 +89,7 @@ define(["require", "exports", "tslib", "../../../Event/Handler", "../../Alignmen
         const scope = _pageHeaderSearch.querySelector(".pageHeaderSearchType");
         Simple_1.default.close(scope.id);
     }
+    exports.closeSearchBar = closeSearchBar;
     /**
      * Initializes the sticky page header handler.
      */
index e93616e174f637c2e209b4837e4c716429d77d9f..e4ee20eec7dcaaa3ef276872368428075657863e 100644 (file)
 
        .pageHeaderSearchMobile {
                grid-area: search;
+
+               &[aria-expanded="true"] .icon::before {
+                       content: $fa-var-times;
+               }
        }
 
        .userPanel {
        }
 
        .pageHeaderSearch {
+               background-color: rgba(0, 0, 0, 0.34);
+               bottom: 0;
                left: 0 !important;
                right: 0 !important;