PMCORE-3052
more chages fox code style restore menu settings remove debugger add documentation
This commit is contained in:
497
resources/assets/js/components/menu/CustomSidebarMenuItem.vue
Normal file
497
resources/assets/js/components/menu/CustomSidebarMenuItem.vue
Normal file
@@ -0,0 +1,497 @@
|
||||
<template>
|
||||
<div id="my-container">
|
||||
<div
|
||||
v-if="item.header && !isItemHidden"
|
||||
class="vsm--header"
|
||||
:class="item.class"
|
||||
v-bind="item.attributes"
|
||||
>
|
||||
{{ item.title }} <b-icon icon="pie-chart-fill"></b-icon>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!isItemHidden"
|
||||
class="vsm--item"
|
||||
:class="[{ 'vsm--item_open': show }]"
|
||||
@mouseover="mouseOverEvent"
|
||||
@mouseout="mouseOutEvent"
|
||||
>
|
||||
<custom-sidebar-menu-link
|
||||
:item="item"
|
||||
:class="itemLinkClass"
|
||||
:attributes="item.attributes"
|
||||
@click.native="clickEvent"
|
||||
>
|
||||
<custom-sidebar-menu-icon
|
||||
v-if="item.icon && !isMobileItem"
|
||||
:icon="item.icon"
|
||||
/>
|
||||
<transition name="fade-animation" :appear="isMobileItem">
|
||||
<template
|
||||
v-if="
|
||||
(isCollapsed && !isFirstLevel) ||
|
||||
!isCollapsed ||
|
||||
isMobileItem
|
||||
"
|
||||
>
|
||||
<span class="vsm--title">
|
||||
{{ item.title }}
|
||||
<b-icon
|
||||
v-if="item.sortable"
|
||||
:icon="item.sortIcon"
|
||||
@click="onClickSortSettings"
|
||||
></b-icon>
|
||||
</span>
|
||||
</template>
|
||||
</transition>
|
||||
<template
|
||||
v-if="
|
||||
(isCollapsed && !isFirstLevel) ||
|
||||
!isCollapsed ||
|
||||
isMobileItem
|
||||
"
|
||||
>
|
||||
<sidebar-menu-badge v-if="item.badge" :badge="item.badge" />
|
||||
<div
|
||||
v-if="itemHasChild"
|
||||
class="vsm--arrow"
|
||||
:class="[
|
||||
{ 'vsm--arrow_open': show },
|
||||
{ 'vsm--arrow_slot': $slots['dropdown-icon'] },
|
||||
]"
|
||||
>
|
||||
<slot name="dropdown-icon" />
|
||||
</div>
|
||||
</template>
|
||||
</custom-sidebar-menu-link>
|
||||
|
||||
<template v-if="itemHasChild">
|
||||
<template
|
||||
v-if="
|
||||
(isCollapsed && !isFirstLevel) ||
|
||||
!isCollapsed ||
|
||||
isMobileItem
|
||||
"
|
||||
>
|
||||
<transition
|
||||
:appear="isMobileItem"
|
||||
name="expand"
|
||||
@enter="expandEnter"
|
||||
@afterEnter="expandAfterEnter"
|
||||
@beforeLeave="expandBeforeLeave"
|
||||
>
|
||||
<div
|
||||
v-if="show"
|
||||
class="vsm--dropdown"
|
||||
:class="isMobileItem && 'vsm--dropdown_mobile-item'"
|
||||
:style="isMobileItem && mobileItemStyle.dropdown"
|
||||
>
|
||||
<div class="vsm--list">
|
||||
<custom-sidebar-menu-item
|
||||
v-for="(subItem, index) in item.child"
|
||||
:key="index"
|
||||
:item="subItem"
|
||||
:level="level + 1"
|
||||
:show-child="showChild"
|
||||
:rtl="rtl"
|
||||
:is-collapsed="isCollapsed"
|
||||
>
|
||||
<slot
|
||||
slot="dropdown-icon"
|
||||
name="dropdown-icon"
|
||||
/>
|
||||
</custom-sidebar-menu-item>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<b-modal
|
||||
ref="modal"
|
||||
v-if="item.sortable"
|
||||
id="my-modal"
|
||||
static
|
||||
title="Custom Case List Order"
|
||||
>
|
||||
<draggable
|
||||
:list="item.child"
|
||||
:disabled="!enabled"
|
||||
class="list-group"
|
||||
ghost-class="ghost"
|
||||
@end="checkMove"
|
||||
@start="dragging = true"
|
||||
handle=".handle"
|
||||
>
|
||||
<div
|
||||
class="list-group-item"
|
||||
v-for="element in item.child"
|
||||
:key="element.title"
|
||||
>
|
||||
<b-row>
|
||||
<b-col
|
||||
><b-icon icon="check-circle"></b-icon>
|
||||
</b-col>
|
||||
<b-col cols="9">{{ element.title }}</b-col>
|
||||
<b-col
|
||||
><i class="fa fa-align-justify handle"></i
|
||||
></b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</draggable>
|
||||
|
||||
<template #modal-footer="{ ok, cancel, hide }">
|
||||
<b-button size="sm" variant="danger" @click="cancel()">
|
||||
Cancel
|
||||
</b-button>
|
||||
</template>
|
||||
</b-modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from "vuedraggable";
|
||||
import CustomSidebarMenuLink from "./CustomSidebarMenuLink";
|
||||
import CustomSidebarMenuIcon from "./CustomSidebarMenuIcon";
|
||||
export default {
|
||||
name: "CustomSidebarMenuItem",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
level: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
isMobileItem: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
mobileItem: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
activeShow: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
showChild: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showOneChild: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rtl: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disableHover: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
mobileItemStyle: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
draggable,
|
||||
CustomSidebarMenuLink,
|
||||
CustomSidebarMenuIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enabled: true,
|
||||
dragging: false,
|
||||
itemShow: false,
|
||||
itemHover: false,
|
||||
exactActive: false,
|
||||
active: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isCollapsed() {
|
||||
return this.$parent.isCollapsed;
|
||||
},
|
||||
itemLinkClass() {
|
||||
return [
|
||||
"vsm--link",
|
||||
!this.isMobileItem ? `vsm--link_level-${this.level}` : "",
|
||||
{ "vsm--link_mobile-item": this.isMobileItem },
|
||||
{ "vsm--link_hover": this.hover },
|
||||
{ "vsm--link_active": this.active },
|
||||
{ "vsm--link_exact-active": this.exactActive },
|
||||
{ "vsm--link_disabled": this.item.disabled },
|
||||
this.item.class,
|
||||
];
|
||||
},
|
||||
draggingInfo() {
|
||||
return this.dragging ? "under drag" : "";
|
||||
},
|
||||
show: {
|
||||
get() {
|
||||
if (!this.itemHasChild) return false;
|
||||
if (this.showChild || this.isMobileItem) return true;
|
||||
return this.itemShow;
|
||||
},
|
||||
set(show) {
|
||||
if (this.showOneChild) {
|
||||
show
|
||||
? this.emitActiveShow(this.item)
|
||||
: this.emitActiveShow(null);
|
||||
}
|
||||
this.itemShow = show;
|
||||
},
|
||||
},
|
||||
isFirstLevel() {
|
||||
return this.level === 1;
|
||||
},
|
||||
itemHasChild() {
|
||||
return !!(this.item.child && this.item.child.length > 0);
|
||||
},
|
||||
isItemHidden() {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
setTimeout(() => {
|
||||
if (this.item.header || this.item.component) return;
|
||||
this.initState();
|
||||
}, 1);
|
||||
},
|
||||
item(newItem, item) {
|
||||
this.emitItemUpdate(newItem, item);
|
||||
},
|
||||
activeShow() {
|
||||
this.itemShow = this.item === this.activeShow;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initState();
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Match the route to ensure the correct location
|
||||
* @param {string} href
|
||||
* @param {string} exactPath
|
||||
* @return {boolean}
|
||||
*/
|
||||
matchRoute({ href, exactPath }) {
|
||||
if (!href) return false;
|
||||
if (this.$router) {
|
||||
const { route } = this.$router.resolve(href);
|
||||
return exactPath
|
||||
? route.path === this.$route.path
|
||||
: this.matchExactRoute(href);
|
||||
} else {
|
||||
return exactPath
|
||||
? href === window.location.pathname
|
||||
: this.matchExactRoute(href);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Match the exact route with the current location
|
||||
* @param {string} href
|
||||
* @return {boolean}
|
||||
*/
|
||||
matchExactRoute(href) {
|
||||
if (!href) return false;
|
||||
if (this.$router) {
|
||||
const { route } = this.$router.resolve(href);
|
||||
return route.fullPath === this.$route.fullPath;
|
||||
} else {
|
||||
return (
|
||||
href ===
|
||||
window.location.pathname +
|
||||
window.location.search +
|
||||
window.location.hash
|
||||
);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Check if the child is active
|
||||
* @param {object} child
|
||||
* @return {boolean}
|
||||
*/
|
||||
isChildActive(child) {
|
||||
if (!child) return false;
|
||||
return child.some((item) => {
|
||||
return this.isLinkActive(item);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Validate if the Alias is active
|
||||
* @param {object} item
|
||||
* @return {boobleam}
|
||||
*/
|
||||
isAliasActive(item) {
|
||||
if (item.alias) {
|
||||
const current = this.$router
|
||||
? this.$route.fullPath
|
||||
: window.location.pathname +
|
||||
window.location.search +
|
||||
window.location.hash;
|
||||
if (Array.isArray(item.alias)) {
|
||||
return item.alias.some((alias) => {
|
||||
return pathToRegexp(alias).test(current);
|
||||
});
|
||||
} else {
|
||||
return pathToRegexp(item.alias).test(current);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* Validate if the link is active
|
||||
* @param {object} item
|
||||
* @return {boolean}
|
||||
*/
|
||||
isLinkActive(item) {
|
||||
return (
|
||||
this.matchRoute(item) ||
|
||||
this.isChildActive(item.child) ||
|
||||
this.isAliasActive(item)
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Ensurre if the link exact is active
|
||||
* @param {object} item
|
||||
* @return {boolean}
|
||||
*/
|
||||
isLinkExactActive(item) {
|
||||
return this.matchExactRoute(item.href);
|
||||
},
|
||||
/**
|
||||
* Initialize the state of the menu item
|
||||
*/
|
||||
initState() {
|
||||
this.initActiveState();
|
||||
this.initShowState();
|
||||
},
|
||||
/**
|
||||
* Initalize the active state of the menu item
|
||||
*/
|
||||
initActiveState() {
|
||||
this.active = this.isLinkActive(this.item);
|
||||
this.exactActive = this.isLinkExactActive(this.item);
|
||||
},
|
||||
/**
|
||||
* Initialize and show active state menu item
|
||||
*/
|
||||
initShowState() {
|
||||
if (!this.itemHasChild || this.showChild) return;
|
||||
if (
|
||||
(this.showOneChild && this.active && !this.show) ||
|
||||
(this.active && !this.show)
|
||||
) {
|
||||
this.show = true;
|
||||
} else if (this.showOneChild && !this.active && this.show) {
|
||||
this.show = false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Handler to check if the item is moving
|
||||
* @param {object} e
|
||||
*/
|
||||
checkMove: function(e) {
|
||||
let aux = this.item.child.splice(e.newIndex, 1);
|
||||
this.item.child.splice(e.newIndex, 0, aux[0]);
|
||||
},
|
||||
/**
|
||||
* Click event Handler
|
||||
* @param {object} event
|
||||
*/
|
||||
clickEvent(event) {
|
||||
if (this.item.disabled) return;
|
||||
if (!this.item.href) {
|
||||
event.preventDefault();
|
||||
}
|
||||
this.emitItemClick(event, this.item, this);
|
||||
this.emitMobileItem(event, event.currentTarget.offsetParent);
|
||||
if (!this.itemHasChild || this.showChild || this.isMobileItem)
|
||||
return;
|
||||
if (!this.item.href || this.exactActive) {
|
||||
this.show = !this.show;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Mouse over event handler
|
||||
* @param {object} event
|
||||
*/
|
||||
mouseOverEvent(event) {
|
||||
if (this.item.disabled) return;
|
||||
event.stopPropagation();
|
||||
this.itemHover = true;
|
||||
if (!this.disableHover) {
|
||||
this.emitMobileItem(event, event.currentTarget);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Mouse out event handler
|
||||
* @param {object} event
|
||||
*/
|
||||
mouseOutEvent(event) {
|
||||
event.stopPropagation();
|
||||
this.itemHover = false;
|
||||
},
|
||||
/**
|
||||
* Expand sidebar menu item handler
|
||||
* @param {object} el
|
||||
*/
|
||||
expandEnter(el) {
|
||||
el.style.height = el.scrollHeight + "px";
|
||||
},
|
||||
/**
|
||||
* Expand after enter menu item handler
|
||||
* @param {object} el
|
||||
*/
|
||||
expandAfterEnter(el) {
|
||||
el.style.height = "auto";
|
||||
},
|
||||
/**
|
||||
* Expand before leace handler
|
||||
* @param {object} el
|
||||
*/
|
||||
expandBeforeLeave(el) {
|
||||
if (this.isCollapsed && this.isFirstLevel) {
|
||||
el.style.display = "none";
|
||||
return;
|
||||
}
|
||||
el.style.height = el.scrollHeight + "px";
|
||||
},
|
||||
/**
|
||||
* Emit Mobile item handler
|
||||
* @param {object} event
|
||||
* @param {object} itemEl
|
||||
*/
|
||||
emitMobileItem(event, itemEl) {
|
||||
if (this.hover) return;
|
||||
if (!this.isCollapsed || !this.isFirstLevel || this.isMobileItem)
|
||||
return;
|
||||
this.$emit("unset-mobile-item", true);
|
||||
setTimeout(() => {
|
||||
if (this.mobileItem !== this.item) {
|
||||
this.$emit("set-mobile-item", { item: this.item, itemEl });
|
||||
}
|
||||
if (event.type === "click" && !this.itemHasChild) {
|
||||
this.$emit("unset-mobile-item", false);
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
/**
|
||||
* Click Sort settings event handler
|
||||
* @param {object} event
|
||||
*/
|
||||
onClickSortSettings(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.$refs["modal"].show();
|
||||
},
|
||||
},
|
||||
inject: ["emitActiveShow", "emitItemClick", "emitItemUpdate"],
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user