454 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			454 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
| import classesToSelector from '../../shared/classes-to-selector.js';
 | |
| import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
 | |
| import { elementIndex, elementOuterSize, elementParents } from '../../shared/utils.js';
 | |
| export default function Pagination({
 | |
|   swiper,
 | |
|   extendParams,
 | |
|   on,
 | |
|   emit
 | |
| }) {
 | |
|   const pfx = 'swiper-pagination';
 | |
|   extendParams({
 | |
|     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: `${pfx}-bullet`,
 | |
|       bulletActiveClass: `${pfx}-bullet-active`,
 | |
|       modifierClass: `${pfx}-`,
 | |
|       currentClass: `${pfx}-current`,
 | |
|       totalClass: `${pfx}-total`,
 | |
|       hiddenClass: `${pfx}-hidden`,
 | |
|       progressbarFillClass: `${pfx}-progressbar-fill`,
 | |
|       progressbarOppositeClass: `${pfx}-progressbar-opposite`,
 | |
|       clickableClass: `${pfx}-clickable`,
 | |
|       lockClass: `${pfx}-lock`,
 | |
|       horizontalClass: `${pfx}-horizontal`,
 | |
|       verticalClass: `${pfx}-vertical`,
 | |
|       paginationDisabledClass: `${pfx}-disabled`
 | |
|     }
 | |
|   });
 | |
|   swiper.pagination = {
 | |
|     el: null,
 | |
|     bullets: []
 | |
|   };
 | |
|   let bulletSize;
 | |
|   let dynamicBulletIndex = 0;
 | |
|   const makeElementsArray = el => {
 | |
|     if (!Array.isArray(el)) el = [el].filter(e => !!e);
 | |
|     return el;
 | |
|   };
 | |
|   function isPaginationDisabled() {
 | |
|     return !swiper.params.pagination.el || !swiper.pagination.el || Array.isArray(swiper.pagination.el) && swiper.pagination.el.length === 0;
 | |
|   }
 | |
