403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/ui/system/menu/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/ui/system/menu/src/menu.js
import { Dom, Event, Tag } from 'main.core';
import { Popup } from 'main.popup';
import { Main } from 'ui.icon-set.api.core';
import 'ui.icon-set.main';

import { MenuItem } from './menu-item';
import { MenuSectionDesign, MenuRichHeaderDesign } from './const';
import type { MenuOptions, MenuItemOptions, MenuSectionOptions } from './types';
import './menu.css';

export class Menu
{
	#options: MenuOptions;
	#items: MenuItem[];
	#popup: Popup;
	#container: HTMLElement;

	constructor(options: MenuOptions)
	{
		const defaultOptions: MenuOptions = {
			noAllPaddings: true,
			autoHide: true,
			autoHideHandler: this.#shouldHide,
			closeOnItemClick: true,
		};

		this.#options = { ...defaultOptions, ...options };
	}

	getOptions(): MenuOptions
	{
		return this.#options;
	}

	getPopup(): Popup
	{
		return this.#popup;
	}

	getPopupContainer(): HTMLElement
	{
		return this.#popup.getPopupContainer();
	}

	show(bindElement: HTMLElement): void
	{
		this.#items ??= this.#prepareItems(this.#options.items);

		this.#popup ??= new Popup({
			...this.#options,
			content: this.#render(),
			events: {
				...this.#options.events,
				onClose: this.#onPopupClose,
				onDestroy: this.#onPopupDestroy,
				onBeforeAdjustPosition: this.#onBeforeAdjustPosition,
			},
		});

		this.#popup.setBindElement(bindElement ?? this.#options.bindElement);
		this.#popup.show();
	}

	updateItems(itemsOptions: MenuItemOptions[]): void
	{
		const openedItem = this.#items?.find((item: MenuItem) => item.getSubMenu()?.getPopup()?.isShown());

		this.#items?.forEach((item: MenuItem): void => item.destroy());
		this.#items = this.#prepareItems(itemsOptions);
		this.#render();

		if (openedItem && !openedItem?.getSubMenu().getOptions().closeOnItemClick)
		{
			this.#items.find((item: MenuItem) => item.getOptions().id === openedItem.getOptions().id)?.showSubMenu();
		}
	}

	close(): void
	{
		this.#popup.close();
	}

	destroy(): void
	{
		this.#items?.forEach((item) => item.destroy());
		this.#popup.destroy();
	}

	#shouldHide = (event: MouseEvent): void => {
		const notSelfClick = !this.getPopupContainer().contains(event.target);
		const notSubMenuClick = !this.#items.some((item) => {
			return item.getSubMenu()?.getPopupContainer()?.contains(event.target);
		});

		return notSelfClick && notSubMenuClick;
	};

	#onPopupClose = (): void => {
		this.#items.forEach((item: MenuItem): void => item.closeSubMenu());
		this.#options.events?.onClose?.();
	};

	#onPopupDestroy = (): void => {
		this.#options.events?.onDestroy?.();
		this.destroy();
	};

	#onBeforeAdjustPosition = (): void => {
		this.#items.forEach((item: MenuItem): void => item.adjustSubMenu());
	};

	#prepareItems(itemsOptions: MenuItemOptions[]): MenuItem[]
	{
		const items: MenuItem[] = itemsOptions.map((itemOptions: ?MenuItemOptions): MenuItem => {
			if (!itemOptions)
			{
				return null;
			}

			const item: MenuItem = new MenuItem(
				{
					...itemOptions,
					onClick: (): void => this.#onItemClick(itemOptions),
				},
				{
					getTargetContainer: () => this.getPopup().getTargetContainer(),
					onMouseEnter: () => items.filter((it) => it !== item).forEach((it) => it.closeSubMenuWithTimeout()),
					onSubMenuItemClick: this.#onSubMenuItemClick,
				},
			);

			return item;
		}).filter((it) => it);

		return items;
	}

	#onItemClick = (itemOptions: MenuItemOptions): void => {
		itemOptions.onClick?.();

		if (!itemOptions.subMenu && this.#options.closeOnItemClick)
		{
			this.close();
		}
	};

	#onSubMenuItemClick = (): void => {
		if (this.#options.closeOnItemClick)
		{
			this.close();
		}
	};

	#render(): HTMLElement
	{
		this.#container ??= Tag.render`
			<div class="ui-popup-menu-container"></div>
		`;

		const itemsContainer = Tag.render`
			<div class="ui-popup-menu-items">
				${this.#renderRichHeader()}
				${this.#renderItems()}
			</div>
		`;

		Dom.clean(this.#container);
		Dom.append(itemsContainer, this.#container);

		return this.#container;
	}

	#renderRichHeader(): HTMLElement
	{
		if (!this.#options.richHeader)
		{
			return '';
		}

		const design = this.#options.richHeader.design ?? MenuRichHeaderDesign.Default;
		const richHeader = Tag.render`
			<div class="ui-popup-menu-rich-header --${design}">
				<div class="ui-popup-menu-rich-header-image">
					<div class="ui-icon-set --${this.#getRichHeaderIcon(design)}"></div>
				</div>
				<div class="ui-popup-menu-rich-header-header">
					${this.#renderRichHeaderSubtitle()}
					<div class="ui-popup-menu-rich-header-title">
						${this.#options.richHeader.title}
					</div>
				</div>
				<div class="ui-popup-menu-rich-header-buttons">
					${this.#renderRichHeaderIcon()}
				</div>
			</div>
		`;

		if (this.#options.richHeader.onClick)
		{
			Event.bind(richHeader, 'click', this.#options.richHeader.onClick);
		}

		return richHeader;
	}

	#getRichHeaderIcon(design: string): string
	{
		return {
			[MenuRichHeaderDesign.Default]: Main.DIAMOND,
			[MenuRichHeaderDesign.Copilot]: Main.COPILOT_AI,
		}[design] ?? Main.DIAMOND;
	}

	#renderRichHeaderSubtitle(): HTMLElement
	{
		if (!this.#options.richHeader.subtitle)
		{
			return '';
		}

		return Tag.render`
			<div class="ui-popup-menu-rich-header-subtitle">
				${this.#options.richHeader.subtitle}
			</div>
		`;
	}

	#renderRichHeaderIcon(): HTMLElement
	{
		if (!this.#options.richHeader.icon)
		{
			return '';
		}

		return Tag.render`
			<div class="ui-popup-menu-rich-header-icon">
				<div class="ui-icon-set --${this.#options.richHeader.icon}"></div>
			</div>
		`;
	}

	#renderItems(): HTMLElement[]
	{
		const baseSection = 'base';
		const itemsBySection = this.#items.reduce((result, item) => {
			const sectionCode = item.getOptions().sectionCode ?? baseSection;
			const sectionItems = result[sectionCode] ?? [];

			return {
				...result,
				[sectionCode]: [...sectionItems, item],
			};
		}, {});

		return [
			...(itemsBySection[baseSection]?.map((item) => item.render()) ?? []),
			...(this.#options.sections?.flatMap((options: MenuSectionOptions) => {
				const items = itemsBySection[options.code];
				if (!items)
				{
					return null;
				}

				return [
					this.#renderSection(options),
					...(items.map((item) => item.render()) ?? []),
				];
			}) ?? []).filter((it) => it),
		];
	}

	#renderSection(options: MenuSectionOptions): HTMLElement
	{
		return Tag.render`
			<div class="ui-popup-menu-section --${options.design ?? MenuSectionDesign.Default}">
				${this.#renderSectionTitle(options.title)}
				<div class="ui-popup-menu-section-divider"></div>
			</div>
		`;
	}

	#renderSectionTitle(title: string): HTMLElement
	{
		if (!title)
		{
			return '';
		}

		return Tag.render`
			<div class="ui-popup-menu-section-title">${title}</div>
		`;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit