2018-08-27 19:22:25 +00:00
|
|
|
import Vue from 'vue'
|
2020-07-23 06:41:22 +00:00
|
|
|
import { mapState } from 'vuex'
|
2018-08-27 19:22:25 +00:00
|
|
|
|
|
|
|
import './tab_switcher.scss'
|
|
|
|
|
|
|
|
export default Vue.component('tab-switcher', {
|
|
|
|
name: 'TabSwitcher',
|
2019-08-12 17:01:38 +00:00
|
|
|
props: {
|
|
|
|
renderOnlyFocused: {
|
|
|
|
required: false,
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
onSwitch: {
|
|
|
|
required: false,
|
2019-11-08 16:14:01 +00:00
|
|
|
type: Function,
|
|
|
|
default: undefined
|
2019-08-12 17:01:38 +00:00
|
|
|
},
|
2019-09-08 10:44:29 +00:00
|
|
|
activeTab: {
|
2019-08-12 17:01:38 +00:00
|
|
|
required: false,
|
2019-11-08 16:14:01 +00:00
|
|
|
type: String,
|
|
|
|
default: undefined
|
2019-08-12 17:01:38 +00:00
|
|
|
},
|
|
|
|
scrollableTabs: {
|
|
|
|
required: false,
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
2020-05-03 14:36:12 +00:00
|
|
|
},
|
|
|
|
sideTabBar: {
|
|
|
|
required: false,
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
2019-08-12 17:01:38 +00:00
|
|
|
}
|
|
|
|
},
|
2018-08-27 19:22:25 +00:00
|
|
|
data () {
|
|
|
|
return {
|
2019-01-17 19:25:50 +00:00
|
|
|
active: this.$slots.default.findIndex(_ => _.tag)
|
2018-08-27 19:22:25 +00:00
|
|
|
}
|
|
|
|
},
|
2019-08-10 18:48:05 +00:00
|
|
|
computed: {
|
|
|
|
activeIndex () {
|
|
|
|
// In case of controlled component
|
|
|
|
if (this.activeTab) {
|
|
|
|
return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
|
|
|
|
} else {
|
|
|
|
return this.active
|
|
|
|
}
|
2020-07-23 06:41:22 +00:00
|
|
|
},
|
|
|
|
bodyLocked () {
|
|
|
|
return this.settingsModalState === 'visible'
|
|
|
|
},
|
|
|
|
...mapState({
|
|
|
|
settingsModalState: state => state.interface.settingsModalState
|
|
|
|
})
|
2019-08-10 18:48:05 +00:00
|
|
|
},
|
2019-07-05 07:02:14 +00:00
|
|
|
beforeUpdate () {
|
|
|
|
const currentSlot = this.$slots.default[this.active]
|
|
|
|
if (!currentSlot.tag) {
|
|
|
|
this.active = this.$slots.default.findIndex(_ => _.tag)
|
|
|
|
}
|
|
|
|
},
|
2018-08-27 19:22:25 +00:00
|
|
|
methods: {
|
2019-08-10 03:48:33 +00:00
|
|
|
activateTab (index) {
|
2019-08-12 17:01:38 +00:00
|
|
|
return (e) => {
|
|
|
|
e.preventDefault()
|
2019-05-14 19:38:16 +00:00
|
|
|
if (typeof this.onSwitch === 'function') {
|
2019-08-10 03:48:08 +00:00
|
|
|
this.onSwitch.call(null, this.$slots.default[index].key)
|
2019-05-14 19:38:16 +00:00
|
|
|
}
|
2019-01-17 19:25:50 +00:00
|
|
|
this.active = index
|
2020-05-25 11:16:03 +00:00
|
|
|
if (this.scrollableTabs) {
|
|
|
|
this.$refs.contents.scrollTop = 0
|
|
|
|
}
|
2019-01-17 19:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
render (h) {
|
2018-08-27 19:22:25 +00:00
|
|
|
const tabs = this.$slots.default
|
2019-07-05 07:02:14 +00:00
|
|
|
.map((slot, index) => {
|
|
|
|
if (!slot.tag) return
|
|
|
|
const classesTab = ['tab']
|
|
|
|
const classesWrapper = ['tab-wrapper']
|
2019-08-10 18:48:05 +00:00
|
|
|
if (this.activeIndex === index) {
|
2019-07-05 07:02:14 +00:00
|
|
|
classesTab.push('active')
|
|
|
|
classesWrapper.push('active')
|
|
|
|
}
|
2019-07-24 19:35:52 +00:00
|
|
|
if (slot.data.attrs.image) {
|
|
|
|
return (
|
2019-08-10 04:26:29 +00:00
|
|
|
<div class={classesWrapper.join(' ')}>
|
2019-07-24 19:35:52 +00:00
|
|
|
<button
|
|
|
|
disabled={slot.data.attrs.disabled}
|
|
|
|
onClick={this.activateTab(index)}
|
|
|
|
class={classesTab.join(' ')}>
|
|
|
|
<img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/>
|
|
|
|
{slot.data.attrs.label ? '' : slot.data.attrs.label}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2019-07-05 07:02:14 +00:00
|
|
|
return (
|
2019-08-10 04:26:29 +00:00
|
|
|
<div class={classesWrapper.join(' ')}>
|
2019-07-05 07:02:14 +00:00
|
|
|
<button
|
|
|
|
disabled={slot.data.attrs.disabled}
|
|
|
|
onClick={this.activateTab(index)}
|
2020-05-25 13:10:14 +00:00
|
|
|
class={classesTab.join(' ')}
|
2020-05-27 00:32:57 +00:00
|
|
|
type="button"
|
2020-05-25 13:10:14 +00:00
|
|
|
>
|
|
|
|
{!slot.data.attrs.icon ? '' : (<i class={'tab-icon icon-' + slot.data.attrs.icon}/>)}
|
2020-05-27 00:32:57 +00:00
|
|
|
<span class="text">
|
|
|
|
{slot.data.attrs.label}
|
|
|
|
</span>
|
2020-05-25 13:10:14 +00:00
|
|
|
</button>
|
2019-07-05 07:02:14 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
})
|
2019-01-17 19:25:50 +00:00
|
|
|
|
|
|
|
const contents = this.$slots.default.map((slot, index) => {
|
|
|
|
if (!slot.tag) return
|
2019-08-10 18:48:05 +00:00
|
|
|
const active = this.activeIndex === index
|
2020-05-23 23:06:55 +00:00
|
|
|
const classes = [ active ? 'active' : 'hidden' ]
|
|
|
|
if (slot.data.attrs.fullHeight) {
|
|
|
|
classes.push('full-height')
|
|
|
|
}
|
2020-05-28 18:26:33 +00:00
|
|
|
const renderSlot = (!this.renderOnlyFocused || active)
|
|
|
|
? slot
|
|
|
|
: ''
|
|
|
|
|
|
|
|
return (
|
2020-05-27 00:32:57 +00:00
|
|
|
<div class={classes}>
|
|
|
|
{
|
|
|
|
this.sideTabBar
|
|
|
|
? <h1 class="mobile-label">{slot.data.attrs.label}</h1>
|
|
|
|
: ''
|
|
|
|
}
|
2020-05-28 18:26:33 +00:00
|
|
|
{renderSlot}
|
2020-05-27 00:32:57 +00:00
|
|
|
</div>
|
|
|
|
)
|
2019-01-17 19:25:50 +00:00
|
|
|
})
|
|
|
|
|
2018-08-27 19:22:25 +00:00
|
|
|
return (
|
2020-05-03 14:36:12 +00:00
|
|
|
<div class={'tab-switcher ' + (this.sideTabBar ? 'side-tabs' : 'top-tabs')}>
|
2019-01-17 20:05:58 +00:00
|
|
|
<div class="tabs">
|
|
|
|
{tabs}
|
|
|
|
</div>
|
2020-07-23 06:41:22 +00:00
|
|
|
<div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} v-body-scroll-lock={this.bodyLocked}>
|
2019-01-17 20:05:58 +00:00
|
|
|
{contents}
|
|
|
|
</div>
|
2018-11-21 19:08:27 +00:00
|
|
|
</div>
|
|
|
|
)
|
2018-08-27 19:22:25 +00:00
|
|
|
}
|
|
|
|
})
|