diff --git a/components/lib/accordion/Accordion.vue b/components/lib/accordion/Accordion.vue index dfd54e2b5..d25a9e809 100755 --- a/components/lib/accordion/Accordion.vue +++ b/components/lib/accordion/Accordion.vue @@ -57,7 +57,7 @@ import ChevronDownIcon from 'primevue/icons/chevrondown'; import ChevronRightIcon from 'primevue/icons/chevronright'; import Ripple from 'primevue/ripple'; -import { DomHandler, UniqueComponentId } from 'primevue/utils'; +import { DomHandler, HelperSet, UniqueComponentId } from 'primevue/utils'; import { mergeProps } from 'vue'; import BaseAccordion from './BaseAccordion.vue'; @@ -65,10 +65,16 @@ export default { name: 'Accordion', extends: BaseAccordion, emits: ['update:activeIndex', 'tab-open', 'tab-close', 'tab-click'], + provide() { + return { + $accordionTabs: this.d_accordionTabs + }; + }, data() { return { id: this.$attrs.id, - d_activeIndex: this.activeIndex + d_activeIndex: this.activeIndex, + d_accordionTabs: new HelperSet({ type: 'AccordionTab' }) }; }, watch: { @@ -82,10 +88,10 @@ export default { mounted() { this.id = this.id || UniqueComponentId(); }, + beforeUnmount() { + this.d_accordionTabs.clear(); + }, methods: { - isAccordionTab(child) { - return child.type.name === 'AccordionTab'; - }, isTabActive(index) { return this.multiple ? this.d_activeIndex && this.d_activeIndex.includes(index) : this.d_activeIndex === index; }, @@ -235,19 +241,7 @@ export default { }, computed: { tabs() { - return this.$slots.default().reduce((tabs, child) => { - if (this.isAccordionTab(child)) { - tabs.push(child); - } else if (child.children && child.children instanceof Array) { - child.children.forEach((nestedChild) => { - if (this.isAccordionTab(nestedChild)) { - tabs.push(nestedChild); - } - }); - } - - return tabs; - }, []); + return this.d_accordionTabs.get(this); } }, components: { diff --git a/components/lib/accordiontab/AccordionTab.vue b/components/lib/accordiontab/AccordionTab.vue index c5f577a91..7f6a97935 100755 --- a/components/lib/accordiontab/AccordionTab.vue +++ b/components/lib/accordiontab/AccordionTab.vue @@ -7,6 +7,13 @@ import BaseAccordionTab from './BaseAccordionTab.vue'; export default { name: 'AccordionTab', - extends: BaseAccordionTab + extends: BaseAccordionTab, + inject: ['$accordionTabs'], + mounted() { + this.$accordionTabs?.add(this.$); + }, + unmounted() { + this.$accordionTabs?.delete(this.$); + } }; diff --git a/components/lib/column/Column.vue b/components/lib/column/Column.vue index 0335aa007..82a8903ea 100755 --- a/components/lib/column/Column.vue +++ b/components/lib/column/Column.vue @@ -4,6 +4,13 @@ import BaseColumn from './BaseColumn.vue'; export default { name: 'Column', extends: BaseColumn, + inject: ['$columns'], + mounted() { + this.$columns?.add(this.$); + }, + unmounted() { + this.$columns?.delete(this.$); + }, render() { return null; } diff --git a/components/lib/columngroup/ColumnGroup.vue b/components/lib/columngroup/ColumnGroup.vue index ed3c6170b..c2144a286 100755 --- a/components/lib/columngroup/ColumnGroup.vue +++ b/components/lib/columngroup/ColumnGroup.vue @@ -4,6 +4,13 @@ import BaseColumnGroup from './BaseColumnGroup.vue'; export default { name: 'ColumnGroup', extends: BaseColumnGroup, + inject: ['$columnGroups'], + mounted() { + this.$columnGroups?.add(this.$); + }, + unmounted() { + this.$columnGroups?.delete(this.$); + }, render() { return null; } diff --git a/components/lib/datatable/DataTable.vue b/components/lib/datatable/DataTable.vue index ad8c89f33..7f0b8e827 100755 --- a/components/lib/datatable/DataTable.vue +++ b/components/lib/datatable/DataTable.vue @@ -283,7 +283,7 @@ import ArrowDownIcon from 'primevue/icons/arrowdown'; import ArrowUpIcon from 'primevue/icons/arrowup'; import SpinnerIcon from 'primevue/icons/spinner'; import Paginator from 'primevue/paginator'; -import { DomHandler, ObjectUtils, UniqueComponentId } from 'primevue/utils'; +import { DomHandler, HelperSet, ObjectUtils, UniqueComponentId } from 'primevue/utils'; import VirtualScroller from 'primevue/virtualscroller'; import BaseDataTable from './BaseDataTable.vue'; import TableBody from './TableBody.vue'; @@ -333,6 +333,12 @@ export default { 'row-edit-save', 'row-edit-cancel' ], + provide() { + return { + $columns: this.d_columns, + $columnGroups: this.d_columnGroups + }; + }, data() { return { d_first: this.first, @@ -346,7 +352,9 @@ export default { d_columnOrder: null, d_editingRowKeys: null, d_editingMeta: {}, - d_filters: this.cloneFilters(this.filters) + d_filters: this.cloneFilters(this.filters), + d_columns: new HelperSet({ type: 'Column' }), + d_columnGroups: new HelperSet({ type: 'ColumnGroup' }) }; }, rowTouched: false, @@ -430,6 +438,9 @@ export default { this.unbindColumnResizeEvents(); this.destroyStyleElement(); this.destroyResponsiveStyle(); + + this.d_columns.clear(); + this.d_columnGroups.clear(); }, updated() { if (this.isStateful()) { @@ -1852,9 +1863,6 @@ export default { hasGlobalFilter() { return this.filters && Object.prototype.hasOwnProperty.call(this.filters, 'global'); }, - getChildren() { - return this.$slots.default ? this.$slots.default() : null; - }, onFilterChange(filters) { this.d_filters = filters; }, @@ -1952,23 +1960,6 @@ export default { this.styleElement = null; } }, - recursiveGetChildren(children, results) { - if (!results) { - results = []; - } - - if (children && children.length) { - children.forEach((child) => { - if (child.children instanceof Array) { - results.concat(this.recursiveGetChildren(child.children, results)); - } else if (child.type.name == 'Column') { - results.push(child); - } - }); - } - - return results; - }, dataToRender(data) { const _data = data || this.processedData; @@ -1989,13 +1980,7 @@ export default { }, computed: { columns() { - let children = this.getChildren(); - - if (!children) { - return; - } - - const cols = this.recursiveGetChildren(children, []); + const cols = this.d_columns.get(this); if (this.reorderableColumns && this.d_columnOrder) { let orderedColumns = []; @@ -2013,31 +1998,14 @@ export default { return cols; }, + columnGroups() { + return this.d_columnGroups.get(this); + }, headerColumnGroup() { - const children = this.getChildren(); - - if (children) { - for (let child of children) { - if (child.type.name === 'ColumnGroup' && this.columnProp(child, 'type') === 'header') { - return child; - } - } - } - - return null; + return this.columnGroups?.find((group) => this.columnProp(group, 'type') === 'header'); }, footerColumnGroup() { - const children = this.getChildren(); - - if (children) { - for (let child of children) { - if (child.type.name === 'ColumnGroup' && this.columnProp(child, 'type') === 'footer') { - return child; - } - } - } - - return null; + return this.columnGroups?.find((group) => this.columnProp(group, 'type') === 'footer'); }, hasFilters() { return this.filters && Object.keys(this.filters).length > 0 && this.filters.constructor === Object; diff --git a/components/lib/datatable/TableFooter.vue b/components/lib/datatable/TableFooter.vue index e915644ec..9de027a19 100755 --- a/components/lib/datatable/TableFooter.vue +++ b/components/lib/datatable/TableFooter.vue @@ -17,7 +17,7 @@ diff --git a/components/lib/tabview/TabView.vue b/components/lib/tabview/TabView.vue index d048080d2..b4a588563 100755 --- a/components/lib/tabview/TabView.vue +++ b/components/lib/tabview/TabView.vue @@ -95,7 +95,7 @@ import ChevronLeftIcon from 'primevue/icons/chevronleft'; import ChevronRightIcon from 'primevue/icons/chevronright'; import Ripple from 'primevue/ripple'; -import { DomHandler, UniqueComponentId } from 'primevue/utils'; +import { DomHandler, HelperSet, UniqueComponentId } from 'primevue/utils'; import { mergeProps } from 'vue'; import BaseTabView from './BaseTabView.vue'; @@ -103,12 +103,18 @@ export default { name: 'TabView', extends: BaseTabView, emits: ['update:activeIndex', 'tab-change', 'tab-click'], + provide() { + return { + $tabPanels: this.d_tabPanels + }; + }, data() { return { id: this.$attrs.id, d_activeIndex: this.activeIndex, isPrevButtonDisabled: true, - isNextButtonDisabled: false + isNextButtonDisabled: false, + d_tabPanels: new HelperSet({ type: 'TabPanel' }) }; }, watch: { @@ -130,10 +136,10 @@ export default { updated() { this.updateInkBar(); }, + beforeUnmount() { + this.d_tabPanels.clear(); + }, methods: { - isTabPanel(child) { - return child.type.name === 'TabPanel'; - }, isTabActive(index) { return this.d_activeIndex === index; }, @@ -342,19 +348,7 @@ export default { }, computed: { tabs() { - return this.$slots.default().reduce((tabs, child) => { - if (this.isTabPanel(child)) { - tabs.push(child); - } else if (child.children && child.children instanceof Array) { - child.children.forEach((nestedChild) => { - if (this.isTabPanel(nestedChild)) { - tabs.push(nestedChild); - } - }); - } - - return tabs; - }, []); + return this.d_tabPanels.get(this); }, prevButtonAriaLabel() { return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.previous : undefined; diff --git a/components/lib/treetable/TreeTable.vue b/components/lib/treetable/TreeTable.vue index ba153a3f7..eee6577c3 100755 --- a/components/lib/treetable/TreeTable.vue +++ b/components/lib/treetable/TreeTable.vue @@ -170,7 +170,7 @@ import { FilterService } from 'primevue/api'; import SpinnerIcon from 'primevue/icons/spinner'; import Paginator from 'primevue/paginator'; -import { DomHandler, ObjectUtils } from 'primevue/utils'; +import { DomHandler, HelperSet, ObjectUtils } from 'primevue/utils'; import BaseTreeTable from './BaseTreeTable.vue'; import FooterCell from './FooterCell.vue'; import HeaderCell from './HeaderCell.vue'; @@ -196,10 +196,11 @@ export default { 'filter', 'column-resize-end' ], - documentColumnResizeListener: null, - documentColumnResizeEndListener: null, - lastResizeHelperX: null, - resizeColumnElement: null, + provide() { + return { + $columns: this.d_columns + }; + }, data() { return { d_expandedKeys: this.expandedKeys || {}, @@ -208,9 +209,14 @@ export default { d_sortField: this.sortField, d_sortOrder: this.sortOrder, d_multiSortMeta: this.multiSortMeta ? [...this.multiSortMeta] : [], - hasASelectedNode: false + hasASelectedNode: false, + d_columns: new HelperSet({ type: 'Column' }) }; }, + documentColumnResizeListener: null, + documentColumnResizeEndListener: null, + lastResizeHelperX: null, + resizeColumnElement: null, watch: { expandedKeys(newValue) { this.d_expandedKeys = newValue; @@ -241,6 +247,9 @@ export default { this.updateScrollWidth(); } }, + beforeUnmount() { + this.d_columns.clear(); + }, methods: { columnProp(col, prop) { return ObjectUtils.getVNodeProp(col, prop); @@ -763,15 +772,7 @@ export default { }, computed: { columns() { - let cols = []; - let children = this.$slots.default(); - - children.forEach((child) => { - if (child.children && child.children instanceof Array) cols = [...cols, ...child.children]; - else if (child.type.name === 'Column') cols.push(child); - }); - - return cols; + return this.d_columns.get(this); }, processedData() { if (this.lazy) { diff --git a/components/lib/utils/HelperSet.js b/components/lib/utils/HelperSet.js new file mode 100644 index 000000000..7e85413f9 --- /dev/null +++ b/components/lib/utils/HelperSet.js @@ -0,0 +1,51 @@ +import ObjectUtils from './ObjectUtils'; + +export default class { + helpers; + type; + constructor({ init, type }) { + this.helpers = new Set(init); + this.type = type; + } + add(instance) { + this.helpers.add(instance); + } + update() { + // @todo + } + delete(instance) { + this.helpers.delete(instance); + } + clear() { + this.helpers.clear(); + } + get(parentInstance, slots) { + const children = this._get(parentInstance, slots); + const computed = children ? this._recursive([...this.helpers], children) : null; + + return ObjectUtils.isNotEmpty(computed) ? computed : null; + } + _isMatched(instance, key) { + const parent = instance?.parent; + + return parent?.vnode?.key === key || (parent && this._isMatched(parent, key)) || false; + } + _get(parentInstance, slots) { + return (slots || parentInstance?.$slots)?.default?.() || null; + } + _recursive(helpers = [], children = []) { + let components = []; + + children.forEach((child) => { + if (child.children instanceof Array) { + components = components.concat(this._recursive(components, child.children)); + } else if (child.type.name === this.type) { + components.push(child); + } else if (ObjectUtils.isNotEmpty(child.key)) { + components = components.concat(helpers.filter((c) => this._isMatched(c, child.key)).map((c) => c.vnode)); + } + }); + + return components; + } +} diff --git a/components/lib/utils/Utils.d.ts b/components/lib/utils/Utils.d.ts index 72af49664..84379242c 100644 --- a/components/lib/utils/Utils.d.ts +++ b/components/lib/utils/Utils.d.ts @@ -102,6 +102,15 @@ export declare class ObjectUtils { static stringify(value: any, indent?: number, currentIndent?: number): string; } +export declare class HelperSet { + constructor(options: { init?: any; type?: string }); + add(instance: any): void; + update(): void; + delete(instance: any): void; + clear(): void; + get(parentInstance?: any, slots?: any): any[] | null | undefined; +} + export declare namespace ZIndexUtils { export function get(el?: HTMLElement): number; export function set(key: string, el: HTMLElement, baseZIndex?: number): void; diff --git a/components/lib/utils/Utils.js b/components/lib/utils/Utils.js index 5c089de70..9ca36d7f0 100644 --- a/components/lib/utils/Utils.js +++ b/components/lib/utils/Utils.js @@ -1,8 +1,9 @@ import ConnectedOverlayScrollHandler from './ConnectedOverlayScrollHandler'; import DomHandler from './DomHandler'; import EventBus from './EventBus'; +import HelperSet from './HelperSet'; import ObjectUtils from './ObjectUtils'; import UniqueComponentId from './UniqueComponentId'; import ZIndexUtils from './ZIndexUtils'; -export { ConnectedOverlayScrollHandler, DomHandler, EventBus, ObjectUtils, UniqueComponentId, ZIndexUtils }; +export { ConnectedOverlayScrollHandler, DomHandler, EventBus, HelperSet, ObjectUtils, UniqueComponentId, ZIndexUtils };