From c04098e4fe438e627372fef6d1a5418d8dc3b617 Mon Sep 17 00:00:00 2001 From: Cagatay Civici Date: Mon, 17 May 2021 18:44:09 +0300 Subject: [PATCH] Fixed #367 - Ability to activate PanelMenu item declaratively or programmatically --- api-generator/components/panelmenu.js | 6 + api-generator/components/tree.js | 2 +- src/components/panelmenu/PanelMenu.d.ts | 1 + src/components/panelmenu/PanelMenu.vue | 27 +- src/components/panelmenu/PanelMenuSub.vue | 14 +- src/views/menumodel/MenuModel.vue | 6 + src/views/panelmenu/PanelMenuDemo.vue | 266 ++++---- src/views/panelmenu/PanelMenuDoc.vue | 740 +++++++++++++++------- src/views/tree/TreeDoc.vue | 2 +- 9 files changed, 720 insertions(+), 344 deletions(-) diff --git a/api-generator/components/panelmenu.js b/api-generator/components/panelmenu.js index 506ac8c1f..b0cd7267f 100644 --- a/api-generator/components/panelmenu.js +++ b/api-generator/components/panelmenu.js @@ -4,6 +4,12 @@ const PanelMenuProps = [ type: "array", default: "null", description: "An array of menuitems." + }, + { + name: "expandedKeys", + type: "array", + default: "null", + description: "A map of keys to represent the expansion state in controlled mode." } ]; diff --git a/api-generator/components/tree.js b/api-generator/components/tree.js index 81e902a76..550c670e7 100644 --- a/api-generator/components/tree.js +++ b/api-generator/components/tree.js @@ -9,7 +9,7 @@ const TreeProps = [ name: "expandedKeys", type: "array", default: "null", - description: "A map of keys to represent the state of the tree expansion state in controlled mode." + description: "A map of keys to represent the expansion state in controlled mode." }, { name: "selectionMode", diff --git a/src/components/panelmenu/PanelMenu.d.ts b/src/components/panelmenu/PanelMenu.d.ts index 31799151e..7e7fdf50e 100755 --- a/src/components/panelmenu/PanelMenu.d.ts +++ b/src/components/panelmenu/PanelMenu.d.ts @@ -1,5 +1,6 @@ interface PanelMenuProps { model?: any[]; + expandedKeys?: any; } declare class PanelMenu { diff --git a/src/components/panelmenu/PanelMenu.vue b/src/components/panelmenu/PanelMenu.vue index fcfb6cf82..e1995d7e9 100755 --- a/src/components/panelmenu/PanelMenu.vue +++ b/src/components/panelmenu/PanelMenu.vue @@ -20,10 +20,11 @@ -
- +
@@ -38,10 +39,15 @@ import {UniqueComponentId} from 'primevue/utils'; export default { name: 'PanelMenu', + emits: ['update:expandedKeys'], props: { model: { type: Array, default: null + }, + expandedKeys: { + type: null, + default: null } }, data() { @@ -68,10 +74,25 @@ export default { else this.activeItem = item; + this.updateExpandedKeys({item: item, expanded: this.activeItem != null}); + if (item.to && navigate) { navigate(event); } }, + updateExpandedKeys(event) { + if (this.expandedKeys) { + let item = event.item; + let _keys = {...this.expandedKeys}; + + if (event.expanded) + _keys[item.key] = true; + else + delete _keys[item.key]; + + this.$emit('update:expandedKeys', _keys); + } + }, getPanelClass(item) { return ['p-panelmenu-panel', item.class]; }, @@ -83,7 +104,7 @@ export default { return ['p-menuitem-icon', item.icon]; }, isActive(item) { - return item === this.activeItem; + return this.expandedKeys ? this.expandedKeys[item.key] : item === this.activeItem; }, getHeaderClass(item) { return ['p-component p-panelmenu-header', {'p-highlight': this.isActive(item), 'p-disabled': item.disabled}]; diff --git a/src/components/panelmenu/PanelMenuSub.vue b/src/components/panelmenu/PanelMenuSub.vue index 74a306dcc..069ea6fab 100755 --- a/src/components/panelmenu/PanelMenuSub.vue +++ b/src/components/panelmenu/PanelMenuSub.vue @@ -18,8 +18,9 @@ -
- +
+
@@ -31,6 +32,7 @@ diff --git a/src/views/panelmenu/PanelMenuDoc.vue b/src/views/panelmenu/PanelMenuDoc.vue index 5b27c84a8..35dee5e55 100755 --- a/src/views/panelmenu/PanelMenuDoc.vue +++ b/src/views/panelmenu/PanelMenuDoc.vue @@ -16,6 +16,7 @@ import PanelMenu from 'primevue/panelmenu'; +

 export default {
 	data() {
@@ -142,6 +143,7 @@ export default {
 }
 
 
+
Templating

PanelMenu offers content customization with the item template that receives the menuitem instance from the model as a parameter.

@@ -152,11 +154,207 @@ export default { </template> </PanelMenu> + + +
Programmatic Control
+

If the menuitem has a key defined, PanelMenu state can be controlled programmatically with the expandedKeys property that defines the keys + that are expanded. This property is a Map instance whose key is the key of a node and value is a boolean. Note that expandedKeys also supports two-way binding with the v-model directive. +

+ +

Example below expands and collapses all nodes with buttons.

+

+
+ +
+

+export default {
+    data() {
+        return {
+            items: [{
+                    key: '0',
+                    label: 'File',
+                    icon: 'pi pi-fw pi-file',
+                    items: [{
+                            key: '0_0',
+                            label: 'New',
+                            icon: 'pi pi-fw pi-plus',
+                            items: [{
+                                    key: '0_0_0',
+                                    label: 'Bookmark',
+                                    icon: 'pi pi-fw pi-bookmark'
+                                },
+                                {
+                                    key: '0_0_1',
+                                    label: 'Video',
+                                    icon: 'pi pi-fw pi-video'
+                                }
+                            ]
+                        },
+                        {
+                            key: '0_1',
+                            label: 'Delete',
+                            icon: 'pi pi-fw pi-trash'
+                        },
+                        {
+                            key: '0_2',
+                            label: 'Export',
+                            icon: 'pi pi-fw pi-external-link'
+                        }
+                    ]
+                },
+                {
+                    key: '1',
+                    label: 'Edit',
+                    icon: 'pi pi-fw pi-pencil',
+                    items: [{
+                            key: '1_0',
+                            label: 'Left',
+                            icon: 'pi pi-fw pi-align-left'
+                        },
+                        {
+                            key: '1_1',
+                            label: 'Right',
+                            icon: 'pi pi-fw pi-align-right'
+                        },
+                        {
+                            key: '1_2',
+                            label: 'Center',
+                            icon: 'pi pi-fw pi-align-center'
+                        },
+                        {
+                            key: '1_3',
+                            label: 'Justify',
+                            icon: 'pi pi-fw pi-align-justify'
+                        }
+                    ]
+                },
+                {
+                    key: '2',
+                    label: 'Users',
+                    icon: 'pi pi-fw pi-user',
+                    items: [{
+                            key: '2_0',
+                            label: 'New',
+                            icon: 'pi pi-fw pi-user-plus',
+
+                        },
+                        {
+                            key: '2_1',
+                            label: 'Delete',
+                            icon: 'pi pi-fw pi-user-minus',
+                        },
+                        {
+                            key: '2_2',
+                            label: 'Search',
+                            icon: 'pi pi-fw pi-users',
+                            items: [{
+                                    key: '2_2_0',
+                                    label: 'Filter',
+                                    icon: 'pi pi-fw pi-filter',
+                                    items: [{
+                                        key: '2_2_0_0',
+                                        label: 'Print',
+                                        icon: 'pi pi-fw pi-print'
+                                    }]
+                                },
+                                {
+                                    key: '2_2_1',
+                                    icon: 'pi pi-fw pi-bars',
+                                    label: 'List'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    key: '3',
+                    label: 'Events',
+                    icon: 'pi pi-fw pi-calendar',
+                    items: [{
+                            key: '3_0',
+                            label: 'Edit',
+                            icon: 'pi pi-fw pi-pencil',
+                            items: [{
+                                    key: '3_0_0',
+                                    label: 'Save',
+                                    icon: 'pi pi-fw pi-calendar-plus'
+                                },
+                                {
+                                    key: '3_0_0',
+                                    label: 'Delete',
+                                    icon: 'pi pi-fw pi-calendar-minus'
+                                }
+                            ]
+                        },
+                        {
+                            key: '3_1',
+                            label: 'Archieve',
+                            icon: 'pi pi-fw pi-calendar-times',
+                            items: [{
+                                key: '3_1_0',
+                                label: 'Remove',
+                                icon: 'pi pi-fw pi-calendar-minus'
+                            }]
+                        }
+                    ]
+                }
+            ],
+            expandedKeys: {}
+        }
+    },
+    methods: {
+        expandAll() {
+            for (let node of this.items) {
+                this.expandNode(node);
+            }
+
+            this.expandedKeys = {
+                ...this.expandedKeys
+            };
+        },
+        collapseAll() {
+            this.expandedKeys = {};
+        },
+        expandNode(node) {
+            if (node.items && node.items.length) {
+                this.expandedKeys[node.key] = true;
+
+                for (let child of node.items) {
+                    this.expandNode(child);
+                }
+            }
+        }
+    }
+}
+
+
+
+ +

In order to display some nodes as expanded by default, simply add their keys to the map.

+

+export default {
+    data() {
+        return {
+            items: //menu model instance,
+            expandedKeys: {}
+        }
+    },
+    mounted() {
+        this.expandedKeys[this.items[0.key]] = true;
+    }
+}
+
 
Properties

Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.

-
+
@@ -172,6 +370,12 @@ export default { + + + + + +
array null An array of menuitems.
expandedKeysarraynullA map of keys to represent the expansion state in controlled mode.
@@ -257,7 +461,15 @@ export default { content: ` @@ -265,123 +477,159 @@ export default { export default { data() { return { - items: [ - { - label: 'File', - icon:'pi pi-fw pi-file', - items: [ - { - label: 'New', - icon:'pi pi-fw pi-plus', - items: [ - { - label: 'Bookmark', - icon:'pi pi-fw pi-bookmark' - }, - { - label: 'Video', - icon:'pi pi-fw pi-video' - } - ] - }, - { - label: 'Delete', - icon:'pi pi-fw pi-trash' - }, - { - label: 'Export', - icon:'pi pi-fw pi-external-link' - } - ] + expandedKeys: {}, + items: [{ + key: '0', + label: 'File', + icon: 'pi pi-fw pi-file', + items: [{ + key: '0_0', + label: 'New', + icon: 'pi pi-fw pi-plus', + items: [{ + key: '0_0_0', + label: 'Bookmark', + icon: 'pi pi-fw pi-bookmark' + }, + { + key: '0_0_1', + label: 'Video', + icon: 'pi pi-fw pi-video' + } + ] + }, + { + key: '0_1', + label: 'Delete', + icon: 'pi pi-fw pi-trash' + }, + { + key: '0_2', + label: 'Export', + icon: 'pi pi-fw pi-external-link' + } + ] }, { - label: 'Edit', - icon:'pi pi-fw pi-pencil', - items: [ - { - label: 'Left', - icon:'pi pi-fw pi-align-left' - }, - { - label: 'Right', - icon:'pi pi-fw pi-align-right' - }, - { - label: 'Center', - icon:'pi pi-fw pi-align-center' - }, - { - label: 'Justify', - icon:'pi pi-fw pi-align-justify' - } - ] + key: '1', + label: 'Edit', + icon: 'pi pi-fw pi-pencil', + items: [{ + key: '1_0', + label: 'Left', + icon: 'pi pi-fw pi-align-left' + }, + { + key: '1_1', + label: 'Right', + icon: 'pi pi-fw pi-align-right' + }, + { + key: '1_2', + label: 'Center', + icon: 'pi pi-fw pi-align-center' + }, + { + key: '1_3', + label: 'Justify', + icon: 'pi pi-fw pi-align-justify' + } + ] }, { - label: 'Users', - icon:'pi pi-fw pi-user', - items: [ - { - label: 'New', - icon:'pi pi-fw pi-user-plus', + key: '2', + label: 'Users', + icon: 'pi pi-fw pi-user', + items: [{ + key: '2_0', + label: 'New', + icon: 'pi pi-fw pi-user-plus', - }, - { - label: 'Delete', - icon:'pi pi-fw pi-user-minus', - }, - { - label: 'Search', - icon:'pi pi-fw pi-users', - items: [ - { - label: 'Filter', - icon:'pi pi-fw pi-filter', - items: [ - { - label: 'Print', - icon:'pi pi-fw pi-print' - } - ] - }, - { - icon:'pi pi-fw pi-bars', - label: 'List' - } - ] - } - ] + }, + { + key: '2_1', + label: 'Delete', + icon: 'pi pi-fw pi-user-minus', + }, + { + key: '2_2', + label: 'Search', + icon: 'pi pi-fw pi-users', + items: [{ + key: '2_2_0', + label: 'Filter', + icon: 'pi pi-fw pi-filter', + items: [{ + key: '2_2_0_0', + label: 'Print', + icon: 'pi pi-fw pi-print' + }] + }, + { + key: '2_2_1', + icon: 'pi pi-fw pi-bars', + label: 'List' + } + ] + } + ] }, { - label: 'Events', - icon:'pi pi-fw pi-calendar', - items: [ - { - label: 'Edit', - icon:'pi pi-fw pi-pencil', - items: [ - { - label: 'Save', - icon:'pi pi-fw pi-calendar-plus' - }, - { - label: 'Delete', - icon:'pi pi-fw pi-calendar-minus' - } - ] - }, - { - label: 'Archieve', - icon:'pi pi-fw pi-calendar-times', - items: [ - { - label: 'Remove', - icon:'pi pi-fw pi-calendar-minus' - } - ] - } - ] + key: '3', + label: 'Events', + icon: 'pi pi-fw pi-calendar', + items: [{ + key: '3_0', + label: 'Edit', + icon: 'pi pi-fw pi-pencil', + items: [{ + key: '3_0_0', + label: 'Save', + icon: 'pi pi-fw pi-calendar-plus' + }, + { + key: '3_0_0', + label: 'Delete', + icon: 'pi pi-fw pi-calendar-minus' + } + ] + }, + { + key: '3_1', + label: 'Archieve', + icon: 'pi pi-fw pi-calendar-times', + items: [{ + key: '3_1_0', + label: 'Remove', + icon: 'pi pi-fw pi-calendar-minus' + }] + } + ] } - ] + ] + } + }, + methods: { + expandAll() { + for (let node of this.items) { + this.expandNode(node); + } + + this.expandedKeys = { + ...this.expandedKeys + }; + }, + collapseAll() { + this.expandedKeys = {}; + }, + expandNode(node) { + if (node.items && node.items.length) { + this.expandedKeys[node.key] = true; + + for (let child of node.items) { + this.expandNode(child); + } + } } } } @@ -399,7 +647,15 @@ export default { content: ` @@ -408,124 +664,158 @@ import { ref } from 'vue'; export default { setup() { - const items = ref([ - { - label: 'File', - icon:'pi pi-fw pi-file', - items: [ - { - label: 'New', - icon:'pi pi-fw pi-plus', - items: [ - { - label: 'Bookmark', - icon:'pi pi-fw pi-bookmark' - }, - { - label: 'Video', - icon:'pi pi-fw pi-video' - } - ] - }, - { - label: 'Delete', - icon:'pi pi-fw pi-trash' - }, - { - label: 'Export', - icon:'pi pi-fw pi-external-link' - } - ] - }, - { - label: 'Edit', - icon:'pi pi-fw pi-pencil', - items: [ - { - label: 'Left', - icon:'pi pi-fw pi-align-left' - }, - { - label: 'Right', - icon:'pi pi-fw pi-align-right' - }, - { - label: 'Center', - icon:'pi pi-fw pi-align-center' - }, - { - label: 'Justify', - icon:'pi pi-fw pi-align-justify' - } - ] - }, - { - label: 'Users', - icon:'pi pi-fw pi-user', - items: [ - { - label: 'New', - icon:'pi pi-fw pi-user-plus', - }, - { - label: 'Delete', - icon:'pi pi-fw pi-user-minus', - }, - { - label: 'Search', - icon:'pi pi-fw pi-users', - items: [ - { - label: 'Filter', - icon:'pi pi-fw pi-filter', - items: [ + const expandedKeys = ref({}); + const items = ref([{ + key: '0', + label: 'File', + icon: 'pi pi-fw pi-file', + items: [{ + key: '0_0', + label: 'New', + icon: 'pi pi-fw pi-plus', + items: [{ + key: '0_0_0', + label: 'Bookmark', + icon: 'pi pi-fw pi-bookmark' + }, { - label: 'Print', - icon:'pi pi-fw pi-print' + key: '0_0_1', + label: 'Video', + icon: 'pi pi-fw pi-video' } ] - }, - { - icon:'pi pi-fw pi-bars', - label: 'List' - } - ] - } - ] - }, - { - label: 'Events', - icon:'pi pi-fw pi-calendar', - items: [ - { - label: 'Edit', - icon:'pi pi-fw pi-pencil', - items: [ - { - label: 'Save', - icon:'pi pi-fw pi-calendar-plus' - }, - { + }, + { + key: '0_1', label: 'Delete', - icon:'pi pi-fw pi-calendar-minus' - } - ] - }, - { - label: 'Archieve', - icon:'pi pi-fw pi-calendar-times', - items: [ - { - label: 'Remove', - icon:'pi pi-fw pi-calendar-minus' - } - ] - } - ] - } - ]); + icon: 'pi pi-fw pi-trash' + }, + { + key: '0_2', + label: 'Export', + icon: 'pi pi-fw pi-external-link' + } + ] + }, + { + key: '1', + label: 'Edit', + icon: 'pi pi-fw pi-pencil', + items: [{ + key: '1_0', + label: 'Left', + icon: 'pi pi-fw pi-align-left' + }, + { + key: '1_1', + label: 'Right', + icon: 'pi pi-fw pi-align-right' + }, + { + key: '1_2', + label: 'Center', + icon: 'pi pi-fw pi-align-center' + }, + { + key: '1_3', + label: 'Justify', + icon: 'pi pi-fw pi-align-justify' + } + ] + }, + { + key: '2', + label: 'Users', + icon: 'pi pi-fw pi-user', + items: [{ + key: '2_0', + label: 'New', + icon: 'pi pi-fw pi-user-plus', - return { items } + }, + { + key: '2_1', + label: 'Delete', + icon: 'pi pi-fw pi-user-minus', + }, + { + key: '2_2', + label: 'Search', + icon: 'pi pi-fw pi-users', + items: [{ + key: '2_2_0', + label: 'Filter', + icon: 'pi pi-fw pi-filter', + items: [{ + key: '2_2_0_0', + label: 'Print', + icon: 'pi pi-fw pi-print' + }] + }, + { + key: '2_2_1', + icon: 'pi pi-fw pi-bars', + label: 'List' + } + ] + } + ] + }, + { + key: '3', + label: 'Events', + icon: 'pi pi-fw pi-calendar', + items: [{ + key: '3_0', + label: 'Edit', + icon: 'pi pi-fw pi-pencil', + items: [{ + key: '3_0_0', + label: 'Save', + icon: 'pi pi-fw pi-calendar-plus' + }, + { + key: '3_0_0', + label: 'Delete', + icon: 'pi pi-fw pi-calendar-minus' + } + ] + }, + { + key: '3_1', + label: 'Archieve', + icon: 'pi pi-fw pi-calendar-times', + items: [{ + key: '3_1_0', + label: 'Remove', + icon: 'pi pi-fw pi-calendar-minus' + }] + } + ] + } + ]); + + const expandAll = () => { + for (let node of nodes.value) { + expandNode(node); + } + + expandedKeys.value = {...expandedKeys.value}; + }; + const collapseAll = () => { + expandedKeys.value = {}; + }; + const expandNode = (node) => { + if (node.children && node.children.length) { + expandedKeys.value[node.key] = true; + + for (let child of node.children) { + expandNode(child); + } + } + }; + + return { items, expandedKeys, expandAll, collapseAll, expandNode } } } <\\/script> diff --git a/src/views/tree/TreeDoc.vue b/src/views/tree/TreeDoc.vue index 3a9b6834b..4b34606e6 100755 --- a/src/views/tree/TreeDoc.vue +++ b/src/views/tree/TreeDoc.vue @@ -593,7 +593,7 @@ export default { expandedKeys array null - A map of keys to represent the state of the tree expansion state in controlled mode. + A map of keys to represent the expansion state in controlled mode. selectionMode