2020-12-08 19:12:30 +00:00
|
|
|
<template>
|
|
|
|
|
<div class="tabs-component">
|
|
|
|
|
<ul role="tablist" class="tabs-component-tabs">
|
|
|
|
|
<li
|
|
|
|
|
v-for="(tab, i) in tabs"
|
|
|
|
|
:key="i"
|
|
|
|
|
:class="{ 'is-active': tab.isActive, 'is-disabled': tab.isDisabled }"
|
|
|
|
|
class="tabs-component-tab"
|
|
|
|
|
role="presentation"
|
|
|
|
|
v-show="tab.isVisible"
|
|
|
|
|
>
|
|
|
|
|
<span
|
|
|
|
|
v-html="tab.header"
|
2022-04-14 12:50:58 -04:00
|
|
|
:aria-label="tab.hash"
|
2020-12-08 19:12:30 +00:00
|
|
|
:aria-selected="tab.isActive"
|
|
|
|
|
@click="selectTab(tab.hash, $event)"
|
|
|
|
|
class="tabs-component-tab-a"
|
|
|
|
|
role="tab"
|
|
|
|
|
></span>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
<div class="tabs-component-panels">
|
|
|
|
|
<slot />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import expiringStorage from "./expiringStorage";
|
|
|
|
|
export default {
|
|
|
|
|
props: {
|
|
|
|
|
cacheLifetime: {
|
|
|
|
|
default: 5,
|
|
|
|
|
},
|
|
|
|
|
options: {
|
|
|
|
|
type: Object,
|
|
|
|
|
required: false,
|
|
|
|
|
default: () => ({
|
|
|
|
|
useUrlFragment: true,
|
|
|
|
|
defaultTabHash: null,
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
data: () => ({
|
|
|
|
|
tabs: [],
|
|
|
|
|
activeTabHash: "",
|
|
|
|
|
activeTabIndex: 0,
|
|
|
|
|
lastActiveTabHash: "",
|
|
|
|
|
}),
|
|
|
|
|
computed: {
|
|
|
|
|
storageKey() {
|
|
|
|
|
return `vue-tabs-component.cache.${window.location.host}${window.location.pathname}`;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
|
this.tabs = this.$children;
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
|
|
|
|
window.addEventListener("hashchange", () =>
|
|
|
|
|
this.selectTab(window.location.hash)
|
|
|
|
|
);
|
|
|
|
|
if (this.findTab(window.location.hash)) {
|
|
|
|
|
this.selectTab(window.location.hash);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const previousSelectedTabHash = expiringStorage.get(this.storageKey);
|
|
|
|
|
if (this.findTab(previousSelectedTabHash)) {
|
|
|
|
|
this.selectTab(previousSelectedTabHash);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
this.options.defaultTabHash !== null &&
|
|
|
|
|
this.findTab("#" + this.options.defaultTabHash)
|
|
|
|
|
) {
|
|
|
|
|
this.selectTab("#" + this.options.defaultTabHash);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (this.tabs.length) {
|
|
|
|
|
this.selectTab(this.tabs[0].hash);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
findTab(hash) {
|
|
|
|
|
return this.tabs.find((tab) => tab.hash === hash);
|
|
|
|
|
},
|
|
|
|
|
selectTab(selectedTabHash, event) {
|
|
|
|
|
// See if we should store the hash in the url fragment.
|
|
|
|
|
if (event && !this.options.useUrlFragment) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
const selectedTab = this.findTab(selectedTabHash);
|
|
|
|
|
if (!selectedTab) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (selectedTab.isDisabled) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (this.lastActiveTabHash === selectedTab.hash) {
|
|
|
|
|
this.$emit("clicked", { tab: selectedTab });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.tabs.forEach((tab) => {
|
|
|
|
|
tab.isActive = tab.hash === selectedTab.hash;
|
|
|
|
|
});
|
|
|
|
|
this.$emit("changed", { tab: selectedTab });
|
|
|
|
|
this.activeTabHash = selectedTab.hash;
|
|
|
|
|
this.activeTabIndex = this.getTabIndex(selectedTabHash);
|
|
|
|
|
this.lastActiveTabHash = this.activeTabHash = selectedTab.hash;
|
|
|
|
|
expiringStorage.set(
|
|
|
|
|
this.storageKey,
|
|
|
|
|
selectedTab.hash,
|
|
|
|
|
this.cacheLifetime
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
setTabVisible(hash, visible) {
|
|
|
|
|
const tab = this.findTab(hash);
|
|
|
|
|
if (!tab) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
tab.isVisible = visible;
|
|
|
|
|
if (tab.isActive) {
|
|
|
|
|
// If tab is active, set a different one as active.
|
|
|
|
|
tab.isActive = visible;
|
|
|
|
|
this.tabs.every((tab, index, array) => {
|
|
|
|
|
if (tab.isVisible) {
|
|
|
|
|
tab.isActive = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getTabIndex(hash) {
|
|
|
|
|
const tab = this.findTab(hash);
|
|
|
|
|
|
|
|
|
|
return this.tabs.indexOf(tab);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getTabHash(index) {
|
|
|
|
|
const tab = this.tabs.find((tab) => this.tabs.indexOf(tab) === index);
|
|
|
|
|
|
|
|
|
|
if (!tab) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tab.hash;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getActiveTab() {
|
|
|
|
|
return this.findTab(this.activeTabHash);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getActiveTabIndex() {
|
|
|
|
|
return this.getTabIndex(this.activeTabHash);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
</script>
|