Files

276 lines
6.6 KiB
JavaScript

import accessibility from "../directives/accessibility.js";
import TabView from '../../../index.ci.php/public/js/components/primevue/tabview/tabview.esm.min.js';
import TabPanel from '../../../index.ci.php/public/js/components/primevue/tabpanel/tabpanel.esm.min.js';
export default {
components: {
tabview: TabView,
tabpanel: TabPanel
},
directives: {
accessibility
},
emits: [
'update:modelValue',
'change',
'changed'
],
props: {
config: {
type: [String, Array, Object, Promise],
required: true
},
default: String,
modelValue: [String, Number, Boolean, Array, Object, Date, Function, Symbol],
vertical: Boolean,
border: Boolean,
useprimevue: {
type: Boolean,
default: false
}
},
data() {
return {
current: null,
tabs: {},
count: null
}
},
computed: {
currentTab() {
if (this.tabs[this.current])
return this.tabs[this.current];
return { component: 'div' };
},
value: {
get() {
return this.modelValue;
},
set(v) {
this.$emit('update:modelValue', v);
}
},
calcActiveIndex: function() {
let keys = Object.keys(this.tabs);
let index = keys.indexOf(this.default);
if( index === -1 ) {
return 0;
} else {
return index;
}
}
},
watch: {
config(n) {
this.initConfig(n);
}
},
methods: {
handleTabClick: function (e) {
let keys = Object.keys(this.tabs);
this.change(keys[e.index]);
},
change(key) {
this.$emit("change", key)
this.current = key;
this.$nextTick(() => this.$emit("changed", key));
},
initConfig(config) {
if (!config)
return;
if (config instanceof Promise)
return config
.then(result => result.data)
.then(this.initConfig)
.catch(this.$fhcAlert.handleSystemError);
if (typeof config === 'string' || config instanceof String)
return this.$api
.get(config)
.then(result => result.data)
.then(this.initConfig)
.catch(this.$fhcAlert.handleSystemError);
const tabs = {};
function _addToTabs(key, item) {
if (!item.component)
return console.error('Component missing for ' + key);
//making it reactive for showing headerSuffix
const value = Vue.reactive({
suffix: '',
showSuffix: item.showSuffix || false
});
tabs[key] = {
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
title: Vue.computed(() => item.title || key),
config: item.config,
key,
value,
suffixhelper: item.suffixhelper ?? null
};
}
if (Array.isArray(config)) {
config.forEach((item, key) => _addToTabs(key, item));
}
else {
Object.entries(config).forEach(([key, item]) => _addToTabs(key, item));
}
if (this.current === null || !tabs[this.current]) {
if (tabs[this.default])
this.current = this.default;
else
this.current = Object.keys(tabs)[0];
}
this.tabs = tabs;
},
updateSuffix() {
this.getTabSuffix(this.currentTab);
},
removeInvalidCountTabs(){
if(this.modelValue.length)
{
let countIst = this.modelValue.length;
const tabsToDelete = [];
Object.entries(this.config).forEach(([key, item]) => {
const target = item?.config ? item : item?.value || item;
// check config for validCountMulti
if (target.config?.validCountMulti !== undefined) {
let tab;
let countSoll;
tab = key;
countSoll = target.config.validCountMulti;
//check if tab is existing
if (countSoll !== undefined && countSoll == countIst) {
//add tab if it was removed before
if (tab in this.tabs == false) {
const value = Vue.reactive({
suffix: '',
showSuffix: item.showSuffix || false
});
this.tabs[tab] = {
component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))),
title: Vue.computed(() => item.title || tab),
config: item.config,
tab,
value,
suffixhelper: item.suffixhelper ?? null
};
}
}
//add to toDeleteArray if count is not allowed
if (countSoll !== undefined && countSoll !== countIst) {
tabsToDelete.push(tab);
}
}
});
// Delete all tabs with count not allowed
tabsToDelete.forEach(k => {
delete this.tabs[k];
});
}
},
async getTabSuffix(tab) {
if (!tab.value.showSuffix) {
return;
}
if (tab.suffixhelper !== null) {
const suffixhelper = await import(tab.suffixhelper);
const suffix = await suffixhelper.getSuffix(this.$api, this.modelValue);
tab.value.suffix = suffix;
} else {
tab.value.suffix = '';
}
},
getTabSuffixes() {
Object.entries(this.tabs).forEach(([key, item]) => this.getTabSuffix(item));
}
},
created() {
this.initConfig(this.config);
},
mounted() {
this.getTabSuffixes();
this.removeInvalidCountTabs();
},
updated() {
this.getTabSuffixes();
this.removeInvalidCountTabs();
},
template: `
<template v-if="useprimevue">
<tabview
class="d-flex flex-column"
:scrollable="true"
:lazy="true"
:activeIndex="calcActiveIndex"
:pt="{navContainer:{style: 'flex: 0 0 auto;'}, panelContainer:{class: 'overflow-y-scroll p-2', style: 'flex: 1 1 auto;'}}"
@tab-click="handleTabClick"
>
<tabpanel
v-for="tab in tabs"
:key="tab.key"
:header="tab.title + ((tab.value.showSuffix && tab.value.suffix !== '') ? ' ' + tab.value.suffix : '')"
:pt="{headerAction:{class: 'px-2 py-1'}}"
>
<keep-alive>
<component
:is="tab.component"
v-model="value"
:config="tab.config"
@update:suffix="updateSuffix($event)"
></component>
</keep-alive>
</tabpanel>
</tabview>
</template>
<template v-else="">
<div class="fhc-tabs d-flex" :class="vertical ? 'align-items-stretch gap-3' : (border ? 'flex-column' : 'flex-column gap-3')" v-if="Object.keys(tabs).length">
<div class="nav" :class="vertical ? 'nav-pills flex-column' : 'nav-tabs'">
<div
v-for="tab in tabs"
:key="tab.key"
class="nav-item nav-link"
:class="{active: tab.key == current}"
@click="change(tab.key)"
:aria-current="tab.key == current ? 'page' : ''"
v-accessibility:tab.[vertical]
>
{{tab.title}} <span v-if="tab.value.showSuffix && tab.value.suffix"> {{ tab.value.suffix }}</span>
</div>
</div>
<div :style="vertical ? '' : 'flex: 1 1 0%; height: 0%'" class="overflow-auto flex-grow-1" :class="vertical || !border ? '' : 'p-3 border-bottom border-start border-end'">
<keep-alive>
<component
ref="current"
:is="currentTab.component"
v-model="value"
:config="currentTab.config"
@update:suffix="updateSuffix($event)"
></component>
</keep-alive>
</div>
</div>
</template>`
};