import { trigger, transition, style, animate } from '@angular/animations'; import * as i2 from '@angular/common'; import { isPlatformBrowser, DOCUMENT, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { PLATFORM_ID, Pipe, Inject, EventEmitter, forwardRef, Component, ViewEncapsulation, Input, Output, computed, signal, booleanAttribute, numberAttribute, ChangeDetectionStrategy, ViewChild, ContentChildren, NgModule } from '@angular/core'; import * as i3 from '@angular/router'; import { RouterModule } from '@angular/router'; import * as i5 from 'primeng/api'; import { PrimeTemplate } from 'primeng/api'; import { DomHandler, ConnectedOverlayScrollHandler } from 'primeng/dom'; import * as i4 from 'primeng/ripple'; import { RippleModule } from 'primeng/ripple'; import * as i6 from 'primeng/tooltip'; import { TooltipModule } from 'primeng/tooltip'; import { UniqueComponentId, ZIndexUtils } from 'primeng/utils'; import * as i1 from '@angular/platform-browser'; class SafeHtmlPipe { platformId; sanitizer; constructor(platformId, sanitizer) { this.platformId = platformId; this.sanitizer = sanitizer; } transform(value) { if (!value || !isPlatformBrowser(this.platformId)) { return value; } return this.sanitizer.bypassSecurityTrustHtml(value); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: PLATFORM_ID }, { token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.7", ngImport: i0, type: SafeHtmlPipe, name: "safeHtml" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: SafeHtmlPipe, decorators: [{ type: Pipe, args: [{ name: 'safeHtml' }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: i1.DomSanitizer }] }); class MenuItemContent { item; itemTemplate; onMenuItemClick = new EventEmitter(); menu; constructor(menu) { this.menu = menu; } onItemClick(event, item) { this.onMenuItemClick.emit({ originalEvent: event, item }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: MenuItemContent, deps: [{ token: forwardRef(() => Menu) }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.7", type: MenuItemContent, selector: "[pMenuItemContent]", inputs: { item: ["pMenuItemContent", "item"], itemTemplate: "itemTemplate" }, outputs: { onMenuItemClick: "onMenuItemClick" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: i4.Ripple, selector: "[pRipple]" }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }], encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: MenuItemContent, decorators: [{ type: Component, args: [{ selector: '[pMenuItemContent]', template: ` `, encapsulation: ViewEncapsulation.None, host: { class: 'p-element' } }] }], ctorParameters: () => [{ type: Menu, decorators: [{ type: Inject, args: [forwardRef(() => Menu)] }] }], propDecorators: { item: [{ type: Input, args: ['pMenuItemContent'] }], itemTemplate: [{ type: Input }], onMenuItemClick: [{ type: Output }] } }); /** * Menu is a navigation / command component that supports dynamic and static positioning. * @group Components */ class Menu { document; platformId; el; renderer; cd; config; overlayService; /** * An array of menuitems. * @group Props */ model; /** * Defines if menu would displayed as a popup. * @group Props */ popup; /** * Inline style of the component. * @group Props */ style; /** * Style class of the component. * @group Props */ styleClass; /** * Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name). * @group Props */ appendTo; /** * Whether to automatically manage layering. * @group Props */ autoZIndex = true; /** * Base zIndex value to use in layering. * @group Props */ baseZIndex = 0; /** * Transition options of the show animation. * @group Props */ showTransitionOptions = '.12s cubic-bezier(0, 0, 0.2, 1)'; /** * Transition options of the hide animation. * @group Props */ hideTransitionOptions = '.1s linear'; /** * Defines a string value that labels an interactive element. * @group Props */ ariaLabel; /** * Identifier of the underlying input element. * @group Props */ ariaLabelledBy; /** * Current id state as a string. * @group Props */ id; /** * Index of the element in tabbing order. * @group Props */ tabindex = 0; /** * Callback to invoke when overlay menu is shown. * @group Emits */ onShow = new EventEmitter(); /** * Callback to invoke when overlay menu is hidden. * @group Emits */ onHide = new EventEmitter(); /** * Callback to invoke when the list loses focus. * @param {Event} event - blur event. * @group Emits */ onBlur = new EventEmitter(); /** * Callback to invoke when the list receives focus. * @param {Event} event - focus event. * @group Emits */ onFocus = new EventEmitter(); listViewChild; containerViewChild; templates; startTemplate; endTemplate; itemTemplate; submenuHeaderTemplate; container; scrollHandler; documentClickListener; documentResizeListener; preventDocumentDefault; target; visible; focusedOptionId = computed(() => { return this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : null; }); focusedOptionIndex = signal(-1); selectedOptionIndex = signal(-1); focused = false; overlayVisible = false; relativeAlign; constructor(document, platformId, el, renderer, cd, config, overlayService) { this.document = document; this.platformId = platformId; this.el = el; this.renderer = renderer; this.cd = cd; this.config = config; this.overlayService = overlayService; this.id = this.id || UniqueComponentId(); } /** * Toggles the visibility of the popup menu. * @param {Event} event - Browser event. * @group Method */ toggle(event) { if (this.visible) this.hide(); else this.show(event); this.preventDocumentDefault = true; } /** * Displays the popup menu. * @param {Event} event - Browser event. * @group Method */ show(event) { this.target = event.currentTarget; this.relativeAlign = event.relativeAlign; this.visible = true; this.preventDocumentDefault = true; this.overlayVisible = true; this.cd.markForCheck(); } ngOnInit() { if (!this.popup) { this.bindDocumentClickListener(); } } ngAfterContentInit() { this.templates?.forEach((item) => { switch (item.getType()) { case 'start': this.startTemplate = item.template; break; case 'end': this.endTemplate = item.template; break; case 'itemTemplate': this.itemTemplate = item.template; break; case 'submenuheader': this.submenuHeaderTemplate = item.template; break; default: this.itemTemplate = item.template; break; } }); } getTabIndexValue() { return this.tabindex !== undefined ? this.tabindex.toString() : null; } onOverlayAnimationStart(event) { switch (event.toState) { case 'visible': if (this.popup) { this.container = event.element; this.moveOnTop(); this.onShow.emit({}); this.appendOverlay(); this.alignOverlay(); this.bindDocumentClickListener(); this.bindDocumentResizeListener(); this.bindScrollListener(); DomHandler.focus(this.listViewChild.nativeElement); } break; case 'void': this.onOverlayHide(); this.onHide.emit({}); break; } } onOverlayAnimationEnd(event) { switch (event.toState) { case 'void': if (this.autoZIndex) { ZIndexUtils.clear(event.element); } break; } } alignOverlay() { if (this.relativeAlign) DomHandler.relativePosition(this.container, this.target); else DomHandler.absolutePosition(this.container, this.target); } appendOverlay() { if (this.appendTo) { if (this.appendTo === 'body') this.renderer.appendChild(this.document.body, this.container); else DomHandler.appendChild(this.container, this.appendTo); } } restoreOverlayAppend() { if (this.container && this.appendTo) { this.renderer.appendChild(this.el.nativeElement, this.container); } } moveOnTop() { if (this.autoZIndex) { ZIndexUtils.set('menu', this.container, this.baseZIndex + this.config.zIndex.menu); } } /** * Hides the popup menu. * @group Method */ hide() { this.visible = false; this.relativeAlign = false; this.cd.markForCheck(); } onWindowResize() { if (this.visible && !DomHandler.isTouchDevice()) { this.hide(); } } menuitemId(item, id, index, childIndex) { return item?.id ?? `${id}_${index}${childIndex !== undefined ? '_' + childIndex : ''}`; } isItemFocused(id) { return this.focusedOptionId() === id; } label(label) { return typeof label === 'function' ? label() : label; } disabled(disabled) { return typeof disabled === 'function' ? disabled() : typeof disabled === 'undefined' ? false : disabled; } activedescendant() { return this.focused ? this.focusedOptionId() : undefined; } onListFocus(event) { if (!this.focused) { this.focused = true; this.onFocus.emit(event); } } onListBlur(event) { if (this.focused) { this.focused = false; this.changeFocusedOptionIndex(-1); this.selectedOptionIndex.set(-1); this.focusedOptionIndex.set(-1); this.onBlur.emit(event); } } onListKeyDown(event) { switch (event.code) { case 'ArrowDown': this.onArrowDownKey(event); break; case 'ArrowUp': this.onArrowUpKey(event); break; case 'Home': this.onHomeKey(event); break; case 'End': this.onEndKey(event); break; case 'Enter': this.onEnterKey(event); break; case 'NumpadEnter': this.onEnterKey(event); break; case 'Space': this.onSpaceKey(event); break; case 'Escape': case 'Tab': if (this.popup) { DomHandler.focus(this.target); this.hide(); } this.overlayVisible && this.hide(); break; default: break; } } onArrowDownKey(event) { const optionIndex = this.findNextOptionIndex(this.focusedOptionIndex()); this.changeFocusedOptionIndex(optionIndex); event.preventDefault(); } onArrowUpKey(event) { if (event.altKey && this.popup) { DomHandler.focus(this.target); this.hide(); event.preventDefault(); } else { const optionIndex = this.findPrevOptionIndex(this.focusedOptionIndex()); this.changeFocusedOptionIndex(optionIndex); event.preventDefault(); } } onHomeKey(event) { this.changeFocusedOptionIndex(0); event.preventDefault(); } onEndKey(event) { this.changeFocusedOptionIndex(DomHandler.find(this.containerViewChild.nativeElement, 'li[data-pc-section="menuitem"][data-p-disabled="false"]').length - 1); event.preventDefault(); } onEnterKey(event) { const element = DomHandler.findSingle(this.containerViewChild.nativeElement, `li[id="${`${this.focusedOptionIndex()}`}"]`); const anchorElement = element && DomHandler.findSingle(element, 'a[data-pc-section="action"]'); this.popup && DomHandler.focus(this.target); anchorElement ? anchorElement.click() : element && element.click(); event.preventDefault(); } onSpaceKey(event) { this.onEnterKey(event); } findNextOptionIndex(index) { const links = DomHandler.find(this.containerViewChild.nativeElement, 'li[data-pc-section="menuitem"][data-p-disabled="false"]'); const matchedOptionIndex = [...links].findIndex((link) => link.id === index); return matchedOptionIndex > -1 ? matchedOptionIndex + 1 : 0; } findPrevOptionIndex(index) { const links = DomHandler.find(this.containerViewChild.nativeElement, 'li[data-pc-section="menuitem"][data-p-disabled="false"]'); const matchedOptionIndex = [...links].findIndex((link) => link.id === index); return matchedOptionIndex > -1 ? matchedOptionIndex - 1 : 0; } changeFocusedOptionIndex(index) { const links = DomHandler.find(this.containerViewChild.nativeElement, 'li[data-pc-section="menuitem"][data-p-disabled="false"]'); if (links.length > 0) { let order = index >= links.length ? links.length - 1 : index < 0 ? 0 : index; order > -1 && this.focusedOptionIndex.set(links[order].getAttribute('id')); } } itemClick(event, id) { const { originalEvent, item } = event; if (!this.focused) { this.focused = true; this.onFocus.emit(); } if (item.disabled) { originalEvent.preventDefault(); return; } if (!item.url && !item.routerLink) { originalEvent.preventDefault(); } if (item.command) { item.command({ originalEvent: originalEvent, item: item }); } if (this.popup) { this.hide(); } if (!this.popup && this.focusedOptionIndex() !== id) { this.focusedOptionIndex.set(id); } } onOverlayClick(event) { if (this.popup) { this.overlayService.add({ originalEvent: event, target: this.el.nativeElement }); } this.preventDocumentDefault = true; } bindDocumentClickListener() { if (!this.documentClickListener && isPlatformBrowser(this.platformId)) { const documentTarget = this.el ? this.el.nativeElement.ownerDocument : 'document'; this.documentClickListener = this.renderer.listen(documentTarget, 'click', (event) => { const isOutsideContainer = this.containerViewChild.nativeElement && !this.containerViewChild.nativeElement.contains(event.target); const isOutsideTarget = !(this.target && (this.target === event.target || this.target.contains(event.target))); if (!this.popup && isOutsideContainer && isOutsideTarget) { this.onListBlur(event); } if (this.preventDocumentDefault && this.overlayVisible && isOutsideContainer && isOutsideTarget) { this.hide(); this.preventDocumentDefault = false; } }); } } unbindDocumentClickListener() { if (this.documentClickListener) { this.documentClickListener(); this.documentClickListener = null; } } bindDocumentResizeListener() { if (!this.documentResizeListener && isPlatformBrowser(this.platformId)) { const window = this.document.defaultView; this.documentResizeListener = this.renderer.listen(window, 'resize', this.onWindowResize.bind(this)); } } unbindDocumentResizeListener() { if (this.documentResizeListener) { this.documentResizeListener(); this.documentResizeListener = null; } } bindScrollListener() { if (!this.scrollHandler && isPlatformBrowser(this.platformId)) { this.scrollHandler = new ConnectedOverlayScrollHandler(this.target, () => { if (this.visible) { this.hide(); } }); } this.scrollHandler?.bindScrollListener(); } unbindScrollListener() { if (this.scrollHandler) { this.scrollHandler.unbindScrollListener(); } } onOverlayHide() { this.unbindDocumentClickListener(); this.unbindDocumentResizeListener(); this.unbindScrollListener(); this.preventDocumentDefault = false; if (!this.cd.destroyed) { this.target = null; } } ngOnDestroy() { if (this.popup) { if (this.scrollHandler) { this.scrollHandler.destroy(); this.scrollHandler = null; } if (this.container && this.autoZIndex) { ZIndexUtils.clear(this.container); } this.restoreOverlayAppend(); this.onOverlayHide(); } if (!this.popup) { this.unbindDocumentClickListener(); } } hasSubMenu() { if (this.model) { for (var item of this.model) { if (item.items) { return true; } } } return false; } isItemHidden(item) { if (item.separator) { return item.visible === false || (item.items && item.items.some((subitem) => subitem.visible !== false)); } return item.visible === false; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: Menu, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i5.PrimeNGConfig }, { token: i5.OverlayService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "17.3.7", type: Menu, selector: "p-menu", inputs: { model: "model", popup: ["popup", "popup", booleanAttribute], style: "style", styleClass: "styleClass", appendTo: "appendTo", autoZIndex: ["autoZIndex", "autoZIndex", booleanAttribute], baseZIndex: ["baseZIndex", "baseZIndex", numberAttribute], showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", id: "id", tabindex: ["tabindex", "tabindex", numberAttribute] }, outputs: { onShow: "onShow", onHide: "onHide", onBlur: "onBlur", onFocus: "onFocus" }, host: { classAttribute: "p-element" }, queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "listViewChild", first: true, predicate: ["list"], descendants: true }, { propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `