Files
thetool/public/plugins/vue/tt-components/tt-modal.js
2025-12-05 13:57:38 +00:00

90 lines
3.8 KiB
JavaScript

Vue.component('tt-modal', {
props: {
show: {type: [Boolean, Object], default: false},
title: {type: String, default: 'Überschrift'},
delete: {type: Boolean, default: true},
deleteText: {type: String, default: 'Löschen'},
save: {type: Boolean, default: true},
saveLoading: {type: Boolean, default: false},
saveText: {type: String, default: 'Speichern'},
disableMinHeight: {type: Boolean, default: false}
},
watch: {
show(newVal) {
if (!newVal) {
this.$emit('close')
document.documentElement.style.overflow = ''
document.documentElement.style.paddingRight = ''
}
if (newVal) {
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
document.documentElement.style.overflow = 'hidden'
document.documentElement.style.paddingRight = scrollbarWidth + 'px'
this.$nextTick(() => {
const input = this.$refs.modal.querySelector('input')
if (input && !input.classList.contains('tt-autocomplete')) input.focus()
})
}
}
},
created() {
document.addEventListener('keydown', this.keydownHandler)
},
destroyed() {
document.removeEventListener('keydown', this.keydownHandler)
document.documentElement.style.overflow = ''
document.documentElement.style.paddingRight = ''
},
methods: {
keydownHandler(event) {
if (!this.show) return
if (event.key === 'Escape') this.$emit('update:show', false)
if (event.key === 'Enter' && this.save) {
if (event.target.tagName === 'TEXTAREA' || event.target.tagName === 'INPUT') return
this.$emit('submit')
}
}
},
data: () => ({
window: window,
isMobile: navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i) !== null
}),
template: `
<div class="modal show d-block"
role="dialog"
tabindex="-1"
style="background: rgba(0, 0, 0, 0.5);"
ref="modal"
@keydown.esc="$emit('update:show', false)"
v-if="show">
<div class="modal-dialog modal-lg modal-dialog-scrollable" role="document" @mousedown.stop>
<div class="modal-content" :style="{minHeight: disableMinHeight ? 'auto' : '45vh'}">
<div class="modal-header">
<h5 class="modal-title">{{title}}</h5>
<button type="button" class="close" @click="$emit('update:show', false)">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<slot></slot>
</div>
<div class="modal-footer">
<slot name="footer">
<slot name="footer-prepend"></slot>
<button v-if="save" class="btn btn-primary position-relative" @click="$emit('submit')" :disabled="saveLoading">
<span v-if="!saveLoading">{{ saveText }}</span>
<span v-if="saveLoading" class="top-50 start-50 translate-middle">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<span class="sr-only">Loading...</span>
</span>
</button>
<button v-if="$props.delete" class="btn btn-danger" @click="$emit('delete')">{{deleteText}}</button>
<button class="btn btn-secondary" @click="$emit('update:show', false)">Schließen</button>
</slot>
</div>
</div>
</div>
</div>
`
})