432 lines
11 KiB
JavaScript
432 lines
11 KiB
JavaScript
|
import isNumber from 'is-number';
|
||
|
import $ from 'jquery';
|
||
|
|
||
|
const $doc = $(document);
|
||
|
const { screenSizes } = window.VPData;
|
||
|
|
||
|
function getSwiperVersion(Swiper) {
|
||
|
let ver = 8;
|
||
|
|
||
|
// in version 8 added new parameter `maxBackfaceHiddenSlides`.
|
||
|
if (typeof Swiper.defaults.maxBackfaceHiddenSlides === 'undefined') {
|
||
|
ver = 7;
|
||
|
}
|
||
|
|
||
|
// in version 7 added new parameter `rewind`.
|
||
|
if (typeof Swiper.defaults.rewind === 'undefined') {
|
||
|
ver = 6;
|
||
|
}
|
||
|
|
||
|
// in version 6 added new parameter `loopPreventsSlide`.
|
||
|
if (typeof Swiper.defaults.loopPreventsSlide === 'undefined') {
|
||
|
ver = 5;
|
||
|
}
|
||
|
|
||
|
return ver;
|
||
|
}
|
||
|
|
||
|
// Extend VP class.
|
||
|
$doc.on('extendClass.vpf', (event, VP) => {
|
||
|
if (event.namespace !== 'vpf') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Init Swiper plugin
|
||
|
*
|
||
|
* @param {mixed} options - slider options.
|
||
|
*/
|
||
|
VP.prototype.initSwiper = function (options = false) {
|
||
|
const self = this;
|
||
|
|
||
|
if (
|
||
|
self.options.layout === 'slider' &&
|
||
|
typeof window.Swiper !== 'undefined'
|
||
|
) {
|
||
|
const $parent = self.$items_wrap.parent();
|
||
|
|
||
|
$parent.addClass('swiper');
|
||
|
self.$items_wrap.addClass('swiper-wrapper');
|
||
|
self.$items_wrap.children().addClass('swiper-slide');
|
||
|
|
||
|
// calculate responsive.
|
||
|
let slidesPerView = self.options.sliderSlidesPerView || 3;
|
||
|
const breakPoints = {};
|
||
|
|
||
|
if (self.options.sliderEffect === 'fade') {
|
||
|
slidesPerView = 1;
|
||
|
}
|
||
|
|
||
|
if (isNumber(slidesPerView)) {
|
||
|
let count = slidesPerView;
|
||
|
let currentPoint = Math.min(screenSizes.length - 1, count - 1);
|
||
|
|
||
|
for (; currentPoint >= 0; currentPoint -= 1) {
|
||
|
if (
|
||
|
count > 0 &&
|
||
|
typeof screenSizes[currentPoint] !== 'undefined'
|
||
|
) {
|
||
|
breakPoints[screenSizes[currentPoint] + 1] = {
|
||
|
slidesPerView: count,
|
||
|
};
|
||
|
}
|
||
|
count -= 1;
|
||
|
}
|
||
|
|
||
|
slidesPerView = count || 1;
|
||
|
}
|
||
|
|
||
|
let optionsThumbs = false;
|
||
|
let $thumbsParent = false;
|
||
|
options = options || {
|
||
|
speed: (parseFloat(self.options.sliderSpeed) || 0) * 1000,
|
||
|
autoHeight: self.options.sliderItemsHeight === 'auto',
|
||
|
effect: self.options.sliderEffect || 'slide',
|
||
|
// fix fade items collapse (mostly in Default items style).
|
||
|
fadeEffect: {
|
||
|
crossFade: true,
|
||
|
},
|
||
|
spaceBetween: parseFloat(self.options.itemsGap) || 0,
|
||
|
centeredSlides: self.options.sliderCenteredSlides === 'true',
|
||
|
freeMode: {
|
||
|
enabled: self.options.sliderFreeMode === 'true',
|
||
|
sticky: self.options.sliderFreeModeSticky === 'true',
|
||
|
},
|
||
|
loop: self.options.sliderLoop === 'true',
|
||
|
// This feature is cool, but not working properly when loop enabled
|
||
|
// and fast clicking on previous button is not working properly
|
||
|
// https://github.com/nolimits4web/swiper/issues/5945
|
||
|
// loopPreventsSlide: false,
|
||
|
autoplay: parseFloat(self.options.sliderAutoplay) > 0 && {
|
||
|
delay: parseFloat(self.options.sliderAutoplay) * 1000,
|
||
|
disableOnInteraction: false,
|
||
|
},
|
||
|
navigation: self.options.sliderArrows === 'true' && {
|
||
|
nextEl: '.vp-portfolio__items-arrow-next',
|
||
|
prevEl: '.vp-portfolio__items-arrow-prev',
|
||
|
},
|
||
|
pagination: self.options.sliderBullets === 'true' && {
|
||
|
el: '.vp-portfolio__items-bullets',
|
||
|
clickable: true,
|
||
|
dynamicBullets:
|
||
|
self.options.sliderBulletsDynamic === 'true',
|
||
|
renderBullet(index, className) {
|
||
|
return `<span class="${className}" data-bullet-index="${index}" data-bullet-number="${
|
||
|
index + 1
|
||
|
}"></span>`;
|
||
|
},
|
||
|
},
|
||
|
mousewheel: self.options.sliderMousewheel === 'true',
|
||
|
slidesPerView,
|
||
|
breakpoints: breakPoints,
|
||
|
keyboard: true,
|
||
|
grabCursor: true,
|
||
|
preloadImages: false,
|
||
|
|
||
|
// fixes text selection when swipe in the items gap.
|
||
|
touchEventsTarget: 'container',
|
||
|
};
|
||
|
|
||
|
// fix first load slide position (seems like a conflict with lazySizes)
|
||
|
// issue: https://github.com/nk-crew/visual-portfolio/issues/54
|
||
|
if (options.speed === 0) {
|
||
|
options.speed = 1;
|
||
|
}
|
||
|
let positionFix = 0;
|
||
|
|
||
|
options.on = {
|
||
|
transitionEnd() {
|
||
|
if (positionFix === 0) {
|
||
|
positionFix = 1;
|
||
|
this.setTransition(1);
|
||
|
this.setTranslate(this.translate + 0.1);
|
||
|
} else if (positionFix === 1) {
|
||
|
positionFix = 2;
|
||
|
this.slideReset();
|
||
|
}
|
||
|
},
|
||
|
// These events used to add fixes for
|
||
|
// conflict with custom cursor movement.
|
||
|
touchStart(swiper, e) {
|
||
|
self.emitEvent('swiperTouchStart', [swiper, e]);
|
||
|
},
|
||
|
touchMove(swiper, e) {
|
||
|
self.emitEvent('swiperTouchMove', [swiper, e]);
|
||
|
},
|
||
|
touchEnd(swiper, e) {
|
||
|
self.emitEvent('swiperTouchEnd', [swiper, e]);
|
||
|
},
|
||
|
};
|
||
|
|
||
|
self.emitEvent('beforeInitSwiper', [options]);
|
||
|
|
||
|
// thumbnails.
|
||
|
if (self.$slider_thumbnails_wrap.length) {
|
||
|
$thumbsParent = self.$slider_thumbnails_wrap.parent();
|
||
|
|
||
|
$thumbsParent.addClass('swiper');
|
||
|
self.$slider_thumbnails_wrap.addClass('swiper-wrapper');
|
||
|
self.$slider_thumbnails_wrap
|
||
|
.children()
|
||
|
.addClass('swiper-slide');
|
||
|
|
||
|
// calculate responsive.
|
||
|
let thumbnailsPerView =
|
||
|
self.options.sliderThumbnailsPerView || 8;
|
||
|
const thumbnailsBreakPoints = {};
|
||
|
|
||
|
if (isNumber(thumbnailsPerView)) {
|
||
|
let count = thumbnailsPerView;
|
||
|
let currentPoint = Math.min(
|
||
|
screenSizes.length - 1,
|
||
|
count - 1
|
||
|
);
|
||
|
|
||
|
for (; currentPoint >= 0; currentPoint -= 1) {
|
||
|
if (
|
||
|
count > 0 &&
|
||
|
typeof screenSizes[currentPoint] !== 'undefined'
|
||
|
) {
|
||
|
thumbnailsBreakPoints[
|
||
|
screenSizes[currentPoint] + 1
|
||
|
] = {
|
||
|
slidesPerView: count,
|
||
|
};
|
||
|
}
|
||
|
count -= 1;
|
||
|
}
|
||
|
|
||
|
thumbnailsPerView = count || 1;
|
||
|
}
|
||
|
|
||
|
optionsThumbs = {
|
||
|
autoHeight: self.options.sliderThumbnailsHeight === 'auto',
|
||
|
effect: 'slide',
|
||
|
spaceBetween:
|
||
|
parseFloat(self.options.sliderThumbnailsGap) || 0,
|
||
|
loop: false,
|
||
|
// This feature is cool, but not working properly when loop enabled
|
||
|
// and fast clicking on previous button is not working properly
|
||
|
// https://github.com/nolimits4web/swiper/issues/5945
|
||
|
// loopPreventsSlide: false,
|
||
|
freeMode: {
|
||
|
enabled: true,
|
||
|
sticky: true,
|
||
|
},
|
||
|
loopedSlides: 5,
|
||
|
slidesPerView: thumbnailsPerView,
|
||
|
breakpoints: thumbnailsBreakPoints,
|
||
|
keyboard: true,
|
||
|
grabCursor: true,
|
||
|
watchSlidesVisibility: true,
|
||
|
watchSlidesProgress: true,
|
||
|
preloadImages: false,
|
||
|
|
||
|
// fixed text selection when swipe in the items gap.
|
||
|
touchEventsTarget: 'container',
|
||
|
on: {
|
||
|
// These events used to add fixes for
|
||
|
// conflict with custom cursor movement.
|
||
|
touchStart(swiper, e) {
|
||
|
self.emitEvent('swiperTouchStart', [swiper, e]);
|
||
|
},
|
||
|
touchMove(swiper, e) {
|
||
|
self.emitEvent('swiperTouchMove', [swiper, e]);
|
||
|
},
|
||
|
touchEnd(swiper, e) {
|
||
|
self.emitEvent('swiperTouchEnd', [swiper, e]);
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// Fallbacks for old Swiper versions.
|
||
|
(() => {
|
||
|
const swiperVersion = getSwiperVersion(window.Swiper);
|
||
|
const isThumbsEnabled =
|
||
|
optionsThumbs && $thumbsParent && $thumbsParent[0];
|
||
|
|
||
|
// Since v7 used container class `swiper`, we should also add old `swiper-container` class.
|
||
|
if (swiperVersion < 7) {
|
||
|
$parent.addClass('swiper-container');
|
||
|
|
||
|
if (isThumbsEnabled) {
|
||
|
$thumbsParent.addClass('swiper-container');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Since v7 freeMode options moved under `freeMode` object.
|
||
|
if (swiperVersion < 7) {
|
||
|
options.freeModeSticky = options.freeMode.sticky;
|
||
|
options.freeMode = options.freeMode.enabled;
|
||
|
|
||
|
if (isThumbsEnabled) {
|
||
|
optionsThumbs.freeModeSticky =
|
||
|
optionsThumbs.freeMode.sticky;
|
||
|
optionsThumbs.freeMode = optionsThumbs.freeMode.enabled;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Since v5 `breakpointsInverse` option is removed and it is now `true` by default, but in older versions it was `false`.
|
||
|
if (swiperVersion >= 5) {
|
||
|
options.breakpointsInverse = true;
|
||
|
|
||
|
if (isThumbsEnabled) {
|
||
|
optionsThumbs.breakpointsInverse = true;
|
||
|
}
|
||
|
}
|
||
|
})();
|
||
|
|
||
|
// Init Swiper.
|
||
|
if (optionsThumbs && $thumbsParent && $thumbsParent[0]) {
|
||
|
const swiperThumbs = new window.Swiper(
|
||
|
$thumbsParent[0],
|
||
|
optionsThumbs
|
||
|
);
|
||
|
|
||
|
options.thumbs = {
|
||
|
swiper: swiperThumbs,
|
||
|
};
|
||
|
}
|
||
|
const instance = new window.Swiper($parent[0], options);
|
||
|
|
||
|
// Autoplay Hover Pause.
|
||
|
if (
|
||
|
self.options.sliderAutoplayHoverPause === 'true' &&
|
||
|
parseFloat(self.options.sliderAutoplay) > 0
|
||
|
) {
|
||
|
self.$item.on(
|
||
|
`mouseenter.vpf-uid-${self.uid}`,
|
||
|
'.swiper',
|
||
|
() => {
|
||
|
$parent[0].swiper.autoplay.stop();
|
||
|
}
|
||
|
);
|
||
|
self.$item.on(
|
||
|
`mouseleave.vpf-uid-${self.uid}`,
|
||
|
'.swiper',
|
||
|
() => {
|
||
|
$parent[0].swiper.autoplay.start();
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
self.emitEvent('initSwiper', [options, instance]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Destroy Swiper plugin
|
||
|
*/
|
||
|
VP.prototype.destroySwiper = function () {
|
||
|
const self = this;
|
||
|
const $parent = self.$items_wrap.parent();
|
||
|
const $thumbsParent = self.$slider_thumbnails_wrap.length
|
||
|
? self.$slider_thumbnails_wrap.parent()
|
||
|
: false;
|
||
|
|
||
|
const SliderSwiper = $parent[0].swiper;
|
||
|
const ThumbsSwiper = $thumbsParent ? $thumbsParent[0].swiper : false;
|
||
|
|
||
|
let isDestroyed = false;
|
||
|
|
||
|
// Thumbnails.
|
||
|
if (ThumbsSwiper) {
|
||
|
ThumbsSwiper.destroy();
|
||
|
|
||
|
$thumbsParent.removeClass('swiper');
|
||
|
self.$slider_thumbnails_wrap.removeClass('swiper-wrapper');
|
||
|
self.$slider_thumbnails_wrap.children().removeClass('swiper-slide');
|
||
|
|
||
|
isDestroyed = true;
|
||
|
}
|
||
|
|
||
|
// Slider.
|
||
|
if (SliderSwiper) {
|
||
|
SliderSwiper.destroy();
|
||
|
|
||
|
$parent.removeClass('swiper');
|
||
|
self.$items_wrap.removeClass('swiper-wrapper');
|
||
|
self.$items_wrap.children().removeClass('swiper-slide');
|
||
|
|
||
|
$parent
|
||
|
.find('.vp-portfolio__items-bullets')
|
||
|
.removeClass(
|
||
|
'swiper-pagination-clickable swiper-pagination-bullets-dynamic'
|
||
|
)
|
||
|
.removeAttr('style')
|
||
|
.html('');
|
||
|
|
||
|
isDestroyed = true;
|
||
|
}
|
||
|
|
||
|
if (isDestroyed) {
|
||
|
self.emitEvent('destroySwiper');
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
|
||
|
// Add Items.
|
||
|
$doc.on('addItems.vpf', (event, self, $items, removeExisting, $newVP) => {
|
||
|
if (event.namespace !== 'vpf') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const Swiper = self.$items_wrap.parent()[0].swiper;
|
||
|
|
||
|
if (!Swiper) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Slider.
|
||
|
{
|
||
|
if (removeExisting) {
|
||
|
Swiper.removeAllSlides();
|
||
|
}
|
||
|
|
||
|
const appendArr = [];
|
||
|
$items.addClass('swiper-slide').each(function () {
|
||
|
appendArr.push(this);
|
||
|
});
|
||
|
Swiper.appendSlide(appendArr);
|
||
|
}
|
||
|
|
||
|
// Thumbnails.
|
||
|
const ThumbsSwiper = self.$slider_thumbnails_wrap.length
|
||
|
? self.$slider_thumbnails_wrap.parent()[0].swiper
|
||
|
: false;
|
||
|
if (ThumbsSwiper) {
|
||
|
if (removeExisting) {
|
||
|
ThumbsSwiper.removeAllSlides();
|
||
|
}
|
||
|
|
||
|
const appendArr = [];
|
||
|
$newVP
|
||
|
.find('.vp-portfolio__thumbnails > .vp-portfolio__thumbnail-wrap')
|
||
|
.clone()
|
||
|
.addClass('swiper-slide')
|
||
|
.each(function () {
|
||
|
appendArr.push(this);
|
||
|
});
|
||
|
ThumbsSwiper.appendSlide(appendArr);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Init.
|
||
|
$doc.on('init.vpf', (event, self) => {
|
||
|
if (event.namespace !== 'vpf') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.initSwiper();
|
||
|
});
|
||
|
|
||
|
// Destroy.
|
||
|
$doc.on('destroy.vpf', (event, self) => {
|
||
|
if (event.namespace !== 'vpf') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self.destroySwiper();
|
||
|
});
|