From 75a070d64a6b6b97570a77dbab0c5a3808890257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87etin?= <69278826+cetincakiroglu@users.noreply.github.com> Date: Wed, 27 Sep 2023 18:28:30 +0300 Subject: [PATCH] Fixed #13763 - Add MenuItem API id property support for menu components --- src/app/components/breadcrumb/breadcrumb.ts | 16 +++--- src/app/components/contextmenu/contextmenu.ts | 35 ++++++++----- src/app/components/dock/dock.ts | 16 +++--- src/app/components/megamenu/megamenu.ts | 39 ++++++++------- src/app/components/menubar/menubar.ts | 40 +++++++++------ src/app/components/panelmenu/panelmenu.ts | 36 ++++++------- src/app/components/slidemenu/slidemenu.ts | 50 ++++++++++++------- src/app/components/steps/steps.ts | 3 +- src/app/components/tieredmenu/tieredmenu.ts | 28 +++++------ 9 files changed, 143 insertions(+), 120 deletions(-) diff --git a/src/app/components/breadcrumb/breadcrumb.ts b/src/app/components/breadcrumb/breadcrumb.ts index 0122a85ad8f..3f70c88e507 100755 --- a/src/app/components/breadcrumb/breadcrumb.ts +++ b/src/app/components/breadcrumb/breadcrumb.ts @@ -13,9 +13,9 @@ import { BreadcrumbItemClickEvent } from './breadcrumb.interface'; @Component({ selector: 'p-breadcrumb', template: ` -
- -
+ + `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, diff --git a/src/app/components/contextmenu/contextmenu.ts b/src/app/components/contextmenu/contextmenu.ts index be9f044e328..26c9a783b21 100755 --- a/src/app/components/contextmenu/contextmenu.ts +++ b/src/app/components/contextmenu/contextmenu.ts @@ -236,7 +236,7 @@ export class ContextMenuSub { } getItemId(processedItem: any): string { - return `${this.menuId}_${processedItem.key}`; + return processedItem.item && processedItem.item?.id ? processedItem.item.id : `${this.menuId}_${processedItem.key}`; } getItemKey(processedItem: any): string { @@ -489,7 +489,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { activeItemPath = signal([]); - focusedItemInfo = signal({ index: -1, level: 0, parentKey: '' }); + focusedItemInfo = signal({ index: -1, level: 0, parentKey: '', item: null }); submenuVisible = signal(false); @@ -515,8 +515,8 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { } get focusedItemId() { - const focusedItemInfo = this.focusedItemInfo(); - return focusedItemInfo.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItemInfo.parentKey) ? '_' + focusedItemInfo.parentKey : ''}_${focusedItemInfo.index}` : null; + const focusedItem = this.focusedItemInfo(); + return focusedItem.item && focusedItem.item?.id ? focusedItem.item.id : focusedItem.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItem.parentKey) ? '_' + focusedItem.parentKey : ''}_${focusedItem.index}` : null; } constructor( @@ -668,10 +668,10 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { const selected = this.isSelected(processedItem); if (selected) { - const { index, key, level, parentKey } = processedItem; + const { index, key, level, parentKey, item } = processedItem; this.activeItemPath.set(this.activeItemPath().filter((p) => key !== p.key && key.startsWith(p.key))); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); DomHandler.focus(this.rootmenu.sublistViewChild.nativeElement); } else { @@ -757,7 +757,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key, item: processedItem.item }); this.searchValue = ''; this.onArrowDownKey(event); } @@ -790,7 +790,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { const root = ObjectUtils.isEmpty(processedItem.parent); if (!root) { - this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '' }); + this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '', item: processedItem.item }); this.searchValue = ''; this.onArrowDownKey(event); } @@ -817,13 +817,16 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { onEscapeKey(event: KeyboardEvent) { this.hide(); + const processedItem = this.findVisibleItem(this.findFirstFocusedItemIndex()); this.focusedItemInfo.mutate((value) => { value.index = this.findFirstFocusedItemIndex(); + value.item = processedItem.item }); event.preventDefault(); } + onTabKey(event: KeyboardEvent) { if (this.focusedItemInfo().index !== -1) { const processedItem = this.visibleItems[this.focusedItemInfo().index]; @@ -867,7 +870,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { activeItemPath.push(processedItem); this.submenuVisible.set(true); } - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item: processedItem.item }); this.activeItemPath.set(activeItemPath); isFocus && DomHandler.focus(this.rootmenu.sublistViewChild.nativeElement); @@ -875,14 +878,14 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { onMenuFocus(event: any) { this.focused = true; - const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: -1, level: 0, parentKey: '' }; + const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: -1, level: 0, parentKey: '', item: null }; this.focusedItemInfo.set(focusedItemInfo); } onMenuBlur(event: any) { this.focused = false; - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); this.searchValue = ''; } @@ -939,7 +942,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { hide() { this.visible.set(false); this.activeItemPath.set([]); - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null}); } toggle(event?: any) { @@ -948,7 +951,7 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { show(event: any) { this.activeItemPath.set([]); - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); this.pageX = event.pageX; this.pageY = event.pageY; @@ -1027,6 +1030,10 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { return matched; } + findVisibleItem(index) { + return ObjectUtils.isNotEmpty(this.visibleItems) ? this.visibleItems[index] : null; + } + findLastFocusedItemIndex() { const selectedIndex = this.findSelectedItemIndex(); return selectedIndex < 0 ? this.findLastItemIndex() : selectedIndex; @@ -1063,9 +1070,11 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy { } changeFocusedItemIndex(event: any, index: number) { + const processedItem = this.findVisibleItem(index); if (this.focusedItemInfo().index !== index) { this.focusedItemInfo.mutate((value) => { value.index = index; + value.item = processedItem.item; }); this.scrollInView(); } diff --git a/src/app/components/dock/dock.ts b/src/app/components/dock/dock.ts index 8504d102f81..3816f45d475 100755 --- a/src/app/components/dock/dock.ts +++ b/src/app/components/dock/dock.ts @@ -34,15 +34,15 @@ import { DomHandler } from 'primeng/dom'; >
  • @@ -55,7 +55,6 @@ import { DomHandler } from 'primeng/dom'; class="p-dock-link" [routerLinkActiveOptions]="item.routerLinkActiveOptions || { exact: false }" [target]="item.target" - [attr.id]="item.id" [attr.tabindex]="item.disabled || readonly ? null : item.tabindex ? item.tabindex : '-1'" pTooltip [tooltipOptions]="item.tooltipOptions" @@ -80,7 +79,6 @@ import { DomHandler } from 'primeng/dom'; [tooltipOptions]="item.tooltipOptions" [ngClass]="{ 'p-disabled': item.disabled }" [target]="item.target" - [attr.id]="item.id" [attr.tabindex]="item.disabled || (i !== activeIndex && readonly) ? null : item.tabindex ? item.tabindex : '-1'" [attr.aria-hidden]="true" > @@ -190,8 +188,8 @@ export class Dock implements AfterContentInit { }); } - getItemId(index) { - return `${index}`; + getItemId(item, index) { + return item && item?.id ? item.id : `${index}`; } getItemProp(processedItem, name) { @@ -347,7 +345,7 @@ export class Dock implements AfterContentInit { return item.routerLink && !item.disabled; } - itemClass(index: number) { + itemClass(item, index: number) { return { 'p-dock-item': true, 'p-dock-item-second-prev': this.currentIndex - 2 === index, @@ -355,7 +353,7 @@ export class Dock implements AfterContentInit { 'p-dock-item-current': this.currentIndex === index, 'p-dock-item-next': this.currentIndex + 1 === index, 'p-dock-item-second-next': this.currentIndex + 2 === index, - 'p-focus': this.isItemActive(this.getItemId(index)) + 'p-focus': this.isItemActive(this.getItemId(item, index)) }; } } diff --git a/src/app/components/megamenu/megamenu.ts b/src/app/components/megamenu/megamenu.ts index 1e9a6d684a9..497e216c683 100755 --- a/src/app/components/megamenu/megamenu.ts +++ b/src/app/components/megamenu/megamenu.ts @@ -238,7 +238,7 @@ export class MegaMenuSub { } getItemId(processedItem: any): string { - return `${this.menuId}_${processedItem.key}`; + return processedItem.item && processedItem.item?.id ? processedItem.item.id : `${this.menuId}_${processedItem.key}`; } getSubListId(processedItem) { @@ -468,7 +468,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { activeItem = signal(null); - focusedItemInfo = signal({ index: -1, level: 0, parentKey: '' }); + focusedItemInfo = signal({ index: -1, level: 0, parentKey: '', item: null }); searchValue: string = ''; @@ -502,7 +502,8 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { } get focusedItemId() { - return ObjectUtils.isNotEmpty(this.focusedItemInfo().key) ? `${this.id}_${this.focusedItemInfo().key}` : null; + const focusedItem = this.focusedItemInfo(); + return focusedItem?.item && focusedItem.item?.id ? focusedItem.item.id : ObjectUtils.isNotEmpty(focusedItem.key) ? `${this.id}_${focusedItem.key}` : null; } constructor(@Inject(DOCUMENT) private document: Document, @Inject(PLATFORM_ID) private platformId: any, public el: ElementRef, public renderer: Renderer2, public config: PrimeNGConfig, public cd: ChangeDetectorRef) { @@ -564,7 +565,6 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { level === 0 && item.items && item.items.length > 0 ? item.items.map((_items, _index) => this.createProcessedItems(_items, level + 1, newItem, key, _index)) : this.createProcessedItems(item.items, level + 1, newItem, key); processedItems.push(newItem); }); - return processedItems; } @@ -579,10 +579,10 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { const selected = this.isSelected(processedItem); if (selected) { - const { index, key, parentKey } = processedItem; + const { index, key, parentKey, item } = processedItem; this.activeItem.set(null); - this.focusedItemInfo.set({ index, key, parentKey }); + this.focusedItemInfo.set({ index, key, parentKey, item }); this.dirty = !root; DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); @@ -621,13 +621,13 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { if (ObjectUtils.isEmpty(processedItem)) return; - const { index, key, parentKey, items } = processedItem; + const { index, key, parentKey, items, item } = processedItem; const grouped = ObjectUtils.isNotEmpty(items); if (grouped) { this.activeItem.set(processedItem); } - this.focusedItemInfo.set({ index, key, parentKey }); + this.focusedItemInfo.set({ index, key, parentKey, item }); grouped && (this.dirty = true); isFocus && DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); @@ -635,7 +635,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { hide(event?, isFocus?: boolean) { this.activeItem.set(null); - this.focusedItemInfo.set({ index: -1, key: '', parentKey: '' }); + this.focusedItemInfo.set({ index: -1, key: '', parentKey: '', item: null }); isFocus && DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); this.dirty = false; @@ -647,13 +647,13 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { const index = this.findFirstFocusedItemIndex(); const processedItem = this.findVisibleItem(index); - this.focusedItemInfo.set({ index, key: processedItem.key, parentKey: processedItem.parentKey }); + this.focusedItemInfo.set({ index, key: processedItem.key, parentKey: processedItem.parentKey, item: processedItem.item }); } } onMenuBlur(event: any) { this.focused = false; - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); this.searchValue = ''; this.dirty = false; } @@ -815,6 +815,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { this.focusedItemInfo.mutate((value) => { value.index = index; value.key = ObjectUtils.isNotEmpty(processedItem) ? processedItem.key : ''; + value.item = processedItem.item; }); this.scrollInView(); @@ -823,14 +824,16 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { onArrowDownKey(event: KeyboardEvent) { if (this.orientation === 'horizontal') { if (ObjectUtils.isNotEmpty(this.activeItem()) && this.activeItem().key === this.focusedItemInfo().key) { - this.focusedItemInfo.set({ index: -1, key: '', parentKey: this.activeItem().key }); + const { key, item } = this.activeItem(); + this.focusedItemInfo.set({ index: -1, key: '', parentKey: key, item }); } else { const processedItem = this.findVisibleItem(this.focusedItemInfo().index); const grouped = this.isProccessedItemGroup(processedItem); if (grouped) { + const { parentKey, key, item } = processedItem; this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, key: processedItem.key, parentKey: processedItem.parentKey }); + this.focusedItemInfo.set({ index: -1, key: key, parentKey: parentKey, item: item }); this.searchValue = ''; } } @@ -848,14 +851,14 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { if (grouped) { if (this.orientation === 'vertical') { if (ObjectUtils.isNotEmpty(this.activeItem()) && this.activeItem().key === processedItem.key) { - this.focusedItemInfo.set({ index: -1, key: '', parentKey: this.activeItem().key }); + this.focusedItemInfo.set({ index: -1, key: '', parentKey: this.activeItem().key, item: processedItem.item }); } else { const processedItem = this.findVisibleItem(this.focusedItemInfo().index); const grouped = this.isProccessedItemGroup(processedItem); if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, key: processedItem.key, parentKey: processedItem.parentKey }); + this.focusedItemInfo.set({ index: -1, key: processedItem.key, parentKey: processedItem.parentKey, item: processedItem.item }); this.searchValue = ''; } } @@ -882,7 +885,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { if (!grouped && ObjectUtils.isNotEmpty(this.activeItem)) { if (this.focusedItemInfo().index === 0) { - this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key, parentKey: this.activeItem().parentKey }); + this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key, parentKey: this.activeItem().parentKey, item: processedItem.item }); this.activeItem.set(null); } else { this.changeFocusedItemInfo(event, this.findFirstItemIndex()); @@ -912,7 +915,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { } else { if (this.orientation === 'vertical' && ObjectUtils.isNotEmpty(this.activeItem())) { if (processedItem.columnIndex === 0) { - this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key, parentKey: this.activeItem().parentKey }); + this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key, parentKey: this.activeItem().parentKey, item: processedItem.item }); this.activeItem.set(null); } } @@ -942,7 +945,7 @@ export class MegaMenu implements AfterContentInit, OnDestroy, OnInit { onEscapeKey(event: KeyboardEvent) { if (ObjectUtils.isNotEmpty(this.activeItem())) { - this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key }); + this.focusedItemInfo.set({ index: this.activeItem().index, key: this.activeItem().key, item: this.activeItem().item }); this.activeItem.set(null); } diff --git a/src/app/components/menubar/menubar.ts b/src/app/components/menubar/menubar.ts index 592374f341b..243c4b0d87f 100755 --- a/src/app/components/menubar/menubar.ts +++ b/src/app/components/menubar/menubar.ts @@ -256,7 +256,7 @@ export class MenubarSub implements OnInit, OnDestroy { } getItemId(processedItem: any): string { - return `${this.menuId}_${processedItem.key}`; + return processedItem.item && processedItem.item?.id ? processedItem.item.id : `${this.menuId}_${processedItem.key}`; } getItemKey(processedItem: any): string { @@ -502,7 +502,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { number = signal(0); - focusedItemInfo = signal({ index: -1, level: 0, parentKey: '' }); + focusedItemInfo = signal({ index: -1, level: 0, parentKey: '', item: null }); searchValue: string = ''; @@ -526,8 +526,8 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { } get focusedItemId() { - const focusedItemInfo = this.focusedItemInfo(); - return focusedItemInfo.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItemInfo.parentKey) ? '_' + focusedItemInfo.parentKey : ''}_${focusedItemInfo.index}` : null; + const focusedItem = this.focusedItemInfo(); + return focusedItem.item && focusedItem.item?.id ? focusedItem.item.id : focusedItem.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItem.parentKey) ? '_' + focusedItem.parentKey : ''}_${focusedItem.index}` : null; } constructor( @@ -622,10 +622,10 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { const selected = this.isSelected(processedItem); if (selected) { - const { index, key, level, parentKey } = processedItem; + const { index, key, level, parentKey, item } = processedItem; this.activeItemPath.set(this.activeItemPath().filter((p) => key !== p.key && key.startsWith(p.key))); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); this.dirty = !root; DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); @@ -652,9 +652,11 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { } changeFocusedItemIndex(event: any, index: number) { + const processedItem = this.findVisibleItem(index); if (this.focusedItemInfo().index !== index) { this.focusedItemInfo.mutate((value) => { value.index = index; + value.item = processedItem.item; }); this.scrollInView(); } @@ -674,12 +676,12 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { if (ObjectUtils.isEmpty(processedItem)) return; - const { index, key, level, parentKey, items } = processedItem; + const { index, key, level, parentKey, items, item } = processedItem; const grouped = ObjectUtils.isNotEmpty(items); const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== parentKey && p.parentKey !== key); grouped && activeItemPath.push(processedItem); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); this.activeItemPath.set(activeItemPath); grouped && (this.dirty = true); @@ -711,20 +713,22 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { } this.activeItemPath.set([]); - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); isFocus && DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); this.dirty = false; } show() { - this.focusedItemInfo.set({ index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' }); + const processedItem = this.findVisibleItem(this.findFirstFocusedItemIndex()); + this.focusedItemInfo.set({ index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' , item: processedItem.item}); DomHandler.focus(this.rootmenu.menubarViewChild.nativeElement); } onMenuFocus(event: any) { this.focused = true; - const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' }; + const processedItem = this.findVisibleItem(this.findFirstFocusedItemIndex()); + const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '', item: processedItem.item }; this.focusedItemInfo.set(focusedItemInfo); this.onFocus.emit(event); @@ -732,7 +736,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { onMenuBlur(event: any) { this.focused = false; - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); this.searchValue = ''; this.dirty = false; this.onBlur.emit(event); @@ -799,6 +803,10 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { } } + findVisibleItem(index) { + return ObjectUtils.isNotEmpty(this.visibleItems) ? this.visibleItems[index] : null; + } + findFirstFocusedItemIndex() { const selectedIndex = this.findSelectedItemIndex(); @@ -899,7 +907,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key, item: processedItem.item }); this.onArrowRightKey(event); } } else { @@ -919,7 +927,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key, item: processedItem.item }); this.onArrowDownKey(event); } } else { @@ -939,7 +947,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key, item: processedItem.item }); const itemIndex = this.findLastItemIndex(); this.changeFocusedItemIndex(event, itemIndex); @@ -947,7 +955,7 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { } else { const parentItem = this.activeItemPath().find((p) => p.key === processedItem.parentKey); if (this.focusedItemInfo().index === 0) { - this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '' }); + this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '', item: processedItem.item }); this.searchValue = ''; this.onArrowLeftKey(event); const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== this.focusedItemInfo().parentKey); diff --git a/src/app/components/panelmenu/panelmenu.ts b/src/app/components/panelmenu/panelmenu.ts index 32f17035aac..5bc429c8b19 100644 --- a/src/app/components/panelmenu/panelmenu.ts +++ b/src/app/components/panelmenu/panelmenu.ts @@ -193,7 +193,7 @@ export class PanelMenuSub { constructor(@Inject(forwardRef(() => PanelMenu)) public panelMenu: PanelMenu, public el: ElementRef) {} getItemId(processedItem) { - return `${this.panelId}_${processedItem.key}`; + return processedItem.item?.id ?? `${this.panelId}_${processedItem.key}`; } getItemKey(processedItem) { @@ -324,7 +324,8 @@ export class PanelMenuList implements OnChanges { }); get focusedItemId() { - return ObjectUtils.isNotEmpty(this.focusedItem()) ? `${this.panelId}_${this.focusedItem().key}` : undefined; + const focusedItem = this.focusedItem(); + return focusedItem && focusedItem.item?.id ? focusedItem.item.id : ObjectUtils.isNotEmpty(this.focusedItem()) ? `${this.panelId}_${this.focusedItem().key}` : undefined; } ngOnChanges(changes: SimpleChanges) { @@ -372,7 +373,7 @@ export class PanelMenuList implements OnChanges { } isValidItem(processedItem) { - return !!processedItem && !this.isItemDisabled(processedItem); + return !!processedItem && !this.isItemDisabled(processedItem) && !processedItem.separator; } findFirstItem() { @@ -531,7 +532,6 @@ export class PanelMenuList implements OnChanges { onArrowDownKey(event) { const processedItem = ObjectUtils.isNotEmpty(this.focusedItem()) ? this.findNextItem(this.focusedItem()) : this.findFirstItem(); - this.changeFocusedItem({ originalEvent: event, processedItem, focusOnNext: true }); event.preventDefault(); } @@ -606,13 +606,13 @@ export class PanelMenuList implements OnChanges { findNextItem(processedItem) { const index = this.visibleItems().findIndex((item) => item.key === processedItem.key); + const matchedItem = index < this.visibleItems().length - 1 ? this.visibleItems() .slice(index + 1) .find((pItem) => this.isValidItem(pItem)) : undefined; - return matchedItem || processedItem; } @@ -688,13 +688,13 @@ export class PanelMenuList implements OnChanges { [class]="getItemProp(item, 'styleClass')" [ngStyle]="getItemProp(item, 'style')" [pTooltip]="getItemProp(item, 'tooltip')" - [id]="getHeaderId(i)" + [id]="getHeaderId(item, i)" [tabindex]="0" role="button" [tooltipOptions]="getItemProp(item, 'tooltipOptions')" [attr.aria-expanded]="isItemActive(item)" [attr.aria-label]="getItemProp(item, 'label')" - [attr.aria-controls]="getContentId(i)" + [attr.aria-controls]="getContentId(item, i)" [attr.aria-disabled]="isItemDisabled(item)" [attr.data-p-highlight]="isItemActive(item)" [attr.data-p-disabled]="isItemDisabled(item)" @@ -762,13 +762,13 @@ export class PanelMenuList implements OnChanges { [@rootItem]="getAnimation(item)" (@rootItem.done)="onToggleDone()" role="region" - [id]="getContentId(i)" - [attr.aria-labelledby]="getHeaderId(i)" + [id]="getContentId(item, i)" + [attr.aria-labelledby]="getHeaderId(item, i)" [attr.data-pc-section]="'toggleablecontent'" >
    (value.index = -1)); + this.focusedItemInfo.mutate((value) => { + value.index = -1; + value.item = null; + }); break; default: break; @@ -837,9 +840,10 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { const processedItem = this.visibleItems[this.focusedItemInfo().index]; const grouped = this.isProccessedItemGroup(processedItem); if (grouped) { - let { index, level, key } = processedItem; + let { index, level, key, item } = processedItem; this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: 0, level: processedItem.level, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: 0, level: level, parentKey: key}); + this.searchValue = ''; this.animate('right'); } @@ -878,7 +882,7 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { if (!root) { let { level, index, parentKey } = parentItem; - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item: parentItem.item }); this.searchValue = ''; } @@ -905,7 +909,10 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { onEscapeKey(event: KeyboardEvent) { if (this.popup) { this.hide(event, true); - this.focusedItemInfo().index = this.findFirstFocusedItemIndex(); + this.focusedItemInfo.mutate(value => { + value.index = this.findLastFocusedItemIndex(); + value.item = null; + }) event.preventDefault(); } @@ -934,7 +941,10 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { const anchorElement = element && DomHandler.findSingle(element, 'a[data-pc-section="action"]'); anchorElement ? anchorElement.click() : element && element.click(); - this.focusedItemInfo.mutate((value) => (value.index = processedItem.index)); + this.focusedItemInfo.mutate((value) => { + value.index = processedItem.index; + value.item = processedItem.item; + }); } } @@ -945,24 +955,24 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { const { processedItem, isFocus } = event; if (ObjectUtils.isEmpty(processedItem)) return; - const { index, key, level, parentKey, items } = processedItem; + const { index, key, level, parentKey, items, item } = processedItem; const grouped = ObjectUtils.isNotEmpty(items); const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== parentKey && p.parentKey !== key); grouped && activeItemPath.push(processedItem); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); this.activeItemPath.set(activeItemPath); isFocus && DomHandler.focus(this.rootmenu.sublistViewChild.nativeElement); } onMenuFocus() { this.focused = true; - + this.bindOutsideClickListener(); this.bindTransitionListeners(); if (!this.left && this.focusedItemInfo().level > 0) { - this.focusedItemInfo.set({ index: 0, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: 0, level: 0, parentKey: '', item: this.findVisibleItem(0).item }); } if (this.focusedItemInfo().index === -1 && this.left < 0) { @@ -970,16 +980,17 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { } if (this.focusedItemInfo().index === -1 && !this.left) { - this.focusedItemInfo.set({ index: 0, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: 0, level: 0, parentKey: '', item: this.findVisibleItem(0).item}); } } onMenuBlur() { this.focused = false; - this.popup && this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.popup && this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); if (!this.popup) { this.focusedItemInfo.mutate((value) => { value.index = -1; + value.item = null; }); } this.searchValue = ''; @@ -1014,7 +1025,6 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { this.activeItemPath.set(newActiveItemPath); } } - this.transition = false; event.preventDefault(); }); @@ -1166,6 +1176,10 @@ export class SlideMenu implements OnInit, AfterContentInit, OnDestroy { return matched; } + findVisibleItem(index) { + return ObjectUtils.isNotEmpty(this.visibleItems) ? this.visibleItems[index] : null; + } + findLastFocusedItemIndex() { const selectedIndex = this.findSelectedItemIndex(); return selectedIndex < 0 ? this.findLastItemIndex() : selectedIndex; diff --git a/src/app/components/steps/steps.ts b/src/app/components/steps/steps.ts index af6aaa7b8f4..9f67dcf88c1 100755 --- a/src/app/components/steps/steps.ts +++ b/src/app/components/steps/steps.ts @@ -24,6 +24,7 @@ import { Subscription } from 'rxjs'; role="tab" [attr.aria-selected]="i === activeIndex" [attr.aria-expanded]="i === activeIndex" + [attr.id]="item.id" pTooltip [tooltipOptions]="item.tooltipOptions" [ngClass]="{ 'p-highlight p-steps-current': isActive(item, i), 'p-disabled': item.disabled || (readonly && !isActive(item, i)) }" @@ -40,7 +41,6 @@ import { Subscription } from 'rxjs'; (click)="onItemClick($event, item, i)" (keydown)="onItemKeydown($event, item, i)" [target]="item.target" - [attr.id]="item.id" [attr.tabindex]="item.disabled || readonly ? null : item.tabindex ? item.tabindex : '-1'" [fragment]="item.fragment" [queryParamsHandling]="item.queryParamsHandling" @@ -62,7 +62,6 @@ import { Subscription } from 'rxjs'; (click)="onItemClick($event, item, i)" (keydown)="onItemKeydown($event, item, i)" [target]="item.target" - [attr.id]="item.id" [attr.tabindex]="item.disabled || (i !== activeIndex && readonly) ? null : item.tabindex ? item.tabindex : '-1'" [ariaCurrentWhenActive]="exact ? 'step' : undefined" > diff --git a/src/app/components/tieredmenu/tieredmenu.ts b/src/app/components/tieredmenu/tieredmenu.ts index 0350491e5aa..3f2f0a202c1 100755 --- a/src/app/components/tieredmenu/tieredmenu.ts +++ b/src/app/components/tieredmenu/tieredmenu.ts @@ -45,7 +45,7 @@ import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils'; [tabindex]="tabindex" [attr.aria-label]="ariaLabel" [attr.aria-labelledBy]="ariaLabelledBy" - [attr.aria-aria-activedescendant]="focusedItemId" + [attr.aria-activedescendant]="focusedItemId" [attr.aria-orientation]="'vertical'" [attr.data-pc-section]="'menu'" (keydown)="menuKeydown.emit($event)" @@ -245,7 +245,7 @@ export class TieredMenuSub { } getItemId(processedItem: any): string { - return `${this.menuId}_${processedItem.key}`; + return processedItem.item?.id ?? `${this.menuId}_${processedItem.key}`; } getItemKey(processedItem: any): string { @@ -496,7 +496,7 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { number = signal(0); - focusedItemInfo = signal({ index: -1, level: 0, parentKey: '' }); + focusedItemInfo = signal({ index: -1, level: 0, parentKey: '', item: null }); searchValue: string = ''; @@ -508,7 +508,6 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { get visibleItems() { const processedItem = this.activeItemPath().find((p) => p.key === this.focusedItemInfo().parentKey); - return processedItem ? processedItem.items : this.processedItems; } @@ -521,7 +520,7 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { get focusedItemId() { const focusedItemInfo = this.focusedItemInfo(); - return focusedItemInfo.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItemInfo.parentKey) ? '_' + focusedItemInfo.parentKey : ''}_${focusedItemInfo.index}` : null; + return focusedItemInfo.item?.id ? focusedItemInfo.item.id : focusedItemInfo.index !== -1 ? `${this.id}${ObjectUtils.isNotEmpty(focusedItemInfo.parentKey) ? '_' + focusedItemInfo.parentKey : ''}_${focusedItemInfo.index}` : null; } constructor( @@ -643,10 +642,10 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { const selected = this.isSelected(processedItem); if (selected) { - const { index, key, level, parentKey } = processedItem; + const { index, key, level, parentKey, item } = processedItem; this.activeItemPath.set(this.activeItemPath().filter((p) => key !== p.key && key.startsWith(p.key))); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); this.dirty = true; DomHandler.focus(this.rootmenu.sublistViewChild.nativeElement); @@ -744,10 +743,11 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { onArrowRightKey(event: KeyboardEvent) { const processedItem = this.visibleItems[this.focusedItemInfo().index]; const grouped = this.isProccessedItemGroup(processedItem); + const item = processedItem.item; if (grouped) { this.onItemChange({ originalEvent: event, processedItem }); - this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key }); + this.focusedItemInfo.set({ index: -1, parentKey: processedItem.key, item}); this.searchValue = ''; this.onArrowDownKey(event); } @@ -780,7 +780,7 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { const root = ObjectUtils.isEmpty(processedItem.parent); if (!root) { - this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '' }); + this.focusedItemInfo.set({ index: -1, parentKey: parentItem ? parentItem.parentKey : '', item: processedItem.item }); this.searchValue = ''; this.onArrowDownKey(event); } @@ -847,12 +847,12 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { if (ObjectUtils.isEmpty(processedItem)) return; - const { index, key, level, parentKey, items } = processedItem; + const { index, key, level, parentKey, items, item } = processedItem; const grouped = ObjectUtils.isNotEmpty(items); const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== parentKey && p.parentKey !== key); grouped && activeItemPath.push(processedItem); - this.focusedItemInfo.set({ index, level, parentKey }); + this.focusedItemInfo.set({ index, level, parentKey, item }); this.activeItemPath.set(activeItemPath); grouped && (this.dirty = true); @@ -861,14 +861,13 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { onMenuFocus(event: any) { this.focused = true; - const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' }; - + const focusedItemInfo = this.focusedItemInfo().index !== -1 ? this.focusedItemInfo() : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '', item: this.visibleItems[this.findFirstFocusedItemIndex()]?.item }; this.focusedItemInfo.set(focusedItemInfo); } onMenuBlur(event: any) { this.focused = false; - this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '' }); + this.focusedItemInfo.set({ index: -1, level: 0, parentKey: '', item: null }); this.searchValue = ''; this.dirty = false; } @@ -1050,6 +1049,7 @@ export class TieredMenu implements OnInit, AfterContentInit, OnDestroy { if (this.focusedItemInfo().index !== index) { this.focusedItemInfo.mutate((value) => { value.index = index; + value.item = this.visibleItems[index].item; }); this.scrollInView(); }