mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-01 12:19:28 +00:00
275 lines
6.6 KiB
JavaScript
275 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', 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 : '')"
|
|
>
|
|
<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>`
|
|
};
|
|
|