uiv
Version:
Bootstrap 3 components implemented by Vue 2.
173 lines (169 loc) • 4.31 kB
JavaScript
import Dropdown from '../dropdown/Dropdown.js'
import { PortalTarget } from 'portal-vue'
import { isNumber, isFunction, isExist, isString, assign, hasOwnProperty } from '../../utils/object.utils'
const BEFORE_CHANGE_EVENT = 'before-change'
export default {
components: { Dropdown, PortalTarget },
props: {
value: {
type: Number,
validator: v => v >= 0
},
transition: {
type: Number,
default: 150
},
justified: Boolean,
pills: Boolean,
stacked: Boolean,
customNavClass: null,
customContentClass: null
},
data () {
return {
tabs: [],
activeIndex: 0 // Make v-model not required
}
},
watch: {
value: {
immediate: true,
handler (value) {
if (isNumber(value)) {
this.activeIndex = value
this.selectCurrent()
}
}
},
tabs (tabs) {
tabs.forEach((tab, index) => {
tab.transition = this.transition
if (index === this.activeIndex) {
tab.show()
}
})
this.selectCurrent()
}
},
computed: {
navClasses () {
const tabClasses = {
nav: true,
'nav-justified': this.justified,
'nav-tabs': !this.pills,
'nav-pills': this.pills,
'nav-stacked': this.stacked && this.pills
}
const customNavClass = this.customNavClass
if (isExist(customNavClass)) {
if (isString(customNavClass)) {
return assign({}, tabClasses, {
[customNavClass]: true
})
} else {
return assign({}, tabClasses, customNavClass)
}
} else {
return tabClasses
}
},
contentClasses () {
const contentClasses = {
'tab-content': true
}
const customContentClass = this.customContentClass
if (isExist(customContentClass)) {
if (isString(customContentClass)) {
return assign({}, contentClasses, {
[customContentClass]: true
})
} else {
return assign({}, contentClasses, customContentClass)
}
} else {
return contentClasses
}
},
groupedTabs () {
let tabs = []
const hash = {}
this.tabs.forEach(tab => {
if (tab.group) {
if (hasOwnProperty(hash, tab.group)) {
tabs[hash[tab.group]].tabs.push(tab)
} else {
tabs.push({
tabs: [tab],
group: tab.group
})
hash[tab.group] = tabs.length - 1
}
if (tab.active) {
tabs[hash[tab.group]].active = true
}
if (tab.pullRight) {
tabs[hash[tab.group]].pullRight = true
}
} else {
tabs.push(tab)
}
})
tabs = tabs.map(tab => {
if (Array.isArray(tab.tabs)) {
tab.hidden = tab.tabs.filter(v => v.hidden).length === tab.tabs.length
}
return tab
})
return tabs
}
},
methods: {
getTabClasses (tab, isSubTab = false) {
const defaultClasses = {
active: tab.active,
disabled: tab.disabled,
'pull-right': tab.pullRight && !isSubTab
}
// return with new classes added to tab
return assign(defaultClasses, tab.tabClasses)
},
selectCurrent () {
let found = false
this.tabs.forEach((tab, index) => {
if (index === this.activeIndex) {
found = !tab.active
tab.active = true
} else {
tab.active = false
}
})
if (found) {
this.$emit('change', this.activeIndex)
}
},
selectValidate (index) {
if (isFunction(this.$listeners[BEFORE_CHANGE_EVENT])) {
this.$emit(BEFORE_CHANGE_EVENT, this.activeIndex, index, (result) => {
if (!isExist(result)) {
this.$select(index)
}
})
} else {
this.$select(index)
}
},
select (index) {
if (!this.tabs[index].disabled && index !== this.activeIndex) {
this.selectValidate(index)
}
},
$select (index) {
if (isNumber(this.value)) {
this.$emit('input', index)
} else {
this.activeIndex = index
this.selectCurrent()
}
}
}
}