pagination.mjs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. import { c as classesToSelector } from '../shared/classes-to-selector.mjs';
  2. import { c as createElementIfNotDefined } from '../shared/create-element-if-not-defined.mjs';
  3. import { m as makeElementsArray, f as elementOuterSize, h as elementIndex, a as elementParents } from '../shared/utils.mjs';
  4. function Pagination(_ref) {
  5. let {
  6. swiper,
  7. extendParams,
  8. on,
  9. emit
  10. } = _ref;
  11. const pfx = 'swiper-pagination';
  12. extendParams({
  13. pagination: {
  14. el: null,
  15. bulletElement: 'span',
  16. clickable: false,
  17. hideOnClick: false,
  18. renderBullet: null,
  19. renderProgressbar: null,
  20. renderFraction: null,
  21. renderCustom: null,
  22. progressbarOpposite: false,
  23. type: 'bullets',
  24. // 'bullets' or 'progressbar' or 'fraction' or 'custom'
  25. dynamicBullets: false,
  26. dynamicMainBullets: 1,
  27. formatFractionCurrent: number => number,
  28. formatFractionTotal: number => number,
  29. bulletClass: `${pfx}-bullet`,
  30. bulletActiveClass: `${pfx}-bullet-active`,
  31. modifierClass: `${pfx}-`,
  32. currentClass: `${pfx}-current`,
  33. totalClass: `${pfx}-total`,
  34. hiddenClass: `${pfx}-hidden`,
  35. progressbarFillClass: `${pfx}-progressbar-fill`,
  36. progressbarOppositeClass: `${pfx}-progressbar-opposite`,
  37. clickableClass: `${pfx}-clickable`,
  38. lockClass: `${pfx}-lock`,
  39. horizontalClass: `${pfx}-horizontal`,
  40. verticalClass: `${pfx}-vertical`,
  41. paginationDisabledClass: `${pfx}-disabled`
  42. }
  43. });
  44. swiper.pagination = {
  45. el: null,
  46. bullets: []
  47. };
  48. let bulletSize;
  49. let dynamicBulletIndex = 0;
  50. function isPaginationDisabled() {
  51. return !swiper.params.pagination.el || !swiper.pagination.el || Array.isArray(swiper.pagination.el) && swiper.pagination.el.length === 0;
  52. }
  53. function setSideBullets(bulletEl, position) {
  54. const {
  55. bulletActiveClass
  56. } = swiper.params.pagination;
  57. if (!bulletEl) return;
  58. bulletEl = bulletEl[`${position === 'prev' ? 'previous' : 'next'}ElementSibling`];
  59. if (bulletEl) {
  60. bulletEl.classList.add(`${bulletActiveClass}-${position}`);
  61. bulletEl = bulletEl[`${position === 'prev' ? 'previous' : 'next'}ElementSibling`];
  62. if (bulletEl) {
  63. bulletEl.classList.add(`${bulletActiveClass}-${position}-${position}`);
  64. }
  65. }
  66. }
  67. function getMoveDirection(prevIndex, nextIndex, length) {
  68. prevIndex = prevIndex % length;
  69. nextIndex = nextIndex % length;
  70. if (nextIndex === prevIndex + 1) {
  71. return 'next';
  72. } else if (nextIndex === prevIndex - 1) {
  73. return 'previous';
  74. }
  75. return;
  76. }
  77. function onBulletClick(e) {
  78. const bulletEl = e.target.closest(classesToSelector(swiper.params.pagination.bulletClass));
  79. if (!bulletEl) {
  80. return;
  81. }
  82. e.preventDefault();
  83. const index = elementIndex(bulletEl) * swiper.params.slidesPerGroup;
  84. if (swiper.params.loop) {
  85. if (swiper.realIndex === index) return;
  86. const moveDirection = getMoveDirection(swiper.realIndex, index, swiper.slides.length);
  87. if (moveDirection === 'next') {
  88. swiper.slideNext();
  89. } else if (moveDirection === 'previous') {
  90. swiper.slidePrev();
  91. } else {
  92. swiper.slideToLoop(index);
  93. }
  94. } else {
  95. swiper.slideTo(index);
  96. }
  97. }
  98. function update() {
  99. // Render || Update Pagination bullets/items
  100. const rtl = swiper.rtl;
  101. const params = swiper.params.pagination;
  102. if (isPaginationDisabled()) return;
  103. let el = swiper.pagination.el;
  104. el = makeElementsArray(el);
  105. // Current/Total
  106. let current;
  107. let previousIndex;
  108. const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
  109. const total = swiper.params.loop ? Math.ceil(slidesLength / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
  110. if (swiper.params.loop) {
  111. previousIndex = swiper.previousRealIndex || 0;
  112. current = swiper.params.slidesPerGroup > 1 ? Math.floor(swiper.realIndex / swiper.params.slidesPerGroup) : swiper.realIndex;
  113. } else if (typeof swiper.snapIndex !== 'undefined') {
  114. current = swiper.snapIndex;
  115. previousIndex = swiper.previousSnapIndex;
  116. } else {
  117. previousIndex = swiper.previousIndex || 0;
  118. current = swiper.activeIndex || 0;
  119. }
  120. // Types
  121. if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) {
  122. const bullets = swiper.pagination.bullets;
  123. let firstIndex;
  124. let lastIndex;
  125. let midIndex;
  126. if (params.dynamicBullets) {
  127. bulletSize = elementOuterSize(bullets[0], swiper.isHorizontal() ? 'width' : 'height', true);
  128. el.forEach(subEl => {
  129. subEl.style[swiper.isHorizontal() ? 'width' : 'height'] = `${bulletSize * (params.dynamicMainBullets + 4)}px`;
  130. });
  131. if (params.dynamicMainBullets > 1 && previousIndex !== undefined) {
  132. dynamicBulletIndex += current - (previousIndex || 0);
  133. if (dynamicBulletIndex > params.dynamicMainBullets - 1) {
  134. dynamicBulletIndex = params.dynamicMainBullets - 1;
  135. } else if (dynamicBulletIndex < 0) {
  136. dynamicBulletIndex = 0;
  137. }
  138. }
  139. firstIndex = Math.max(current - dynamicBulletIndex, 0);
  140. lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);
  141. midIndex = (lastIndex + firstIndex) / 2;
  142. }
  143. bullets.forEach(bulletEl => {
  144. 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();
  145. bulletEl.classList.remove(...classesToRemove);
  146. });
  147. if (el.length > 1) {
  148. bullets.forEach(bullet => {
  149. const bulletIndex = elementIndex(bullet);
  150. if (bulletIndex === current) {
  151. bullet.classList.add(...params.bulletActiveClass.split(' '));
  152. } else if (swiper.isElement) {
  153. bullet.setAttribute('part', 'bullet');
  154. }
  155. if (params.dynamicBullets) {
  156. if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {
  157. bullet.classList.add(...`${params.bulletActiveClass}-main`.split(' '));
  158. }
  159. if (bulletIndex === firstIndex) {
  160. setSideBullets(bullet, 'prev');
  161. }
  162. if (bulletIndex === lastIndex) {
  163. setSideBullets(bullet, 'next');
  164. }
  165. }
  166. });
  167. } else {
  168. const bullet = bullets[current];
  169. if (bullet) {
  170. bullet.classList.add(...params.bulletActiveClass.split(' '));
  171. }
  172. if (swiper.isElement) {
  173. bullets.forEach((bulletEl, bulletIndex) => {
  174. bulletEl.setAttribute('part', bulletIndex === current ? 'bullet-active' : 'bullet');
  175. });
  176. }
  177. if (params.dynamicBullets) {
  178. const firstDisplayedBullet = bullets[firstIndex];
  179. const lastDisplayedBullet = bullets[lastIndex];
  180. for (let i = firstIndex; i <= lastIndex; i += 1) {
  181. if (bullets[i]) {
  182. bullets[i].classList.add(...`${params.bulletActiveClass}-main`.split(' '));
  183. }
  184. }
  185. setSideBullets(firstDisplayedBullet, 'prev');
  186. setSideBullets(lastDisplayedBullet, 'next');
  187. }
  188. }
  189. if (params.dynamicBullets) {
  190. const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);
  191. const bulletsOffset = (bulletSize * dynamicBulletsLength - bulletSize) / 2 - midIndex * bulletSize;
  192. const offsetProp = rtl ? 'right' : 'left';
  193. bullets.forEach(bullet => {
  194. bullet.style[swiper.isHorizontal() ? offsetProp : 'top'] = `${bulletsOffset}px`;
  195. });
  196. }
  197. }
  198. el.forEach((subEl, subElIndex) => {
  199. if (params.type === 'fraction') {
  200. subEl.querySelectorAll(classesToSelector(params.currentClass)).forEach(fractionEl => {
  201. fractionEl.textContent = params.formatFractionCurrent(current + 1);
  202. });
  203. subEl.querySelectorAll(classesToSelector(params.totalClass)).forEach(totalEl => {
  204. totalEl.textContent = params.formatFractionTotal(total);
  205. });
  206. }
  207. if (params.type === 'progressbar') {
  208. let progressbarDirection;
  209. if (params.progressbarOpposite) {
  210. progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal';
  211. } else {
  212. progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical';
  213. }
  214. const scale = (current + 1) / total;
  215. let scaleX = 1;
  216. let scaleY = 1;
  217. if (progressbarDirection === 'horizontal') {
  218. scaleX = scale;
  219. } else {
  220. scaleY = scale;
  221. }
  222. subEl.querySelectorAll(classesToSelector(params.progressbarFillClass)).forEach(progressEl => {
  223. progressEl.style.transform = `translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`;
  224. progressEl.style.transitionDuration = `${swiper.params.speed}ms`;
  225. });
  226. }
  227. if (params.type === 'custom' && params.renderCustom) {
  228. subEl.innerHTML = params.renderCustom(swiper, current + 1, total);
  229. if (subElIndex === 0) emit('paginationRender', subEl);
  230. } else {
  231. if (subElIndex === 0) emit('paginationRender', subEl);
  232. emit('paginationUpdate', subEl);
  233. }
  234. if (swiper.params.watchOverflow && swiper.enabled) {
  235. subEl.classList[swiper.isLocked ? 'add' : 'remove'](params.lockClass);
  236. }
  237. });
  238. }
  239. function render() {
  240. // Render Container
  241. const params = swiper.params.pagination;
  242. if (isPaginationDisabled()) return;
  243. const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.grid && swiper.params.grid.rows > 1 ? swiper.slides.length / Math.ceil(swiper.params.grid.rows) : swiper.slides.length;
  244. let el = swiper.pagination.el;
  245. el = makeElementsArray(el);
  246. let paginationHTML = '';
  247. if (params.type === 'bullets') {
  248. let numberOfBullets = swiper.params.loop ? Math.ceil(slidesLength / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
  249. if (swiper.params.freeMode && swiper.params.freeMode.enabled && numberOfBullets > slidesLength) {
  250. numberOfBullets = slidesLength;
  251. }
  252. for (let i = 0; i < numberOfBullets; i += 1) {
  253. if (params.renderBullet) {
  254. paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
  255. } else {
  256. // prettier-ignore
  257. paginationHTML += `<${params.bulletElement} ${swiper.isElement ? 'part="bullet"' : ''} class="${params.bulletClass}"></${params.bulletElement}>`;
  258. }
  259. }
  260. }
  261. if (params.type === 'fraction') {
  262. if (params.renderFraction) {
  263. paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
  264. } else {
  265. paginationHTML = `<span class="${params.currentClass}"></span>` + ' / ' + `<span class="${params.totalClass}"></span>`;
  266. }
  267. }
  268. if (params.type === 'progressbar') {
  269. if (params.renderProgressbar) {
  270. paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
  271. } else {
  272. paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
  273. }
  274. }
  275. swiper.pagination.bullets = [];
  276. el.forEach(subEl => {
  277. if (params.type !== 'custom') {
  278. subEl.innerHTML = paginationHTML || '';
  279. }
  280. if (params.type === 'bullets') {
  281. swiper.pagination.bullets.push(...subEl.querySelectorAll(classesToSelector(params.bulletClass)));
  282. }
  283. });
  284. if (params.type !== 'custom') {
  285. emit('paginationRender', el[0]);
  286. }
  287. }
  288. function init() {
  289. swiper.params.pagination = createElementIfNotDefined(swiper, swiper.originalParams.pagination, swiper.params.pagination, {
  290. el: 'swiper-pagination'
  291. });
  292. const params = swiper.params.pagination;
  293. if (!params.el) return;
  294. let el;
  295. if (typeof params.el === 'string' && swiper.isElement) {
  296. el = swiper.el.querySelector(params.el);
  297. }
  298. if (!el && typeof params.el === 'string') {
  299. el = [...document.querySelectorAll(params.el)];
  300. }
  301. if (!el) {
  302. el = params.el;
  303. }
  304. if (!el || el.length === 0) return;
  305. if (swiper.params.uniqueNavElements && typeof params.el === 'string' && Array.isArray(el) && el.length > 1) {
  306. el = [...swiper.el.querySelectorAll(params.el)];
  307. // check if it belongs to another nested Swiper
  308. if (el.length > 1) {
  309. el = el.filter(subEl => {
  310. if (elementParents(subEl, '.swiper')[0] !== swiper.el) return false;
  311. return true;
  312. })[0];
  313. }
  314. }
  315. if (Array.isArray(el) && el.length === 1) el = el[0];
  316. Object.assign(swiper.pagination, {
  317. el
  318. });
  319. el = makeElementsArray(el);
  320. el.forEach(subEl => {
  321. if (params.type === 'bullets' && params.clickable) {
  322. subEl.classList.add(...(params.clickableClass || '').split(' '));
  323. }
  324. subEl.classList.add(params.modifierClass + params.type);
  325. subEl.classList.add(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
  326. if (params.type === 'bullets' && params.dynamicBullets) {
  327. subEl.classList.add(`${params.modifierClass}${params.type}-dynamic`);
  328. dynamicBulletIndex = 0;
  329. if (params.dynamicMainBullets < 1) {
  330. params.dynamicMainBullets = 1;
  331. }
  332. }
  333. if (params.type === 'progressbar' && params.progressbarOpposite) {
  334. subEl.classList.add(params.progressbarOppositeClass);
  335. }
  336. if (params.clickable) {
  337. subEl.addEventListener('click', onBulletClick);
  338. }
  339. if (!swiper.enabled) {
  340. subEl.classList.add(params.lockClass);
  341. }
  342. });
  343. }
  344. function destroy() {
  345. const params = swiper.params.pagination;
  346. if (isPaginationDisabled()) return;
  347. let el = swiper.pagination.el;
  348. if (el) {
  349. el = makeElementsArray(el);
  350. el.forEach(subEl => {
  351. subEl.classList.remove(params.hiddenClass);
  352. subEl.classList.remove(params.modifierClass + params.type);
  353. subEl.classList.remove(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
  354. if (params.clickable) {
  355. subEl.classList.remove(...(params.clickableClass || '').split(' '));
  356. subEl.removeEventListener('click', onBulletClick);
  357. }
  358. });
  359. }
  360. if (swiper.pagination.bullets) swiper.pagination.bullets.forEach(subEl => subEl.classList.remove(...params.bulletActiveClass.split(' ')));
  361. }
  362. on('changeDirection', () => {
  363. if (!swiper.pagination || !swiper.pagination.el) return;
  364. const params = swiper.params.pagination;
  365. let {
  366. el
  367. } = swiper.pagination;
  368. el = makeElementsArray(el);
  369. el.forEach(subEl => {
  370. subEl.classList.remove(params.horizontalClass, params.verticalClass);
  371. subEl.classList.add(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
  372. });
  373. });
  374. on('init', () => {
  375. if (swiper.params.pagination.enabled === false) {
  376. // eslint-disable-next-line
  377. disable();
  378. } else {
  379. init();
  380. render();
  381. update();
  382. }
  383. });
  384. on('activeIndexChange', () => {
  385. if (typeof swiper.snapIndex === 'undefined') {
  386. update();
  387. }
  388. });
  389. on('snapIndexChange', () => {
  390. update();
  391. });
  392. on('snapGridLengthChange', () => {
  393. render();
  394. update();
  395. });
  396. on('destroy', () => {
  397. destroy();
  398. });
  399. on('enable disable', () => {
  400. let {
  401. el
  402. } = swiper.pagination;
  403. if (el) {
  404. el = makeElementsArray(el);
  405. el.forEach(subEl => subEl.classList[swiper.enabled ? 'remove' : 'add'](swiper.params.pagination.lockClass));
  406. }
  407. });
  408. on('lock unlock', () => {
  409. update();
  410. });
  411. on('click', (_s, e) => {
  412. const targetEl = e.target;
  413. const el = makeElementsArray(swiper.pagination.el);
  414. if (swiper.params.pagination.el && swiper.params.pagination.hideOnClick && el && el.length > 0 && !targetEl.classList.contains(swiper.params.pagination.bulletClass)) {
  415. if (swiper.navigation && (swiper.navigation.nextEl && targetEl === swiper.navigation.nextEl || swiper.navigation.prevEl && targetEl === swiper.navigation.prevEl)) return;
  416. const isHidden = el[0].classList.contains(swiper.params.pagination.hiddenClass);
  417. if (isHidden === true) {
  418. emit('paginationShow');
  419. } else {
  420. emit('paginationHide');
  421. }
  422. el.forEach(subEl => subEl.classList.toggle(swiper.params.pagination.hiddenClass));
  423. }
  424. });
  425. const enable = () => {
  426. swiper.el.classList.remove(swiper.params.pagination.paginationDisabledClass);
  427. let {
  428. el
  429. } = swiper.pagination;
  430. if (el) {
  431. el = makeElementsArray(el);
  432. el.forEach(subEl => subEl.classList.remove(swiper.params.pagination.paginationDisabledClass));
  433. }
  434. init();
  435. render();
  436. update();
  437. };
  438. const disable = () => {
  439. swiper.el.classList.add(swiper.params.pagination.paginationDisabledClass);
  440. let {
  441. el
  442. } = swiper.pagination;
  443. if (el) {
  444. el = makeElementsArray(el);
  445. el.forEach(subEl => subEl.classList.add(swiper.params.pagination.paginationDisabledClass));
  446. }
  447. destroy();
  448. };
  449. Object.assign(swiper.pagination, {
  450. enable,
  451. disable,
  452. render,
  453. update,
  454. init,
  455. destroy
  456. });
  457. }
  458. export { Pagination as default };