You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.6 KiB
JavaScript
147 lines
3.6 KiB
JavaScript
import _ from 'lodash';
|
|
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
|
|
|
const TAB_TRANSITION_DURATION = 300;
|
|
|
|
export default class Tab extends DOMAttachedObject {
|
|
static DOMAttachKey = 'vjTabInstance';
|
|
|
|
static initAll() {
|
|
$('.section__tabs').get().forEach((tab) => {
|
|
Tab.getOrConstruct($(tab));
|
|
});
|
|
}
|
|
|
|
static initEventListeners() {
|
|
$(document).on('click', '.section__tab-header-item', (ev) => {
|
|
const targetIndex = $(ev.currentTarget).attr('data-tab-index');
|
|
const $container = $(ev.currentTarget).closest('.section__tab-container');
|
|
const tabInstance = Tab.get($container);
|
|
tabInstance.switchToTab(parseInt(targetIndex, 10));
|
|
});
|
|
}
|
|
|
|
constructor($dom) {
|
|
super($dom);
|
|
this.attached = false;
|
|
this.attach();
|
|
}
|
|
|
|
async switchToTab(idx) {
|
|
if (idx === this.currentIndex) return;
|
|
if (this.isAnimating) return;
|
|
|
|
const $tabs = this.$content.children();
|
|
const $currentTab = $tabs.eq(this.currentIndex);
|
|
const $newTab = $tabs.eq(idx);
|
|
|
|
// 0. Change header
|
|
this.$header
|
|
.children()
|
|
.removeClass('selected')
|
|
.eq(idx)
|
|
.addClass('selected');
|
|
|
|
// 1. Prepare for animating
|
|
this.isAnimating = true;
|
|
$newTab.addClass('active');
|
|
const animateParameter = {};
|
|
if (idx < this.currentIndex) {
|
|
animateParameter.from = '-100%';
|
|
animateParameter.to = '0%';
|
|
} else {
|
|
animateParameter.from = '0%';
|
|
animateParameter.to = '-100%';
|
|
}
|
|
$newTab
|
|
.css('opacity', 0);
|
|
this.$content
|
|
.css('x', animateParameter.from)
|
|
.width();
|
|
|
|
// 2. Animate transition
|
|
$currentTab
|
|
.transition({
|
|
opacity: 0,
|
|
}, {
|
|
duration: TAB_TRANSITION_DURATION,
|
|
easing: 'linear',
|
|
});
|
|
$newTab
|
|
.transition({
|
|
opacity: 1,
|
|
}, {
|
|
duration: TAB_TRANSITION_DURATION,
|
|
easing: 'linear',
|
|
});
|
|
await this.$content
|
|
.transition({
|
|
x: animateParameter.to,
|
|
}, {
|
|
duration: TAB_TRANSITION_DURATION,
|
|
easing: 'easeOutCubic',
|
|
})
|
|
.promise();
|
|
|
|
// 3. Hide previous content
|
|
this.$content
|
|
.children()
|
|
.eq(this.currentIndex)
|
|
.removeClass('active');
|
|
this.$content
|
|
.css('x', '0');
|
|
|
|
// 4. Finalize
|
|
this.currentIndex = idx;
|
|
this.isAnimating = false;
|
|
}
|
|
|
|
attach() {
|
|
if (this.attached) {
|
|
return false;
|
|
}
|
|
|
|
const $container = this.$dom
|
|
.closest('.section__tab-container');
|
|
const $headerWrapper = $(document.createElement('div'))
|
|
.addClass('section__tab-header-wrapper')
|
|
.appendTo($container);
|
|
const $contentWrapper = $(document.createElement('div'))
|
|
.appendTo($container);
|
|
this.$header = $(document.createElement('ul'))
|
|
.addClass('section__tab-header')
|
|
.attr('data-slideout-ignore', 'on')
|
|
.appendTo($headerWrapper);
|
|
this.$content = $(document.createElement('div'))
|
|
.addClass('section__tab-content')
|
|
.appendTo($contentWrapper);
|
|
|
|
this.$dom.find('.section__tab-title').get().forEach((element, idx) => {
|
|
$(document.createElement('li')).text($(element).text())
|
|
.addClass('section__tab-header-item')
|
|
.attr('data-tab-index', idx)
|
|
.appendTo(this.$header);
|
|
});
|
|
|
|
this.$dom.find('.section__tab-main')
|
|
.appendTo(this.$content);
|
|
|
|
this.$dom.remove();
|
|
this.$dom = $container;
|
|
|
|
this.currentIndex = 0;
|
|
this.$content
|
|
.children()
|
|
.eq(0)
|
|
.addClass('active');
|
|
this.$header
|
|
.children()
|
|
.eq(0)
|
|
.addClass('selected');
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
_.assign(Tab, DOMAttachedObject);
|