|   function setSideBullets(bulletEl, position) {
 | |
|     const {
 | |
|       bulletActiveClass
 | |
|     } = swiper.params.pagination;
 | |
|     if (!bulletEl) return;
 | |
|     bulletEl = bulletEl[`${position === 'prev' ? 'previous' : 'next'}ElementSibling`];
 | |
|     if (bulletEl) {
 | |
|       bulletEl.classList.add(`${bulletActiveClass}-${position}`);
 | |
|       bulletEl = bulletEl[`${position === 'prev' ? 'previous' : 'next'}ElementSibling`];
 | |
|       if (bulletEl) {
 | |
|         bulletEl.classList.add(`${bulletActiveClass}-${position}-${position}`);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   function onBulletClick(e) {
 | |
|     const bulletEl = e.target.closest(classesToSelector(swiper.params.pagination.bulletClass));
 | |
|     if (!bulletEl) {
 | |
|       return;
 | |
|     }
 | |
|     e.preventDefault();
 | |
|     const index = elementIndex(bulletEl) * swiper.params.slidesPerGroup;
 | |
|     if (swiper.params.loop) {
 | |
|       if (swiper.realIndex === index) return;
 | |
|       const newSlideIndex = swiper.getSlideIndexByData(index);
 | |
|       const currentSlideIndex = swiper.getSlideIndexByData(swiper.realIndex);
 | |
|       if (newSlideIndex > swiper.slides.length - swiper.loopedSlides) {
 | |
|         swiper.loopFix({
 | |
|           direction: newSlideIndex > currentSlideIndex ? 'next' : 'prev',
 | |
|           activeSlideIndex: newSlideIndex,
 | |
|           slideTo: false
 | |
|         });
 | |
|       }
 | |
|       swiper.slideToLoop(index);
 | |
|     } else {
 | |
|       swiper.slideTo(index);
 | |
|     }
 | |
|   }
 | |
|   function update() {
 | |
|     // Render || Update Pagination bullets/items
 | |
|     const rtl = swiper.rtl;
 | |
|     const params = swiper.params.pagination;
 | |
|     if (isPaginationDisabled()) return;
 | |
|     let el = swiper.pagination.el;
 | |
|     el = makeElementsArray(el);
 | |
|     // Current/Total
 | |
|     let current;
 | |
|     let previousIndex;
 | |
|     const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
 | |
|     const total = swiper.params.loop ? Math.ceil(slidesLength / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
 | |
|     if (swiper.params.loop) {
 | |
|       previousIndex = swiper.previousRealIndex || 0;
 | |
|       current = swiper.params.slidesPerGroup > 1 ? Math.floor(swiper.realIndex / swiper.params.slidesPerGroup) : swiper.realIndex;
 | |
|     } else if (typeof swiper.snapIndex !== 'undefined') {
 | |
|       current = swiper.snapIndex;
 | |
|       previousIndex = swiper.previousSnapIndex;
 | |
|     } else {
 | |
|       previousIndex = swiper.previousIndex || 0;
 | |
|       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) {
 | |
|         bulletSize = elementOuterSize(bullets[0], swiper.isHorizontal() ? 'width' : 'height', true);
 | |
|         el.forEach(subEl => {
 | |
|           subEl.style[swiper.isHorizontal() ? 'width' : 'height'] = `${bulletSize * (params.dynamicMainBullets + 4)}px`;
 | |
|         });
 | |
|         if (params.dynamicMainBullets > 1 && previousIndex !== undefined) {
 | |
|           dynamicBulletIndex += current - (previousIndex || 0);
 | |
|           if (dynamicBulletIndex > params.dynamicMainBullets - 1) {
 | |
|             dynamicBulletIndex = params.dynamicMainBullets - 1;
 | |
|           } else if (dynamicBulletIndex < 0) {
 | |
|             dynamicBulletIndex = 0;
 | |
|           }
 | |
|         }
 | |
|         firstIndex = Math.max(current - dynamicBulletIndex, 0);
 | |
|         lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);
 | |
|         midIndex = (lastIndex + firstIndex) / 2;
 | |
|       }
 | |
|       bullets.forEach(bulletEl => {
 | |
|         const classesToRemove = [...['', '-next', '-next-next', '-prev', '-prev-prev', '-main'].map(suffix => `${params.bulletActiveClass}${suffix}`)].map(s => typeof s === 'string' && s.includes(' ') ? s.split(' ') : s).flat();
 | |
|         bulletEl.classList.remove(...classesToRemove);
 | |
|       });
 | |
|       if (el.length > 1) {
 | |
|         bullets.forEach(bullet => {
 | |
|           const bulletIndex = elementIndex(bullet);
 | |
|           if (bulletIndex === current) {
 | |
|             bullet.classList.add(...params.bulletActiveClass.split(' '));
 | |
|           } else if (swiper.isElement) {
 | |
|             bullet.setAttribute('part', 'bullet');
 | |
|           }
 | |
|           if (params.dynamicBullets) {
 | |
|             if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {
 | |
|               bullet.classList.add(...`${params.bulletActiveClass}-main`.split(' '));
 | |
|             }
 | |
|             if (bulletIndex === firstIndex) {
 | |
|               setSideBullets(bullet, 'prev');
 | |
|             }
 | |
|             if (bulletIndex === lastIndex) {
 | |
|               setSideBullets(bullet, 'next');
 | |
|             }
 | |
|           }
 | |
|         });
 | |
|       } else {
 | |
|         const bullet = bullets[current];
 | |
|         if (bullet) {
 | |
|           bullet.classList.add(...params.bulletActiveClass.split(' '));
 | |
|         }
 | |
|         if (swiper.isElement) {
 | |
|           bullets.forEach((bulletEl, bulletIndex) => {
 | |
|             bulletEl.setAttribute('part', bulletIndex === current ? 'bullet-active' : 'bullet');
 | |
|           });
 | |
|         }
 | |
|         if (params.dynamicBullets) {
 | |
|           const firstDisplayedBullet = bullets[firstIndex];
 | |
|           const lastDisplayedBullet = bullets[lastIndex];
 | |
|           for (let i = firstIndex; i <= lastIndex; i += 1) {
 | |
|             if (bullets[i]) {
 | |
|               bullets[i].classList.add(...`${params.bulletActiveClass}-main`.split(' '));
 | |
|             }
 | |
|           }
 | |
|           setSideBullets(firstDisplayedBullet, 'prev');
 | |
|           setSideBullets(lastDisplayedBullet, 'next');
 | |
|         }
 | |
|       }
 | |
|       if (params.dynamicBullets) {
 | |
|         const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);
 | |
|         const bulletsOffset = (bulletSize * dynamicBulletsLength - bulletSize) / 2 - midIndex * bulletSize;
 | |
|         const offsetProp = rtl ? 'right' : 'left';
 | |
|         bullets.forEach(bullet => {
 | |
|           bullet.style[swiper.isHorizontal() ? offsetProp : 'top'] = `${bulletsOffset}px`;
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|     el.forEach((subEl, subElIndex) => {
 | |
|       if (params.type === 'fraction') {
 | |
|         subEl.querySelectorAll(classesToSelector(params.currentClass)).forEach(fractionEl => {
 | |
|           fractionEl.textContent = params.formatFractionCurrent(current + 1);
 | |
|         });
 | |
|         subEl.querySelectorAll(classesToSelector(params.totalClass)).forEach(totalEl => {
 | |
|           totalEl.textContent = 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;
 | |
|         }
 | |
|         subEl.querySelectorAll(classesToSelector(params.progressbarFillClass)).forEach(progressEl => {
 | |
|           progressEl.style.transform = `translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`;
 | |
|           progressEl.style.transitionDuration = `${swiper.params.speed}ms`;
 | |
|         });
 | |
|       }
 | |
|       if (params.type === 'custom' && params.renderCustom) {
 | |
|         subEl.innerHTML = params.renderCustom(swiper, current + 1, total);
 | |
|         if (subElIndex === 0) emit('paginationRender', subEl);
 | |
|       } else {
 | |
|         if (subElIndex === 0) emit('paginationRender', subEl);
 | |
|         emit('paginationUpdate', subEl);
 | |
|       }
 | |
|       if (swiper.params.watchOverflow && swiper.enabled) {
 | |
|         subEl.classList[swiper.isLocked ? 'add' : 'remove'](params.lockClass);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   function render() {
 | |
|     // Render Container
 | |
|     const params = swiper.params.pagination;
 | |
|     if (isPaginationDisabled()) return;
 | |
|     const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
 | |
|     let el = swiper.pagination.el;
 | |
|     el = makeElementsArray(el);
 | |
|     let paginationHTML = '';
 | |
|     if (params.type === 'bullets') {
 | |
|       let numberOfBullets = swiper.params.loop ? Math.ceil(slidesLength / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
 | |
|       if (swiper.params.freeMode && swiper.params.freeMode.enabled && numberOfBullets > slidesLength) {
 | |
|         numberOfBullets = slidesLength;
 | |
|       }
 | |
|       for (let i = 0; i < numberOfBullets; i += 1) {
 | |
|         if (params.renderBullet) {
 | |
|           paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
 | |
|         } else {
 | |
|           // prettier-ignore
 | |
|           paginationHTML += `<${params.bulletElement} ${swiper.isElement ? 'part="bullet"' : ''} class="${params.bulletClass}"></${params.bulletElement}>`;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (params.type === 'fraction') {
 | |
|       if (params.renderFraction) {
 | |
|         paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
 | |
|       } else {
 | |
|         paginationHTML = `<span class="${params.currentClass}"></span>` + ' / ' + `<span class="${params.totalClass}"></span>`;
 | |
|       }
 | |
|     }
 | |
|     if (params.type === 'progressbar') {
 | |
|       if (params.renderProgressbar) {
 | |
|         paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
 | |
|       } else {
 | |
|         paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
 | |
|       }
 | |
|     }
 | |
|     swiper.pagination.bullets = [];
 | |
|     el.forEach(subEl => {
 | |
|       if (params.type !== 'custom') {
 | |
|         subEl.innerHTML = paginationHTML || '';
 | |
|       }
 | |
|       if (params.type === 'bullets') {
 | |
|         swiper.pagination.bullets.push(...subEl.querySelectorAll(classesToSelector(params.bulletClass)));
 | |
|       }
 | |
|     });
 | |
|     if (params.type !== 'custom') {
 | |
|       emit('paginationRender', el[0]);
 | |
|     }
 | |
|   }
 | |
|   function init() {
 | |
|     swiper.params.pagination = createElementIfNotDefined(swiper, swiper.originalParams.pagination, swiper.params.pagination, {
 | |
|       el: 'swiper-pagination'
 | |
|     });
 | |
|     const params = swiper.params.pagination;
 | |
|     if (!params.el) return;
 | |
|     let el;
 | |
|     if (typeof params.el === 'string' && swiper.isElement) {
 | |
|       el = swiper.el.shadowRoot.querySelector(params.el);
 | |
|     }
 | |
|     if (!el && typeof params.el === 'string') {
 | |
|       el = [...document.querySelectorAll(params.el)];
 | |
|     }
 | |
|     if (!el) {
 | |
|       el = params.el;
 | |
|     }
 | |
|     if (!el || el.length === 0) return;
 | |
|     if (swiper.params.uniqueNavElements && typeof params.el === 'string' && Array.isArray(el) && el.length > 1) {
 | |
|       el = [...swiper.el.querySelectorAll(params.el)];
 | |
|       // check if it belongs to another nested Swiper
 | |
|       if (el.length > 1) {
 | |
|         el = el.filter(subEl => {
 | |
|           if (elementParents(subEl, '.swiper')[0] !== swiper.el) return false;
 | |
|           return true;
 | |
|         })[0];
 | |
|       }
 | |
|     }
 | |
|     if (Array.isArray(el) && el.length === 1) el = el[0];
 | |
|     Object.assign(swiper.pagination, {
 | |
|       el
 | |
|     });
 | |
|     el = makeElementsArray(el);
 | |
|     el.forEach(subEl => {
 | |
|       if (params.type === 'bullets' && params.clickable) {
 | |
|         subEl.classList.add(params.clickableClass);
 | |
|       }
 | |
|       subEl.classList.add(params.modifierClass + params.type);
 | |
|       subEl.classList.add(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
 | |
|       if (params.type === 'bullets' && params.dynamicBullets) {
 | |
|         subEl.classList.add(`${params.modifierClass}${params.type}-dynamic`);
 | |
|         dynamicBulletIndex = 0;
 | |
|         if (params.dynamicMainBullets < 1) {
 | |
|           params.dynamicMainBullets = 1;
 | |
|         }
 | |
|       }
 | |
|       if (params.type === 'progressbar' && params.progressbarOpposite) {
 | |
|         subEl.classList.add(params.progressbarOppositeClass);
 | |
|       }
 | |
|       if (params.clickable) {
 | |
|         subEl.addEventListener('click', onBulletClick);
 | |
|       }
 | |
|       if (!swiper.enabled) {
 | |
|         subEl.classList.add(params.lockClass);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
|   function destroy() {
 | |
|     const params = swiper.params.pagination;
 | |
|     if (isPaginationDisabled()) return;
 | |
|     let el = swiper.pagination.el;
 | |
|     if (el) {
 | |
|       el = makeElementsArray(el);
 | |
|       el.forEach(subEl => {
 | |
|         subEl.classList.remove(params.hiddenClass);
 | |
|         subEl.classList.remove(params.modifierClass + params.type);
 | |
|         subEl.classList.remove(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
 | |
|         if (params.clickable) {
 | |
|           subEl.removeEventListener('click', onBulletClick);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     if (swiper.pagination.bullets) swiper.pagination.bullets.forEach(subEl => subEl.classList.remove(...params.bulletActiveClass.split(' ')));
 | |
|   }
 | |
|   on('changeDirection', () => {
 | |
|     if (!swiper.pagination || !swiper.pagination.el) return;
 | |
|     const params = swiper.params.pagination;
 | |
|     let {
 | |
|       el
 | |
|     } = swiper.pagination;
 | |
|     el = makeElementsArray(el);
 | |
|     el.forEach(subEl => {
 | |
|       subEl.classList.remove(params.horizontalClass, params.verticalClass);
 | |
|       subEl.classList.add(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
 | |
|     });
 | |
|   });
 | |
|   on('init', () => {
 | |
|     if (swiper.params.pagination.enabled === false) {
 | |
|       // eslint-disable-next-line
 | |
|       disable();
 | |
|     } else {
 | |
|       init();
 | |
|       render();
 | |
|       update();
 | |
|     }
 | |
|   });
 | |
|   on('activeIndexChange', () => {
 | |
|     if (typeof swiper.snapIndex === 'undefined') {
 | |
|       update();
 | |
|     }
 | |
|   });
 | |
|   on('snapIndexChange', () => {
 | |
|     update();
 | |
|   });
 | |
|   on('snapGridLengthChange', () => {
 | |
|     render();
 | |
|     update();
 | |
|   });
 | |
|   on('destroy', () => {
 | |
|     destroy();
 | |
|   });
 | |
|   on('enable disable', () => {
 | |
|     let {
 | |
|       el
 | |
|     } = swiper.pagination;
 | |
|     if (el) {
 | |
|       el = makeElementsArray(el);
 | |
|       el.forEach(subEl => subEl.classList[swiper.enabled ? 'remove' : 'add'](swiper.params.pagination.lockClass));
 | |
|     }
 | |
|   });
 | |
|   on('lock unlock', () => {
 | |
|     update();
 | |
|   });
 | |
|   on('click', (_s, e) => {
 | |
|     const targetEl = e.target;
 | |
|     let {
 | |
|       el
 | |
|     } = swiper.pagination;
 | |
|     if (!Array.isArray(el)) el = [el].filter(element => !!element);
 | |
|     if (swiper.params.pagination.el && swiper.params.pagination.hideOnClick && el && el.length > 0 && !targetEl.classList.contains(swiper.params.pagination.bulletClass)) {
 | |
|       if (swiper.navigation && (swiper.navigation.nextEl && targetEl === swiper.navigation.nextEl || swiper.navigation.prevEl && targetEl === swiper.navigation.prevEl)) return;
 | |
|       const isHidden = el[0].classList.contains(swiper.params.pagination.hiddenClass);
 | |
|       if (isHidden === true) {
 | |
|         emit('paginationShow');
 | |
|       } else {
 | |
|         emit('paginationHide');
 | |
|       }
 | |
|       el.forEach(subEl => subEl.classList.toggle(swiper.params.pagination.hiddenClass));
 | |
|     }
 | |
|   });
 | |
|   const enable = () => {
 | |
|     swiper.el.classList.remove(swiper.params.pagination.paginationDisabledClass);
 | |
|     let {
 | |
|       el
 | |
|     } = swiper.pagination;
 | |
|     if (el) {
 | |
|       el = makeElementsArray(el);
 | |
|       el.forEach(subEl => subEl.classList.remove(swiper.params.pagination.paginationDisabledClass));
 | |
|     }
 | |
|     init();
 | |
|     render();
 | |
|     update();
 | |
|   };
 | |
|   const disable = () => {
 | |
|     swiper.el.classList.add(swiper.params.pagination.paginationDisabledClass);
 | |
|     let {
 | |
|       el
 | |
|     } = swiper.pagination;
 | |
|     if (el) {
 | |
|       el = makeElementsArray(el);
 | |
|       el.forEach(subEl => subEl.classList.add(swiper.params.pagination.paginationDisabledClass));
 | |
|     }
 | |
|     destroy();
 | |
|   };
 | |
|   Object.assign(swiper.pagination, {
 | |
|     enable,
 | |
|     disable,
 | |
|     render,
 | |
|     update,
 | |
|     init,
 | |
|     destroy
 | |
|   });
 | |
| } |