mirror of
https://github.com/primefaces/primevue.git
synced 2025-05-09 17:02:38 +00:00
Fixed #3802 - Improve folder structure for nuxt configurations
This commit is contained in:
parent
851950270b
commit
f5fe822afb
563 changed files with 1703 additions and 1095 deletions
391
components/lib/panelmenu/PanelMenuList.vue
Normal file
391
components/lib/panelmenu/PanelMenuList.vue
Normal file
|
@ -0,0 +1,391 @@
|
|||
<template>
|
||||
<PanelMenuSub
|
||||
:id="panelId + '_list'"
|
||||
class="p-panelmenu-root-list"
|
||||
role="tree"
|
||||
:tabindex="-1"
|
||||
:aria-activedescendant="focused ? focusedItemId : undefined"
|
||||
:panelId="panelId"
|
||||
:focusedItemId="focused ? focusedItemId : undefined"
|
||||
:items="processedItems"
|
||||
:template="template"
|
||||
:activeItemPath="activeItemPath"
|
||||
:exact="exact"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@keydown="onKeyDown"
|
||||
@item-toggle="onItemToggle"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DomHandler, ObjectUtils } from 'primevue/utils';
|
||||
import PanelMenuSub from './PanelMenuSub.vue';
|
||||
|
||||
export default {
|
||||
name: 'PanelMenuList',
|
||||
emits: ['item-toggle', 'header-focus'],
|
||||
props: {
|
||||
panelId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
template: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
expandedKeys: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
exact: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
searchTimeout: null,
|
||||
searchValue: null,
|
||||
data() {
|
||||
return {
|
||||
focused: false,
|
||||
focusedItem: null,
|
||||
activeItemPath: []
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
expandedKeys(newValue) {
|
||||
this.autoUpdateActiveItemPath(newValue);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.autoUpdateActiveItemPath(this.expandedKeys);
|
||||
},
|
||||
methods: {
|
||||
getItemProp(processedItem, name) {
|
||||
return processedItem && processedItem.item ? ObjectUtils.getItemValue(processedItem.item[name]) : undefined;
|
||||
},
|
||||
getItemLabel(processedItem) {
|
||||
return this.getItemProp(processedItem, 'label');
|
||||
},
|
||||
isItemVisible(processedItem) {
|
||||
return this.getItemProp(processedItem, 'visible') !== false;
|
||||
},
|
||||
isItemDisabled(processedItem) {
|
||||
return this.getItemProp(processedItem, 'disabled');
|
||||
},
|
||||
isItemActive(processedItem) {
|
||||
return this.activeItemPath.some((path) => path.key === processedItem.parentKey);
|
||||
},
|
||||
isItemGroup(processedItem) {
|
||||
return ObjectUtils.isNotEmpty(processedItem.items);
|
||||
},
|
||||
onFocus(event) {
|
||||
this.focused = true;
|
||||
this.focusedItem = this.focusedItem || (this.isElementInPanel(event, event.relatedTarget) ? this.findFirstItem() : this.findLastItem());
|
||||
},
|
||||
onBlur() {
|
||||
this.focused = false;
|
||||
this.focusedItem = null;
|
||||
this.searchValue = '';
|
||||
},
|
||||
onKeyDown(event) {
|
||||
const metaKey = event.metaKey || event.ctrlKey;
|
||||
|
||||
switch (event.code) {
|
||||
case 'ArrowDown':
|
||||
this.onArrowDownKey(event);
|
||||
break;
|
||||
|
||||
case 'ArrowUp':
|
||||
this.onArrowUpKey(event);
|
||||
break;
|
||||
|
||||
case 'ArrowLeft':
|
||||
this.onArrowLeftKey(event);
|
||||
break;
|
||||
|
||||
case 'ArrowRight':
|
||||
this.onArrowRightKey(event);
|
||||
break;
|
||||
|
||||
case 'Home':
|
||||
this.onHomeKey(event);
|
||||
break;
|
||||
|
||||
case 'End':
|
||||
this.onEndKey(event);
|
||||
break;
|
||||
|
||||
case 'Space':
|
||||
this.onSpaceKey(event);
|
||||
break;
|
||||
|
||||
case 'Enter':
|
||||
this.onEnterKey(event);
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
case 'Tab':
|
||||
case 'PageDown':
|
||||
case 'PageUp':
|
||||
case 'Backspace':
|
||||
case 'ShiftLeft':
|
||||
case 'ShiftRight':
|
||||
//NOOP
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!metaKey && ObjectUtils.isPrintableCharacter(event.key)) {
|
||||
this.searchItems(event, event.key);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
onArrowDownKey(event) {
|
||||
const processedItem = ObjectUtils.isNotEmpty(this.focusedItem) ? this.findNextItem(this.focusedItem) : this.findFirstItem();
|
||||
|
||||
this.changeFocusedItem({ originalEvent: event, processedItem, focusOnNext: true });
|
||||
event.preventDefault();
|
||||
},
|
||||
onArrowUpKey(event) {
|
||||
const processedItem = ObjectUtils.isNotEmpty(this.focusedItem) ? this.findPrevItem(this.focusedItem) : this.findLastItem();
|
||||
|
||||
this.changeFocusedItem({ originalEvent: event, processedItem, selfCheck: true });
|
||||
event.preventDefault();
|
||||
},
|
||||
onArrowLeftKey(event) {
|
||||
if (ObjectUtils.isNotEmpty(this.focusedItem)) {
|
||||
const matched = this.activeItemPath.some((p) => p.key === this.focusedItem.key);
|
||||
|
||||
if (matched) {
|
||||
this.activeItemPath = this.activeItemPath.filter((p) => p.key !== this.focusedItem.key);
|
||||
} else {
|
||||
this.focusedItem = ObjectUtils.isNotEmpty(this.focusedItem.parent) ? this.focusedItem.parent : this.focusedItem;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
onArrowRightKey(event) {
|
||||
if (ObjectUtils.isNotEmpty(this.focusedItem)) {
|
||||
const grouped = this.isItemGroup(this.focusedItem);
|
||||
|
||||
if (grouped) {
|
||||
const matched = this.activeItemPath.some((p) => p.key === this.focusedItem.key);
|
||||
|
||||
if (matched) {
|
||||
this.onArrowDownKey(event);
|
||||
} else {
|
||||
this.activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== this.focusedItem.parentKey);
|
||||
this.activeItemPath.push(this.focusedItem);
|
||||
}
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
onHomeKey(event) {
|
||||
this.changeFocusedItem({ originalEvent: event, processedItem: this.findFirstItem(), allowHeaderFocus: false });
|
||||
event.preventDefault();
|
||||
},
|
||||
onEndKey(event) {
|
||||
this.changeFocusedItem({ originalEvent: event, processedItem: this.findLastItem(), focusOnNext: true, allowHeaderFocus: false });
|
||||
event.preventDefault();
|
||||
},
|
||||
onEnterKey(event) {
|
||||
if (ObjectUtils.isNotEmpty(this.focusedItem)) {
|
||||
const element = DomHandler.findSingle(this.$el, `li[id="${`${this.focusedItemId}`}"]`);
|
||||
const anchorElement = element && (DomHandler.findSingle(element, '.p-menuitem-link') || DomHandler.findSingle(element, 'a,button'));
|
||||
|
||||
anchorElement ? anchorElement.click() : element && element.click();
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
},
|
||||
onSpaceKey(event) {
|
||||
this.onEnterKey(event);
|
||||
},
|
||||
onItemToggle(event) {
|
||||
const { processedItem, expanded } = event;
|
||||
|
||||
if (this.expandedKeys) {
|
||||
this.$emit('item-toggle', { item: processedItem.item, expanded });
|
||||
} else {
|
||||
this.activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== processedItem.parentKey);
|
||||
expanded && this.activeItemPath.push(processedItem);
|
||||
}
|
||||
|
||||
this.focusedItem = processedItem;
|
||||
DomHandler.focus(this.$el);
|
||||
},
|
||||
isElementInPanel(event, element) {
|
||||
const panel = event.currentTarget.closest('.p-panelmenu-panel');
|
||||
|
||||
return panel && panel.contains(element);
|
||||
},
|
||||
isItemMatched(processedItem) {
|
||||
return this.isValidItem(processedItem) && this.getItemLabel(processedItem).toLocaleLowerCase(this.searchLocale).startsWith(this.searchValue.toLocaleLowerCase(this.searchLocale));
|
||||
},
|
||||
isVisibleItem(processedItem) {
|
||||
return !!processedItem && (processedItem.level === 0 || this.isItemActive(processedItem)) && this.isItemVisible(processedItem);
|
||||
},
|
||||
isValidItem(processedItem) {
|
||||
return !!processedItem && !this.isItemDisabled(processedItem);
|
||||
},
|
||||
findFirstItem() {
|
||||
return this.visibleItems.find((processedItem) => this.isValidItem(processedItem));
|
||||
},
|
||||
findLastItem() {
|
||||
return ObjectUtils.findLast(this.visibleItems, (processedItem) => this.isValidItem(processedItem));
|
||||
},
|
||||
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;
|
||||
},
|
||||
findPrevItem(processedItem) {
|
||||
const index = this.visibleItems.findIndex((item) => item.key === processedItem.key);
|
||||
const matchedItem = index > 0 ? ObjectUtils.findLast(this.visibleItems.slice(0, index), (pItem) => this.isValidItem(pItem)) : undefined;
|
||||
|
||||
return matchedItem || processedItem;
|
||||
},
|
||||
searchItems(event, char) {
|
||||
this.searchValue = (this.searchValue || '') + char;
|
||||
|
||||
let matchedItem = null;
|
||||
let matched = false;
|
||||
|
||||
if (ObjectUtils.isNotEmpty(this.focusedItem)) {
|
||||
const focusedItemIndex = this.visibleItems.findIndex((processedItem) => processedItem.key === this.focusedItem.key);
|
||||
|
||||
matchedItem = this.visibleItems.slice(focusedItemIndex).find((processedItem) => this.isItemMatched(processedItem));
|
||||
matchedItem = ObjectUtils.isEmpty(matchedItem) ? this.visibleItems.slice(0, focusedItemIndex).find((processedItem) => this.isItemMatched(processedItem)) : matchedItem;
|
||||
} else {
|
||||
matchedItem = this.visibleItems.find((processedItem) => this.isItemMatched(processedItem));
|
||||
}
|
||||
|
||||
if (ObjectUtils.isNotEmpty(matchedItem)) {
|
||||
matched = true;
|
||||
}
|
||||
|
||||
if (ObjectUtils.isEmpty(matchedItem) && ObjectUtils.isEmpty(this.focusedItem)) {
|
||||
matchedItem = this.findFirstItem();
|
||||
}
|
||||
|
||||
if (ObjectUtils.isNotEmpty(matchedItem)) {
|
||||
this.changeFocusedItem({
|
||||
originalEvent: event,
|
||||
processedItem: matchedItem,
|
||||
allowHeaderFocus: false
|
||||
});
|
||||
}
|
||||
|
||||
if (this.searchTimeout) {
|
||||
clearTimeout(this.searchTimeout);
|
||||
}
|
||||
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.searchValue = '';
|
||||
this.searchTimeout = null;
|
||||
}, 500);
|
||||
|
||||
return matched;
|
||||
},
|
||||
changeFocusedItem(event) {
|
||||
const { originalEvent, processedItem, focusOnNext, selfCheck, allowHeaderFocus = true } = event;
|
||||
|
||||
if (ObjectUtils.isNotEmpty(this.focusedItem) && this.focusedItem.key !== processedItem.key) {
|
||||
this.focusedItem = processedItem;
|
||||
this.scrollInView();
|
||||
} else if (allowHeaderFocus) {
|
||||
this.$emit('header-focus', { originalEvent, focusOnNext, selfCheck });
|
||||
}
|
||||
},
|
||||
scrollInView() {
|
||||
const element = DomHandler.findSingle(this.$el, `li[id="${`${this.focusedItemId}`}"]`);
|
||||
|
||||
if (element) {
|
||||
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
||||
}
|
||||
},
|
||||
autoUpdateActiveItemPath(expandedKeys) {
|
||||
this.activeItemPath = Object.entries(expandedKeys || {}).reduce((acc, [key, val]) => {
|
||||
if (val) {
|
||||
const processedItem = this.findProcessedItemByItemKey(key);
|
||||
|
||||
processedItem && acc.push(processedItem);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
},
|
||||
findProcessedItemByItemKey(key, processedItems, level = 0) {
|
||||
processedItems = processedItems || (level === 0 && this.processedItems);
|
||||
|
||||
if (!processedItems) return null;
|
||||
|
||||
for (let i = 0; i < processedItems.length; i++) {
|
||||
const processedItem = processedItems[i];
|
||||
|
||||
if (this.getItemProp(processedItem, 'key') === key) return processedItem;
|
||||
|
||||
const matchedItem = this.findProcessedItemByItemKey(key, processedItem.items, level + 1);
|
||||
|
||||
if (matchedItem) return matchedItem;
|
||||
}
|
||||
},
|
||||
createProcessedItems(items, level = 0, parent = {}, parentKey = '') {
|
||||
const processedItems = [];
|
||||
|
||||
items &&
|
||||
items.forEach((item, index) => {
|
||||
const key = (parentKey !== '' ? parentKey + '_' : '') + index;
|
||||
const newItem = {
|
||||
item,
|
||||
index,
|
||||
level,
|
||||
key,
|
||||
parent,
|
||||
parentKey
|
||||
};
|
||||
|
||||
newItem['items'] = this.createProcessedItems(item.items, level + 1, newItem, key);
|
||||
processedItems.push(newItem);
|
||||
});
|
||||
|
||||
return processedItems;
|
||||
},
|
||||
flatItems(processedItems, processedFlattenItems = []) {
|
||||
processedItems &&
|
||||
processedItems.forEach((processedItem) => {
|
||||
if (this.isVisibleItem(processedItem)) {
|
||||
processedFlattenItems.push(processedItem);
|
||||
this.flatItems(processedItem.items, processedFlattenItems);
|
||||
}
|
||||
});
|
||||
|
||||
return processedFlattenItems;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
processedItems() {
|
||||
return this.createProcessedItems(this.items || []);
|
||||
},
|
||||
visibleItems() {
|
||||
return this.flatItems(this.processedItems);
|
||||
},
|
||||
focusedItemId() {
|
||||
return ObjectUtils.isNotEmpty(this.focusedItem) ? `${this.panelId}_${this.focusedItem.key}` : null;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
PanelMenuSub: PanelMenuSub
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue