Refactor select.vue to use the outside click directive [SCI-9496]

This commit is contained in:
Martin Artnik 2023-10-13 16:12:01 +02:00
parent 957f539e32
commit 45e45d1543
2 changed files with 15 additions and 37 deletions

View file

@ -16,7 +16,9 @@ export default {
exclude.forEach(refName => { exclude.forEach(refName => {
if (!clickedOnExcludedEl) { if (!clickedOnExcludedEl) {
const excludedEl = vnode.context.$refs[refName]; const excludedEl = vnode.context.$refs[refName];
clickedOnExcludedEl = excludedEl?.contains(e.target); if (!excludedEl) return;
clickedOnExcludedEl = (excludedEl._isVue ? excludedEl.$el : excludedEl).contains(e.target);
} }
}); });

View file

@ -1,5 +1,5 @@
<template> <template>
<div @click="toggle" ref="container" class="sn-select" :class="{ 'sn-select--open': isOpen, 'sn-select--blank': !valueLabel, 'disabled': disabled }"> <div v-click-outside="{ handler: 'close', exclude: ['optionsContainer'] }" @click="toggle" ref="container" class="sn-select" :class="{ 'sn-select--open': isOpen, 'sn-select--blank': !valueLabel, 'disabled': disabled }">
<slot> <slot>
<button ref="focusElement" class="sn-select__value"> <button ref="focusElement" class="sn-select__value">
<span>{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span> <span>{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
@ -37,6 +37,7 @@
</template> </template>
<script> <script>
import PerfectScrollbar from 'vue2-perfect-scrollbar'; import PerfectScrollbar from 'vue2-perfect-scrollbar';
import outsideClick from '../../packs/vue/directives/outside_click';
export default { export default {
name: 'Select', name: 'Select',
@ -48,12 +49,13 @@
noOptionsPlaceholder: { type: String }, noOptionsPlaceholder: { type: String },
disabled: { type: Boolean, default: false } disabled: { type: Boolean, default: false }
}, },
comments: { PerfectScrollbar }, directives: {
'click-outside': outsideClick
},
data() { data() {
return { return {
isOpen: false, isOpen: false,
optionPositionStyle: '', optionPositionStyle: ''
blurPrevented: false
} }
}, },
computed: { computed: {
@ -66,34 +68,13 @@
} }
}, },
mounted() { mounted() {
this.focusElement.onblur = this.blur;
document.addEventListener('scroll', this.updateOptionPosition); document.addEventListener('scroll', this.updateOptionPosition);
}, },
beforeDestroy() { beforeDestroy() {
document.removeEventListener('scroll', this.updateOptionPosition); document.removeEventListener('scroll', this.updateOptionPosition);
}, },
methods: { methods: {
preventBlur() {
this.blurPrevented = true;
},
allowBlur() {
setTimeout(() => { this.blurPrevented = false }, 200);
},
blur() {
setTimeout(() => {
if (this.blurPrevented) {
this.focusElement.focus();
} else {
this.isOpen = false;
this.$emit('blur');
}
}, 100);
},
toggle() { toggle() {
if (this.isOpen && this.blurPrevented) {
return;
}
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
if (this.isOpen) { if (this.isOpen) {
@ -103,14 +84,16 @@
}); });
this.$refs.optionsContainer.scrollTop = 0; this.$refs.optionsContainer.scrollTop = 0;
this.updateOptionPosition(); this.updateOptionPosition();
this.setUpBlurHandlers();
} else { } else {
this.optionPositionStyle = ''; this.close()
this.$emit('close');
} }
}, },
close() {
this.isOpen = false;
this.optionPositionStyle = '';
this.$emit('close');
},
setValue(value) { setValue(value) {
this.focusElement.blur();
this.$emit('change', value); this.$emit('change', value);
}, },
updateOptionPosition() { updateOptionPosition() {
@ -129,13 +112,6 @@
} }
this.optionPositionStyle = `position: fixed; top: ${top}px; left: ${left}px; width: ${width}px` this.optionPositionStyle = `position: fixed; top: ${top}px; left: ${left}px; width: ${width}px`
},
setUpBlurHandlers() {
setTimeout(() => {
this.$refs.optionsContainer.$el.querySelector('.ps__thumb-y').addEventListener('mousedown', this.preventBlur);
this.$refs.optionsContainer.$el.querySelector('.ps__thumb-y').addEventListener('mouseup', this.allowBlur);
document.addEventListener('mouseup', this.allowBlur);
}, 100);
} }
} }
} }