The admin panel uses a completely different markup that has no common logic with the frontend.
// perfectScrollbar does not need to be bound anywhere, it just has to be loaded for WCF.js
import "perfect-scrollbar";
+import { PageMenuMainProvider } from "./Ui/Page/Menu/Main/Provider";
// non strict equals by intent
if (window.WCF == null) {
export interface BoostrapOptions {
enableMobileMenu: boolean;
+ pageMenuMainProvider: PageMenuMainProvider;
}
function initA11y() {
options = Core.extend(
{
enableMobileMenu: true,
+ pageMenuMainProvider: undefined,
},
options,
) as BoostrapOptions;
DateTimeRelative.setup();
DatePicker.init();
UiDropdownSimple.setup();
- UiMobile.setup(options.enableMobileMenu);
+ UiMobile.setup(options.enableMobileMenu, options.pageMenuMainProvider);
UiTabMenu.setup();
UiDialog.setup();
UiTooltip.setup();
import * as UiMessageShareProviders from "./Ui/Message/Share/Providers";
import * as UiFeedDialog from "./Ui/Feed/Dialog";
import User from "./User";
+import UiPageMenuMainFrontend from "./Ui/Page/Menu/Main/Frontend";
interface BoostrapOptions {
backgroundQueue: {
// Modify the URL of the background queue URL to always target the current domain to avoid CORS.
options.backgroundQueue.url = window.WSC_API_URL + options.backgroundQueue.url.substr(window.WCF_PATH.length);
- Bootstrap.setup({ enableMobileMenu: true });
+ Bootstrap.setup({
+ enableMobileMenu: true,
+ pageMenuMainProvider: new UiPageMenuMainFrontend(),
+ });
UiPageHeaderMenu.init();
if (options.styleChanger) {
import * as UiDropdownReusable from "./Dropdown/Reusable";
import { closeSearchBar, openSearchBar } from "./Page/Header/Fixed";
import { PageMenuMain } from "./Page/Menu/Main";
+import { PageMenuMainProvider } from "./Page/Menu/Main/Provider";
import { hasValidUserMenu, PageMenuUser } from "./Page/Menu/User";
import * as UiScreen from "./Screen";
let _pageMenuMain: PageMenuMain;
let _pageMenuUser: PageMenuUser | undefined = undefined;
let _messageGroups: HTMLCollection | null = null;
+let _pageMenuMainProvider: PageMenuMainProvider;
const _sidebars: HTMLElement[] = [];
function init(): void {
function initMobileMenu(): void {
if (_enableMobileMenu) {
- _pageMenuMain = new PageMenuMain();
+ _pageMenuMain = new PageMenuMain(_pageMenuMainProvider);
_pageMenuMain.enable();
if (hasValidUserMenu()) {
/**
* Initializes the mobile UI.
*/
-export function setup(enableMobileMenu: boolean): void {
+export function setup(enableMobileMenu: boolean, pageMenuMainProvider: PageMenuMainProvider): void {
_enableMobileMenu = enableMobileMenu;
+ _pageMenuMainProvider = pageMenuMainProvider;
+
document.querySelectorAll(".sidebar").forEach((sidebar: HTMLElement) => {
_sidebars.push(sidebar);
});
import { PageMenuProvider } from "./Provider";
import * as Language from "../../../Language";
import DomUtil from "../../../Dom/Util";
-
-type MenuItemDepth = 0 | 1 | 2;
-
-type MenuItem = {
- active: boolean;
- children: MenuItem[];
- counter: number;
- depth: MenuItemDepth;
- link?: string;
- title: string;
-};
-
-function normalizeMenuItem(menuItem: HTMLElement, depth: MenuItemDepth): MenuItem {
- const anchor = menuItem.querySelector(".boxMenuLink") as HTMLAnchorElement;
- const title = anchor.querySelector(".boxMenuLinkTitle")!.textContent as string;
-
- let counter = 0;
- const outstandingItems = anchor.querySelector(".boxMenuLinkOutstandingItems");
- if (outstandingItems) {
- counter = +outstandingItems.textContent!.replace(/[^0-9]/, "");
- }
-
- const subMenu = menuItem.querySelector("ol");
- let children: MenuItem[] = [];
- if (subMenu instanceof HTMLOListElement) {
- let childDepth = depth;
- if (childDepth < 2) {
- childDepth = (depth + 1) as MenuItemDepth;
- }
-
- children = Array.from(subMenu.children).map((subMenuItem: HTMLElement) => {
- return normalizeMenuItem(subMenuItem, childDepth);
- });
- }
-
- // `link.href` represents the computed link, not the raw value.
- const href = anchor.getAttribute("href");
- let link: string | undefined = undefined;
- if (href && href !== "#") {
- link = anchor.href;
- }
-
- const active = menuItem.classList.contains("active");
-
- return {
- active,
- children,
- counter,
- depth,
- link,
- title,
- };
-}
+import { MenuItem, PageMenuMainProvider } from "./Main/Provider";
type CallbackOpen = (event: MouseEvent) => void;
private readonly callbackOpen: CallbackOpen;
private readonly container: PageMenuContainer;
private readonly mainMenu: HTMLElement;
+ private readonly menuItemProvider: PageMenuMainProvider;
- constructor() {
+ constructor(menuItemProvider: PageMenuMainProvider) {
this.mainMenu = document.querySelector(".mainMenu")!;
+ this.menuItemProvider = menuItemProvider;
this.container = new PageMenuContainer(this, Orientation.Left);
}
private buildMenu(boxMenu: HTMLElement): HTMLElement {
- const menuItems: MenuItem[] = Array.from(boxMenu.children).map((element: HTMLElement) => {
- return normalizeMenuItem(element, 0);
- });
+ const menuItems = this.menuItemProvider.getMenuItems(boxMenu);
const nav = document.createElement("nav");
nav.classList.add("pageMenuMainNavigation");
--- /dev/null
+import { MenuItem, MenuItemDepth, PageMenuMainProvider } from "./Provider";
+
+function normalizeMenuItem(menuItem: HTMLElement, depth: MenuItemDepth): MenuItem {
+ const anchor = menuItem.querySelector(".boxMenuLink") as HTMLAnchorElement;
+ const title = anchor.querySelector(".boxMenuLinkTitle")!.textContent as string;
+
+ let counter = 0;
+ const outstandingItems = anchor.querySelector(".boxMenuLinkOutstandingItems");
+ if (outstandingItems) {
+ counter = +outstandingItems.textContent!.replace(/[^0-9]/, "");
+ }
+
+ const subMenu = menuItem.querySelector("ol");
+ let children: MenuItem[] = [];
+ if (subMenu instanceof HTMLOListElement) {
+ let childDepth = depth;
+ if (childDepth < 2) {
+ childDepth = (depth + 1) as MenuItemDepth;
+ }
+
+ children = Array.from(subMenu.children).map((subMenuItem: HTMLElement) => {
+ return normalizeMenuItem(subMenuItem, childDepth);
+ });
+ }
+
+ // `link.href` represents the computed link, not the raw value.
+ const href = anchor.getAttribute("href");
+ let link: string | undefined = undefined;
+ if (href && href !== "#") {
+ link = anchor.href;
+ }
+
+ const active = menuItem.classList.contains("active");
+
+ return {
+ active,
+ children,
+ counter,
+ depth,
+ link,
+ title,
+ };
+}
+
+export class UiPageMenuMainFrontend implements PageMenuMainProvider {
+ getMenuItems(container:HTMLElement): MenuItem[] {
+ return Array.from(container.children).map((element: HTMLElement) => {
+ return normalizeMenuItem(element, 0);
+ });
+ }
+}
+
+export default UiPageMenuMainFrontend;
--- /dev/null
+export type MenuItemDepth = 0 | 1 | 2;
+
+export type MenuItem = {
+ active: boolean;
+ children: MenuItem[];
+ counter: number;
+ depth: MenuItemDepth;
+ link?: string;
+ title: string;
+};
+
+export interface PageMenuMainProvider {
+ getMenuItems(container: HTMLElement): MenuItem[];
+}
function setup(options) {
options = Core.extend({
enableMobileMenu: true,
+ pageMenuMainProvider: undefined,
}, options);
StringUtil.setupI18n({
decimalPoint: Language.get("wcf.global.decimalPoint"),
DateTimeRelative.setup();
Picker_1.default.init();
Simple_1.default.setup();
- UiMobile.setup(options.enableMobileMenu);
+ UiMobile.setup(options.enableMobileMenu, options.pageMenuMainProvider);
UiTabMenu.setup();
Dialog_1.default.setup();
UiTooltip.setup();
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @module WoltLabSuite/Core/BootstrapFrontend
*/
-define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Controller/Style/Changer", "./Controller/Popover", "./Ui/User/Ignore", "./Ui/Page/Header/Menu", "./Ui/Message/UserConsent", "./Ajax", "./Ui/Message/Share/Dialog", "./Ui/Message/Share/Providers", "./Ui/Feed/Dialog", "./User"], function (require, exports, tslib_1, BackgroundQueue, Bootstrap, ControllerStyleChanger, ControllerPopover, UiUserIgnore, UiPageHeaderMenu, UiMessageUserConsent, Ajax, UiMessageShareDialog, UiMessageShareProviders, UiFeedDialog, User_1) {
+define(["require", "exports", "tslib", "./BackgroundQueue", "./Bootstrap", "./Controller/Style/Changer", "./Controller/Popover", "./Ui/User/Ignore", "./Ui/Page/Header/Menu", "./Ui/Message/UserConsent", "./Ajax", "./Ui/Message/Share/Dialog", "./Ui/Message/Share/Providers", "./Ui/Feed/Dialog", "./User", "./Ui/Page/Menu/Main/Frontend"], function (require, exports, tslib_1, BackgroundQueue, Bootstrap, ControllerStyleChanger, ControllerPopover, UiUserIgnore, UiPageHeaderMenu, UiMessageUserConsent, Ajax, UiMessageShareDialog, UiMessageShareProviders, UiFeedDialog, User_1, Frontend_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setup = void 0;
UiMessageShareProviders = (0, tslib_1.__importStar)(UiMessageShareProviders);
UiFeedDialog = (0, tslib_1.__importStar)(UiFeedDialog);
User_1 = (0, tslib_1.__importDefault)(User_1);
+ Frontend_1 = (0, tslib_1.__importDefault)(Frontend_1);
/**
* Initializes user profile popover.
*/
function setup(options) {
// Modify the URL of the background queue URL to always target the current domain to avoid CORS.
options.backgroundQueue.url = window.WSC_API_URL + options.backgroundQueue.url.substr(window.WCF_PATH.length);
- Bootstrap.setup({ enableMobileMenu: true });
+ Bootstrap.setup({
+ enableMobileMenu: true,
+ pageMenuMainProvider: new Frontend_1.default(),
+ });
UiPageHeaderMenu.init();
if (options.styleChanger) {
ControllerStyleChanger.setup();
let _pageMenuMain;
let _pageMenuUser = undefined;
let _messageGroups = null;
+ let _pageMenuMainProvider;
const _sidebars = [];
function init() {
_enabled = true;
}
function initMobileMenu() {
if (_enableMobileMenu) {
- _pageMenuMain = new Main_1.PageMenuMain();
+ _pageMenuMain = new Main_1.PageMenuMain(_pageMenuMainProvider);
_pageMenuMain.enable();
if ((0, User_1.hasValidUserMenu)()) {
_pageMenuUser = new User_1.PageMenuUser();
/**
* Initializes the mobile UI.
*/
- function setup(enableMobileMenu) {
+ function setup(enableMobileMenu, pageMenuMainProvider) {
_enableMobileMenu = enableMobileMenu;
+ _pageMenuMainProvider = pageMenuMainProvider;
document.querySelectorAll(".sidebar").forEach((sidebar) => {
_sidebars.push(sidebar);
});
Container_1 = (0, tslib_1.__importDefault)(Container_1);
Language = (0, tslib_1.__importStar)(Language);
Util_1 = (0, tslib_1.__importDefault)(Util_1);
- function normalizeMenuItem(menuItem, depth) {
- const anchor = menuItem.querySelector(".boxMenuLink");
- const title = anchor.querySelector(".boxMenuLinkTitle").textContent;
- let counter = 0;
- const outstandingItems = anchor.querySelector(".boxMenuLinkOutstandingItems");
- if (outstandingItems) {
- counter = +outstandingItems.textContent.replace(/[^0-9]/, "");
- }
- const subMenu = menuItem.querySelector("ol");
- let children = [];
- if (subMenu instanceof HTMLOListElement) {
- let childDepth = depth;
- if (childDepth < 2) {
- childDepth = (depth + 1);
- }
- children = Array.from(subMenu.children).map((subMenuItem) => {
- return normalizeMenuItem(subMenuItem, childDepth);
- });
- }
- // `link.href` represents the computed link, not the raw value.
- const href = anchor.getAttribute("href");
- let link = undefined;
- if (href && href !== "#") {
- link = anchor.href;
- }
- const active = menuItem.classList.contains("active");
- return {
- active,
- children,
- counter,
- depth,
- link,
- title,
- };
- }
class PageMenuMain {
- constructor() {
+ constructor(menuItemProvider) {
this.mainMenu = document.querySelector(".mainMenu");
+ this.menuItemProvider = menuItemProvider;
this.container = new Container_1.default(this, "left" /* Left */);
this.callbackOpen = (event) => {
event.preventDefault();
return nav;
}
buildMenu(boxMenu) {
- const menuItems = Array.from(boxMenu.children).map((element) => {
- return normalizeMenuItem(element, 0);
- });
+ const menuItems = this.menuItemProvider.getMenuItems(boxMenu);
const nav = document.createElement("nav");
nav.classList.add("pageMenuMainNavigation");
nav.append(this.buildMenuItemList(menuItems));
--- /dev/null
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.UiPageMenuMainFrontend = void 0;
+ function normalizeMenuItem(menuItem, depth) {
+ const anchor = menuItem.querySelector(".boxMenuLink");
+ const title = anchor.querySelector(".boxMenuLinkTitle").textContent;
+ let counter = 0;
+ const outstandingItems = anchor.querySelector(".boxMenuLinkOutstandingItems");
+ if (outstandingItems) {
+ counter = +outstandingItems.textContent.replace(/[^0-9]/, "");
+ }
+ const subMenu = menuItem.querySelector("ol");
+ let children = [];
+ if (subMenu instanceof HTMLOListElement) {
+ let childDepth = depth;
+ if (childDepth < 2) {
+ childDepth = (depth + 1);
+ }
+ children = Array.from(subMenu.children).map((subMenuItem) => {
+ return normalizeMenuItem(subMenuItem, childDepth);
+ });
+ }
+ // `link.href` represents the computed link, not the raw value.
+ const href = anchor.getAttribute("href");
+ let link = undefined;
+ if (href && href !== "#") {
+ link = anchor.href;
+ }
+ const active = menuItem.classList.contains("active");
+ return {
+ active,
+ children,
+ counter,
+ depth,
+ link,
+ title,
+ };
+ }
+ class UiPageMenuMainFrontend {
+ getMenuItems(container) {
+ return Array.from(container.children).map((element) => {
+ return normalizeMenuItem(element, 0);
+ });
+ }
+ }
+ exports.UiPageMenuMainFrontend = UiPageMenuMainFrontend;
+ exports.default = UiPageMenuMainFrontend;
+});
--- /dev/null
+define(["require", "exports"], function (require, exports) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+});