276 lines
7.5 KiB
Vue
276 lines
7.5 KiB
Vue
|
<template>
|
|||
|
<div class="context-menu-dropdown">
|
|||
|
<div class="dropdown">
|
|||
|
<button
|
|||
|
:data-offset="$attrs.dataOffset ?? undefined"
|
|||
|
class="btn"
|
|||
|
type="button"
|
|||
|
id="context-menu"
|
|||
|
data-toggle="dropdown"
|
|||
|
aria-haspopup="true"
|
|||
|
aria-expanded="false"
|
|||
|
>
|
|||
|
<span class="tavasi tavasi-more-vert"></span>
|
|||
|
</button>
|
|||
|
<div
|
|||
|
:style="{
|
|||
|
width: $attrs.width ?? undefined,
|
|||
|
height: $attrs.height ?? undefined,
|
|||
|
'max-height': $attrs.maxHeight ?? '10rem',
|
|||
|
}"
|
|||
|
class="dropdown-menu"
|
|||
|
aria-labelledby="context-menu"
|
|||
|
>
|
|||
|
<div v-for="(action, index) in contextMenu">
|
|||
|
<div v-if="action.show">
|
|||
|
<div v-if="action.can">
|
|||
|
<button
|
|||
|
v-if="!action.showOutside ?? true"
|
|||
|
v-can="action.can"
|
|||
|
class="dropdown-item"
|
|||
|
type="button"
|
|||
|
:key="index"
|
|||
|
@click="handleAction(action)"
|
|||
|
>
|
|||
|
<!-- put below line if authorization is ok. -->
|
|||
|
<!-- v-can="action.can" -->
|
|||
|
<NuxtImg :src="prepareIcon(action)" alt="" class="img-fluid" />
|
|||
|
{{ action.title }}
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
<div v-else>
|
|||
|
<button
|
|||
|
v-if="!action.showOutside ?? true"
|
|||
|
class="dropdown-item"
|
|||
|
type="button"
|
|||
|
:key="index"
|
|||
|
@click="handleAction(action)"
|
|||
|
>
|
|||
|
<!-- put below line if authorization is ok. -->
|
|||
|
<!-- v-can="action.can" -->
|
|||
|
<NuxtImg :src="prepareIcon(action)" alt="" class="img-fluid" />
|
|||
|
{{ action.title }}
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
/**
|
|||
|
* @vue-prop {Array} list - لیست
|
|||
|
* @vue-prop {*} clickedItem - آیتمی که کلیک شده است
|
|||
|
* @vue-prop {*} contextMenu - منو که از سمت والد دریافت میگردد
|
|||
|
* @vue-prop {*} parentComponent - کامپوننت والد
|
|||
|
*/
|
|||
|
|
|||
|
export default {
|
|||
|
// contextMenu: right click actions
|
|||
|
// list: folder or file list.
|
|||
|
// clickedItem: selected item in the loop.
|
|||
|
props: ["list", "clickedItem", "contextMenu", "parentComponent"],
|
|||
|
emits: [
|
|||
|
"rename-item",
|
|||
|
"remove-item",
|
|||
|
"update-order",
|
|||
|
"import",
|
|||
|
"reply-to",
|
|||
|
"filter",
|
|||
|
"notifications",
|
|||
|
"search",
|
|||
|
"edit-item",
|
|||
|
],
|
|||
|
methods: {
|
|||
|
/**
|
|||
|
* آمادهسازی آیکون.
|
|||
|
*
|
|||
|
* @param {object} options - گزینههای آیکون
|
|||
|
* @returns {string} - مسیر فایل SVG آیکون
|
|||
|
*/
|
|||
|
prepareIcon({ icon }) {
|
|||
|
try {
|
|||
|
return import(`assets/common/img/${icon}.svg`).default;
|
|||
|
} catch (err) {
|
|||
|
return import(`assets/common/img/icomoon/SVG/${icon}.svg`).default;
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* انجام اقدامات کلیک راست بر روی پوشه.
|
|||
|
*
|
|||
|
* انجام تمام اقدامات کلیک راست بر روی پوشه/فایل.
|
|||
|
*
|
|||
|
* @param {object} selectedAction - اقدام انتخابشده توسط کاربر
|
|||
|
*/
|
|||
|
handleAction(selectedAction) {
|
|||
|
switch (selectedAction.action) {
|
|||
|
case "search":
|
|||
|
this.$emit("search");
|
|||
|
break;
|
|||
|
case "notifications":
|
|||
|
this.$emit("notifications");
|
|||
|
break;
|
|||
|
case "filter":
|
|||
|
this.$emit("filter");
|
|||
|
break;
|
|||
|
|
|||
|
case "new-sub-folder":
|
|||
|
this.$emit("new-sub-folder");
|
|||
|
break;
|
|||
|
case "remove":
|
|||
|
this.$emit("remove-item");
|
|||
|
break;
|
|||
|
case "remove-item":
|
|||
|
this.$emit("remove-item");
|
|||
|
break;
|
|||
|
case "rename":
|
|||
|
this.toggleRenameForm(this.list, this.clickedItem);
|
|||
|
this.$emit("rename-item");
|
|||
|
break;
|
|||
|
case "order":
|
|||
|
this.$emit("update-order", selectedAction.value);
|
|||
|
break;
|
|||
|
case "move":
|
|||
|
break;
|
|||
|
case "details":
|
|||
|
break;
|
|||
|
case "copy":
|
|||
|
this.$emit("copy-text");
|
|||
|
break;
|
|||
|
case "import":
|
|||
|
this.$emit("import");
|
|||
|
break;
|
|||
|
case "export":
|
|||
|
break;
|
|||
|
case "archive":
|
|||
|
break;
|
|||
|
case "reply-to":
|
|||
|
this.$emit("reply-to");
|
|||
|
break;
|
|||
|
case "edit-item":
|
|||
|
this.$emit("edit-item");
|
|||
|
break;
|
|||
|
case "close":
|
|||
|
this.$emit("close");
|
|||
|
break;
|
|||
|
case "join-to-group":
|
|||
|
this.$emit("join-to-group");
|
|||
|
break;
|
|||
|
case "remove-from-lobby":
|
|||
|
this.$emit("remove-from-lobby");
|
|||
|
break;
|
|||
|
case "subjecting":
|
|||
|
this.$emit("subjecting");
|
|||
|
break;
|
|||
|
case "show-text":
|
|||
|
this.$emit("show-text");
|
|||
|
break;
|
|||
|
default:
|
|||
|
this.$emit("other", selectedAction.action);
|
|||
|
}
|
|||
|
},
|
|||
|
/**
|
|||
|
* نمایش/مخفی کردن فرم تغییر نام.
|
|||
|
*
|
|||
|
* نمایش یا مخفی کردن فرم تغییر نام در صورت انتخاب گزینه تغییر نام یا بستن فرم تغییر نام.
|
|||
|
* 1- یافتن شاخص مورد انتخاب شده
|
|||
|
* 2- بررسی اینکه آیتم وجود دارد یا خیر.
|
|||
|
* 3- اگر آیتم وجود دارد، سپس تغییر وضعیت editMode را انجام میدهد
|
|||
|
* 4- و در نهایت وضعیت editMode آیتم یافتشده را تنظیم میکند.
|
|||
|
*
|
|||
|
* @param {array} list - لیست پوشه یا فایل
|
|||
|
* @param {object} clickedItem - پوشه/فایلی که کاربر میخواهد آن را تغییر نام دهد.
|
|||
|
*/
|
|||
|
toggleRenameForm(list, clickedItem) {
|
|||
|
const resultIndex = list.findIndex((item) => clickedItem.id === item.id);
|
|||
|
|
|||
|
if (resultIndex > -1) {
|
|||
|
const editMode = list[resultIndex]?.editMode ?? false;
|
|||
|
this.$set(list[resultIndex], "editMode", !editMode);
|
|||
|
this.$set(list[resultIndex], "parentComponent", this.parentComponent);
|
|||
|
}
|
|||
|
},
|
|||
|
},
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped lang="scss">
|
|||
|
.context-menu-dropdown {
|
|||
|
position: absolute;
|
|||
|
left: 0;
|
|||
|
top: 0;
|
|||
|
height: 100%;
|
|||
|
transition: all 0.3s ease;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
|
|||
|
.dropdown {
|
|||
|
.dropdown-menu {
|
|||
|
width: 156px;
|
|||
|
// max-height: 291px;
|
|||
|
min-height: 5em;
|
|||
|
height: auto;
|
|||
|
max-height: 10rem;
|
|||
|
border-radius: 10px;
|
|||
|
background: #fff;
|
|||
|
border: 1px solid #bac4ce;
|
|||
|
overflow-y: auto;
|
|||
|
padding: 1em;
|
|||
|
z-index: 99;
|
|||
|
//top: -3.5em !important;
|
|||
|
left: 2.5em;
|
|||
|
// height: 10rem;
|
|||
|
|
|||
|
.dropdown-item {
|
|||
|
font-weight: normal;
|
|||
|
font-size: 14px;
|
|||
|
text-align: right;
|
|||
|
color: #1b2733;
|
|||
|
border: 1px solid rgba(0, 0, 0, 0);
|
|||
|
padding: 0.2em 0;
|
|||
|
|
|||
|
&:hover,
|
|||
|
&:focus {
|
|||
|
background-color: #f0f0f0;
|
|||
|
//font-weight: bold;
|
|||
|
}
|
|||
|
|
|||
|
.img-fluid {
|
|||
|
width: 1.8em;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.btn {
|
|||
|
padding: 0;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
background: rgba(255, 255, 255, 0.8);
|
|||
|
height: 100%;
|
|||
|
|
|||
|
&[aria-expanded="true"] {
|
|||
|
.tavasi-more-vert:before {
|
|||
|
content: "\e940";
|
|||
|
color: #dc3545;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.tavasi {
|
|||
|
// transition: all 0.2s;
|
|||
|
// font-size: 20px;
|
|||
|
// color: #6f6f6f;
|
|||
|
}
|
|||
|
|
|||
|
&:hover .tavasi {
|
|||
|
transform: scale(1.2);
|
|||
|
// transition: all 0.2s;
|
|||
|
// font-weight: bold;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|