2019-10-30 01:03:26 +05:30
|
|
|
<template>
|
2020-02-03 23:22:28 +05:30
|
|
|
<Popover
|
|
|
|
:show-popup="isShown"
|
|
|
|
:hide-arrow="true"
|
|
|
|
:placement="right ? 'bottom-end' : 'bottom-start'"
|
|
|
|
>
|
2022-02-10 12:11:51 +05:30
|
|
|
<template v-slot:target>
|
|
|
|
<div class="h-full" v-on-outside-click="() => (isShown = false)">
|
|
|
|
<slot
|
|
|
|
:toggleDropdown="toggleDropdown"
|
|
|
|
:highlightItemUp="highlightItemUp"
|
|
|
|
:highlightItemDown="highlightItemDown"
|
|
|
|
:selectHighlightedItem="selectHighlightedItem"
|
|
|
|
></slot>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<template v-slot:content>
|
|
|
|
<div class="bg-white rounded w-full min-w-40">
|
|
|
|
<div class="p-1 max-h-64 overflow-auto text-sm">
|
|
|
|
<div v-if="isLoading" class="p-2 text-gray-600 italic">
|
|
|
|
{{ t('Loading...') }}
|
2020-02-03 19:18:46 +05:30
|
|
|
</div>
|
2022-02-10 12:11:51 +05:30
|
|
|
<div
|
|
|
|
v-if="!isLoading && dropdownItems.length === 0"
|
|
|
|
class="p-2 text-gray-600 italic"
|
|
|
|
>
|
|
|
|
{{ getEmptyMessage() }}
|
|
|
|
</div>
|
|
|
|
<template v-else>
|
|
|
|
<div v-for="d in dropdownItems" :key="d.label">
|
|
|
|
<div
|
|
|
|
v-if="d.isGroup"
|
|
|
|
class="
|
|
|
|
px-2
|
|
|
|
pt-3
|
|
|
|
pb-1
|
|
|
|
text-xs
|
|
|
|
uppercase
|
|
|
|
text-gray-700
|
|
|
|
font-semibold
|
|
|
|
tracking-wider
|
|
|
|
"
|
|
|
|
>
|
|
|
|
{{ d.label }}
|
|
|
|
</div>
|
|
|
|
<a
|
|
|
|
v-else
|
|
|
|
ref="items"
|
|
|
|
class="
|
|
|
|
block
|
|
|
|
p-2
|
|
|
|
rounded-md
|
|
|
|
mt-1
|
|
|
|
first:mt-0
|
|
|
|
cursor-pointer
|
|
|
|
truncate
|
|
|
|
"
|
|
|
|
:class="d.index === highlightedIndex ? 'bg-gray-100' : ''"
|
|
|
|
@mouseenter="highlightedIndex = d.index"
|
|
|
|
@mouseleave="highlightedIndex = -1"
|
|
|
|
@mousedown.prevent
|
|
|
|
@click="selectItem(d)"
|
|
|
|
>
|
|
|
|
<component :is="d.component" v-if="d.component" />
|
|
|
|
<template v-else>{{ d.label }}</template>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</div>
|
2019-10-30 01:03:26 +05:30
|
|
|
</div>
|
2022-02-10 12:11:51 +05:30
|
|
|
</template>
|
2020-02-03 23:22:28 +05:30
|
|
|
</Popover>
|
2019-10-30 01:03:26 +05:30
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2020-02-03 23:22:28 +05:30
|
|
|
import Popover from './Popover';
|
2019-11-20 01:59:25 +05:30
|
|
|
import uniq from 'lodash/uniq';
|
|
|
|
|
2019-10-30 01:03:26 +05:30
|
|
|
export default {
|
|
|
|
name: 'Dropdown',
|
|
|
|
props: {
|
|
|
|
items: {
|
|
|
|
type: Array,
|
2021-11-26 12:51:47 +05:30
|
|
|
default: () => [],
|
2019-10-30 01:03:26 +05:30
|
|
|
},
|
2019-11-20 01:59:25 +05:30
|
|
|
groups: {
|
|
|
|
type: Array,
|
2021-11-26 12:51:47 +05:30
|
|
|
default: null,
|
2019-11-20 01:59:25 +05:30
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
right: {
|
|
|
|
type: Boolean,
|
2021-11-26 12:51:47 +05:30
|
|
|
default: false,
|
2020-02-03 19:18:46 +05:30
|
|
|
},
|
|
|
|
isLoading: {
|
|
|
|
type: Boolean,
|
2021-11-26 12:51:47 +05:30
|
|
|
default: false,
|
|
|
|
},
|
2022-01-12 15:04:16 +05:30
|
|
|
df: {
|
|
|
|
default: null,
|
|
|
|
},
|
|
|
|
doc: {
|
|
|
|
default: null,
|
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
},
|
2020-02-03 23:22:28 +05:30
|
|
|
components: {
|
2021-11-26 12:51:47 +05:30
|
|
|
Popover,
|
2020-02-03 23:22:28 +05:30
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
isShown: false,
|
2021-11-26 12:51:47 +05:30
|
|
|
highlightedIndex: -1,
|
2019-10-30 01:03:26 +05:30
|
|
|
};
|
|
|
|
},
|
2019-11-20 01:59:25 +05:30
|
|
|
computed: {
|
|
|
|
sortedGroups() {
|
|
|
|
if (Array.isArray(this.groups)) {
|
|
|
|
return this.groups;
|
|
|
|
}
|
|
|
|
let groupNames = uniq(
|
|
|
|
this.items
|
2021-11-26 12:51:47 +05:30
|
|
|
.map((d) => d.group)
|
2019-11-20 01:59:25 +05:30
|
|
|
.filter(Boolean)
|
|
|
|
.sort()
|
|
|
|
);
|
|
|
|
if (groupNames.length > 0) {
|
|
|
|
return groupNames;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
dropdownItems() {
|
|
|
|
if (this.sortedGroups) {
|
|
|
|
let itemsByGroup = {};
|
|
|
|
|
|
|
|
for (let item of this.items) {
|
|
|
|
let group = item.group || '';
|
|
|
|
itemsByGroup[group] = itemsByGroup[group] || [];
|
|
|
|
itemsByGroup[group].push(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
let items = [];
|
|
|
|
let i = 0;
|
|
|
|
for (let group of this.sortedGroups) {
|
|
|
|
let groupItems = itemsByGroup[group];
|
2021-11-26 12:51:47 +05:30
|
|
|
groupItems = groupItems.map((d) => {
|
2019-11-20 01:59:25 +05:30
|
|
|
d.index = i;
|
|
|
|
i++;
|
|
|
|
return d;
|
|
|
|
});
|
|
|
|
items = items.concat(
|
|
|
|
{
|
|
|
|
label: group,
|
2021-11-26 12:51:47 +05:30
|
|
|
isGroup: true,
|
2019-11-20 01:59:25 +05:30
|
|
|
},
|
|
|
|
groupItems
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.items.map((d, i) => {
|
|
|
|
d.index = i;
|
|
|
|
return d;
|
|
|
|
});
|
2021-11-26 12:51:47 +05:30
|
|
|
},
|
2019-11-20 01:59:25 +05:30
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
methods: {
|
2022-01-12 15:04:16 +05:30
|
|
|
getEmptyMessage() {
|
|
|
|
const { emptyMessage } = this.df ?? {};
|
|
|
|
if (typeof emptyMessage === 'function') {
|
2022-01-24 12:01:14 +05:30
|
|
|
return this.t(emptyMessage(this.doc));
|
2022-01-12 15:04:16 +05:30
|
|
|
} else if (emptyMessage) {
|
2022-01-24 12:01:14 +05:30
|
|
|
return this.t(emptyMessage);
|
2022-01-12 15:04:16 +05:30
|
|
|
}
|
2022-01-24 12:01:14 +05:30
|
|
|
return this.t('Empty');
|
2022-01-12 15:04:16 +05:30
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
selectItem(d) {
|
|
|
|
if (d.action) {
|
|
|
|
d.action();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
toggleDropdown(flag) {
|
|
|
|
if (flag == null) {
|
|
|
|
this.isShown = !this.isShown;
|
|
|
|
} else {
|
|
|
|
this.isShown = Boolean(flag);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
selectHighlightedItem() {
|
|
|
|
if (![-1, this.items.length].includes(this.highlightedIndex)) {
|
|
|
|
// valid selection
|
|
|
|
let item = this.items[this.highlightedIndex];
|
|
|
|
this.selectItem(item);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
highlightItemUp() {
|
|
|
|
this.highlightedIndex -= 1;
|
|
|
|
if (this.highlightedIndex < 0) {
|
|
|
|
this.highlightedIndex = 0;
|
|
|
|
}
|
|
|
|
this.$nextTick(() => {
|
|
|
|
let index = this.highlightedIndex;
|
|
|
|
if (index !== 0) {
|
|
|
|
index -= 1;
|
|
|
|
}
|
2019-12-03 13:51:50 +05:30
|
|
|
this.scrollToHighlighted();
|
2019-10-30 01:03:26 +05:30
|
|
|
});
|
|
|
|
},
|
|
|
|
highlightItemDown() {
|
|
|
|
this.highlightedIndex += 1;
|
|
|
|
if (this.highlightedIndex > this.items.length) {
|
|
|
|
this.highlightedIndex = this.items.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$nextTick(() => {
|
2019-12-03 13:51:50 +05:30
|
|
|
this.scrollToHighlighted();
|
2019-10-30 01:03:26 +05:30
|
|
|
});
|
2019-12-03 13:51:50 +05:30
|
|
|
},
|
|
|
|
scrollToHighlighted() {
|
|
|
|
let highlightedElement = this.$refs.items[this.highlightedIndex];
|
|
|
|
highlightedElement &&
|
|
|
|
highlightedElement.scrollIntoView({ block: 'nearest' });
|
2021-11-26 12:51:47 +05:30
|
|
|
},
|
|
|
|
},
|
2019-10-30 01:03:26 +05:30
|
|
|
};
|
|
|
|
</script>
|