UNPKG

13.7 kBJavaScriptView Raw
1import $ from '../../shared/dom.js';
2import classesToSelector from '../../shared/classes-to-selector.js';
3import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
4export default function Pagination({
5 swiper,
6 extendParams,
7 on,
8 emit
9}) {
10 const pfx = 'swiper-pagination';
11 extendParams({
12 pagination: {
13 el: null,
14 bulletElement: 'span',
15 clickable: false,
16 hideOnClick: false,
17 renderBullet: null,
18 renderProgressbar: null,
19 renderFraction: null,
20 renderCustom: null,
21 progressbarOpposite: false,
22 type: 'bullets',
23 // 'bullets' or 'progressbar' or 'fraction' or 'custom'
24 dynamicBullets: false,
25 dynamicMainBullets: 1,
26 formatFractionCurrent: number => number,
27 formatFractionTotal: number => number,
28 bulletClass: `${pfx}-bullet`,
29 bulletActiveClass: `${pfx}-bullet-active`,
30 modifierClass: `${pfx}-`,
31 currentClass: `${pfx}-current`,
32 totalClass: `${pfx}-total`,
33 hiddenClass: `${pfx}-hidden`,
34 progressbarFillClass: `${pfx}-progressbar-fill`,
35 progressbarOppositeClass: `${pfx}-progressbar-opposite`,
36 clickableClass: `${pfx}-clickable`,
37 lockClass: `${pfx}-lock`,
38 horizontalClass: `${pfx}-horizontal`,
39 verticalClass: `${pfx}-vertical`
40 }
41 });
42 swiper.pagination = {
43 el: null,
44 $el: null,
45 bullets: []
46 };
47 let bulletSize;
48 let dynamicBulletIndex = 0;
49
50 function isPaginationDisabled() {
51 return !swiper.params.pagination.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0;
52 }
53
54 function setSideBullets($bulletEl, position) {
55 const {
56 bulletActiveClass
57 } = swiper.params.pagination;
58 $bulletEl[position]().addClass(`${bulletActiveClass}-${position}`)[position]().addClass(`${bulletActiveClass}-${position}-${position}`);
59 }
60
61 function update() {
62 // Render || Update Pagination bullets/items
63 const rtl = swiper.rtl;
64 const params = swiper.params.pagination;
65 if (isPaginationDisabled()) return;
66 const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
67 const $el = swiper.pagination.$el; // Current/Total
68
69 let current;
70 const total = swiper.params.loop ? Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
71
72 if (swiper.params.loop) {
73 current = Math.ceil((swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup);
74
75 if (current > slidesLength - 1 - swiper.loopedSlides * 2) {
76 current -= slidesLength - swiper.loopedSlides * 2;
77 }
78
79 if (current > total - 1) current -= total;
80 if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current;
81 } else if (typeof swiper.snapIndex !== 'undefined') {
82 current = swiper.snapIndex;
83 } else {
84 current = swiper.activeIndex || 0;
85 } // Types
86
87
88 if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) {
89 const bullets = swiper.pagination.bullets;
90 let firstIndex;
91 let lastIndex;
92 let midIndex;
93
94 if (params.dynamicBullets) {
95 bulletSize = bullets.eq(0)[swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'](true);
96 $el.css(swiper.isHorizontal() ? 'width' : 'height', `${bulletSize * (params.dynamicMainBullets + 4)}px`);
97
98 if (params.dynamicMainBullets > 1 && swiper.previousIndex !== undefined) {
99 dynamicBulletIndex += current - swiper.previousIndex;
100
101 if (dynamicBulletIndex > params.dynamicMainBullets - 1) {
102 dynamicBulletIndex = params.dynamicMainBullets - 1;
103 } else if (dynamicBulletIndex < 0) {
104 dynamicBulletIndex = 0;
105 }
106 }
107
108 firstIndex = current - dynamicBulletIndex;
109 lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);
110 midIndex = (lastIndex + firstIndex) / 2;
111 }
112
113 bullets.removeClass(['', '-next', '-next-next', '-prev', '-prev-prev', '-main'].map(suffix => `${params.bulletActiveClass}${suffix}`).join(' '));
114
115 if ($el.length > 1) {
116 bullets.each(bullet => {
117 const $bullet = $(bullet);
118 const bulletIndex = $bullet.index();
119
120 if (bulletIndex === current) {
121 $bullet.addClass(params.bulletActiveClass);
122 }
123
124 if (params.dynamicBullets) {
125 if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {
126 $bullet.addClass(`${params.bulletActiveClass}-main`);
127 }
128
129 if (bulletIndex === firstIndex) {
130 setSideBullets($bullet, 'prev');
131 }
132
133 if (bulletIndex === lastIndex) {
134 setSideBullets($bullet, 'next');
135 }
136 }
137 });
138 } else {
139 const $bullet = bullets.eq(current);
140 const bulletIndex = $bullet.index();
141 $bullet.addClass(params.bulletActiveClass);
142
143 if (params.dynamicBullets) {
144 const $firstDisplayedBullet = bullets.eq(firstIndex);
145 const $lastDisplayedBullet = bullets.eq(lastIndex);
146
147 for (let i = firstIndex; i <= lastIndex; i += 1) {
148 bullets.eq(i).addClass(`${params.bulletActiveClass}-main`);
149 }
150
151 if (swiper.params.loop) {
152 if (bulletIndex >= bullets.length - params.dynamicMainBullets) {
153 for (let i = params.dynamicMainBullets; i >= 0; i -= 1) {
154 bullets.eq(bullets.length - i).addClass(`${params.bulletActiveClass}-main`);
155 }
156
157 bullets.eq(bullets.length - params.dynamicMainBullets - 1).addClass(`${params.bulletActiveClass}-prev`);
158 } else {
159 setSideBullets($firstDisplayedBullet, 'prev');
160 setSideBullets($lastDisplayedBullet, 'next');
161 }
162 } else {
163 setSideBullets($firstDisplayedBullet, 'prev');
164 setSideBullets($lastDisplayedBullet, 'next');
165 }
166 }
167 }
168
169 if (params.dynamicBullets) {
170 const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);
171 const bulletsOffset = (bulletSize * dynamicBulletsLength - bulletSize) / 2 - midIndex * bulletSize;
172 const offsetProp = rtl ? 'right' : 'left';
173 bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`);
174 }
175 }
176
177 if (params.type === 'fraction') {
178 $el.find(classesToSelector(params.currentClass)).text(params.formatFractionCurrent(current + 1));
179 $el.find(classesToSelector(params.totalClass)).text(params.formatFractionTotal(total));
180 }
181
182 if (params.type === 'progressbar') {
183 let progressbarDirection;
184
185 if (params.progressbarOpposite) {
186 progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal';
187 } else {
188 progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical';
189 }
190
191 const scale = (current + 1) / total;
192 let scaleX = 1;
193 let scaleY = 1;
194
195 if (progressbarDirection === 'horizontal') {
196 scaleX = scale;
197 } else {
198 scaleY = scale;
199 }
200
201 $el.find(classesToSelector(params.progressbarFillClass)).transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`).transition(swiper.params.speed);
202 }
203
204 if (params.type === 'custom' && params.renderCustom) {
205 $el.html(params.renderCustom(swiper, current + 1, total));
206 emit('paginationRender', $el[0]);
207 } else {
208 emit('paginationUpdate', $el[0]);
209 }
210
211 if (swiper.params.watchOverflow && swiper.enabled) {
212 $el[swiper.isLocked ? 'addClass' : 'removeClass'](params.lockClass);
213 }
214 }
215
216 function render() {
217 // Render Container
218 const params = swiper.params.pagination;
219 if (isPaginationDisabled()) return;
220 const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
221 const $el = swiper.pagination.$el;
222 let paginationHTML = '';
223
224 if (params.type === 'bullets') {
225 let numberOfBullets = swiper.params.loop ? Math.ceil((slidesLength - swiper.loopedSlides * 2) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
226
227 if (swiper.params.freeMode && swiper.params.freeMode.enabled && !swiper.params.loop && numberOfBullets > slidesLength) {
228 numberOfBullets = slidesLength;
229 }
230
231 for (let i = 0; i < numberOfBullets; i += 1) {
232 if (params.renderBullet) {
233 paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
234 } else {
235 paginationHTML += `<${params.bulletElement} class="${params.bulletClass}"></${params.bulletElement}>`;
236 }
237 }
238
239 $el.html(paginationHTML);
240 swiper.pagination.bullets = $el.find(classesToSelector(params.bulletClass));
241 }
242
243 if (params.type === 'fraction') {
244 if (params.renderFraction) {
245 paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
246 } else {
247 paginationHTML = `<span class="${params.currentClass}"></span>` + ' / ' + `<span class="${params.totalClass}"></span>`;
248 }
249
250 $el.html(paginationHTML);
251 }
252
253 if (params.type === 'progressbar') {
254 if (params.renderProgressbar) {
255 paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
256 } else {
257 paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
258 }
259
260 $el.html(paginationHTML);
261 }
262
263 if (params.type !== 'custom') {
264 emit('paginationRender', swiper.pagination.$el[0]);
265 }
266 }
267
268 function init() {
269 swiper.params.pagination = createElementIfNotDefined(swiper, swiper.originalParams.pagination, swiper.params.pagination, {
270 el: 'swiper-pagination'
271 });
272 const params = swiper.params.pagination;
273 if (!params.el) return;
274 let $el = $(params.el);
275 if ($el.length === 0) return;
276
277 if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1) {
278 $el = swiper.$el.find(params.el); // check if it belongs to another nested Swiper
279
280 if ($el.length > 1) {
281 $el = $el.filter(el => {
282 if ($(el).parents('.swiper')[0] !== swiper.el) return false;
283 return true;
284 });
285 }
286 }
287
288 if (params.type === 'bullets' && params.clickable) {
289 $el.addClass(params.clickableClass);
290 }
291
292 $el.addClass(params.modifierClass + params.type);
293 $el.addClass(params.modifierClass + swiper.params.direction);
294
295 if (params.type === 'bullets' && params.dynamicBullets) {
296 $el.addClass(`${params.modifierClass}${params.type}-dynamic`);
297 dynamicBulletIndex = 0;
298
299 if (params.dynamicMainBullets < 1) {
300 params.dynamicMainBullets = 1;
301 }
302 }
303
304 if (params.type === 'progressbar' && params.progressbarOpposite) {
305 $el.addClass(params.progressbarOppositeClass);
306 }
307
308 if (params.clickable) {
309 $el.on('click', classesToSelector(params.bulletClass), function onClick(e) {
310 e.preventDefault();
311 let index = $(this).index() * swiper.params.slidesPerGroup;
312 if (swiper.params.loop) index += swiper.loopedSlides;
313 swiper.slideTo(index);
314 });
315 }
316
317 Object.assign(swiper.pagination, {
318 $el,
319 el: $el[0]
320 });
321
322 if (!swiper.enabled) {
323 $el.addClass(params.lockClass);
324 }
325 }
326
327 function destroy() {
328 const params = swiper.params.pagination;
329 if (isPaginationDisabled()) return;
330 const $el = swiper.pagination.$el;
331 $el.removeClass(params.hiddenClass);
332 $el.removeClass(params.modifierClass + params.type);
333 $el.removeClass(params.modifierClass + swiper.params.direction);
334 if (swiper.pagination.bullets && swiper.pagination.bullets.removeClass) swiper.pagination.bullets.removeClass(params.bulletActiveClass);
335
336 if (params.clickable) {
337 $el.off('click', classesToSelector(params.bulletClass));
338 }
339 }
340
341 on('init', () => {
342 init();
343 render();
344 update();
345 });
346 on('activeIndexChange', () => {
347 if (swiper.params.loop) {
348 update();
349 } else if (typeof swiper.snapIndex === 'undefined') {
350 update();
351 }
352 });
353 on('snapIndexChange', () => {
354 if (!swiper.params.loop) {
355 update();
356 }
357 });
358 on('slidesLengthChange', () => {
359 if (swiper.params.loop) {
360 render();
361 update();
362 }
363 });
364 on('snapGridLengthChange', () => {
365 if (!swiper.params.loop) {
366 render();
367 update();
368 }
369 });
370 on('destroy', () => {
371 destroy();
372 });
373 on('enable disable', () => {
374 const {
375 $el
376 } = swiper.pagination;
377
378 if ($el) {
379 $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.pagination.lockClass);
380 }
381 });
382 on('lock unlock', () => {
383 update();
384 });
385 on('click', (_s, e) => {
386 const targetEl = e.target;
387 const {
388 $el
389 } = swiper.pagination;
390
391 if (swiper.params.pagination.el && swiper.params.pagination.hideOnClick && $el.length > 0 && !$(targetEl).hasClass(swiper.params.pagination.bulletClass)) {
392 if (swiper.navigation && (swiper.navigation.nextEl && targetEl === swiper.navigation.nextEl || swiper.navigation.prevEl && targetEl === swiper.navigation.prevEl)) return;
393 const isHidden = $el.hasClass(swiper.params.pagination.hiddenClass);
394
395 if (isHidden === true) {
396 emit('paginationShow');
397 } else {
398 emit('paginationHide');
399 }
400
401 $el.toggleClass(swiper.params.pagination.hiddenClass);
402 }
403 });
404 Object.assign(swiper.pagination, {
405 render,
406 update,
407 init,
408 destroy
409 });
410}
\No newline at end of file