import $ from '../../utils/dom'; import Utils from '../../utils/utils'; const Pagination = { update() { // Render || Update Pagination bullets/items const swiper = this; const rtl = swiper.rtl; const params = swiper.params.pagination; if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return; const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length; const $el = swiper.pagination.$el; // Current/Total let current; const total = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length; if (swiper.params.loop) { current = Math.ceil((swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup); if (current > slidesLength - 1 - (swiper.loopedSlides * 2)) { current -= (slidesLength - (swiper.loopedSlides * 2)); } if (current > total - 1) current -= total; if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current; } else if (typeof swiper.snapIndex !== 'undefined') { current = swiper.snapIndex; } else { current = swiper.activeIndex || 0; } // Types if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) { const bullets = swiper.pagination.bullets; let firstIndex; let lastIndex; let midIndex; if (params.dynamicBullets) { swiper.pagination.bulletSize = bullets.eq(0)[swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'](true); $el.css(swiper.isHorizontal() ? 'width' : 'height', `${swiper.pagination.bulletSize * (params.dynamicMainBullets + 4)}px`); if (params.dynamicMainBullets > 1 && swiper.previousIndex !== undefined) { swiper.pagination.dynamicBulletIndex += (current - swiper.previousIndex); if (swiper.pagination.dynamicBulletIndex > (params.dynamicMainBullets - 1)) { swiper.pagination.dynamicBulletIndex = params.dynamicMainBullets - 1; } else if (swiper.pagination.dynamicBulletIndex < 0) { swiper.pagination.dynamicBulletIndex = 0; } } firstIndex = current - swiper.pagination.dynamicBulletIndex; lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1); midIndex = (lastIndex + firstIndex) / 2; } bullets.removeClass(`${params.bulletActiveClass} ${params.bulletActiveClass}-next ${params.bulletActiveClass}-next-next ${params.bulletActiveClass}-prev ${params.bulletActiveClass}-prev-prev ${params.bulletActiveClass}-main`); if ($el.length > 1) { bullets.each((index, bullet) => { const $bullet = $(bullet); const bulletIndex = $bullet.index(); if (bulletIndex === current) { $bullet.addClass(params.bulletActiveClass); } if (params.dynamicBullets) { if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) { $bullet.addClass(`${params.bulletActiveClass}-main`); } if (bulletIndex === firstIndex) { $bullet .prev() .addClass(`${params.bulletActiveClass}-prev`) .prev() .addClass(`${params.bulletActiveClass}-prev-prev`); } if (bulletIndex === lastIndex) { $bullet .next() .addClass(`${params.bulletActiveClass}-next`) .next() .addClass(`${params.bulletActiveClass}-next-next`); } } }); } else { const $bullet = bullets.eq(current); const bulletIndex = $bullet.index(); $bullet.addClass(params.bulletActiveClass); if (params.dynamicBullets) { const $firstDisplayedBullet = bullets.eq(firstIndex); const $lastDisplayedBullet = bullets.eq(lastIndex); for (let i = firstIndex; i <= lastIndex; i += 1) { bullets.eq(i).addClass(`${params.bulletActiveClass}-main`); } if (swiper.params.loop) { if (bulletIndex >= bullets.length - params.dynamicMainBullets) { for (let i = params.dynamicMainBullets; i >= 0; i -= 1) { bullets.eq(bullets.length - i).addClass(`${params.bulletActiveClass}-main`); } bullets.eq(bullets.length - params.dynamicMainBullets - 1).addClass(`${params.bulletActiveClass}-prev`); } else { $firstDisplayedBullet .prev() .addClass(`${params.bulletActiveClass}-prev`) .prev() .addClass(`${params.bulletActiveClass}-prev-prev`); $lastDisplayedBullet .next() .addClass(`${params.bulletActiveClass}-next`) .next() .addClass(`${params.bulletActiveClass}-next-next`); } } else { $firstDisplayedBullet .prev() .addClass(`${params.bulletActiveClass}-prev`) .prev() .addClass(`${params.bulletActiveClass}-prev-prev`); $lastDisplayedBullet .next() .addClass(`${params.bulletActiveClass}-next`) .next() .addClass(`${params.bulletActiveClass}-next-next`); } } } if (params.dynamicBullets) { const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4); const bulletsOffset = (((swiper.pagination.bulletSize * dynamicBulletsLength) - (swiper.pagination.bulletSize)) / 2) - (midIndex * swiper.pagination.bulletSize); const offsetProp = rtl ? 'right' : 'left'; bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`); } } if (params.type === 'fraction') { $el.find(`.${params.currentClass}`).text(params.formatFractionCurrent(current + 1)); $el.find(`.${params.totalClass}`).text(params.formatFractionTotal(total)); } if (params.type === 'progressbar') { let progressbarDirection; if (params.progressbarOpposite) { progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal'; } else { progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical'; } const scale = (current + 1) / total; let scaleX = 1; let scaleY = 1; if (progressbarDirection === 'horizontal') { scaleX = scale; } else { scaleY = scale; } $el.find(`.${params.progressbarFillClass}`).transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`).transition(swiper.params.speed); } if (params.type === 'custom' && params.renderCustom) { $el.html(params.renderCustom(swiper, current + 1, total)); swiper.emit('paginationRender', swiper, $el[0]); } else { swiper.emit('paginationUpdate', swiper, $el[0]); } $el[swiper.params.watchOverflow && swiper.isLocked ? 'addClass' : 'removeClass'](params.lockClass); }, render() { // Render Container const swiper = this; const params = swiper.params.pagination; if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return; const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length; const $el = swiper.pagination.$el; let paginationHTML = ''; if (params.type === 'bullets') { const numberOfBullets = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length; for (let i = 0; i < numberOfBullets; i += 1) { if (params.renderBullet) { paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass); } else { paginationHTML += `<${params.bulletElement} class="${params.bulletClass}">`; } } $el.html(paginationHTML); swiper.pagination.bullets = $el.find(`.${params.bulletClass}`); } if (params.type === 'fraction') { if (params.renderFraction) { paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass); } else { paginationHTML = `` + ' / ' + ``; } $el.html(paginationHTML); } if (params.type === 'progressbar') { if (params.renderProgressbar) { paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass); } else { paginationHTML = ``; } $el.html(paginationHTML); } if (params.type !== 'custom') { swiper.emit('paginationRender', swiper.pagination.$el[0]); } }, init() { const swiper = this; const params = swiper.params.pagination; if (!params.el) return; let $el = $(params.el); if ($el.length === 0) return; if ( swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 ) { $el = swiper.$el.find(params.el); } if (params.type === 'bullets' && params.clickable) { $el.addClass(params.clickableClass); } $el.addClass(params.modifierClass + params.type); if (params.type === 'bullets' && params.dynamicBullets) { $el.addClass(`${params.modifierClass}${params.type}-dynamic`); swiper.pagination.dynamicBulletIndex = 0; if (params.dynamicMainBullets < 1) { params.dynamicMainBullets = 1; } } if (params.type === 'progressbar' && params.progressbarOpposite) { $el.addClass(params.progressbarOppositeClass); } if (params.clickable) { $el.on('click', `.${params.bulletClass}`, function onClick(e) { e.preventDefault(); let index = $(this).index() * swiper.params.slidesPerGroup; if (swiper.params.loop) index += swiper.loopedSlides; swiper.slideTo(index); }); } Utils.extend(swiper.pagination, { $el, el: $el[0], }); }, destroy() { const swiper = this; const params = swiper.params.pagination; if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return; const $el = swiper.pagination.$el; $el.removeClass(params.hiddenClass); $el.removeClass(params.modifierClass + params.type); if (swiper.pagination.bullets) swiper.pagination.bullets.removeClass(params.bulletActiveClass); if (params.clickable) { $el.off('click', `.${params.bulletClass}`); } }, }; export default { name: 'pagination', params: { pagination: { el: null, bulletElement: 'span', clickable: false, hideOnClick: false, renderBullet: null, renderProgressbar: null, renderFraction: null, renderCustom: null, progressbarOpposite: false, type: 'bullets', // 'bullets' or 'progressbar' or 'fraction' or 'custom' dynamicBullets: false, dynamicMainBullets: 1, formatFractionCurrent: (number) => number, formatFractionTotal: (number) => number, bulletClass: 'swiper-pagination-bullet', bulletActiveClass: 'swiper-pagination-bullet-active', modifierClass: 'swiper-pagination-', // NEW currentClass: 'swiper-pagination-current', totalClass: 'swiper-pagination-total', hiddenClass: 'swiper-pagination-hidden', progressbarFillClass: 'swiper-pagination-progressbar-fill', progressbarOppositeClass: 'swiper-pagination-progressbar-opposite', clickableClass: 'swiper-pagination-clickable', // NEW lockClass: 'swiper-pagination-lock', }, }, create() { const swiper = this; Utils.extend(swiper, { pagination: { init: Pagination.init.bind(swiper), render: Pagination.render.bind(swiper), update: Pagination.update.bind(swiper), destroy: Pagination.destroy.bind(swiper), dynamicBulletIndex: 0, }, }); }, on: { init() { const swiper = this; swiper.pagination.init(); swiper.pagination.render(); swiper.pagination.update(); }, activeIndexChange() { const swiper = this; if (swiper.params.loop) { swiper.pagination.update(); } else if (typeof swiper.snapIndex === 'undefined') { swiper.pagination.update(); } }, snapIndexChange() { const swiper = this; if (!swiper.params.loop) { swiper.pagination.update(); } }, slidesLengthChange() { const swiper = this; if (swiper.params.loop) { swiper.pagination.render(); swiper.pagination.update(); } }, snapGridLengthChange() { const swiper = this; if (!swiper.params.loop) { swiper.pagination.render(); swiper.pagination.update(); } }, destroy() { const swiper = this; swiper.pagination.destroy(); }, click(e) { const swiper = this; if ( swiper.params.pagination.el && swiper.params.pagination.hideOnClick && swiper.pagination.$el.length > 0 && !$(e.target).hasClass(swiper.params.pagination.bulletClass) ) { const isHidden = swiper.pagination.$el.hasClass(swiper.params.pagination.hiddenClass); if (isHidden === true) { swiper.emit('paginationShow', swiper); } else { swiper.emit('paginationHide', swiper); } swiper.pagination.$el.toggleClass(swiper.params.pagination.hiddenClass); } }, }, };