UNPKG

204 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * SSR Window 2.0.0
5 * Better handling for window object in SSR environment
6 * https://github.com/nolimits4web/ssr-window
7 *
8 * Copyright 2020, Vladimir Kharlampidi
9 *
10 * Licensed under MIT
11 *
12 * Released on: May 12, 2020
13 */
14/* eslint-disable no-param-reassign */
15function isObject(obj) {
16 return (obj !== null &&
17 typeof obj === 'object' &&
18 'constructor' in obj &&
19 obj.constructor === Object);
20}
21function extend(target, src) {
22 if (target === void 0) { target = {}; }
23 if (src === void 0) { src = {}; }
24 Object.keys(src).forEach(function (key) {
25 if (typeof target[key] === 'undefined')
26 target[key] = src[key];
27 else if (isObject(src[key]) &&
28 isObject(target[key]) &&
29 Object.keys(src[key]).length > 0) {
30 extend(target[key], src[key]);
31 }
32 });
33}
34
35var doc = typeof document !== 'undefined' ? document : {};
36var ssrDocument = {
37 body: {},
38 addEventListener: function () { },
39 removeEventListener: function () { },
40 activeElement: {
41 blur: function () { },
42 nodeName: '',
43 },
44 querySelector: function () {
45 return null;
46 },
47 querySelectorAll: function () {
48 return [];
49 },
50 getElementById: function () {
51 return null;
52 },
53 createEvent: function () {
54 return {
55 initEvent: function () { },
56 };
57 },
58 createElement: function () {
59 return {
60 children: [],
61 childNodes: [],
62 style: {},
63 setAttribute: function () { },
64 getElementsByTagName: function () {
65 return [];
66 },
67 };
68 },
69 createElementNS: function () {
70 return {};
71 },
72 importNode: function () {
73 return null;
74 },
75 location: {
76 hash: '',
77 host: '',
78 hostname: '',
79 href: '',
80 origin: '',
81 pathname: '',
82 protocol: '',
83 search: '',
84 },
85};
86extend(doc, ssrDocument);
87
88var win = typeof window !== 'undefined' ? window : {};
89var ssrWindow = {
90 document: ssrDocument,
91 navigator: {
92 userAgent: '',
93 },
94 location: {
95 hash: '',
96 host: '',
97 hostname: '',
98 href: '',
99 origin: '',
100 pathname: '',
101 protocol: '',
102 search: '',
103 },
104 history: {
105 replaceState: function () { },
106 pushState: function () { },
107 go: function () { },
108 back: function () { },
109 },
110 CustomEvent: function CustomEvent() {
111 return this;
112 },
113 addEventListener: function () { },
114 removeEventListener: function () { },
115 getComputedStyle: function () {
116 return {
117 getPropertyValue: function () {
118 return '';
119 },
120 };
121 },
122 Image: function () { },
123 Date: function () { },
124 screen: {},
125 setTimeout: function () { },
126 clearTimeout: function () { },
127 matchMedia: function () {
128 return {};
129 },
130};
131extend(win, ssrWindow);
132
133/**
134 * Dom7 2.1.5
135 * Minimalistic JavaScript library for DOM manipulation, with a jQuery-compatible API
136 * http://framework7.io/docs/dom.html
137 *
138 * Copyright 2020, Vladimir Kharlampidi
139 * The iDangero.us
140 * http://www.idangero.us/
141 *
142 * Licensed under MIT
143 *
144 * Released on: May 15, 2020
145 */
146
147class Dom7 {
148 constructor(arr) {
149 const self = this;
150 // Create array-like object
151 for (let i = 0; i < arr.length; i += 1) {
152 self[i] = arr[i];
153 }
154 self.length = arr.length;
155 // Return collection with methods
156 return this;
157 }
158}
159
160function $(selector, context) {
161 const arr = [];
162 let i = 0;
163 if (selector && !context) {
164 if (selector instanceof Dom7) {
165 return selector;
166 }
167 }
168 if (selector) {
169 // String
170 if (typeof selector === 'string') {
171 let els;
172 let tempParent;
173 const html = selector.trim();
174 if (html.indexOf('<') >= 0 && html.indexOf('>') >= 0) {
175 let toCreate = 'div';
176 if (html.indexOf('<li') === 0) toCreate = 'ul';
177 if (html.indexOf('<tr') === 0) toCreate = 'tbody';
178 if (html.indexOf('<td') === 0 || html.indexOf('<th') === 0) toCreate = 'tr';
179 if (html.indexOf('<tbody') === 0) toCreate = 'table';
180 if (html.indexOf('<option') === 0) toCreate = 'select';
181 tempParent = doc.createElement(toCreate);
182 tempParent.innerHTML = html;
183 for (i = 0; i < tempParent.childNodes.length; i += 1) {
184 arr.push(tempParent.childNodes[i]);
185 }
186 } else {
187 if (!context && selector[0] === '#' && !selector.match(/[ .<>:~]/)) {
188 // Pure ID selector
189 els = [doc.getElementById(selector.trim().split('#')[1])];
190 } else {
191 // Other selectors
192 els = (context || doc).querySelectorAll(selector.trim());
193 }
194 for (i = 0; i < els.length; i += 1) {
195 if (els[i]) arr.push(els[i]);
196 }
197 }
198 } else if (selector.nodeType || selector === win || selector === doc) {
199 // Node/element
200 arr.push(selector);
201 } else if (selector.length > 0 && selector[0].nodeType) {
202 // Array of elements or instance of Dom
203 for (i = 0; i < selector.length; i += 1) {
204 arr.push(selector[i]);
205 }
206 }
207 }
208 return new Dom7(arr);
209}
210
211$.fn = Dom7.prototype;
212$.Class = Dom7;
213$.Dom7 = Dom7;
214
215function unique(arr) {
216 const uniqueArray = [];
217 for (let i = 0; i < arr.length; i += 1) {
218 if (uniqueArray.indexOf(arr[i]) === -1) uniqueArray.push(arr[i]);
219 }
220 return uniqueArray;
221}
222
223// Classes and attributes
224function addClass(className) {
225 if (typeof className === 'undefined') {
226 return this;
227 }
228 const classes = className.split(' ');
229 for (let i = 0; i < classes.length; i += 1) {
230 for (let j = 0; j < this.length; j += 1) {
231 if (typeof this[j] !== 'undefined' && typeof this[j].classList !== 'undefined') this[j].classList.add(classes[i]);
232 }
233 }
234 return this;
235}
236function removeClass(className) {
237 const classes = className.split(' ');
238 for (let i = 0; i < classes.length; i += 1) {
239 for (let j = 0; j < this.length; j += 1) {
240 if (typeof this[j] !== 'undefined' && typeof this[j].classList !== 'undefined') this[j].classList.remove(classes[i]);
241 }
242 }
243 return this;
244}
245function hasClass(className) {
246 if (!this[0]) return false;
247 return this[0].classList.contains(className);
248}
249function toggleClass(className) {
250 const classes = className.split(' ');
251 for (let i = 0; i < classes.length; i += 1) {
252 for (let j = 0; j < this.length; j += 1) {
253 if (typeof this[j] !== 'undefined' && typeof this[j].classList !== 'undefined') this[j].classList.toggle(classes[i]);
254 }
255 }
256 return this;
257}
258function attr(attrs, value) {
259 if (arguments.length === 1 && typeof attrs === 'string') {
260 // Get attr
261 if (this[0]) return this[0].getAttribute(attrs);
262 return undefined;
263 }
264
265 // Set attrs
266 for (let i = 0; i < this.length; i += 1) {
267 if (arguments.length === 2) {
268 // String
269 this[i].setAttribute(attrs, value);
270 } else {
271 // Object
272 // eslint-disable-next-line
273 for (const attrName in attrs) {
274 this[i][attrName] = attrs[attrName];
275 this[i].setAttribute(attrName, attrs[attrName]);
276 }
277 }
278 }
279 return this;
280}
281// eslint-disable-next-line
282function removeAttr(attr) {
283 for (let i = 0; i < this.length; i += 1) {
284 this[i].removeAttribute(attr);
285 }
286 return this;
287}
288function data(key, value) {
289 let el;
290 if (typeof value === 'undefined') {
291 el = this[0];
292 // Get value
293 if (el) {
294 if (el.dom7ElementDataStorage && (key in el.dom7ElementDataStorage)) {
295 return el.dom7ElementDataStorage[key];
296 }
297
298 const dataKey = el.getAttribute(`data-${key}`);
299 if (dataKey) {
300 return dataKey;
301 }
302 return undefined;
303 }
304 return undefined;
305 }
306
307 // Set value
308 for (let i = 0; i < this.length; i += 1) {
309 el = this[i];
310 if (!el.dom7ElementDataStorage) el.dom7ElementDataStorage = {};
311 el.dom7ElementDataStorage[key] = value;
312 }
313 return this;
314}
315// Transforms
316// eslint-disable-next-line
317function transform(transform) {
318 for (let i = 0; i < this.length; i += 1) {
319 const elStyle = this[i].style;
320 elStyle.webkitTransform = transform;
321 elStyle.transform = transform;
322 }
323 return this;
324}
325function transition(duration) {
326 if (typeof duration !== 'string') {
327 duration = `${duration}ms`; // eslint-disable-line
328 }
329 for (let i = 0; i < this.length; i += 1) {
330 const elStyle = this[i].style;
331 elStyle.webkitTransitionDuration = duration;
332 elStyle.transitionDuration = duration;
333 }
334 return this;
335}
336// Events
337function on(...args) {
338 let [eventType, targetSelector, listener, capture] = args;
339 if (typeof args[1] === 'function') {
340 [eventType, listener, capture] = args;
341 targetSelector = undefined;
342 }
343 if (!capture) capture = false;
344
345 function handleLiveEvent(e) {
346 const target = e.target;
347 if (!target) return;
348 const eventData = e.target.dom7EventData || [];
349 if (eventData.indexOf(e) < 0) {
350 eventData.unshift(e);
351 }
352 if ($(target).is(targetSelector)) listener.apply(target, eventData);
353 else {
354 const parents = $(target).parents(); // eslint-disable-line
355 for (let k = 0; k < parents.length; k += 1) {
356 if ($(parents[k]).is(targetSelector)) listener.apply(parents[k], eventData);
357 }
358 }
359 }
360 function handleEvent(e) {
361 const eventData = e && e.target ? e.target.dom7EventData || [] : [];
362 if (eventData.indexOf(e) < 0) {
363 eventData.unshift(e);
364 }
365 listener.apply(this, eventData);
366 }
367 const events = eventType.split(' ');
368 let j;
369 for (let i = 0; i < this.length; i += 1) {
370 const el = this[i];
371 if (!targetSelector) {
372 for (j = 0; j < events.length; j += 1) {
373 const event = events[j];
374 if (!el.dom7Listeners) el.dom7Listeners = {};
375 if (!el.dom7Listeners[event]) el.dom7Listeners[event] = [];
376 el.dom7Listeners[event].push({
377 listener,
378 proxyListener: handleEvent,
379 });
380 el.addEventListener(event, handleEvent, capture);
381 }
382 } else {
383 // Live events
384 for (j = 0; j < events.length; j += 1) {
385 const event = events[j];
386 if (!el.dom7LiveListeners) el.dom7LiveListeners = {};
387 if (!el.dom7LiveListeners[event]) el.dom7LiveListeners[event] = [];
388 el.dom7LiveListeners[event].push({
389 listener,
390 proxyListener: handleLiveEvent,
391 });
392 el.addEventListener(event, handleLiveEvent, capture);
393 }
394 }
395 }
396 return this;
397}
398function off(...args) {
399 let [eventType, targetSelector, listener, capture] = args;
400 if (typeof args[1] === 'function') {
401 [eventType, listener, capture] = args;
402 targetSelector = undefined;
403 }
404 if (!capture) capture = false;
405
406 const events = eventType.split(' ');
407 for (let i = 0; i < events.length; i += 1) {
408 const event = events[i];
409 for (let j = 0; j < this.length; j += 1) {
410 const el = this[j];
411 let handlers;
412 if (!targetSelector && el.dom7Listeners) {
413 handlers = el.dom7Listeners[event];
414 } else if (targetSelector && el.dom7LiveListeners) {
415 handlers = el.dom7LiveListeners[event];
416 }
417 if (handlers && handlers.length) {
418 for (let k = handlers.length - 1; k >= 0; k -= 1) {
419 const handler = handlers[k];
420 if (listener && handler.listener === listener) {
421 el.removeEventListener(event, handler.proxyListener, capture);
422 handlers.splice(k, 1);
423 } else if (listener && handler.listener && handler.listener.dom7proxy && handler.listener.dom7proxy === listener) {
424 el.removeEventListener(event, handler.proxyListener, capture);
425 handlers.splice(k, 1);
426 } else if (!listener) {
427 el.removeEventListener(event, handler.proxyListener, capture);
428 handlers.splice(k, 1);
429 }
430 }
431 }
432 }
433 }
434 return this;
435}
436function trigger(...args) {
437 const events = args[0].split(' ');
438 const eventData = args[1];
439 for (let i = 0; i < events.length; i += 1) {
440 const event = events[i];
441 for (let j = 0; j < this.length; j += 1) {
442 const el = this[j];
443 let evt;
444 try {
445 evt = new win.CustomEvent(event, {
446 detail: eventData,
447 bubbles: true,
448 cancelable: true,
449 });
450 } catch (e) {
451 evt = doc.createEvent('Event');
452 evt.initEvent(event, true, true);
453 evt.detail = eventData;
454 }
455 // eslint-disable-next-line
456 el.dom7EventData = args.filter((data, dataIndex) => dataIndex > 0);
457 el.dispatchEvent(evt);
458 el.dom7EventData = [];
459 delete el.dom7EventData;
460 }
461 }
462 return this;
463}
464function transitionEnd(callback) {
465 const events = ['webkitTransitionEnd', 'transitionend'];
466 const dom = this;
467 let i;
468 function fireCallBack(e) {
469 /* jshint validthis:true */
470 if (e.target !== this) return;
471 callback.call(this, e);
472 for (i = 0; i < events.length; i += 1) {
473 dom.off(events[i], fireCallBack);
474 }
475 }
476 if (callback) {
477 for (i = 0; i < events.length; i += 1) {
478 dom.on(events[i], fireCallBack);
479 }
480 }
481 return this;
482}
483function outerWidth(includeMargins) {
484 if (this.length > 0) {
485 if (includeMargins) {
486 // eslint-disable-next-line
487 const styles = this.styles();
488 return this[0].offsetWidth + parseFloat(styles.getPropertyValue('margin-right')) + parseFloat(styles.getPropertyValue('margin-left'));
489 }
490 return this[0].offsetWidth;
491 }
492 return null;
493}
494function outerHeight(includeMargins) {
495 if (this.length > 0) {
496 if (includeMargins) {
497 // eslint-disable-next-line
498 const styles = this.styles();
499 return this[0].offsetHeight + parseFloat(styles.getPropertyValue('margin-top')) + parseFloat(styles.getPropertyValue('margin-bottom'));
500 }
501 return this[0].offsetHeight;
502 }
503 return null;
504}
505function offset() {
506 if (this.length > 0) {
507 const el = this[0];
508 const box = el.getBoundingClientRect();
509 const body = doc.body;
510 const clientTop = el.clientTop || body.clientTop || 0;
511 const clientLeft = el.clientLeft || body.clientLeft || 0;
512 const scrollTop = el === win ? win.scrollY : el.scrollTop;
513 const scrollLeft = el === win ? win.scrollX : el.scrollLeft;
514 return {
515 top: (box.top + scrollTop) - clientTop,
516 left: (box.left + scrollLeft) - clientLeft,
517 };
518 }
519
520 return null;
521}
522function styles() {
523 if (this[0]) return win.getComputedStyle(this[0], null);
524 return {};
525}
526function css(props, value) {
527 let i;
528 if (arguments.length === 1) {
529 if (typeof props === 'string') {
530 if (this[0]) return win.getComputedStyle(this[0], null).getPropertyValue(props);
531 } else {
532 for (i = 0; i < this.length; i += 1) {
533 // eslint-disable-next-line
534 for (let prop in props) {
535 this[i].style[prop] = props[prop];
536 }
537 }
538 return this;
539 }
540 }
541 if (arguments.length === 2 && typeof props === 'string') {
542 for (i = 0; i < this.length; i += 1) {
543 this[i].style[props] = value;
544 }
545 return this;
546 }
547 return this;
548}
549// Iterate over the collection passing elements to `callback`
550function each(callback) {
551 // Don't bother continuing without a callback
552 if (!callback) return this;
553 // Iterate over the current collection
554 for (let i = 0; i < this.length; i += 1) {
555 // If the callback returns false
556 if (callback.call(this[i], i, this[i]) === false) {
557 // End the loop early
558 return this;
559 }
560 }
561 // Return `this` to allow chained DOM operations
562 return this;
563}
564function filter(callback) {
565 const matchedItems = [];
566 const dom = this;
567 for (let i = 0; i < dom.length; i += 1) {
568 if (callback.call(dom[i], i, dom[i])) matchedItems.push(dom[i]);
569 }
570 return new Dom7(matchedItems);
571}
572// eslint-disable-next-line
573function html(html) {
574 if (typeof html === 'undefined') {
575 return this[0] ? this[0].innerHTML : undefined;
576 }
577
578 for (let i = 0; i < this.length; i += 1) {
579 this[i].innerHTML = html;
580 }
581 return this;
582}
583// eslint-disable-next-line
584function text(text) {
585 if (typeof text === 'undefined') {
586 if (this[0]) {
587 return this[0].textContent.trim();
588 }
589 return null;
590 }
591
592 for (let i = 0; i < this.length; i += 1) {
593 this[i].textContent = text;
594 }
595 return this;
596}
597function is(selector) {
598 const el = this[0];
599 let compareWith;
600 let i;
601 if (!el || typeof selector === 'undefined') return false;
602 if (typeof selector === 'string') {
603 if (el.matches) return el.matches(selector);
604 else if (el.webkitMatchesSelector) return el.webkitMatchesSelector(selector);
605 else if (el.msMatchesSelector) return el.msMatchesSelector(selector);
606
607 compareWith = $(selector);
608 for (i = 0; i < compareWith.length; i += 1) {
609 if (compareWith[i] === el) return true;
610 }
611 return false;
612 } else if (selector === doc) return el === doc;
613 else if (selector === win) return el === win;
614
615 if (selector.nodeType || selector instanceof Dom7) {
616 compareWith = selector.nodeType ? [selector] : selector;
617 for (i = 0; i < compareWith.length; i += 1) {
618 if (compareWith[i] === el) return true;
619 }
620 return false;
621 }
622 return false;
623}
624function index() {
625 let child = this[0];
626 let i;
627 if (child) {
628 i = 0;
629 // eslint-disable-next-line
630 while ((child = child.previousSibling) !== null) {
631 if (child.nodeType === 1) i += 1;
632 }
633 return i;
634 }
635 return undefined;
636}
637// eslint-disable-next-line
638function eq(index) {
639 if (typeof index === 'undefined') return this;
640 const length = this.length;
641 let returnIndex;
642 if (index > length - 1) {
643 return new Dom7([]);
644 }
645 if (index < 0) {
646 returnIndex = length + index;
647 if (returnIndex < 0) return new Dom7([]);
648 return new Dom7([this[returnIndex]]);
649 }
650 return new Dom7([this[index]]);
651}
652function append(...args) {
653 let newChild;
654
655 for (let k = 0; k < args.length; k += 1) {
656 newChild = args[k];
657 for (let i = 0; i < this.length; i += 1) {
658 if (typeof newChild === 'string') {
659 const tempDiv = doc.createElement('div');
660 tempDiv.innerHTML = newChild;
661 while (tempDiv.firstChild) {
662 this[i].appendChild(tempDiv.firstChild);
663 }
664 } else if (newChild instanceof Dom7) {
665 for (let j = 0; j < newChild.length; j += 1) {
666 this[i].appendChild(newChild[j]);
667 }
668 } else {
669 this[i].appendChild(newChild);
670 }
671 }
672 }
673
674 return this;
675}
676function prepend(newChild) {
677 let i;
678 let j;
679 for (i = 0; i < this.length; i += 1) {
680 if (typeof newChild === 'string') {
681 const tempDiv = doc.createElement('div');
682 tempDiv.innerHTML = newChild;
683 for (j = tempDiv.childNodes.length - 1; j >= 0; j -= 1) {
684 this[i].insertBefore(tempDiv.childNodes[j], this[i].childNodes[0]);
685 }
686 } else if (newChild instanceof Dom7) {
687 for (j = 0; j < newChild.length; j += 1) {
688 this[i].insertBefore(newChild[j], this[i].childNodes[0]);
689 }
690 } else {
691 this[i].insertBefore(newChild, this[i].childNodes[0]);
692 }
693 }
694 return this;
695}
696function next(selector) {
697 if (this.length > 0) {
698 if (selector) {
699 if (this[0].nextElementSibling && $(this[0].nextElementSibling).is(selector)) {
700 return new Dom7([this[0].nextElementSibling]);
701 }
702 return new Dom7([]);
703 }
704
705 if (this[0].nextElementSibling) return new Dom7([this[0].nextElementSibling]);
706 return new Dom7([]);
707 }
708 return new Dom7([]);
709}
710function nextAll(selector) {
711 const nextEls = [];
712 let el = this[0];
713 if (!el) return new Dom7([]);
714 while (el.nextElementSibling) {
715 const next = el.nextElementSibling; // eslint-disable-line
716 if (selector) {
717 if ($(next).is(selector)) nextEls.push(next);
718 } else nextEls.push(next);
719 el = next;
720 }
721 return new Dom7(nextEls);
722}
723function prev(selector) {
724 if (this.length > 0) {
725 const el = this[0];
726 if (selector) {
727 if (el.previousElementSibling && $(el.previousElementSibling).is(selector)) {
728 return new Dom7([el.previousElementSibling]);
729 }
730 return new Dom7([]);
731 }
732
733 if (el.previousElementSibling) return new Dom7([el.previousElementSibling]);
734 return new Dom7([]);
735 }
736 return new Dom7([]);
737}
738function prevAll(selector) {
739 const prevEls = [];
740 let el = this[0];
741 if (!el) return new Dom7([]);
742 while (el.previousElementSibling) {
743 const prev = el.previousElementSibling; // eslint-disable-line
744 if (selector) {
745 if ($(prev).is(selector)) prevEls.push(prev);
746 } else prevEls.push(prev);
747 el = prev;
748 }
749 return new Dom7(prevEls);
750}
751function parent(selector) {
752 const parents = []; // eslint-disable-line
753 for (let i = 0; i < this.length; i += 1) {
754 if (this[i].parentNode !== null) {
755 if (selector) {
756 if ($(this[i].parentNode).is(selector)) parents.push(this[i].parentNode);
757 } else {
758 parents.push(this[i].parentNode);
759 }
760 }
761 }
762 return $(unique(parents));
763}
764function parents(selector) {
765 const parents = []; // eslint-disable-line
766 for (let i = 0; i < this.length; i += 1) {
767 let parent = this[i].parentNode; // eslint-disable-line
768 while (parent) {
769 if (selector) {
770 if ($(parent).is(selector)) parents.push(parent);
771 } else {
772 parents.push(parent);
773 }
774 parent = parent.parentNode;
775 }
776 }
777 return $(unique(parents));
778}
779function closest(selector) {
780 let closest = this; // eslint-disable-line
781 if (typeof selector === 'undefined') {
782 return new Dom7([]);
783 }
784 if (!closest.is(selector)) {
785 closest = closest.parents(selector).eq(0);
786 }
787 return closest;
788}
789function find(selector) {
790 const foundElements = [];
791 for (let i = 0; i < this.length; i += 1) {
792 const found = this[i].querySelectorAll(selector);
793 for (let j = 0; j < found.length; j += 1) {
794 foundElements.push(found[j]);
795 }
796 }
797 return new Dom7(foundElements);
798}
799function children(selector) {
800 const children = []; // eslint-disable-line
801 for (let i = 0; i < this.length; i += 1) {
802 const childNodes = this[i].childNodes;
803
804 for (let j = 0; j < childNodes.length; j += 1) {
805 if (!selector) {
806 if (childNodes[j].nodeType === 1) children.push(childNodes[j]);
807 } else if (childNodes[j].nodeType === 1 && $(childNodes[j]).is(selector)) {
808 children.push(childNodes[j]);
809 }
810 }
811 }
812 return new Dom7(unique(children));
813}
814function remove() {
815 for (let i = 0; i < this.length; i += 1) {
816 if (this[i].parentNode) this[i].parentNode.removeChild(this[i]);
817 }
818 return this;
819}
820function add(...args) {
821 const dom = this;
822 let i;
823 let j;
824 for (i = 0; i < args.length; i += 1) {
825 const toAdd = $(args[i]);
826 for (j = 0; j < toAdd.length; j += 1) {
827 dom[dom.length] = toAdd[j];
828 dom.length += 1;
829 }
830 }
831 return dom;
832}
833
834/**
835 * Swiper 5.4.1
836 * Most modern mobile touch slider and framework with hardware accelerated transitions
837 * http://swiperjs.com
838 *
839 * Copyright 2014-2020 Vladimir Kharlampidi
840 *
841 * Released under the MIT License
842 *
843 * Released on: May 20, 2020
844 */
845
846const Methods = {
847 addClass,
848 removeClass,
849 hasClass,
850 toggleClass,
851 attr,
852 removeAttr,
853 data,
854 transform,
855 transition: transition,
856 on,
857 off,
858 trigger,
859 transitionEnd: transitionEnd,
860 outerWidth,
861 outerHeight,
862 offset,
863 css,
864 each,
865 html,
866 text,
867 is,
868 index,
869 eq,
870 append,
871 prepend,
872 next,
873 nextAll,
874 prev,
875 prevAll,
876 parent,
877 parents,
878 closest,
879 find,
880 children,
881 filter,
882 remove,
883 add,
884 styles,
885};
886
887Object.keys(Methods).forEach((methodName) => {
888 $.fn[methodName] = $.fn[methodName] || Methods[methodName];
889});
890
891const Utils = {
892 deleteProps(obj) {
893 const object = obj;
894 Object.keys(object).forEach((key) => {
895 try {
896 object[key] = null;
897 } catch (e) {
898 // no getter for object
899 }
900 try {
901 delete object[key];
902 } catch (e) {
903 // something got wrong
904 }
905 });
906 },
907 nextTick(callback, delay = 0) {
908 return setTimeout(callback, delay);
909 },
910 now() {
911 return Date.now();
912 },
913 getTranslate(el, axis = 'x') {
914 let matrix;
915 let curTransform;
916 let transformMatrix;
917
918 const curStyle = win.getComputedStyle(el, null);
919
920 if (win.WebKitCSSMatrix) {
921 curTransform = curStyle.transform || curStyle.webkitTransform;
922 if (curTransform.split(',').length > 6) {
923 curTransform = curTransform.split(', ').map((a) => a.replace(',', '.')).join(', ');
924 }
925 // Some old versions of Webkit choke when 'none' is passed; pass
926 // empty string instead in this case
927 transformMatrix = new win.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
928 } else {
929 transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
930 matrix = transformMatrix.toString().split(',');
931 }
932
933 if (axis === 'x') {
934 // Latest Chrome and webkits Fix
935 if (win.WebKitCSSMatrix) curTransform = transformMatrix.m41;
936 // Crazy IE10 Matrix
937 else if (matrix.length === 16) curTransform = parseFloat(matrix[12]);
938 // Normal Browsers
939 else curTransform = parseFloat(matrix[4]);
940 }
941 if (axis === 'y') {
942 // Latest Chrome and webkits Fix
943 if (win.WebKitCSSMatrix) curTransform = transformMatrix.m42;
944 // Crazy IE10 Matrix
945 else if (matrix.length === 16) curTransform = parseFloat(matrix[13]);
946 // Normal Browsers
947 else curTransform = parseFloat(matrix[5]);
948 }
949 return curTransform || 0;
950 },
951 parseUrlQuery(url) {
952 const query = {};
953 let urlToParse = url || win.location.href;
954 let i;
955 let params;
956 let param;
957 let length;
958 if (typeof urlToParse === 'string' && urlToParse.length) {
959 urlToParse = urlToParse.indexOf('?') > -1 ? urlToParse.replace(/\S*\?/, '') : '';
960 params = urlToParse.split('&').filter((paramsPart) => paramsPart !== '');
961 length = params.length;
962
963 for (i = 0; i < length; i += 1) {
964 param = params[i].replace(/#\S+/g, '').split('=');
965 query[decodeURIComponent(param[0])] = typeof param[1] === 'undefined' ? undefined : decodeURIComponent(param[1]) || '';
966 }
967 }
968 return query;
969 },
970 isObject(o) {
971 return typeof o === 'object' && o !== null && o.constructor && o.constructor === Object;
972 },
973 extend(...args) {
974 const to = Object(args[0]);
975 const noExtend = ['__proto__', 'constructor', 'prototype'];
976 for (let i = 1; i < args.length; i += 1) {
977 const nextSource = args[i];
978 if (nextSource !== undefined && nextSource !== null) {
979 const keysArray = Object.keys(Object(nextSource)).filter((key) => noExtend.indexOf(key) < 0);
980 for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
981 const nextKey = keysArray[nextIndex];
982 const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
983 if (desc !== undefined && desc.enumerable) {
984 if (Utils.isObject(to[nextKey]) && Utils.isObject(nextSource[nextKey])) {
985 Utils.extend(to[nextKey], nextSource[nextKey]);
986 } else if (!Utils.isObject(to[nextKey]) && Utils.isObject(nextSource[nextKey])) {
987 to[nextKey] = {};
988 Utils.extend(to[nextKey], nextSource[nextKey]);
989 } else {
990 to[nextKey] = nextSource[nextKey];
991 }
992 }
993 }
994 }
995 }
996 return to;
997 },
998};
999
1000const Support = (function Support() {
1001 return {
1002 touch: !!(('ontouchstart' in win) || (win.DocumentTouch && doc instanceof win.DocumentTouch)),
1003
1004 pointerEvents: !!win.PointerEvent && ('maxTouchPoints' in win.navigator) && win.navigator.maxTouchPoints >= 0,
1005
1006 observer: (function checkObserver() {
1007 return ('MutationObserver' in win || 'WebkitMutationObserver' in win);
1008 }()),
1009
1010 passiveListener: (function checkPassiveListener() {
1011 let supportsPassive = false;
1012 try {
1013 const opts = Object.defineProperty({}, 'passive', {
1014 // eslint-disable-next-line
1015 get() {
1016 supportsPassive = true;
1017 },
1018 });
1019 win.addEventListener('testPassiveListener', null, opts);
1020 } catch (e) {
1021 // No support
1022 }
1023 return supportsPassive;
1024 }()),
1025
1026 gestures: (function checkGestures() {
1027 return 'ongesturestart' in win;
1028 }()),
1029 };
1030}());
1031
1032class SwiperClass {
1033 constructor(params = {}) {
1034 const self = this;
1035 self.params = params;
1036
1037 // Events
1038 self.eventsListeners = {};
1039
1040 if (self.params && self.params.on) {
1041 Object.keys(self.params.on).forEach((eventName) => {
1042 self.on(eventName, self.params.on[eventName]);
1043 });
1044 }
1045 }
1046
1047 on(events, handler, priority) {
1048 const self = this;
1049 if (typeof handler !== 'function') return self;
1050 const method = priority ? 'unshift' : 'push';
1051 events.split(' ').forEach((event) => {
1052 if (!self.eventsListeners[event]) self.eventsListeners[event] = [];
1053 self.eventsListeners[event][method](handler);
1054 });
1055 return self;
1056 }
1057
1058 once(events, handler, priority) {
1059 const self = this;
1060 if (typeof handler !== 'function') return self;
1061 function onceHandler(...args) {
1062 self.off(events, onceHandler);
1063 if (onceHandler.f7proxy) {
1064 delete onceHandler.f7proxy;
1065 }
1066 handler.apply(self, args);
1067 }
1068 onceHandler.f7proxy = handler;
1069 return self.on(events, onceHandler, priority);
1070 }
1071
1072 off(events, handler) {
1073 const self = this;
1074 if (!self.eventsListeners) return self;
1075 events.split(' ').forEach((event) => {
1076 if (typeof handler === 'undefined') {
1077 self.eventsListeners[event] = [];
1078 } else if (self.eventsListeners[event] && self.eventsListeners[event].length) {
1079 self.eventsListeners[event].forEach((eventHandler, index) => {
1080 if (eventHandler === handler || (eventHandler.f7proxy && eventHandler.f7proxy === handler)) {
1081 self.eventsListeners[event].splice(index, 1);
1082 }
1083 });
1084 }
1085 });
1086 return self;
1087 }
1088
1089 emit(...args) {
1090 const self = this;
1091 if (!self.eventsListeners) return self;
1092 let events;
1093 let data;
1094 let context;
1095 if (typeof args[0] === 'string' || Array.isArray(args[0])) {
1096 events = args[0];
1097 data = args.slice(1, args.length);
1098 context = self;
1099 } else {
1100 events = args[0].events;
1101 data = args[0].data;
1102 context = args[0].context || self;
1103 }
1104 const eventsArray = Array.isArray(events) ? events : events.split(' ');
1105 eventsArray.forEach((event) => {
1106 if (self.eventsListeners && self.eventsListeners[event]) {
1107 const handlers = [];
1108 self.eventsListeners[event].forEach((eventHandler) => {
1109 handlers.push(eventHandler);
1110 });
1111 handlers.forEach((eventHandler) => {
1112 eventHandler.apply(context, data);
1113 });
1114 }
1115 });
1116 return self;
1117 }
1118
1119 useModulesParams(instanceParams) {
1120 const instance = this;
1121 if (!instance.modules) return;
1122 Object.keys(instance.modules).forEach((moduleName) => {
1123 const module = instance.modules[moduleName];
1124 // Extend params
1125 if (module.params) {
1126 Utils.extend(instanceParams, module.params);
1127 }
1128 });
1129 }
1130
1131 useModules(modulesParams = {}) {
1132 const instance = this;
1133 if (!instance.modules) return;
1134 Object.keys(instance.modules).forEach((moduleName) => {
1135 const module = instance.modules[moduleName];
1136 const moduleParams = modulesParams[moduleName] || {};
1137 // Extend instance methods and props
1138 if (module.instance) {
1139 Object.keys(module.instance).forEach((modulePropName) => {
1140 const moduleProp = module.instance[modulePropName];
1141 if (typeof moduleProp === 'function') {
1142 instance[modulePropName] = moduleProp.bind(instance);
1143 } else {
1144 instance[modulePropName] = moduleProp;
1145 }
1146 });
1147 }
1148 // Add event listeners
1149 if (module.on && instance.on) {
1150 Object.keys(module.on).forEach((moduleEventName) => {
1151 instance.on(moduleEventName, module.on[moduleEventName]);
1152 });
1153 }
1154
1155 // Module create callback
1156 if (module.create) {
1157 module.create.bind(instance)(moduleParams);
1158 }
1159 });
1160 }
1161
1162 static set components(components) {
1163 const Class = this;
1164 if (!Class.use) return;
1165 Class.use(components);
1166 }
1167
1168 static installModule(module, ...params) {
1169 const Class = this;
1170 if (!Class.prototype.modules) Class.prototype.modules = {};
1171 const name = module.name || (`${Object.keys(Class.prototype.modules).length}_${Utils.now()}`);
1172 Class.prototype.modules[name] = module;
1173 // Prototype
1174 if (module.proto) {
1175 Object.keys(module.proto).forEach((key) => {
1176 Class.prototype[key] = module.proto[key];
1177 });
1178 }
1179 // Class
1180 if (module.static) {
1181 Object.keys(module.static).forEach((key) => {
1182 Class[key] = module.static[key];
1183 });
1184 }
1185 // Callback
1186 if (module.install) {
1187 module.install.apply(Class, params);
1188 }
1189 return Class;
1190 }
1191
1192 static use(module, ...params) {
1193 const Class = this;
1194 if (Array.isArray(module)) {
1195 module.forEach((m) => Class.installModule(m));
1196 return Class;
1197 }
1198 return Class.installModule(module, ...params);
1199 }
1200}
1201
1202function updateSize () {
1203 const swiper = this;
1204 let width;
1205 let height;
1206 const $el = swiper.$el;
1207 if (typeof swiper.params.width !== 'undefined') {
1208 width = swiper.params.width;
1209 } else {
1210 width = $el[0].clientWidth;
1211 }
1212 if (typeof swiper.params.height !== 'undefined') {
1213 height = swiper.params.height;
1214 } else {
1215 height = $el[0].clientHeight;
1216 }
1217 if ((width === 0 && swiper.isHorizontal()) || (height === 0 && swiper.isVertical())) {
1218 return;
1219 }
1220
1221 // Subtract paddings
1222 width = width - parseInt($el.css('padding-left'), 10) - parseInt($el.css('padding-right'), 10);
1223 height = height - parseInt($el.css('padding-top'), 10) - parseInt($el.css('padding-bottom'), 10);
1224
1225 Utils.extend(swiper, {
1226 width,
1227 height,
1228 size: swiper.isHorizontal() ? width : height,
1229 });
1230}
1231
1232function updateSlides () {
1233 const swiper = this;
1234 const params = swiper.params;
1235
1236 const {
1237 $wrapperEl, size: swiperSize, rtlTranslate: rtl, wrongRTL,
1238 } = swiper;
1239 const isVirtual = swiper.virtual && params.virtual.enabled;
1240 const previousSlidesLength = isVirtual ? swiper.virtual.slides.length : swiper.slides.length;
1241 const slides = $wrapperEl.children(`.${swiper.params.slideClass}`);
1242 const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;
1243 let snapGrid = [];
1244 const slidesGrid = [];
1245 const slidesSizesGrid = [];
1246
1247 function slidesForMargin(slideIndex) {
1248 if (!params.cssMode) return true;
1249 if (slideIndex === slides.length - 1) {
1250 return false;
1251 }
1252 return true;
1253 }
1254
1255 let offsetBefore = params.slidesOffsetBefore;
1256 if (typeof offsetBefore === 'function') {
1257 offsetBefore = params.slidesOffsetBefore.call(swiper);
1258 }
1259
1260 let offsetAfter = params.slidesOffsetAfter;
1261 if (typeof offsetAfter === 'function') {
1262 offsetAfter = params.slidesOffsetAfter.call(swiper);
1263 }
1264
1265 const previousSnapGridLength = swiper.snapGrid.length;
1266 const previousSlidesGridLength = swiper.snapGrid.length;
1267
1268 let spaceBetween = params.spaceBetween;
1269 let slidePosition = -offsetBefore;
1270 let prevSlideSize = 0;
1271 let index = 0;
1272 if (typeof swiperSize === 'undefined') {
1273 return;
1274 }
1275 if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
1276 spaceBetween = (parseFloat(spaceBetween.replace('%', '')) / 100) * swiperSize;
1277 }
1278
1279 swiper.virtualSize = -spaceBetween;
1280
1281 // reset margins
1282 if (rtl) slides.css({ marginLeft: '', marginTop: '' });
1283 else slides.css({ marginRight: '', marginBottom: '' });
1284
1285 let slidesNumberEvenToRows;
1286 if (params.slidesPerColumn > 1) {
1287 if (Math.floor(slidesLength / params.slidesPerColumn) === slidesLength / swiper.params.slidesPerColumn) {
1288 slidesNumberEvenToRows = slidesLength;
1289 } else {
1290 slidesNumberEvenToRows = Math.ceil(slidesLength / params.slidesPerColumn) * params.slidesPerColumn;
1291 }
1292 if (params.slidesPerView !== 'auto' && params.slidesPerColumnFill === 'row') {
1293 slidesNumberEvenToRows = Math.max(slidesNumberEvenToRows, params.slidesPerView * params.slidesPerColumn);
1294 }
1295 }
1296
1297 // Calc slides
1298 let slideSize;
1299 const slidesPerColumn = params.slidesPerColumn;
1300 const slidesPerRow = slidesNumberEvenToRows / slidesPerColumn;
1301 const numFullColumns = Math.floor(slidesLength / params.slidesPerColumn);
1302 for (let i = 0; i < slidesLength; i += 1) {
1303 slideSize = 0;
1304 const slide = slides.eq(i);
1305 if (params.slidesPerColumn > 1) {
1306 // Set slides order
1307 let newSlideOrderIndex;
1308 let column;
1309 let row;
1310 if (params.slidesPerColumnFill === 'row' && params.slidesPerGroup > 1) {
1311 const groupIndex = Math.floor(i / (params.slidesPerGroup * params.slidesPerColumn));
1312 const slideIndexInGroup = i - params.slidesPerColumn * params.slidesPerGroup * groupIndex;
1313 const columnsInGroup = groupIndex === 0
1314 ? params.slidesPerGroup
1315 : Math.min(Math.ceil((slidesLength - groupIndex * slidesPerColumn * params.slidesPerGroup) / slidesPerColumn), params.slidesPerGroup);
1316 row = Math.floor(slideIndexInGroup / columnsInGroup);
1317 column = (slideIndexInGroup - row * columnsInGroup) + groupIndex * params.slidesPerGroup;
1318
1319 newSlideOrderIndex = column + ((row * slidesNumberEvenToRows) / slidesPerColumn);
1320 slide
1321 .css({
1322 '-webkit-box-ordinal-group': newSlideOrderIndex,
1323 '-moz-box-ordinal-group': newSlideOrderIndex,
1324 '-ms-flex-order': newSlideOrderIndex,
1325 '-webkit-order': newSlideOrderIndex,
1326 order: newSlideOrderIndex,
1327 });
1328 } else if (params.slidesPerColumnFill === 'column') {
1329 column = Math.floor(i / slidesPerColumn);
1330 row = i - (column * slidesPerColumn);
1331 if (column > numFullColumns || (column === numFullColumns && row === slidesPerColumn - 1)) {
1332 row += 1;
1333 if (row >= slidesPerColumn) {
1334 row = 0;
1335 column += 1;
1336 }
1337 }
1338 } else {
1339 row = Math.floor(i / slidesPerRow);
1340 column = i - (row * slidesPerRow);
1341 }
1342 slide.css(
1343 `margin-${swiper.isHorizontal() ? 'top' : 'left'}`,
1344 (row !== 0 && params.spaceBetween) && (`${params.spaceBetween}px`)
1345 );
1346 }
1347 if (slide.css('display') === 'none') continue; // eslint-disable-line
1348
1349 if (params.slidesPerView === 'auto') {
1350 const slideStyles = win.getComputedStyle(slide[0], null);
1351 const currentTransform = slide[0].style.transform;
1352 const currentWebKitTransform = slide[0].style.webkitTransform;
1353 if (currentTransform) {
1354 slide[0].style.transform = 'none';
1355 }
1356 if (currentWebKitTransform) {
1357 slide[0].style.webkitTransform = 'none';
1358 }
1359 if (params.roundLengths) {
1360 slideSize = swiper.isHorizontal()
1361 ? slide.outerWidth(true)
1362 : slide.outerHeight(true);
1363 } else {
1364 // eslint-disable-next-line
1365 if (swiper.isHorizontal()) {
1366 const width = parseFloat(slideStyles.getPropertyValue('width'));
1367 const paddingLeft = parseFloat(slideStyles.getPropertyValue('padding-left'));
1368 const paddingRight = parseFloat(slideStyles.getPropertyValue('padding-right'));
1369 const marginLeft = parseFloat(slideStyles.getPropertyValue('margin-left'));
1370 const marginRight = parseFloat(slideStyles.getPropertyValue('margin-right'));
1371 const boxSizing = slideStyles.getPropertyValue('box-sizing');
1372 if (boxSizing && boxSizing === 'border-box') {
1373 slideSize = width + marginLeft + marginRight;
1374 } else {
1375 slideSize = width + paddingLeft + paddingRight + marginLeft + marginRight;
1376 }
1377 } else {
1378 const height = parseFloat(slideStyles.getPropertyValue('height'));
1379 const paddingTop = parseFloat(slideStyles.getPropertyValue('padding-top'));
1380 const paddingBottom = parseFloat(slideStyles.getPropertyValue('padding-bottom'));
1381 const marginTop = parseFloat(slideStyles.getPropertyValue('margin-top'));
1382 const marginBottom = parseFloat(slideStyles.getPropertyValue('margin-bottom'));
1383 const boxSizing = slideStyles.getPropertyValue('box-sizing');
1384 if (boxSizing && boxSizing === 'border-box') {
1385 slideSize = height + marginTop + marginBottom;
1386 } else {
1387 slideSize = height + paddingTop + paddingBottom + marginTop + marginBottom;
1388 }
1389 }
1390 }
1391 if (currentTransform) {
1392 slide[0].style.transform = currentTransform;
1393 }
1394 if (currentWebKitTransform) {
1395 slide[0].style.webkitTransform = currentWebKitTransform;
1396 }
1397 if (params.roundLengths) slideSize = Math.floor(slideSize);
1398 } else {
1399 slideSize = (swiperSize - ((params.slidesPerView - 1) * spaceBetween)) / params.slidesPerView;
1400 if (params.roundLengths) slideSize = Math.floor(slideSize);
1401
1402 if (slides[i]) {
1403 if (swiper.isHorizontal()) {
1404 slides[i].style.width = `${slideSize}px`;
1405 } else {
1406 slides[i].style.height = `${slideSize}px`;
1407 }
1408 }
1409 }
1410 if (slides[i]) {
1411 slides[i].swiperSlideSize = slideSize;
1412 }
1413 slidesSizesGrid.push(slideSize);
1414
1415
1416 if (params.centeredSlides) {
1417 slidePosition = slidePosition + (slideSize / 2) + (prevSlideSize / 2) + spaceBetween;
1418 if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - (swiperSize / 2) - spaceBetween;
1419 if (i === 0) slidePosition = slidePosition - (swiperSize / 2) - spaceBetween;
1420 if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
1421 if (params.roundLengths) slidePosition = Math.floor(slidePosition);
1422 if ((index) % params.slidesPerGroup === 0) snapGrid.push(slidePosition);
1423 slidesGrid.push(slidePosition);
1424 } else {
1425 if (params.roundLengths) slidePosition = Math.floor(slidePosition);
1426 if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) snapGrid.push(slidePosition);
1427 slidesGrid.push(slidePosition);
1428 slidePosition = slidePosition + slideSize + spaceBetween;
1429 }
1430
1431 swiper.virtualSize += slideSize + spaceBetween;
1432
1433 prevSlideSize = slideSize;
1434
1435 index += 1;
1436 }
1437 swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;
1438 let newSlidesGrid;
1439
1440 if (
1441 rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {
1442 $wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
1443 }
1444 if (params.setWrapperSize) {
1445 if (swiper.isHorizontal()) $wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
1446 else $wrapperEl.css({ height: `${swiper.virtualSize + params.spaceBetween}px` });
1447 }
1448
1449 if (params.slidesPerColumn > 1) {
1450 swiper.virtualSize = (slideSize + params.spaceBetween) * slidesNumberEvenToRows;
1451 swiper.virtualSize = Math.ceil(swiper.virtualSize / params.slidesPerColumn) - params.spaceBetween;
1452 if (swiper.isHorizontal()) $wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
1453 else $wrapperEl.css({ height: `${swiper.virtualSize + params.spaceBetween}px` });
1454 if (params.centeredSlides) {
1455 newSlidesGrid = [];
1456 for (let i = 0; i < snapGrid.length; i += 1) {
1457 let slidesGridItem = snapGrid[i];
1458 if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);
1459 if (snapGrid[i] < swiper.virtualSize + snapGrid[0]) newSlidesGrid.push(slidesGridItem);
1460 }
1461 snapGrid = newSlidesGrid;
1462 }
1463 }
1464
1465 // Remove last grid elements depending on width
1466 if (!params.centeredSlides) {
1467 newSlidesGrid = [];
1468 for (let i = 0; i < snapGrid.length; i += 1) {
1469 let slidesGridItem = snapGrid[i];
1470 if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);
1471 if (snapGrid[i] <= swiper.virtualSize - swiperSize) {
1472 newSlidesGrid.push(slidesGridItem);
1473 }
1474 }
1475 snapGrid = newSlidesGrid;
1476 if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1477 snapGrid.push(swiper.virtualSize - swiperSize);
1478 }
1479 }
1480 if (snapGrid.length === 0) snapGrid = [0];
1481
1482 if (params.spaceBetween !== 0) {
1483 if (swiper.isHorizontal()) {
1484 if (rtl) slides.filter(slidesForMargin).css({ marginLeft: `${spaceBetween}px` });
1485 else slides.filter(slidesForMargin).css({ marginRight: `${spaceBetween}px` });
1486 } else slides.filter(slidesForMargin).css({ marginBottom: `${spaceBetween}px` });
1487 }
1488
1489 if (params.centeredSlides && params.centeredSlidesBounds) {
1490 let allSlidesSize = 0;
1491 slidesSizesGrid.forEach((slideSizeValue) => {
1492 allSlidesSize += slideSizeValue + (params.spaceBetween ? params.spaceBetween : 0);
1493 });
1494 allSlidesSize -= params.spaceBetween;
1495 const maxSnap = allSlidesSize - swiperSize;
1496 snapGrid = snapGrid.map((snap) => {
1497 if (snap < 0) return -offsetBefore;
1498 if (snap > maxSnap) return maxSnap + offsetAfter;
1499 return snap;
1500 });
1501 }
1502
1503 if (params.centerInsufficientSlides) {
1504 let allSlidesSize = 0;
1505 slidesSizesGrid.forEach((slideSizeValue) => {
1506 allSlidesSize += slideSizeValue + (params.spaceBetween ? params.spaceBetween : 0);
1507 });
1508 allSlidesSize -= params.spaceBetween;
1509 if (allSlidesSize < swiperSize) {
1510 const allSlidesOffset = (swiperSize - allSlidesSize) / 2;
1511 snapGrid.forEach((snap, snapIndex) => {
1512 snapGrid[snapIndex] = snap - allSlidesOffset;
1513 });
1514 slidesGrid.forEach((snap, snapIndex) => {
1515 slidesGrid[snapIndex] = snap + allSlidesOffset;
1516 });
1517 }
1518 }
1519
1520 Utils.extend(swiper, {
1521 slides,
1522 snapGrid,
1523 slidesGrid,
1524 slidesSizesGrid,
1525 });
1526
1527 if (slidesLength !== previousSlidesLength) {
1528 swiper.emit('slidesLengthChange');
1529 }
1530 if (snapGrid.length !== previousSnapGridLength) {
1531 if (swiper.params.watchOverflow) swiper.checkOverflow();
1532 swiper.emit('snapGridLengthChange');
1533 }
1534 if (slidesGrid.length !== previousSlidesGridLength) {
1535 swiper.emit('slidesGridLengthChange');
1536 }
1537
1538 if (params.watchSlidesProgress || params.watchSlidesVisibility) {
1539 swiper.updateSlidesOffset();
1540 }
1541}
1542
1543function updateAutoHeight (speed) {
1544 const swiper = this;
1545 const activeSlides = [];
1546 let newHeight = 0;
1547 let i;
1548 if (typeof speed === 'number') {
1549 swiper.setTransition(speed);
1550 } else if (speed === true) {
1551 swiper.setTransition(swiper.params.speed);
1552 }
1553 // Find slides currently in view
1554 if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {
1555 if (swiper.params.centeredSlides) {
1556 swiper.visibleSlides.each((index, slide) => {
1557 activeSlides.push(slide);
1558 });
1559 } else {
1560 for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1561 const index = swiper.activeIndex + i;
1562 if (index > swiper.slides.length) break;
1563 activeSlides.push(swiper.slides.eq(index)[0]);
1564 }
1565 }
1566 } else {
1567 activeSlides.push(swiper.slides.eq(swiper.activeIndex)[0]);
1568 }
1569
1570 // Find new height from highest slide in view
1571 for (i = 0; i < activeSlides.length; i += 1) {
1572 if (typeof activeSlides[i] !== 'undefined') {
1573 const height = activeSlides[i].offsetHeight;
1574 newHeight = height > newHeight ? height : newHeight;
1575 }
1576 }
1577
1578 // Update Height
1579 if (newHeight) swiper.$wrapperEl.css('height', `${newHeight}px`);
1580}
1581
1582function updateSlidesOffset () {
1583 const swiper = this;
1584 const slides = swiper.slides;
1585 for (let i = 0; i < slides.length; i += 1) {
1586 slides[i].swiperSlideOffset = swiper.isHorizontal() ? slides[i].offsetLeft : slides[i].offsetTop;
1587 }
1588}
1589
1590function updateSlidesProgress (translate = (this && this.translate) || 0) {
1591 const swiper = this;
1592 const params = swiper.params;
1593
1594 const { slides, rtlTranslate: rtl } = swiper;
1595
1596 if (slides.length === 0) return;
1597 if (typeof slides[0].swiperSlideOffset === 'undefined') swiper.updateSlidesOffset();
1598
1599 let offsetCenter = -translate;
1600 if (rtl) offsetCenter = translate;
1601
1602 // Visible Slides
1603 slides.removeClass(params.slideVisibleClass);
1604
1605 swiper.visibleSlidesIndexes = [];
1606 swiper.visibleSlides = [];
1607
1608 for (let i = 0; i < slides.length; i += 1) {
1609 const slide = slides[i];
1610 const slideProgress = (
1611 (offsetCenter + (params.centeredSlides ? swiper.minTranslate() : 0)) - slide.swiperSlideOffset
1612 ) / (slide.swiperSlideSize + params.spaceBetween);
1613 if (params.watchSlidesVisibility || (params.centeredSlides && params.autoHeight)) {
1614 const slideBefore = -(offsetCenter - slide.swiperSlideOffset);
1615 const slideAfter = slideBefore + swiper.slidesSizesGrid[i];
1616 const isVisible = (slideBefore >= 0 && slideBefore < swiper.size - 1)
1617 || (slideAfter > 1 && slideAfter <= swiper.size)
1618 || (slideBefore <= 0 && slideAfter >= swiper.size);
1619 if (isVisible) {
1620 swiper.visibleSlides.push(slide);
1621 swiper.visibleSlidesIndexes.push(i);
1622 slides.eq(i).addClass(params.slideVisibleClass);
1623 }
1624 }
1625 slide.progress = rtl ? -slideProgress : slideProgress;
1626 }
1627 swiper.visibleSlides = $(swiper.visibleSlides);
1628}
1629
1630function updateProgress (translate) {
1631 const swiper = this;
1632 if (typeof translate === 'undefined') {
1633 const multiplier = swiper.rtlTranslate ? -1 : 1;
1634 // eslint-disable-next-line
1635 translate = (swiper && swiper.translate && (swiper.translate * multiplier)) || 0;
1636 }
1637 const params = swiper.params;
1638 const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
1639 let { progress, isBeginning, isEnd } = swiper;
1640 const wasBeginning = isBeginning;
1641 const wasEnd = isEnd;
1642 if (translatesDiff === 0) {
1643 progress = 0;
1644 isBeginning = true;
1645 isEnd = true;
1646 } else {
1647 progress = (translate - swiper.minTranslate()) / (translatesDiff);
1648 isBeginning = progress <= 0;
1649 isEnd = progress >= 1;
1650 }
1651 Utils.extend(swiper, {
1652 progress,
1653 isBeginning,
1654 isEnd,
1655 });
1656
1657 if (params.watchSlidesProgress || params.watchSlidesVisibility || (params.centeredSlides && params.autoHeight)) swiper.updateSlidesProgress(translate);
1658
1659 if (isBeginning && !wasBeginning) {
1660 swiper.emit('reachBeginning toEdge');
1661 }
1662 if (isEnd && !wasEnd) {
1663 swiper.emit('reachEnd toEdge');
1664 }
1665 if ((wasBeginning && !isBeginning) || (wasEnd && !isEnd)) {
1666 swiper.emit('fromEdge');
1667 }
1668
1669 swiper.emit('progress', progress);
1670}
1671
1672function updateSlidesClasses () {
1673 const swiper = this;
1674
1675 const {
1676 slides, params, $wrapperEl, activeIndex, realIndex,
1677 } = swiper;
1678 const isVirtual = swiper.virtual && params.virtual.enabled;
1679
1680 slides.removeClass(`${params.slideActiveClass} ${params.slideNextClass} ${params.slidePrevClass} ${params.slideDuplicateActiveClass} ${params.slideDuplicateNextClass} ${params.slideDuplicatePrevClass}`);
1681
1682 let activeSlide;
1683 if (isVirtual) {
1684 activeSlide = swiper.$wrapperEl.find(`.${params.slideClass}[data-swiper-slide-index="${activeIndex}"]`);
1685 } else {
1686 activeSlide = slides.eq(activeIndex);
1687 }
1688
1689 // Active classes
1690 activeSlide.addClass(params.slideActiveClass);
1691
1692 if (params.loop) {
1693 // Duplicate to all looped slides
1694 if (activeSlide.hasClass(params.slideDuplicateClass)) {
1695 $wrapperEl
1696 .children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${realIndex}"]`)
1697 .addClass(params.slideDuplicateActiveClass);
1698 } else {
1699 $wrapperEl
1700 .children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${realIndex}"]`)
1701 .addClass(params.slideDuplicateActiveClass);
1702 }
1703 }
1704 // Next Slide
1705 let nextSlide = activeSlide.nextAll(`.${params.slideClass}`).eq(0).addClass(params.slideNextClass);
1706 if (params.loop && nextSlide.length === 0) {
1707 nextSlide = slides.eq(0);
1708 nextSlide.addClass(params.slideNextClass);
1709 }
1710 // Prev Slide
1711 let prevSlide = activeSlide.prevAll(`.${params.slideClass}`).eq(0).addClass(params.slidePrevClass);
1712 if (params.loop && prevSlide.length === 0) {
1713 prevSlide = slides.eq(-1);
1714 prevSlide.addClass(params.slidePrevClass);
1715 }
1716 if (params.loop) {
1717 // Duplicate to all looped slides
1718 if (nextSlide.hasClass(params.slideDuplicateClass)) {
1719 $wrapperEl
1720 .children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${nextSlide.attr('data-swiper-slide-index')}"]`)
1721 .addClass(params.slideDuplicateNextClass);
1722 } else {
1723 $wrapperEl
1724 .children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${nextSlide.attr('data-swiper-slide-index')}"]`)
1725 .addClass(params.slideDuplicateNextClass);
1726 }
1727 if (prevSlide.hasClass(params.slideDuplicateClass)) {
1728 $wrapperEl
1729 .children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${prevSlide.attr('data-swiper-slide-index')}"]`)
1730 .addClass(params.slideDuplicatePrevClass);
1731 } else {
1732 $wrapperEl
1733 .children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${prevSlide.attr('data-swiper-slide-index')}"]`)
1734 .addClass(params.slideDuplicatePrevClass);
1735 }
1736 }
1737}
1738
1739function updateActiveIndex (newActiveIndex) {
1740 const swiper = this;
1741 const translate = swiper.rtlTranslate ? swiper.translate : -swiper.translate;
1742 const {
1743 slidesGrid, snapGrid, params, activeIndex: previousIndex, realIndex: previousRealIndex, snapIndex: previousSnapIndex,
1744 } = swiper;
1745 let activeIndex = newActiveIndex;
1746 let snapIndex;
1747 if (typeof activeIndex === 'undefined') {
1748 for (let i = 0; i < slidesGrid.length; i += 1) {
1749 if (typeof slidesGrid[i + 1] !== 'undefined') {
1750 if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1] - ((slidesGrid[i + 1] - slidesGrid[i]) / 2)) {
1751 activeIndex = i;
1752 } else if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1]) {
1753 activeIndex = i + 1;
1754 }
1755 } else if (translate >= slidesGrid[i]) {
1756 activeIndex = i;
1757 }
1758 }
1759 // Normalize slideIndex
1760 if (params.normalizeSlideIndex) {
1761 if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;
1762 }
1763 }
1764 if (snapGrid.indexOf(translate) >= 0) {
1765 snapIndex = snapGrid.indexOf(translate);
1766 } else {
1767 const skip = Math.min(params.slidesPerGroupSkip, activeIndex);
1768 snapIndex = skip + Math.floor((activeIndex - skip) / params.slidesPerGroup);
1769 }
1770 if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
1771 if (activeIndex === previousIndex) {
1772 if (snapIndex !== previousSnapIndex) {
1773 swiper.snapIndex = snapIndex;
1774 swiper.emit('snapIndexChange');
1775 }
1776 return;
1777 }
1778
1779 // Get real index
1780 const realIndex = parseInt(swiper.slides.eq(activeIndex).attr('data-swiper-slide-index') || activeIndex, 10);
1781
1782 Utils.extend(swiper, {
1783 snapIndex,
1784 realIndex,
1785 previousIndex,
1786 activeIndex,
1787 });
1788 swiper.emit('activeIndexChange');
1789 swiper.emit('snapIndexChange');
1790 if (previousRealIndex !== realIndex) {
1791 swiper.emit('realIndexChange');
1792 }
1793 if (swiper.initialized || swiper.params.runCallbacksOnInit) {
1794 swiper.emit('slideChange');
1795 }
1796}
1797
1798function updateClickedSlide (e) {
1799 const swiper = this;
1800 const params = swiper.params;
1801 const slide = $(e.target).closest(`.${params.slideClass}`)[0];
1802 let slideFound = false;
1803 if (slide) {
1804 for (let i = 0; i < swiper.slides.length; i += 1) {
1805 if (swiper.slides[i] === slide) slideFound = true;
1806 }
1807 }
1808
1809 if (slide && slideFound) {
1810 swiper.clickedSlide = slide;
1811 if (swiper.virtual && swiper.params.virtual.enabled) {
1812 swiper.clickedIndex = parseInt($(slide).attr('data-swiper-slide-index'), 10);
1813 } else {
1814 swiper.clickedIndex = $(slide).index();
1815 }
1816 } else {
1817 swiper.clickedSlide = undefined;
1818 swiper.clickedIndex = undefined;
1819 return;
1820 }
1821 if (params.slideToClickedSlide && swiper.clickedIndex !== undefined && swiper.clickedIndex !== swiper.activeIndex) {
1822 swiper.slideToClickedSlide();
1823 }
1824}
1825
1826var update = {
1827 updateSize,
1828 updateSlides,
1829 updateAutoHeight,
1830 updateSlidesOffset,
1831 updateSlidesProgress,
1832 updateProgress,
1833 updateSlidesClasses,
1834 updateActiveIndex,
1835 updateClickedSlide,
1836};
1837
1838function getTranslate (axis = this.isHorizontal() ? 'x' : 'y') {
1839 const swiper = this;
1840
1841 const {
1842 params, rtlTranslate: rtl, translate, $wrapperEl,
1843 } = swiper;
1844
1845 if (params.virtualTranslate) {
1846 return rtl ? -translate : translate;
1847 }
1848 if (params.cssMode) {
1849 return translate;
1850 }
1851
1852 let currentTranslate = Utils.getTranslate($wrapperEl[0], axis);
1853 if (rtl) currentTranslate = -currentTranslate;
1854
1855 return currentTranslate || 0;
1856}
1857
1858function setTranslate (translate, byController) {
1859 const swiper = this;
1860 const {
1861 rtlTranslate: rtl, params, $wrapperEl, wrapperEl, progress,
1862 } = swiper;
1863 let x = 0;
1864 let y = 0;
1865 const z = 0;
1866
1867 if (swiper.isHorizontal()) {
1868 x = rtl ? -translate : translate;
1869 } else {
1870 y = translate;
1871 }
1872
1873 if (params.roundLengths) {
1874 x = Math.floor(x);
1875 y = Math.floor(y);
1876 }
1877
1878 if (params.cssMode) {
1879 wrapperEl[swiper.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = swiper.isHorizontal() ? -x : -y;
1880 } else if (!params.virtualTranslate) {
1881 $wrapperEl.transform(`translate3d(${x}px, ${y}px, ${z}px)`);
1882 }
1883 swiper.previousTranslate = swiper.translate;
1884 swiper.translate = swiper.isHorizontal() ? x : y;
1885
1886 // Check if we need to update progress
1887 let newProgress;
1888 const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
1889 if (translatesDiff === 0) {
1890 newProgress = 0;
1891 } else {
1892 newProgress = (translate - swiper.minTranslate()) / (translatesDiff);
1893 }
1894 if (newProgress !== progress) {
1895 swiper.updateProgress(translate);
1896 }
1897
1898 swiper.emit('setTranslate', swiper.translate, byController);
1899}
1900
1901function minTranslate () {
1902 return (-this.snapGrid[0]);
1903}
1904
1905function maxTranslate () {
1906 return (-this.snapGrid[this.snapGrid.length - 1]);
1907}
1908
1909function translateTo (translate = 0, speed = this.params.speed, runCallbacks = true, translateBounds = true, internal) {
1910 const swiper = this;
1911
1912 const {
1913 params,
1914 wrapperEl,
1915 } = swiper;
1916
1917 if (swiper.animating && params.preventInteractionOnTransition) {
1918 return false;
1919 }
1920
1921 const minTranslate = swiper.minTranslate();
1922 const maxTranslate = swiper.maxTranslate();
1923 let newTranslate;
1924 if (translateBounds && translate > minTranslate) newTranslate = minTranslate;
1925 else if (translateBounds && translate < maxTranslate) newTranslate = maxTranslate;
1926 else newTranslate = translate;
1927
1928 // Update progress
1929 swiper.updateProgress(newTranslate);
1930
1931 if (params.cssMode) {
1932 const isH = swiper.isHorizontal();
1933 if (speed === 0) {
1934 wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = -newTranslate;
1935 } else {
1936 // eslint-disable-next-line
1937 if (wrapperEl.scrollTo) {
1938 wrapperEl.scrollTo({
1939 [isH ? 'left' : 'top']: -newTranslate,
1940 behavior: 'smooth',
1941 });
1942 } else {
1943 wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = -newTranslate;
1944 }
1945 }
1946 return true;
1947 }
1948
1949 if (speed === 0) {
1950 swiper.setTransition(0);
1951 swiper.setTranslate(newTranslate);
1952 if (runCallbacks) {
1953 swiper.emit('beforeTransitionStart', speed, internal);
1954 swiper.emit('transitionEnd');
1955 }
1956 } else {
1957 swiper.setTransition(speed);
1958 swiper.setTranslate(newTranslate);
1959 if (runCallbacks) {
1960 swiper.emit('beforeTransitionStart', speed, internal);
1961 swiper.emit('transitionStart');
1962 }
1963 if (!swiper.animating) {
1964 swiper.animating = true;
1965 if (!swiper.onTranslateToWrapperTransitionEnd) {
1966 swiper.onTranslateToWrapperTransitionEnd = function transitionEnd(e) {
1967 if (!swiper || swiper.destroyed) return;
1968 if (e.target !== this) return;
1969 swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.onTranslateToWrapperTransitionEnd);
1970 swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.onTranslateToWrapperTransitionEnd);
1971 swiper.onTranslateToWrapperTransitionEnd = null;
1972 delete swiper.onTranslateToWrapperTransitionEnd;
1973 if (runCallbacks) {
1974 swiper.emit('transitionEnd');
1975 }
1976 };
1977 }
1978 swiper.$wrapperEl[0].addEventListener('transitionend', swiper.onTranslateToWrapperTransitionEnd);
1979 swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.onTranslateToWrapperTransitionEnd);
1980 }
1981 }
1982
1983 return true;
1984}
1985
1986var translate = {
1987 getTranslate,
1988 setTranslate,
1989 minTranslate,
1990 maxTranslate,
1991 translateTo,
1992};
1993
1994function setTransition (duration, byController) {
1995 const swiper = this;
1996
1997 if (!swiper.params.cssMode) {
1998 swiper.$wrapperEl.transition(duration);
1999 }
2000
2001 swiper.emit('setTransition', duration, byController);
2002}
2003
2004function transitionStart (runCallbacks = true, direction) {
2005 const swiper = this;
2006 const { activeIndex, params, previousIndex } = swiper;
2007 if (params.cssMode) return;
2008 if (params.autoHeight) {
2009 swiper.updateAutoHeight();
2010 }
2011
2012 let dir = direction;
2013 if (!dir) {
2014 if (activeIndex > previousIndex) dir = 'next';
2015 else if (activeIndex < previousIndex) dir = 'prev';
2016 else dir = 'reset';
2017 }
2018
2019 swiper.emit('transitionStart');
2020
2021 if (runCallbacks && activeIndex !== previousIndex) {
2022 if (dir === 'reset') {
2023 swiper.emit('slideResetTransitionStart');
2024 return;
2025 }
2026 swiper.emit('slideChangeTransitionStart');
2027 if (dir === 'next') {
2028 swiper.emit('slideNextTransitionStart');
2029 } else {
2030 swiper.emit('slidePrevTransitionStart');
2031 }
2032 }
2033}
2034
2035function transitionEnd$1 (runCallbacks = true, direction) {
2036 const swiper = this;
2037 const { activeIndex, previousIndex, params } = swiper;
2038 swiper.animating = false;
2039 if (params.cssMode) return;
2040 swiper.setTransition(0);
2041
2042 let dir = direction;
2043 if (!dir) {
2044 if (activeIndex > previousIndex) dir = 'next';
2045 else if (activeIndex < previousIndex) dir = 'prev';
2046 else dir = 'reset';
2047 }
2048
2049 swiper.emit('transitionEnd');
2050
2051 if (runCallbacks && activeIndex !== previousIndex) {
2052 if (dir === 'reset') {
2053 swiper.emit('slideResetTransitionEnd');
2054 return;
2055 }
2056 swiper.emit('slideChangeTransitionEnd');
2057 if (dir === 'next') {
2058 swiper.emit('slideNextTransitionEnd');
2059 } else {
2060 swiper.emit('slidePrevTransitionEnd');
2061 }
2062 }
2063}
2064
2065var transition$1 = {
2066 setTransition,
2067 transitionStart,
2068 transitionEnd: transitionEnd$1,
2069};
2070
2071function slideTo (index = 0, speed = this.params.speed, runCallbacks = true, internal) {
2072 const swiper = this;
2073 let slideIndex = index;
2074 if (slideIndex < 0) slideIndex = 0;
2075
2076 const {
2077 params, snapGrid, slidesGrid, previousIndex, activeIndex, rtlTranslate: rtl, wrapperEl,
2078 } = swiper;
2079 if (swiper.animating && params.preventInteractionOnTransition) {
2080 return false;
2081 }
2082
2083 const skip = Math.min(swiper.params.slidesPerGroupSkip, slideIndex);
2084 let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);
2085 if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
2086
2087 if ((activeIndex || params.initialSlide || 0) === (previousIndex || 0) && runCallbacks) {
2088 swiper.emit('beforeSlideChangeStart');
2089 }
2090
2091 const translate = -snapGrid[snapIndex];
2092
2093 // Update progress
2094 swiper.updateProgress(translate);
2095
2096 // Normalize slideIndex
2097 if (params.normalizeSlideIndex) {
2098 for (let i = 0; i < slidesGrid.length; i += 1) {
2099 if (-Math.floor(translate * 100) >= Math.floor(slidesGrid[i] * 100)) {
2100 slideIndex = i;
2101 }
2102 }
2103 }
2104 // Directions locks
2105 if (swiper.initialized && slideIndex !== activeIndex) {
2106 if (!swiper.allowSlideNext && translate < swiper.translate && translate < swiper.minTranslate()) {
2107 return false;
2108 }
2109 if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
2110 if ((activeIndex || 0) !== slideIndex) return false;
2111 }
2112 }
2113
2114 let direction;
2115 if (slideIndex > activeIndex) direction = 'next';
2116 else if (slideIndex < activeIndex) direction = 'prev';
2117 else direction = 'reset';
2118
2119
2120 // Update Index
2121 if ((rtl && -translate === swiper.translate) || (!rtl && translate === swiper.translate)) {
2122 swiper.updateActiveIndex(slideIndex);
2123 // Update Height
2124 if (params.autoHeight) {
2125 swiper.updateAutoHeight();
2126 }
2127 swiper.updateSlidesClasses();
2128 if (params.effect !== 'slide') {
2129 swiper.setTranslate(translate);
2130 }
2131 if (direction !== 'reset') {
2132 swiper.transitionStart(runCallbacks, direction);
2133 swiper.transitionEnd(runCallbacks, direction);
2134 }
2135 return false;
2136 }
2137 if (params.cssMode) {
2138 const isH = swiper.isHorizontal();
2139 let t = -translate;
2140 if (rtl) {
2141 t = wrapperEl.scrollWidth - wrapperEl.offsetWidth - t;
2142 }
2143 if (speed === 0) {
2144 wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
2145 } else {
2146 // eslint-disable-next-line
2147 if (wrapperEl.scrollTo) {
2148 wrapperEl.scrollTo({
2149 [isH ? 'left' : 'top']: t,
2150 behavior: 'smooth',
2151 });
2152 } else {
2153 wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
2154 }
2155 }
2156 return true;
2157 }
2158
2159 if (speed === 0) {
2160 swiper.setTransition(0);
2161 swiper.setTranslate(translate);
2162 swiper.updateActiveIndex(slideIndex);
2163 swiper.updateSlidesClasses();
2164 swiper.emit('beforeTransitionStart', speed, internal);
2165 swiper.transitionStart(runCallbacks, direction);
2166 swiper.transitionEnd(runCallbacks, direction);
2167 } else {
2168 swiper.setTransition(speed);
2169 swiper.setTranslate(translate);
2170 swiper.updateActiveIndex(slideIndex);
2171 swiper.updateSlidesClasses();
2172 swiper.emit('beforeTransitionStart', speed, internal);
2173 swiper.transitionStart(runCallbacks, direction);
2174 if (!swiper.animating) {
2175 swiper.animating = true;
2176 if (!swiper.onSlideToWrapperTransitionEnd) {
2177 swiper.onSlideToWrapperTransitionEnd = function transitionEnd(e) {
2178 if (!swiper || swiper.destroyed) return;
2179 if (e.target !== this) return;
2180 swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);
2181 swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);
2182 swiper.onSlideToWrapperTransitionEnd = null;
2183 delete swiper.onSlideToWrapperTransitionEnd;
2184 swiper.transitionEnd(runCallbacks, direction);
2185 };
2186 }
2187 swiper.$wrapperEl[0].addEventListener('transitionend', swiper.onSlideToWrapperTransitionEnd);
2188 swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.onSlideToWrapperTransitionEnd);
2189 }
2190 }
2191
2192 return true;
2193}
2194
2195function slideToLoop (index = 0, speed = this.params.speed, runCallbacks = true, internal) {
2196 const swiper = this;
2197 let newIndex = index;
2198 if (swiper.params.loop) {
2199 newIndex += swiper.loopedSlides;
2200 }
2201
2202 return swiper.slideTo(newIndex, speed, runCallbacks, internal);
2203}
2204
2205/* eslint no-unused-vars: "off" */
2206function slideNext (speed = this.params.speed, runCallbacks = true, internal) {
2207 const swiper = this;
2208 const { params, animating } = swiper;
2209 const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : params.slidesPerGroup;
2210 if (params.loop) {
2211 if (animating) return false;
2212 swiper.loopFix();
2213 // eslint-disable-next-line
2214 swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
2215 }
2216 return swiper.slideTo(swiper.activeIndex + increment, speed, runCallbacks, internal);
2217}
2218
2219/* eslint no-unused-vars: "off" */
2220function slidePrev (speed = this.params.speed, runCallbacks = true, internal) {
2221 const swiper = this;
2222 const {
2223 params, animating, snapGrid, slidesGrid, rtlTranslate,
2224 } = swiper;
2225
2226 if (params.loop) {
2227 if (animating) return false;
2228 swiper.loopFix();
2229 // eslint-disable-next-line
2230 swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
2231 }
2232 const translate = rtlTranslate ? swiper.translate : -swiper.translate;
2233 function normalize(val) {
2234 if (val < 0) return -Math.floor(Math.abs(val));
2235 return Math.floor(val);
2236 }
2237 const normalizedTranslate = normalize(translate);
2238 const normalizedSnapGrid = snapGrid.map((val) => normalize(val));
2239 slidesGrid.map((val) => normalize(val));
2240
2241 snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate)];
2242 let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];
2243 if (typeof prevSnap === 'undefined' && params.cssMode) {
2244 snapGrid.forEach((snap) => {
2245 if (!prevSnap && normalizedTranslate >= snap) prevSnap = snap;
2246 });
2247 }
2248 let prevIndex;
2249 if (typeof prevSnap !== 'undefined') {
2250 prevIndex = slidesGrid.indexOf(prevSnap);
2251 if (prevIndex < 0) prevIndex = swiper.activeIndex - 1;
2252 }
2253 return swiper.slideTo(prevIndex, speed, runCallbacks, internal);
2254}
2255
2256/* eslint no-unused-vars: "off" */
2257function slideReset (speed = this.params.speed, runCallbacks = true, internal) {
2258 const swiper = this;
2259 return swiper.slideTo(swiper.activeIndex, speed, runCallbacks, internal);
2260}
2261
2262/* eslint no-unused-vars: "off" */
2263function slideToClosest (speed = this.params.speed, runCallbacks = true, internal, threshold = 0.5) {
2264 const swiper = this;
2265 let index = swiper.activeIndex;
2266 const skip = Math.min(swiper.params.slidesPerGroupSkip, index);
2267 const snapIndex = skip + Math.floor((index - skip) / swiper.params.slidesPerGroup);
2268
2269 const translate = swiper.rtlTranslate ? swiper.translate : -swiper.translate;
2270
2271 if (translate >= swiper.snapGrid[snapIndex]) {
2272 // The current translate is on or after the current snap index, so the choice
2273 // is between the current index and the one after it.
2274 const currentSnap = swiper.snapGrid[snapIndex];
2275 const nextSnap = swiper.snapGrid[snapIndex + 1];
2276 if ((translate - currentSnap) > (nextSnap - currentSnap) * threshold) {
2277 index += swiper.params.slidesPerGroup;
2278 }
2279 } else {
2280 // The current translate is before the current snap index, so the choice
2281 // is between the current index and the one before it.
2282 const prevSnap = swiper.snapGrid[snapIndex - 1];
2283 const currentSnap = swiper.snapGrid[snapIndex];
2284 if ((translate - prevSnap) <= (currentSnap - prevSnap) * threshold) {
2285 index -= swiper.params.slidesPerGroup;
2286 }
2287 }
2288 index = Math.max(index, 0);
2289 index = Math.min(index, swiper.slidesGrid.length - 1);
2290
2291 return swiper.slideTo(index, speed, runCallbacks, internal);
2292}
2293
2294function slideToClickedSlide () {
2295 const swiper = this;
2296 const { params, $wrapperEl } = swiper;
2297
2298 const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
2299 let slideToIndex = swiper.clickedIndex;
2300 let realIndex;
2301 if (params.loop) {
2302 if (swiper.animating) return;
2303 realIndex = parseInt($(swiper.clickedSlide).attr('data-swiper-slide-index'), 10);
2304 if (params.centeredSlides) {
2305 if (
2306 (slideToIndex < swiper.loopedSlides - (slidesPerView / 2))
2307 || (slideToIndex > (swiper.slides.length - swiper.loopedSlides) + (slidesPerView / 2))
2308 ) {
2309 swiper.loopFix();
2310 slideToIndex = $wrapperEl
2311 .children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`)
2312 .eq(0)
2313 .index();
2314
2315 Utils.nextTick(() => {
2316 swiper.slideTo(slideToIndex);
2317 });
2318 } else {
2319 swiper.slideTo(slideToIndex);
2320 }
2321 } else if (slideToIndex > swiper.slides.length - slidesPerView) {
2322 swiper.loopFix();
2323 slideToIndex = $wrapperEl
2324 .children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`)
2325 .eq(0)
2326 .index();
2327
2328 Utils.nextTick(() => {
2329 swiper.slideTo(slideToIndex);
2330 });
2331 } else {
2332 swiper.slideTo(slideToIndex);
2333 }
2334 } else {
2335 swiper.slideTo(slideToIndex);
2336 }
2337}
2338
2339var slide = {
2340 slideTo,
2341 slideToLoop,
2342 slideNext,
2343 slidePrev,
2344 slideReset,
2345 slideToClosest,
2346 slideToClickedSlide,
2347};
2348
2349function loopCreate () {
2350 const swiper = this;
2351 const { params, $wrapperEl } = swiper;
2352 // Remove duplicated slides
2353 $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}`).remove();
2354
2355 let slides = $wrapperEl.children(`.${params.slideClass}`);
2356
2357 if (params.loopFillGroupWithBlank) {
2358 const blankSlidesNum = params.slidesPerGroup - (slides.length % params.slidesPerGroup);
2359 if (blankSlidesNum !== params.slidesPerGroup) {
2360 for (let i = 0; i < blankSlidesNum; i += 1) {
2361 const blankNode = $(doc.createElement('div')).addClass(`${params.slideClass} ${params.slideBlankClass}`);
2362 $wrapperEl.append(blankNode);
2363 }
2364 slides = $wrapperEl.children(`.${params.slideClass}`);
2365 }
2366 }
2367
2368 if (params.slidesPerView === 'auto' && !params.loopedSlides) params.loopedSlides = slides.length;
2369
2370 swiper.loopedSlides = Math.ceil(parseFloat(params.loopedSlides || params.slidesPerView, 10));
2371 swiper.loopedSlides += params.loopAdditionalSlides;
2372 if (swiper.loopedSlides > slides.length) {
2373 swiper.loopedSlides = slides.length;
2374 }
2375
2376 const prependSlides = [];
2377 const appendSlides = [];
2378 slides.each((index, el) => {
2379 const slide = $(el);
2380 if (index < swiper.loopedSlides) appendSlides.push(el);
2381 if (index < slides.length && index >= slides.length - swiper.loopedSlides) prependSlides.push(el);
2382 slide.attr('data-swiper-slide-index', index);
2383 });
2384 for (let i = 0; i < appendSlides.length; i += 1) {
2385 $wrapperEl.append($(appendSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
2386 }
2387 for (let i = prependSlides.length - 1; i >= 0; i -= 1) {
2388 $wrapperEl.prepend($(prependSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
2389 }
2390}
2391
2392function loopFix () {
2393 const swiper = this;
2394
2395 swiper.emit('beforeLoopFix');
2396
2397 const {
2398 activeIndex, slides, loopedSlides, allowSlidePrev, allowSlideNext, snapGrid, rtlTranslate: rtl,
2399 } = swiper;
2400 let newIndex;
2401 swiper.allowSlidePrev = true;
2402 swiper.allowSlideNext = true;
2403
2404 const snapTranslate = -snapGrid[activeIndex];
2405 const diff = snapTranslate - swiper.getTranslate();
2406
2407 // Fix For Negative Oversliding
2408 if (activeIndex < loopedSlides) {
2409 newIndex = (slides.length - (loopedSlides * 3)) + activeIndex;
2410 newIndex += loopedSlides;
2411 const slideChanged = swiper.slideTo(newIndex, 0, false, true);
2412 if (slideChanged && diff !== 0) {
2413 swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);
2414 }
2415 } else if (activeIndex >= slides.length - loopedSlides) {
2416 // Fix For Positive Oversliding
2417 newIndex = -slides.length + activeIndex + loopedSlides;
2418 newIndex += loopedSlides;
2419 const slideChanged = swiper.slideTo(newIndex, 0, false, true);
2420 if (slideChanged && diff !== 0) {
2421 swiper.setTranslate((rtl ? -swiper.translate : swiper.translate) - diff);
2422 }
2423 }
2424 swiper.allowSlidePrev = allowSlidePrev;
2425 swiper.allowSlideNext = allowSlideNext;
2426
2427 swiper.emit('loopFix');
2428}
2429
2430function loopDestroy () {
2431 const swiper = this;
2432 const { $wrapperEl, params, slides } = swiper;
2433 $wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass},.${params.slideClass}.${params.slideBlankClass}`).remove();
2434 slides.removeAttr('data-swiper-slide-index');
2435}
2436
2437var loop = {
2438 loopCreate,
2439 loopFix,
2440 loopDestroy,
2441};
2442
2443function setGrabCursor (moving) {
2444 const swiper = this;
2445 if (Support.touch || !swiper.params.simulateTouch || (swiper.params.watchOverflow && swiper.isLocked) || swiper.params.cssMode) return;
2446 const el = swiper.el;
2447 el.style.cursor = 'move';
2448 el.style.cursor = moving ? '-webkit-grabbing' : '-webkit-grab';
2449 el.style.cursor = moving ? '-moz-grabbin' : '-moz-grab';
2450 el.style.cursor = moving ? 'grabbing' : 'grab';
2451}
2452
2453function unsetGrabCursor () {
2454 const swiper = this;
2455 if (Support.touch || (swiper.params.watchOverflow && swiper.isLocked) || swiper.params.cssMode) return;
2456 swiper.el.style.cursor = '';
2457}
2458
2459var grabCursor = {
2460 setGrabCursor,
2461 unsetGrabCursor,
2462};
2463
2464function appendSlide (slides) {
2465 const swiper = this;
2466 const { $wrapperEl, params } = swiper;
2467 if (params.loop) {
2468 swiper.loopDestroy();
2469 }
2470 if (typeof slides === 'object' && 'length' in slides) {
2471 for (let i = 0; i < slides.length; i += 1) {
2472 if (slides[i]) $wrapperEl.append(slides[i]);
2473 }
2474 } else {
2475 $wrapperEl.append(slides);
2476 }
2477 if (params.loop) {
2478 swiper.loopCreate();
2479 }
2480 if (!(params.observer && Support.observer)) {
2481 swiper.update();
2482 }
2483}
2484
2485function prependSlide (slides) {
2486 const swiper = this;
2487 const { params, $wrapperEl, activeIndex } = swiper;
2488
2489 if (params.loop) {
2490 swiper.loopDestroy();
2491 }
2492 let newActiveIndex = activeIndex + 1;
2493 if (typeof slides === 'object' && 'length' in slides) {
2494 for (let i = 0; i < slides.length; i += 1) {
2495 if (slides[i]) $wrapperEl.prepend(slides[i]);
2496 }
2497 newActiveIndex = activeIndex + slides.length;
2498 } else {
2499 $wrapperEl.prepend(slides);
2500 }
2501 if (params.loop) {
2502 swiper.loopCreate();
2503 }
2504 if (!(params.observer && Support.observer)) {
2505 swiper.update();
2506 }
2507 swiper.slideTo(newActiveIndex, 0, false);
2508}
2509
2510function addSlide (index, slides) {
2511 const swiper = this;
2512 const { $wrapperEl, params, activeIndex } = swiper;
2513 let activeIndexBuffer = activeIndex;
2514 if (params.loop) {
2515 activeIndexBuffer -= swiper.loopedSlides;
2516 swiper.loopDestroy();
2517 swiper.slides = $wrapperEl.children(`.${params.slideClass}`);
2518 }
2519 const baseLength = swiper.slides.length;
2520 if (index <= 0) {
2521 swiper.prependSlide(slides);
2522 return;
2523 }
2524 if (index >= baseLength) {
2525 swiper.appendSlide(slides);
2526 return;
2527 }
2528 let newActiveIndex = activeIndexBuffer > index ? activeIndexBuffer + 1 : activeIndexBuffer;
2529
2530 const slidesBuffer = [];
2531 for (let i = baseLength - 1; i >= index; i -= 1) {
2532 const currentSlide = swiper.slides.eq(i);
2533 currentSlide.remove();
2534 slidesBuffer.unshift(currentSlide);
2535 }
2536
2537 if (typeof slides === 'object' && 'length' in slides) {
2538 for (let i = 0; i < slides.length; i += 1) {
2539 if (slides[i]) $wrapperEl.append(slides[i]);
2540 }
2541 newActiveIndex = activeIndexBuffer > index ? activeIndexBuffer + slides.length : activeIndexBuffer;
2542 } else {
2543 $wrapperEl.append(slides);
2544 }
2545
2546 for (let i = 0; i < slidesBuffer.length; i += 1) {
2547 $wrapperEl.append(slidesBuffer[i]);
2548 }
2549
2550 if (params.loop) {
2551 swiper.loopCreate();
2552 }
2553 if (!(params.observer && Support.observer)) {
2554 swiper.update();
2555 }
2556 if (params.loop) {
2557 swiper.slideTo(newActiveIndex + swiper.loopedSlides, 0, false);
2558 } else {
2559 swiper.slideTo(newActiveIndex, 0, false);
2560 }
2561}
2562
2563function removeSlide (slidesIndexes) {
2564 const swiper = this;
2565 const { params, $wrapperEl, activeIndex } = swiper;
2566
2567 let activeIndexBuffer = activeIndex;
2568 if (params.loop) {
2569 activeIndexBuffer -= swiper.loopedSlides;
2570 swiper.loopDestroy();
2571 swiper.slides = $wrapperEl.children(`.${params.slideClass}`);
2572 }
2573 let newActiveIndex = activeIndexBuffer;
2574 let indexToRemove;
2575
2576 if (typeof slidesIndexes === 'object' && 'length' in slidesIndexes) {
2577 for (let i = 0; i < slidesIndexes.length; i += 1) {
2578 indexToRemove = slidesIndexes[i];
2579 if (swiper.slides[indexToRemove]) swiper.slides.eq(indexToRemove).remove();
2580 if (indexToRemove < newActiveIndex) newActiveIndex -= 1;
2581 }
2582 newActiveIndex = Math.max(newActiveIndex, 0);
2583 } else {
2584 indexToRemove = slidesIndexes;
2585 if (swiper.slides[indexToRemove]) swiper.slides.eq(indexToRemove).remove();
2586 if (indexToRemove < newActiveIndex) newActiveIndex -= 1;
2587 newActiveIndex = Math.max(newActiveIndex, 0);
2588 }
2589
2590 if (params.loop) {
2591 swiper.loopCreate();
2592 }
2593
2594 if (!(params.observer && Support.observer)) {
2595 swiper.update();
2596 }
2597 if (params.loop) {
2598 swiper.slideTo(newActiveIndex + swiper.loopedSlides, 0, false);
2599 } else {
2600 swiper.slideTo(newActiveIndex, 0, false);
2601 }
2602}
2603
2604function removeAllSlides () {
2605 const swiper = this;
2606
2607 const slidesIndexes = [];
2608 for (let i = 0; i < swiper.slides.length; i += 1) {
2609 slidesIndexes.push(i);
2610 }
2611 swiper.removeSlide(slidesIndexes);
2612}
2613
2614var manipulation = {
2615 appendSlide,
2616 prependSlide,
2617 addSlide,
2618 removeSlide,
2619 removeAllSlides,
2620};
2621
2622const Device = (function Device() {
2623 const platform = win.navigator.platform;
2624 const ua = win.navigator.userAgent;
2625
2626 const device = {
2627 ios: false,
2628 android: false,
2629 androidChrome: false,
2630 desktop: false,
2631 iphone: false,
2632 ipod: false,
2633 ipad: false,
2634 edge: false,
2635 ie: false,
2636 firefox: false,
2637 macos: false,
2638 windows: false,
2639 cordova: !!(win.cordova || win.phonegap),
2640 phonegap: !!(win.cordova || win.phonegap),
2641 electron: false,
2642 };
2643
2644 const screenWidth = win.screen.width;
2645 const screenHeight = win.screen.height;
2646
2647 const android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // eslint-disable-line
2648 let ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
2649 const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
2650 const iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/);
2651 const ie = ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0;
2652 const edge = ua.indexOf('Edge/') >= 0;
2653 const firefox = ua.indexOf('Gecko/') >= 0 && ua.indexOf('Firefox/') >= 0;
2654 const windows = platform === 'Win32';
2655 const electron = ua.toLowerCase().indexOf('electron') >= 0;
2656 let macos = platform === 'MacIntel';
2657
2658 // iPadOs 13 fix
2659 if (!ipad
2660 && macos
2661 && Support.touch
2662 && (
2663 (screenWidth === 1024 && screenHeight === 1366) // Pro 12.9
2664 || (screenWidth === 834 && screenHeight === 1194) // Pro 11
2665 || (screenWidth === 834 && screenHeight === 1112) // Pro 10.5
2666 || (screenWidth === 768 && screenHeight === 1024) // other
2667 )
2668 ) {
2669 ipad = ua.match(/(Version)\/([\d.]+)/);
2670 macos = false;
2671 }
2672
2673 device.ie = ie;
2674 device.edge = edge;
2675 device.firefox = firefox;
2676
2677 // Android
2678 if (android && !windows) {
2679 device.os = 'android';
2680 device.osVersion = android[2];
2681 device.android = true;
2682 device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
2683 }
2684 if (ipad || iphone || ipod) {
2685 device.os = 'ios';
2686 device.ios = true;
2687 }
2688 // iOS
2689 if (iphone && !ipod) {
2690 device.osVersion = iphone[2].replace(/_/g, '.');
2691 device.iphone = true;
2692 }
2693 if (ipad) {
2694 device.osVersion = ipad[2].replace(/_/g, '.');
2695 device.ipad = true;
2696 }
2697 if (ipod) {
2698 device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
2699 device.ipod = true;
2700 }
2701 // iOS 8+ changed UA
2702 if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
2703 if (device.osVersion.split('.')[0] === '10') {
2704 device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
2705 }
2706 }
2707
2708 // Webview
2709 device.webView = !!((iphone || ipad || ipod) && (ua.match(/.*AppleWebKit(?!.*Safari)/i) || win.navigator.standalone))
2710 || (win.matchMedia && win.matchMedia('(display-mode: standalone)').matches);
2711 device.webview = device.webView;
2712 device.standalone = device.webView;
2713
2714 // Desktop
2715 device.desktop = !(device.ios || device.android) || electron;
2716 if (device.desktop) {
2717 device.electron = electron;
2718 device.macos = macos;
2719 device.windows = windows;
2720 if (device.macos) {
2721 device.os = 'macos';
2722 }
2723 if (device.windows) {
2724 device.os = 'windows';
2725 }
2726 }
2727
2728 // Pixel Ratio
2729 device.pixelRatio = win.devicePixelRatio || 1;
2730
2731 // Export object
2732 return device;
2733}());
2734
2735function onTouchStart (event) {
2736 const swiper = this;
2737 const data = swiper.touchEventsData;
2738 const { params, touches } = swiper;
2739
2740 if (swiper.animating && params.preventInteractionOnTransition) {
2741 return;
2742 }
2743 let e = event;
2744 if (e.originalEvent) e = e.originalEvent;
2745 const $targetEl = $(e.target);
2746
2747 if (params.touchEventsTarget === 'wrapper') {
2748 if (!$targetEl.closest(swiper.wrapperEl).length) return;
2749 }
2750 data.isTouchEvent = e.type === 'touchstart';
2751 if (!data.isTouchEvent && 'which' in e && e.which === 3) return;
2752 if (!data.isTouchEvent && 'button' in e && e.button > 0) return;
2753 if (data.isTouched && data.isMoved) return;
2754 if (params.noSwiping && $targetEl.closest(params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`)[0]) {
2755 swiper.allowClick = true;
2756 return;
2757 }
2758 if (params.swipeHandler) {
2759 if (!$targetEl.closest(params.swipeHandler)[0]) return;
2760 }
2761
2762 touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
2763 touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
2764 const startX = touches.currentX;
2765 const startY = touches.currentY;
2766
2767 // Do NOT start if iOS edge swipe is detected. Otherwise iOS app (UIWebView) cannot swipe-to-go-back anymore
2768
2769 const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;
2770 const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;
2771 if (
2772 edgeSwipeDetection
2773 && ((startX <= edgeSwipeThreshold)
2774 || (startX >= win.screen.width - edgeSwipeThreshold))
2775 ) {
2776 return;
2777 }
2778
2779 Utils.extend(data, {
2780 isTouched: true,
2781 isMoved: false,
2782 allowTouchCallbacks: true,
2783 isScrolling: undefined,
2784 startMoving: undefined,
2785 });
2786
2787 touches.startX = startX;
2788 touches.startY = startY;
2789 data.touchStartTime = Utils.now();
2790 swiper.allowClick = true;
2791 swiper.updateSize();
2792 swiper.swipeDirection = undefined;
2793 if (params.threshold > 0) data.allowThresholdMove = false;
2794 if (e.type !== 'touchstart') {
2795 let preventDefault = true;
2796 if ($targetEl.is(data.formElements)) preventDefault = false;
2797 if (
2798 doc.activeElement
2799 && $(doc.activeElement).is(data.formElements)
2800 && doc.activeElement !== $targetEl[0]
2801 ) {
2802 doc.activeElement.blur();
2803 }
2804
2805 const shouldPreventDefault = preventDefault && swiper.allowTouchMove && params.touchStartPreventDefault;
2806 if (params.touchStartForcePreventDefault || shouldPreventDefault) {
2807 e.preventDefault();
2808 }
2809 }
2810 swiper.emit('touchStart', e);
2811}
2812
2813function onTouchMove (event) {
2814 const swiper = this;
2815 const data = swiper.touchEventsData;
2816 const { params, touches, rtlTranslate: rtl } = swiper;
2817 let e = event;
2818 if (e.originalEvent) e = e.originalEvent;
2819 if (!data.isTouched) {
2820 if (data.startMoving && data.isScrolling) {
2821 swiper.emit('touchMoveOpposite', e);
2822 }
2823 return;
2824 }
2825 if (data.isTouchEvent && e.type !== 'touchmove') return;
2826 const targetTouch = e.type === 'touchmove' && e.targetTouches && (e.targetTouches[0] || e.changedTouches[0]);
2827 const pageX = e.type === 'touchmove' ? targetTouch.pageX : e.pageX;
2828 const pageY = e.type === 'touchmove' ? targetTouch.pageY : e.pageY;
2829 if (e.preventedByNestedSwiper) {
2830 touches.startX = pageX;
2831 touches.startY = pageY;
2832 return;
2833 }
2834 if (!swiper.allowTouchMove) {
2835 // isMoved = true;
2836 swiper.allowClick = false;
2837 if (data.isTouched) {
2838 Utils.extend(touches, {
2839 startX: pageX,
2840 startY: pageY,
2841 currentX: pageX,
2842 currentY: pageY,
2843 });
2844 data.touchStartTime = Utils.now();
2845 }
2846 return;
2847 }
2848 if (data.isTouchEvent && params.touchReleaseOnEdges && !params.loop) {
2849 if (swiper.isVertical()) {
2850 // Vertical
2851 if (
2852 (pageY < touches.startY && swiper.translate <= swiper.maxTranslate())
2853 || (pageY > touches.startY && swiper.translate >= swiper.minTranslate())
2854 ) {
2855 data.isTouched = false;
2856 data.isMoved = false;
2857 return;
2858 }
2859 } else if (
2860 (pageX < touches.startX && swiper.translate <= swiper.maxTranslate())
2861 || (pageX > touches.startX && swiper.translate >= swiper.minTranslate())
2862 ) {
2863 return;
2864 }
2865 }
2866 if (data.isTouchEvent && doc.activeElement) {
2867 if (e.target === doc.activeElement && $(e.target).is(data.formElements)) {
2868 data.isMoved = true;
2869 swiper.allowClick = false;
2870 return;
2871 }
2872 }
2873 if (data.allowTouchCallbacks) {
2874 swiper.emit('touchMove', e);
2875 }
2876 if (e.targetTouches && e.targetTouches.length > 1) return;
2877
2878 touches.currentX = pageX;
2879 touches.currentY = pageY;
2880
2881 const diffX = touches.currentX - touches.startX;
2882 const diffY = touches.currentY - touches.startY;
2883 if (swiper.params.threshold && Math.sqrt((diffX ** 2) + (diffY ** 2)) < swiper.params.threshold) return;
2884
2885 if (typeof data.isScrolling === 'undefined') {
2886 let touchAngle;
2887 if ((swiper.isHorizontal() && touches.currentY === touches.startY) || (swiper.isVertical() && touches.currentX === touches.startX)) {
2888 data.isScrolling = false;
2889 } else {
2890 // eslint-disable-next-line
2891 if ((diffX * diffX) + (diffY * diffY) >= 25) {
2892 touchAngle = (Math.atan2(Math.abs(diffY), Math.abs(diffX)) * 180) / Math.PI;
2893 data.isScrolling = swiper.isHorizontal() ? touchAngle > params.touchAngle : (90 - touchAngle > params.touchAngle);
2894 }
2895 }
2896 }
2897 if (data.isScrolling) {
2898 swiper.emit('touchMoveOpposite', e);
2899 }
2900 if (typeof data.startMoving === 'undefined') {
2901 if (touches.currentX !== touches.startX || touches.currentY !== touches.startY) {
2902 data.startMoving = true;
2903 }
2904 }
2905 if (data.isScrolling) {
2906 data.isTouched = false;
2907 return;
2908 }
2909 if (!data.startMoving) {
2910 return;
2911 }
2912 swiper.allowClick = false;
2913 if (!params.cssMode && e.cancelable) {
2914 e.preventDefault();
2915 }
2916 if (params.touchMoveStopPropagation && !params.nested) {
2917 e.stopPropagation();
2918 }
2919
2920 if (!data.isMoved) {
2921 if (params.loop) {
2922 swiper.loopFix();
2923 }
2924 data.startTranslate = swiper.getTranslate();
2925 swiper.setTransition(0);
2926 if (swiper.animating) {
2927 swiper.$wrapperEl.trigger('webkitTransitionEnd transitionend');
2928 }
2929 data.allowMomentumBounce = false;
2930 // Grab Cursor
2931 if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
2932 swiper.setGrabCursor(true);
2933 }
2934 swiper.emit('sliderFirstMove', e);
2935 }
2936 swiper.emit('sliderMove', e);
2937 data.isMoved = true;
2938
2939 let diff = swiper.isHorizontal() ? diffX : diffY;
2940 touches.diff = diff;
2941
2942 diff *= params.touchRatio;
2943 if (rtl) diff = -diff;
2944
2945 swiper.swipeDirection = diff > 0 ? 'prev' : 'next';
2946 data.currentTranslate = diff + data.startTranslate;
2947
2948 let disableParentSwiper = true;
2949 let resistanceRatio = params.resistanceRatio;
2950 if (params.touchReleaseOnEdges) {
2951 resistanceRatio = 0;
2952 }
2953 if ((diff > 0 && data.currentTranslate > swiper.minTranslate())) {
2954 disableParentSwiper = false;
2955 if (params.resistance) data.currentTranslate = (swiper.minTranslate() - 1) + ((-swiper.minTranslate() + data.startTranslate + diff) ** resistanceRatio);
2956 } else if (diff < 0 && data.currentTranslate < swiper.maxTranslate()) {
2957 disableParentSwiper = false;
2958 if (params.resistance) data.currentTranslate = (swiper.maxTranslate() + 1) - ((swiper.maxTranslate() - data.startTranslate - diff) ** resistanceRatio);
2959 }
2960
2961 if (disableParentSwiper) {
2962 e.preventedByNestedSwiper = true;
2963 }
2964
2965 // Directions locks
2966 if (!swiper.allowSlideNext && swiper.swipeDirection === 'next' && data.currentTranslate < data.startTranslate) {
2967 data.currentTranslate = data.startTranslate;
2968 }
2969 if (!swiper.allowSlidePrev && swiper.swipeDirection === 'prev' && data.currentTranslate > data.startTranslate) {
2970 data.currentTranslate = data.startTranslate;
2971 }
2972
2973
2974 // Threshold
2975 if (params.threshold > 0) {
2976 if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
2977 if (!data.allowThresholdMove) {
2978 data.allowThresholdMove = true;
2979 touches.startX = touches.currentX;
2980 touches.startY = touches.currentY;
2981 data.currentTranslate = data.startTranslate;
2982 touches.diff = swiper.isHorizontal() ? touches.currentX - touches.startX : touches.currentY - touches.startY;
2983 return;
2984 }
2985 } else {
2986 data.currentTranslate = data.startTranslate;
2987 return;
2988 }
2989 }
2990
2991 if (!params.followFinger || params.cssMode) return;
2992
2993 // Update active index in free mode
2994 if (params.freeMode || params.watchSlidesProgress || params.watchSlidesVisibility) {
2995 swiper.updateActiveIndex();
2996 swiper.updateSlidesClasses();
2997 }
2998 if (params.freeMode) {
2999 // Velocity
3000 if (data.velocities.length === 0) {
3001 data.velocities.push({
3002 position: touches[swiper.isHorizontal() ? 'startX' : 'startY'],
3003 time: data.touchStartTime,
3004 });
3005 }
3006 data.velocities.push({
3007 position: touches[swiper.isHorizontal() ? 'currentX' : 'currentY'],
3008 time: Utils.now(),
3009 });
3010 }
3011 // Update progress
3012 swiper.updateProgress(data.currentTranslate);
3013 // Update translate
3014 swiper.setTranslate(data.currentTranslate);
3015}
3016
3017function onTouchEnd (event) {
3018 const swiper = this;
3019 const data = swiper.touchEventsData;
3020
3021 const {
3022 params, touches, rtlTranslate: rtl, $wrapperEl, slidesGrid, snapGrid,
3023 } = swiper;
3024 let e = event;
3025 if (e.originalEvent) e = e.originalEvent;
3026 if (data.allowTouchCallbacks) {
3027 swiper.emit('touchEnd', e);
3028 }
3029 data.allowTouchCallbacks = false;
3030 if (!data.isTouched) {
3031 if (data.isMoved && params.grabCursor) {
3032 swiper.setGrabCursor(false);
3033 }
3034 data.isMoved = false;
3035 data.startMoving = false;
3036 return;
3037 }
3038 // Return Grab Cursor
3039 if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3040 swiper.setGrabCursor(false);
3041 }
3042
3043 // Time diff
3044 const touchEndTime = Utils.now();
3045 const timeDiff = touchEndTime - data.touchStartTime;
3046
3047 // Tap, doubleTap, Click
3048 if (swiper.allowClick) {
3049 swiper.updateClickedSlide(e);
3050 swiper.emit('tap click', e);
3051 if (timeDiff < 300 && (touchEndTime - data.lastClickTime) < 300) {
3052 swiper.emit('doubleTap doubleClick', e);
3053 }
3054 }
3055
3056 data.lastClickTime = Utils.now();
3057 Utils.nextTick(() => {
3058 if (!swiper.destroyed) swiper.allowClick = true;
3059 });
3060
3061 if (!data.isTouched || !data.isMoved || !swiper.swipeDirection || touches.diff === 0 || data.currentTranslate === data.startTranslate) {
3062 data.isTouched = false;
3063 data.isMoved = false;
3064 data.startMoving = false;
3065 return;
3066 }
3067 data.isTouched = false;
3068 data.isMoved = false;
3069 data.startMoving = false;
3070
3071 let currentPos;
3072 if (params.followFinger) {
3073 currentPos = rtl ? swiper.translate : -swiper.translate;
3074 } else {
3075 currentPos = -data.currentTranslate;
3076 }
3077
3078 if (params.cssMode) {
3079 return;
3080 }
3081
3082 if (params.freeMode) {
3083 if (currentPos < -swiper.minTranslate()) {
3084 swiper.slideTo(swiper.activeIndex);
3085 return;
3086 }
3087 if (currentPos > -swiper.maxTranslate()) {
3088 if (swiper.slides.length < snapGrid.length) {
3089 swiper.slideTo(snapGrid.length - 1);
3090 } else {
3091 swiper.slideTo(swiper.slides.length - 1);
3092 }
3093 return;
3094 }
3095
3096 if (params.freeModeMomentum) {
3097 if (data.velocities.length > 1) {
3098 const lastMoveEvent = data.velocities.pop();
3099 const velocityEvent = data.velocities.pop();
3100
3101 const distance = lastMoveEvent.position - velocityEvent.position;
3102 const time = lastMoveEvent.time - velocityEvent.time;
3103 swiper.velocity = distance / time;
3104 swiper.velocity /= 2;
3105 if (Math.abs(swiper.velocity) < params.freeModeMinimumVelocity) {
3106 swiper.velocity = 0;
3107 }
3108 // this implies that the user stopped moving a finger then released.
3109 // There would be no events with distance zero, so the last event is stale.
3110 if (time > 150 || (Utils.now() - lastMoveEvent.time) > 300) {
3111 swiper.velocity = 0;
3112 }
3113 } else {
3114 swiper.velocity = 0;
3115 }
3116 swiper.velocity *= params.freeModeMomentumVelocityRatio;
3117
3118 data.velocities.length = 0;
3119 let momentumDuration = 1000 * params.freeModeMomentumRatio;
3120 const momentumDistance = swiper.velocity * momentumDuration;
3121
3122 let newPosition = swiper.translate + momentumDistance;
3123 if (rtl) newPosition = -newPosition;
3124
3125 let doBounce = false;
3126 let afterBouncePosition;
3127 const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeModeMomentumBounceRatio;
3128 let needsLoopFix;
3129 if (newPosition < swiper.maxTranslate()) {
3130 if (params.freeModeMomentumBounce) {
3131 if (newPosition + swiper.maxTranslate() < -bounceAmount) {
3132 newPosition = swiper.maxTranslate() - bounceAmount;
3133 }
3134 afterBouncePosition = swiper.maxTranslate();
3135 doBounce = true;
3136 data.allowMomentumBounce = true;
3137 } else {
3138 newPosition = swiper.maxTranslate();
3139 }
3140 if (params.loop && params.centeredSlides) needsLoopFix = true;
3141 } else if (newPosition > swiper.minTranslate()) {
3142 if (params.freeModeMomentumBounce) {
3143 if (newPosition - swiper.minTranslate() > bounceAmount) {
3144 newPosition = swiper.minTranslate() + bounceAmount;
3145 }
3146 afterBouncePosition = swiper.minTranslate();
3147 doBounce = true;
3148 data.allowMomentumBounce = true;
3149 } else {
3150 newPosition = swiper.minTranslate();
3151 }
3152 if (params.loop && params.centeredSlides) needsLoopFix = true;
3153 } else if (params.freeModeSticky) {
3154 let nextSlide;
3155 for (let j = 0; j < snapGrid.length; j += 1) {
3156 if (snapGrid[j] > -newPosition) {
3157 nextSlide = j;
3158 break;
3159 }
3160 }
3161
3162 if (Math.abs(snapGrid[nextSlide] - newPosition) < Math.abs(snapGrid[nextSlide - 1] - newPosition) || swiper.swipeDirection === 'next') {
3163 newPosition = snapGrid[nextSlide];
3164 } else {
3165 newPosition = snapGrid[nextSlide - 1];
3166 }
3167 newPosition = -newPosition;
3168 }
3169 if (needsLoopFix) {
3170 swiper.once('transitionEnd', () => {
3171 swiper.loopFix();
3172 });
3173 }
3174 // Fix duration
3175 if (swiper.velocity !== 0) {
3176 if (rtl) {
3177 momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity);
3178 } else {
3179 momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity);
3180 }
3181 if (params.freeModeSticky) {
3182 // If freeModeSticky is active and the user ends a swipe with a slow-velocity
3183 // event, then durations can be 20+ seconds to slide one (or zero!) slides.
3184 // It's easy to see this when simulating touch with mouse events. To fix this,
3185 // limit single-slide swipes to the default slide duration. This also has the
3186 // nice side effect of matching slide speed if the user stopped moving before
3187 // lifting finger or mouse vs. moving slowly before lifting the finger/mouse.
3188 // For faster swipes, also apply limits (albeit higher ones).
3189 const moveDistance = Math.abs((rtl ? -newPosition : newPosition) - swiper.translate);
3190 const currentSlideSize = swiper.slidesSizesGrid[swiper.activeIndex];
3191 if (moveDistance < currentSlideSize) {
3192 momentumDuration = params.speed;
3193 } else if (moveDistance < 2 * currentSlideSize) {
3194 momentumDuration = params.speed * 1.5;
3195 } else {
3196 momentumDuration = params.speed * 2.5;
3197 }
3198 }
3199 } else if (params.freeModeSticky) {
3200 swiper.slideToClosest();
3201 return;
3202 }
3203
3204 if (params.freeModeMomentumBounce && doBounce) {
3205 swiper.updateProgress(afterBouncePosition);
3206 swiper.setTransition(momentumDuration);
3207 swiper.setTranslate(newPosition);
3208 swiper.transitionStart(true, swiper.swipeDirection);
3209 swiper.animating = true;
3210 $wrapperEl.transitionEnd(() => {
3211 if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return;
3212 swiper.emit('momentumBounce');
3213 swiper.setTransition(params.speed);
3214 setTimeout(() => {
3215 swiper.setTranslate(afterBouncePosition);
3216 $wrapperEl.transitionEnd(() => {
3217 if (!swiper || swiper.destroyed) return;
3218 swiper.transitionEnd();
3219 });
3220 }, 0);
3221 });
3222 } else if (swiper.velocity) {
3223 swiper.updateProgress(newPosition);
3224 swiper.setTransition(momentumDuration);
3225 swiper.setTranslate(newPosition);
3226 swiper.transitionStart(true, swiper.swipeDirection);
3227 if (!swiper.animating) {
3228 swiper.animating = true;
3229 $wrapperEl.transitionEnd(() => {
3230 if (!swiper || swiper.destroyed) return;
3231 swiper.transitionEnd();
3232 });
3233 }
3234 } else {
3235 swiper.updateProgress(newPosition);
3236 }
3237
3238 swiper.updateActiveIndex();
3239 swiper.updateSlidesClasses();
3240 } else if (params.freeModeSticky) {
3241 swiper.slideToClosest();
3242 return;
3243 }
3244
3245 if (!params.freeModeMomentum || timeDiff >= params.longSwipesMs) {
3246 swiper.updateProgress();
3247 swiper.updateActiveIndex();
3248 swiper.updateSlidesClasses();
3249 }
3250 return;
3251 }
3252
3253 // Find current slide
3254 let stopIndex = 0;
3255 let groupSize = swiper.slidesSizesGrid[0];
3256 for (let i = 0; i < slidesGrid.length; i += (i < params.slidesPerGroupSkip ? 1 : params.slidesPerGroup)) {
3257 const increment = (i < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup);
3258 if (typeof slidesGrid[i + increment] !== 'undefined') {
3259 if (currentPos >= slidesGrid[i] && currentPos < slidesGrid[i + increment]) {
3260 stopIndex = i;
3261 groupSize = slidesGrid[i + increment] - slidesGrid[i];
3262 }
3263 } else if (currentPos >= slidesGrid[i]) {
3264 stopIndex = i;
3265 groupSize = slidesGrid[slidesGrid.length - 1] - slidesGrid[slidesGrid.length - 2];
3266 }
3267 }
3268
3269 // Find current slide size
3270 const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
3271 const increment = (stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup);
3272
3273 if (timeDiff > params.longSwipesMs) {
3274 // Long touches
3275 if (!params.longSwipes) {
3276 swiper.slideTo(swiper.activeIndex);
3277 return;
3278 }
3279 if (swiper.swipeDirection === 'next') {
3280 if (ratio >= params.longSwipesRatio) swiper.slideTo(stopIndex + increment);
3281 else swiper.slideTo(stopIndex);
3282 }
3283 if (swiper.swipeDirection === 'prev') {
3284 if (ratio > (1 - params.longSwipesRatio)) swiper.slideTo(stopIndex + increment);
3285 else swiper.slideTo(stopIndex);
3286 }
3287 } else {
3288 // Short swipes
3289 if (!params.shortSwipes) {
3290 swiper.slideTo(swiper.activeIndex);
3291 return;
3292 }
3293 const isNavButtonTarget = swiper.navigation && (e.target === swiper.navigation.nextEl || e.target === swiper.navigation.prevEl);
3294 if (!isNavButtonTarget) {
3295 if (swiper.swipeDirection === 'next') {
3296 swiper.slideTo(stopIndex + increment);
3297 }
3298 if (swiper.swipeDirection === 'prev') {
3299 swiper.slideTo(stopIndex);
3300 }
3301 } else if (e.target === swiper.navigation.nextEl) {
3302 swiper.slideTo(stopIndex + increment);
3303 } else {
3304 swiper.slideTo(stopIndex);
3305 }
3306 }
3307}
3308
3309function onResize () {
3310 const swiper = this;
3311
3312 const { params, el } = swiper;
3313
3314 if (el && el.offsetWidth === 0) return;
3315
3316 // Breakpoints
3317 if (params.breakpoints) {
3318 swiper.setBreakpoint();
3319 }
3320
3321 // Save locks
3322 const { allowSlideNext, allowSlidePrev, snapGrid } = swiper;
3323
3324 // Disable locks on resize
3325 swiper.allowSlideNext = true;
3326 swiper.allowSlidePrev = true;
3327
3328 swiper.updateSize();
3329 swiper.updateSlides();
3330
3331 swiper.updateSlidesClasses();
3332 if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
3333 swiper.slideTo(swiper.slides.length - 1, 0, false, true);
3334 } else {
3335 swiper.slideTo(swiper.activeIndex, 0, false, true);
3336 }
3337
3338 if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
3339 swiper.autoplay.run();
3340 }
3341 // Return locks after resize
3342 swiper.allowSlidePrev = allowSlidePrev;
3343 swiper.allowSlideNext = allowSlideNext;
3344
3345 if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
3346 swiper.checkOverflow();
3347 }
3348}
3349
3350function onClick (e) {
3351 const swiper = this;
3352 if (!swiper.allowClick) {
3353 if (swiper.params.preventClicks) e.preventDefault();
3354 if (swiper.params.preventClicksPropagation && swiper.animating) {
3355 e.stopPropagation();
3356 e.stopImmediatePropagation();
3357 }
3358 }
3359}
3360
3361function onScroll () {
3362 const swiper = this;
3363 const { wrapperEl, rtlTranslate } = swiper;
3364 swiper.previousTranslate = swiper.translate;
3365 if (swiper.isHorizontal()) {
3366 if (rtlTranslate) {
3367 swiper.translate = ((wrapperEl.scrollWidth - wrapperEl.offsetWidth) - wrapperEl.scrollLeft);
3368 } else {
3369 swiper.translate = -wrapperEl.scrollLeft;
3370 }
3371 } else {
3372 swiper.translate = -wrapperEl.scrollTop;
3373 }
3374 // eslint-disable-next-line
3375 if (swiper.translate === -0) swiper.translate = 0;
3376
3377 swiper.updateActiveIndex();
3378 swiper.updateSlidesClasses();
3379
3380 let newProgress;
3381 const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
3382 if (translatesDiff === 0) {
3383 newProgress = 0;
3384 } else {
3385 newProgress = (swiper.translate - swiper.minTranslate()) / (translatesDiff);
3386 }
3387 if (newProgress !== swiper.progress) {
3388 swiper.updateProgress(rtlTranslate ? -swiper.translate : swiper.translate);
3389 }
3390
3391 swiper.emit('setTranslate', swiper.translate, false);
3392}
3393
3394let dummyEventAttached = false;
3395function dummyEventListener() {}
3396
3397function attachEvents() {
3398 const swiper = this;
3399 const {
3400 params, touchEvents, el, wrapperEl,
3401 } = swiper;
3402
3403 swiper.onTouchStart = onTouchStart.bind(swiper);
3404 swiper.onTouchMove = onTouchMove.bind(swiper);
3405 swiper.onTouchEnd = onTouchEnd.bind(swiper);
3406 if (params.cssMode) {
3407 swiper.onScroll = onScroll.bind(swiper);
3408 }
3409
3410 swiper.onClick = onClick.bind(swiper);
3411
3412 const capture = !!params.nested;
3413
3414 // Touch Events
3415 if (!Support.touch && Support.pointerEvents) {
3416 el.addEventListener(touchEvents.start, swiper.onTouchStart, false);
3417 doc.addEventListener(touchEvents.move, swiper.onTouchMove, capture);
3418 doc.addEventListener(touchEvents.end, swiper.onTouchEnd, false);
3419 } else {
3420 if (Support.touch) {
3421 const passiveListener = touchEvents.start === 'touchstart' && Support.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
3422 el.addEventListener(touchEvents.start, swiper.onTouchStart, passiveListener);
3423 el.addEventListener(touchEvents.move, swiper.onTouchMove, Support.passiveListener ? { passive: false, capture } : capture);
3424 el.addEventListener(touchEvents.end, swiper.onTouchEnd, passiveListener);
3425 if (touchEvents.cancel) {
3426 el.addEventListener(touchEvents.cancel, swiper.onTouchEnd, passiveListener);
3427 }
3428 if (!dummyEventAttached) {
3429 doc.addEventListener('touchstart', dummyEventListener);
3430 dummyEventAttached = true;
3431 }
3432 }
3433 if ((params.simulateTouch && !Device.ios && !Device.android) || (params.simulateTouch && !Support.touch && Device.ios)) {
3434 el.addEventListener('mousedown', swiper.onTouchStart, false);
3435 doc.addEventListener('mousemove', swiper.onTouchMove, capture);
3436 doc.addEventListener('mouseup', swiper.onTouchEnd, false);
3437 }
3438 }
3439 // Prevent Links Clicks
3440 if (params.preventClicks || params.preventClicksPropagation) {
3441 el.addEventListener('click', swiper.onClick, true);
3442 }
3443 if (params.cssMode) {
3444 wrapperEl.addEventListener('scroll', swiper.onScroll);
3445 }
3446
3447 // Resize handler
3448 if (params.updateOnWindowResize) {
3449 swiper.on((Device.ios || Device.android ? 'resize orientationchange observerUpdate' : 'resize observerUpdate'), onResize, true);
3450 } else {
3451 swiper.on('observerUpdate', onResize, true);
3452 }
3453}
3454
3455function detachEvents() {
3456 const swiper = this;
3457
3458 const {
3459 params, touchEvents, el, wrapperEl,
3460 } = swiper;
3461
3462 const capture = !!params.nested;
3463
3464 // Touch Events
3465 if (!Support.touch && Support.pointerEvents) {
3466 el.removeEventListener(touchEvents.start, swiper.onTouchStart, false);
3467 doc.removeEventListener(touchEvents.move, swiper.onTouchMove, capture);
3468 doc.removeEventListener(touchEvents.end, swiper.onTouchEnd, false);
3469 } else {
3470 if (Support.touch) {
3471 const passiveListener = touchEvents.start === 'onTouchStart' && Support.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
3472 el.removeEventListener(touchEvents.start, swiper.onTouchStart, passiveListener);
3473 el.removeEventListener(touchEvents.move, swiper.onTouchMove, capture);
3474 el.removeEventListener(touchEvents.end, swiper.onTouchEnd, passiveListener);
3475 if (touchEvents.cancel) {
3476 el.removeEventListener(touchEvents.cancel, swiper.onTouchEnd, passiveListener);
3477 }
3478 }
3479 if ((params.simulateTouch && !Device.ios && !Device.android) || (params.simulateTouch && !Support.touch && Device.ios)) {
3480 el.removeEventListener('mousedown', swiper.onTouchStart, false);
3481 doc.removeEventListener('mousemove', swiper.onTouchMove, capture);
3482 doc.removeEventListener('mouseup', swiper.onTouchEnd, false);
3483 }
3484 }
3485 // Prevent Links Clicks
3486 if (params.preventClicks || params.preventClicksPropagation) {
3487 el.removeEventListener('click', swiper.onClick, true);
3488 }
3489
3490 if (params.cssMode) {
3491 wrapperEl.removeEventListener('scroll', swiper.onScroll);
3492 }
3493
3494 // Resize handler
3495 swiper.off((Device.ios || Device.android ? 'resize orientationchange observerUpdate' : 'resize observerUpdate'), onResize);
3496}
3497
3498var events = {
3499 attachEvents,
3500 detachEvents,
3501};
3502
3503function setBreakpoint () {
3504 const swiper = this;
3505 const {
3506 activeIndex, initialized, loopedSlides = 0, params, $el,
3507 } = swiper;
3508 const breakpoints = params.breakpoints;
3509 if (!breakpoints || (breakpoints && Object.keys(breakpoints).length === 0)) return;
3510
3511 // Get breakpoint for window width and update parameters
3512 const breakpoint = swiper.getBreakpoint(breakpoints);
3513
3514 if (breakpoint && swiper.currentBreakpoint !== breakpoint) {
3515 const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
3516 if (breakpointOnlyParams) {
3517 ['slidesPerView', 'spaceBetween', 'slidesPerGroup', 'slidesPerGroupSkip', 'slidesPerColumn'].forEach((param) => {
3518 const paramValue = breakpointOnlyParams[param];
3519 if (typeof paramValue === 'undefined') return;
3520 if (param === 'slidesPerView' && (paramValue === 'AUTO' || paramValue === 'auto')) {
3521 breakpointOnlyParams[param] = 'auto';
3522 } else if (param === 'slidesPerView') {
3523 breakpointOnlyParams[param] = parseFloat(paramValue);
3524 } else {
3525 breakpointOnlyParams[param] = parseInt(paramValue, 10);
3526 }
3527 });
3528 }
3529
3530 const breakpointParams = breakpointOnlyParams || swiper.originalParams;
3531 const wasMultiRow = params.slidesPerColumn > 1;
3532 const isMultiRow = breakpointParams.slidesPerColumn > 1;
3533 if (wasMultiRow && !isMultiRow) {
3534 $el.removeClass(`${params.containerModifierClass}multirow ${params.containerModifierClass}multirow-column`);
3535 } else if (!wasMultiRow && isMultiRow) {
3536 $el.addClass(`${params.containerModifierClass}multirow`);
3537 if (breakpointParams.slidesPerColumnFill === 'column') {
3538 $el.addClass(`${params.containerModifierClass}multirow-column`);
3539 }
3540 }
3541
3542 const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
3543 const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
3544
3545 if (directionChanged && initialized) {
3546 swiper.changeDirection();
3547 }
3548
3549 Utils.extend(swiper.params, breakpointParams);
3550
3551 Utils.extend(swiper, {
3552 allowTouchMove: swiper.params.allowTouchMove,
3553 allowSlideNext: swiper.params.allowSlideNext,
3554 allowSlidePrev: swiper.params.allowSlidePrev,
3555 });
3556
3557 swiper.currentBreakpoint = breakpoint;
3558
3559 if (needsReLoop && initialized) {
3560 swiper.loopDestroy();
3561 swiper.loopCreate();
3562 swiper.updateSlides();
3563 swiper.slideTo((activeIndex - loopedSlides) + swiper.loopedSlides, 0, false);
3564 }
3565
3566 swiper.emit('breakpoint', breakpointParams);
3567 }
3568}
3569
3570function getBreakpoint (breakpoints) {
3571 // Get breakpoint for window width
3572 if (!breakpoints) return undefined;
3573 let breakpoint = false;
3574
3575 const points = Object.keys(breakpoints).map((point) => {
3576 if (typeof point === 'string' && point.indexOf('@') === 0) {
3577 const minRatio = parseFloat(point.substr(1));
3578 const value = win.innerHeight * minRatio;
3579 return { value, point };
3580 }
3581 return { value: point, point };
3582 });
3583
3584 points.sort((a, b) => parseInt(a.value, 10) - parseInt(b.value, 10));
3585 for (let i = 0; i < points.length; i += 1) {
3586 const { point, value } = points[i];
3587 if (value <= win.innerWidth) {
3588 breakpoint = point;
3589 }
3590 }
3591 return breakpoint || 'max';
3592}
3593
3594var breakpoints = { setBreakpoint, getBreakpoint };
3595
3596function addClasses () {
3597 const swiper = this;
3598 const {
3599 classNames, params, rtl, $el,
3600 } = swiper;
3601 const suffixes = [];
3602
3603 suffixes.push('initialized');
3604 suffixes.push(params.direction);
3605
3606 if (params.freeMode) {
3607 suffixes.push('free-mode');
3608 }
3609 if (params.autoHeight) {
3610 suffixes.push('autoheight');
3611 }
3612 if (rtl) {
3613 suffixes.push('rtl');
3614 }
3615 if (params.slidesPerColumn > 1) {
3616 suffixes.push('multirow');
3617 if (params.slidesPerColumnFill === 'column') {
3618 suffixes.push('multirow-column');
3619 }
3620 }
3621 if (Device.android) {
3622 suffixes.push('android');
3623 }
3624 if (Device.ios) {
3625 suffixes.push('ios');
3626 }
3627
3628 if (params.cssMode) {
3629 suffixes.push('css-mode');
3630 }
3631
3632 suffixes.forEach((suffix) => {
3633 classNames.push(params.containerModifierClass + suffix);
3634 });
3635
3636 $el.addClass(classNames.join(' '));
3637}
3638
3639function removeClasses () {
3640 const swiper = this;
3641 const { $el, classNames } = swiper;
3642
3643 $el.removeClass(classNames.join(' '));
3644}
3645
3646var classes = { addClasses, removeClasses };
3647
3648function loadImage (imageEl, src, srcset, sizes, checkForComplete, callback) {
3649 let image;
3650 function onReady() {
3651 if (callback) callback();
3652 }
3653 const isPicture = $(imageEl).parent('picture')[0];
3654
3655 if (!isPicture && (!imageEl.complete || !checkForComplete)) {
3656 if (src) {
3657 image = new win.Image();
3658 image.onload = onReady;
3659 image.onerror = onReady;
3660 if (sizes) {
3661 image.sizes = sizes;
3662 }
3663 if (srcset) {
3664 image.srcset = srcset;
3665 }
3666 if (src) {
3667 image.src = src;
3668 }
3669 } else {
3670 onReady();
3671 }
3672 } else {
3673 // image already loaded...
3674 onReady();
3675 }
3676}
3677
3678function preloadImages () {
3679 const swiper = this;
3680 swiper.imagesToLoad = swiper.$el.find('img');
3681 function onReady() {
3682 if (typeof swiper === 'undefined' || swiper === null || !swiper || swiper.destroyed) return;
3683 if (swiper.imagesLoaded !== undefined) swiper.imagesLoaded += 1;
3684 if (swiper.imagesLoaded === swiper.imagesToLoad.length) {
3685 if (swiper.params.updateOnImagesReady) swiper.update();
3686 swiper.emit('imagesReady');
3687 }
3688 }
3689 for (let i = 0; i < swiper.imagesToLoad.length; i += 1) {
3690 const imageEl = swiper.imagesToLoad[i];
3691 swiper.loadImage(
3692 imageEl,
3693 imageEl.currentSrc || imageEl.getAttribute('src'),
3694 imageEl.srcset || imageEl.getAttribute('srcset'),
3695 imageEl.sizes || imageEl.getAttribute('sizes'),
3696 true,
3697 onReady
3698 );
3699 }
3700}
3701
3702var images = {
3703 loadImage,
3704 preloadImages,
3705};
3706
3707function checkOverflow() {
3708 const swiper = this;
3709 const params = swiper.params;
3710 const wasLocked = swiper.isLocked;
3711 const lastSlidePosition = swiper.slides.length > 0 && (params.slidesOffsetBefore + (params.spaceBetween * (swiper.slides.length - 1)) + ((swiper.slides[0]).offsetWidth) * swiper.slides.length);
3712
3713 if (params.slidesOffsetBefore && params.slidesOffsetAfter && lastSlidePosition) {
3714 swiper.isLocked = lastSlidePosition <= swiper.size;
3715 } else {
3716 swiper.isLocked = swiper.snapGrid.length === 1;
3717 }
3718
3719 swiper.allowSlideNext = !swiper.isLocked;
3720 swiper.allowSlidePrev = !swiper.isLocked;
3721
3722 // events
3723 if (wasLocked !== swiper.isLocked) swiper.emit(swiper.isLocked ? 'lock' : 'unlock');
3724
3725 if (wasLocked && wasLocked !== swiper.isLocked) {
3726 swiper.isEnd = false;
3727 swiper.navigation.update();
3728 }
3729}
3730
3731var checkOverflow$1 = { checkOverflow };
3732
3733var defaults = {
3734 init: true,
3735 direction: 'horizontal',
3736 touchEventsTarget: 'container',
3737 initialSlide: 0,
3738 speed: 300,
3739 cssMode: false,
3740 updateOnWindowResize: true,
3741 //
3742 preventInteractionOnTransition: false,
3743
3744 // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
3745 edgeSwipeDetection: false,
3746 edgeSwipeThreshold: 20,
3747
3748 // Free mode
3749 freeMode: false,
3750 freeModeMomentum: true,
3751 freeModeMomentumRatio: 1,
3752 freeModeMomentumBounce: true,
3753 freeModeMomentumBounceRatio: 1,
3754 freeModeMomentumVelocityRatio: 1,
3755 freeModeSticky: false,
3756 freeModeMinimumVelocity: 0.02,
3757
3758 // Autoheight
3759 autoHeight: false,
3760
3761 // Set wrapper width
3762 setWrapperSize: false,
3763
3764 // Virtual Translate
3765 virtualTranslate: false,
3766
3767 // Effects
3768 effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
3769
3770 // Breakpoints
3771 breakpoints: undefined,
3772
3773 // Slides grid
3774 spaceBetween: 0,
3775 slidesPerView: 1,
3776 slidesPerColumn: 1,
3777 slidesPerColumnFill: 'column',
3778 slidesPerGroup: 1,
3779 slidesPerGroupSkip: 0,
3780 centeredSlides: false,
3781 centeredSlidesBounds: false,
3782 slidesOffsetBefore: 0, // in px
3783 slidesOffsetAfter: 0, // in px
3784 normalizeSlideIndex: true,
3785 centerInsufficientSlides: false,
3786
3787 // Disable swiper and hide navigation when container not overflow
3788 watchOverflow: false,
3789
3790 // Round length
3791 roundLengths: false,
3792
3793 // Touches
3794 touchRatio: 1,
3795 touchAngle: 45,
3796 simulateTouch: true,
3797 shortSwipes: true,
3798 longSwipes: true,
3799 longSwipesRatio: 0.5,
3800 longSwipesMs: 300,
3801 followFinger: true,
3802 allowTouchMove: true,
3803 threshold: 0,
3804 touchMoveStopPropagation: false,
3805 touchStartPreventDefault: true,
3806 touchStartForcePreventDefault: false,
3807 touchReleaseOnEdges: false,
3808
3809 // Unique Navigation Elements
3810 uniqueNavElements: true,
3811
3812 // Resistance
3813 resistance: true,
3814 resistanceRatio: 0.85,
3815
3816 // Progress
3817 watchSlidesProgress: false,
3818 watchSlidesVisibility: false,
3819
3820 // Cursor
3821 grabCursor: false,
3822
3823 // Clicks
3824 preventClicks: true,
3825 preventClicksPropagation: true,
3826 slideToClickedSlide: false,
3827
3828 // Images
3829 preloadImages: true,
3830 updateOnImagesReady: true,
3831
3832 // loop
3833 loop: false,
3834 loopAdditionalSlides: 0,
3835 loopedSlides: null,
3836 loopFillGroupWithBlank: false,
3837
3838 // Swiping/no swiping
3839 allowSlidePrev: true,
3840 allowSlideNext: true,
3841 swipeHandler: null, // '.swipe-handler',
3842 noSwiping: true,
3843 noSwipingClass: 'swiper-no-swiping',
3844 noSwipingSelector: null,
3845
3846 // Passive Listeners
3847 passiveListeners: true,
3848
3849 // NS
3850 containerModifierClass: 'swiper-container-', // NEW
3851 slideClass: 'swiper-slide',
3852 slideBlankClass: 'swiper-slide-invisible-blank',
3853 slideActiveClass: 'swiper-slide-active',
3854 slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
3855 slideVisibleClass: 'swiper-slide-visible',
3856 slideDuplicateClass: 'swiper-slide-duplicate',
3857 slideNextClass: 'swiper-slide-next',
3858 slideDuplicateNextClass: 'swiper-slide-duplicate-next',
3859 slidePrevClass: 'swiper-slide-prev',
3860 slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
3861 wrapperClass: 'swiper-wrapper',
3862
3863 // Callbacks
3864 runCallbacksOnInit: true,
3865};
3866
3867/* eslint no-param-reassign: "off" */
3868
3869const prototypes = {
3870 update,
3871 translate,
3872 transition: transition$1,
3873 slide,
3874 loop,
3875 grabCursor,
3876 manipulation,
3877 events,
3878 breakpoints,
3879 checkOverflow: checkOverflow$1,
3880 classes,
3881 images,
3882};
3883
3884const extendedDefaults = {};
3885
3886class Swiper extends SwiperClass {
3887 constructor(...args) {
3888 let el;
3889 let params;
3890 if (args.length === 1 && args[0].constructor && args[0].constructor === Object) {
3891 params = args[0];
3892 } else {
3893 [el, params] = args;
3894 }
3895 if (!params) params = {};
3896
3897 params = Utils.extend({}, params);
3898 if (el && !params.el) params.el = el;
3899
3900 super(params);
3901
3902 Object.keys(prototypes).forEach((prototypeGroup) => {
3903 Object.keys(prototypes[prototypeGroup]).forEach((protoMethod) => {
3904 if (!Swiper.prototype[protoMethod]) {
3905 Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
3906 }
3907 });
3908 });
3909
3910 // Swiper Instance
3911 const swiper = this;
3912 if (typeof swiper.modules === 'undefined') {
3913 swiper.modules = {};
3914 }
3915 Object.keys(swiper.modules).forEach((moduleName) => {
3916 const module = swiper.modules[moduleName];
3917 if (module.params) {
3918 const moduleParamName = Object.keys(module.params)[0];
3919 const moduleParams = module.params[moduleParamName];
3920 if (typeof moduleParams !== 'object' || moduleParams === null) return;
3921 if (!(moduleParamName in params && 'enabled' in moduleParams)) return;
3922 if (params[moduleParamName] === true) {
3923 params[moduleParamName] = { enabled: true };
3924 }
3925 if (
3926 typeof params[moduleParamName] === 'object'
3927 && !('enabled' in params[moduleParamName])
3928 ) {
3929 params[moduleParamName].enabled = true;
3930 }
3931 if (!params[moduleParamName]) params[moduleParamName] = { enabled: false };
3932 }
3933 });
3934
3935 // Extend defaults with modules params
3936 const swiperParams = Utils.extend({}, defaults);
3937 swiper.useModulesParams(swiperParams);
3938
3939 // Extend defaults with passed params
3940 swiper.params = Utils.extend({}, swiperParams, extendedDefaults, params);
3941 swiper.originalParams = Utils.extend({}, swiper.params);
3942 swiper.passedParams = Utils.extend({}, params);
3943
3944 // Save Dom lib
3945 swiper.$ = $;
3946
3947 // Find el
3948 const $el = $(swiper.params.el);
3949 el = $el[0];
3950
3951 if (!el) {
3952 return undefined;
3953 }
3954
3955 if ($el.length > 1) {
3956 const swipers = [];
3957 $el.each((index, containerEl) => {
3958 const newParams = Utils.extend({}, params, { el: containerEl });
3959 swipers.push(new Swiper(newParams));
3960 });
3961 return swipers;
3962 }
3963
3964 el.swiper = swiper;
3965 $el.data('swiper', swiper);
3966
3967 // Find Wrapper
3968 let $wrapperEl;
3969 if (el && el.shadowRoot && el.shadowRoot.querySelector) {
3970 $wrapperEl = $(el.shadowRoot.querySelector(`.${swiper.params.wrapperClass}`));
3971 // Children needs to return slot items
3972 $wrapperEl.children = (options) => $el.children(options);
3973 } else {
3974 $wrapperEl = $el.children(`.${swiper.params.wrapperClass}`);
3975 }
3976 // Extend Swiper
3977 Utils.extend(swiper, {
3978 $el,
3979 el,
3980 $wrapperEl,
3981 wrapperEl: $wrapperEl[0],
3982
3983 // Classes
3984 classNames: [],
3985
3986 // Slides
3987 slides: $(),
3988 slidesGrid: [],
3989 snapGrid: [],
3990 slidesSizesGrid: [],
3991
3992 // isDirection
3993 isHorizontal() {
3994 return swiper.params.direction === 'horizontal';
3995 },
3996 isVertical() {
3997 return swiper.params.direction === 'vertical';
3998 },
3999 // RTL
4000 rtl: (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
4001 rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
4002 wrongRTL: $wrapperEl.css('display') === '-webkit-box',
4003
4004 // Indexes
4005 activeIndex: 0,
4006 realIndex: 0,
4007
4008 //
4009 isBeginning: true,
4010 isEnd: false,
4011
4012 // Props
4013 translate: 0,
4014 previousTranslate: 0,
4015 progress: 0,
4016 velocity: 0,
4017 animating: false,
4018
4019 // Locks
4020 allowSlideNext: swiper.params.allowSlideNext,
4021 allowSlidePrev: swiper.params.allowSlidePrev,
4022
4023 // Touch Events
4024 touchEvents: (function touchEvents() {
4025 const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
4026 let desktop = ['mousedown', 'mousemove', 'mouseup'];
4027 if (Support.pointerEvents) {
4028 desktop = ['pointerdown', 'pointermove', 'pointerup'];
4029 }
4030 swiper.touchEventsTouch = {
4031 start: touch[0],
4032 move: touch[1],
4033 end: touch[2],
4034 cancel: touch[3],
4035 };
4036 swiper.touchEventsDesktop = {
4037 start: desktop[0],
4038 move: desktop[1],
4039 end: desktop[2],
4040 };
4041 return Support.touch || !swiper.params.simulateTouch ? swiper.touchEventsTouch : swiper.touchEventsDesktop;
4042 }()),
4043 touchEventsData: {
4044 isTouched: undefined,
4045 isMoved: undefined,
4046 allowTouchCallbacks: undefined,
4047 touchStartTime: undefined,
4048 isScrolling: undefined,
4049 currentTranslate: undefined,
4050 startTranslate: undefined,
4051 allowThresholdMove: undefined,
4052 // Form elements to match
4053 formElements: 'input, select, option, textarea, button, video, label',
4054 // Last click time
4055 lastClickTime: Utils.now(),
4056 clickTimeout: undefined,
4057 // Velocities
4058 velocities: [],
4059 allowMomentumBounce: undefined,
4060 isTouchEvent: undefined,
4061 startMoving: undefined,
4062 },
4063
4064 // Clicks
4065 allowClick: true,
4066
4067 // Touches
4068 allowTouchMove: swiper.params.allowTouchMove,
4069
4070 touches: {
4071 startX: 0,
4072 startY: 0,
4073 currentX: 0,
4074 currentY: 0,
4075 diff: 0,
4076 },
4077
4078 // Images
4079 imagesToLoad: [],
4080 imagesLoaded: 0,
4081
4082 });
4083
4084 // Install Modules
4085 swiper.useModules();
4086
4087 // Init
4088 if (swiper.params.init) {
4089 swiper.init();
4090 }
4091
4092 // Return app instance
4093 return swiper;
4094 }
4095
4096 slidesPerViewDynamic() {
4097 const swiper = this;
4098 const {
4099 params, slides, slidesGrid, size: swiperSize, activeIndex,
4100 } = swiper;
4101 let spv = 1;
4102 if (params.centeredSlides) {
4103 let slideSize = slides[activeIndex].swiperSlideSize;
4104 let breakLoop;
4105 for (let i = activeIndex + 1; i < slides.length; i += 1) {
4106 if (slides[i] && !breakLoop) {
4107 slideSize += slides[i].swiperSlideSize;
4108 spv += 1;
4109 if (slideSize > swiperSize) breakLoop = true;
4110 }
4111 }
4112 for (let i = activeIndex - 1; i >= 0; i -= 1) {
4113 if (slides[i] && !breakLoop) {
4114 slideSize += slides[i].swiperSlideSize;
4115 spv += 1;
4116 if (slideSize > swiperSize) breakLoop = true;
4117 }
4118 }
4119 } else {
4120 for (let i = activeIndex + 1; i < slides.length; i += 1) {
4121 if (slidesGrid[i] - slidesGrid[activeIndex] < swiperSize) {
4122 spv += 1;
4123 }
4124 }
4125 }
4126 return spv;
4127 }
4128
4129 update() {
4130 const swiper = this;
4131 if (!swiper || swiper.destroyed) return;
4132 const { snapGrid, params } = swiper;
4133 // Breakpoints
4134 if (params.breakpoints) {
4135 swiper.setBreakpoint();
4136 }
4137 swiper.updateSize();
4138 swiper.updateSlides();
4139 swiper.updateProgress();
4140 swiper.updateSlidesClasses();
4141
4142 function setTranslate() {
4143 const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;
4144 const newTranslate = Math.min(Math.max(translateValue, swiper.maxTranslate()), swiper.minTranslate());
4145 swiper.setTranslate(newTranslate);
4146 swiper.updateActiveIndex();
4147 swiper.updateSlidesClasses();
4148 }
4149 let translated;
4150 if (swiper.params.freeMode) {
4151 setTranslate();
4152 if (swiper.params.autoHeight) {
4153 swiper.updateAutoHeight();
4154 }
4155 } else {
4156 if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
4157 translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
4158 } else {
4159 translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4160 }
4161 if (!translated) {
4162 setTranslate();
4163 }
4164 }
4165 if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
4166 swiper.checkOverflow();
4167 }
4168 swiper.emit('update');
4169 }
4170
4171 changeDirection(newDirection, needUpdate = true) {
4172 const swiper = this;
4173 const currentDirection = swiper.params.direction;
4174 if (!newDirection) {
4175 // eslint-disable-next-line
4176 newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
4177 }
4178 if ((newDirection === currentDirection) || (newDirection !== 'horizontal' && newDirection !== 'vertical')) {
4179 return swiper;
4180 }
4181
4182 swiper.$el
4183 .removeClass(`${swiper.params.containerModifierClass}${currentDirection}`)
4184 .addClass(`${swiper.params.containerModifierClass}${newDirection}`);
4185
4186 swiper.params.direction = newDirection;
4187
4188 swiper.slides.each((slideIndex, slideEl) => {
4189 if (newDirection === 'vertical') {
4190 slideEl.style.width = '';
4191 } else {
4192 slideEl.style.height = '';
4193 }
4194 });
4195
4196 swiper.emit('changeDirection');
4197 if (needUpdate) swiper.update();
4198
4199 return swiper;
4200 }
4201
4202 init() {
4203 const swiper = this;
4204 if (swiper.initialized) return;
4205
4206 swiper.emit('beforeInit');
4207
4208 // Set breakpoint
4209 if (swiper.params.breakpoints) {
4210 swiper.setBreakpoint();
4211 }
4212
4213 // Add Classes
4214 swiper.addClasses();
4215
4216 // Create loop
4217 if (swiper.params.loop) {
4218 swiper.loopCreate();
4219 }
4220
4221 // Update size
4222 swiper.updateSize();
4223
4224 // Update slides
4225 swiper.updateSlides();
4226
4227 if (swiper.params.watchOverflow) {
4228 swiper.checkOverflow();
4229 }
4230
4231 // Set Grab Cursor
4232 if (swiper.params.grabCursor) {
4233 swiper.setGrabCursor();
4234 }
4235
4236 if (swiper.params.preloadImages) {
4237 swiper.preloadImages();
4238 }
4239
4240 // Slide To Initial Slide
4241 if (swiper.params.loop) {
4242 swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit);
4243 } else {
4244 swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit);
4245 }
4246
4247 // Attach events
4248 swiper.attachEvents();
4249
4250 // Init Flag
4251 swiper.initialized = true;
4252
4253 // Emit
4254 swiper.emit('init');
4255 }
4256
4257 destroy(deleteInstance = true, cleanStyles = true) {
4258 const swiper = this;
4259 const {
4260 params, $el, $wrapperEl, slides,
4261 } = swiper;
4262
4263 if (typeof swiper.params === 'undefined' || swiper.destroyed) {
4264 return null;
4265 }
4266
4267 swiper.emit('beforeDestroy');
4268
4269 // Init Flag
4270 swiper.initialized = false;
4271
4272 // Detach events
4273 swiper.detachEvents();
4274
4275 // Destroy loop
4276 if (params.loop) {
4277 swiper.loopDestroy();
4278 }
4279
4280 // Cleanup styles
4281 if (cleanStyles) {
4282 swiper.removeClasses();
4283 $el.removeAttr('style');
4284 $wrapperEl.removeAttr('style');
4285 if (slides && slides.length) {
4286 slides
4287 .removeClass([
4288 params.slideVisibleClass,
4289 params.slideActiveClass,
4290 params.slideNextClass,
4291 params.slidePrevClass,
4292 ].join(' '))
4293 .removeAttr('style')
4294 .removeAttr('data-swiper-slide-index');
4295 }
4296 }
4297
4298 swiper.emit('destroy');
4299
4300 // Detach emitter events
4301 Object.keys(swiper.eventsListeners).forEach((eventName) => {
4302 swiper.off(eventName);
4303 });
4304
4305 if (deleteInstance !== false) {
4306 swiper.$el[0].swiper = null;
4307 swiper.$el.data('swiper', null);
4308 Utils.deleteProps(swiper);
4309 }
4310 swiper.destroyed = true;
4311
4312 return null;
4313 }
4314
4315 static extendDefaults(newDefaults) {
4316 Utils.extend(extendedDefaults, newDefaults);
4317 }
4318
4319 static get extendedDefaults() {
4320 return extendedDefaults;
4321 }
4322
4323 static get defaults() {
4324 return defaults;
4325 }
4326
4327 static get Class() {
4328 return SwiperClass;
4329 }
4330
4331 static get $() {
4332 return $;
4333 }
4334}
4335
4336var Device$1 = {
4337 name: 'device',
4338 proto: {
4339 device: Device,
4340 },
4341 static: {
4342 device: Device,
4343 },
4344};
4345
4346var Support$1 = {
4347 name: 'support',
4348 proto: {
4349 support: Support,
4350 },
4351 static: {
4352 support: Support,
4353 },
4354};
4355
4356const Browser = (function Browser() {
4357 function isSafari() {
4358 const ua = win.navigator.userAgent.toLowerCase();
4359 return (ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0);
4360 }
4361 return {
4362 isEdge: !!win.navigator.userAgent.match(/Edge/g),
4363 isSafari: isSafari(),
4364 isUiWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(win.navigator.userAgent),
4365 };
4366}());
4367
4368var Browser$1 = {
4369 name: 'browser',
4370 proto: {
4371 browser: Browser,
4372 },
4373 static: {
4374 browser: Browser,
4375 },
4376};
4377
4378var Resize = {
4379 name: 'resize',
4380 create() {
4381 const swiper = this;
4382 Utils.extend(swiper, {
4383 resize: {
4384 resizeHandler() {
4385 if (!swiper || swiper.destroyed || !swiper.initialized) return;
4386 swiper.emit('beforeResize');
4387 swiper.emit('resize');
4388 },
4389 orientationChangeHandler() {
4390 if (!swiper || swiper.destroyed || !swiper.initialized) return;
4391 swiper.emit('orientationchange');
4392 },
4393 },
4394 });
4395 },
4396 on: {
4397 init() {
4398 const swiper = this;
4399 // Emit resize
4400 win.addEventListener('resize', swiper.resize.resizeHandler);
4401
4402 // Emit orientationchange
4403 win.addEventListener('orientationchange', swiper.resize.orientationChangeHandler);
4404 },
4405 destroy() {
4406 const swiper = this;
4407 win.removeEventListener('resize', swiper.resize.resizeHandler);
4408 win.removeEventListener('orientationchange', swiper.resize.orientationChangeHandler);
4409 },
4410 },
4411};
4412
4413const Observer = {
4414 func: win.MutationObserver || win.WebkitMutationObserver,
4415 attach(target, options = {}) {
4416 const swiper = this;
4417
4418 const ObserverFunc = Observer.func;
4419 const observer = new ObserverFunc((mutations) => {
4420 // The observerUpdate event should only be triggered
4421 // once despite the number of mutations. Additional
4422 // triggers are redundant and are very costly
4423 if (mutations.length === 1) {
4424 swiper.emit('observerUpdate', mutations[0]);
4425 return;
4426 }
4427 const observerUpdate = function observerUpdate() {
4428 swiper.emit('observerUpdate', mutations[0]);
4429 };
4430
4431 if (win.requestAnimationFrame) {
4432 win.requestAnimationFrame(observerUpdate);
4433 } else {
4434 win.setTimeout(observerUpdate, 0);
4435 }
4436 });
4437
4438 observer.observe(target, {
4439 attributes: typeof options.attributes === 'undefined' ? true : options.attributes,
4440 childList: typeof options.childList === 'undefined' ? true : options.childList,
4441 characterData: typeof options.characterData === 'undefined' ? true : options.characterData,
4442 });
4443
4444 swiper.observer.observers.push(observer);
4445 },
4446 init() {
4447 const swiper = this;
4448 if (!Support.observer || !swiper.params.observer) return;
4449 if (swiper.params.observeParents) {
4450 const containerParents = swiper.$el.parents();
4451 for (let i = 0; i < containerParents.length; i += 1) {
4452 swiper.observer.attach(containerParents[i]);
4453 }
4454 }
4455 // Observe container
4456 swiper.observer.attach(swiper.$el[0], { childList: swiper.params.observeSlideChildren });
4457
4458 // Observe wrapper
4459 swiper.observer.attach(swiper.$wrapperEl[0], { attributes: false });
4460 },
4461 destroy() {
4462 const swiper = this;
4463 swiper.observer.observers.forEach((observer) => {
4464 observer.disconnect();
4465 });
4466 swiper.observer.observers = [];
4467 },
4468};
4469
4470var Observer$1 = {
4471 name: 'observer',
4472 params: {
4473 observer: false,
4474 observeParents: false,
4475 observeSlideChildren: false,
4476 },
4477 create() {
4478 const swiper = this;
4479 Utils.extend(swiper, {
4480 observer: {
4481 init: Observer.init.bind(swiper),
4482 attach: Observer.attach.bind(swiper),
4483 destroy: Observer.destroy.bind(swiper),
4484 observers: [],
4485 },
4486 });
4487 },
4488 on: {
4489 init() {
4490 const swiper = this;
4491 swiper.observer.init();
4492 },
4493 destroy() {
4494 const swiper = this;
4495 swiper.observer.destroy();
4496 },
4497 },
4498};
4499
4500const Keyboard = {
4501 handle(event) {
4502 const swiper = this;
4503 const { rtlTranslate: rtl } = swiper;
4504 let e = event;
4505 if (e.originalEvent) e = e.originalEvent; // jquery fix
4506 const kc = e.keyCode || e.charCode;
4507 // Directions locks
4508 if (!swiper.allowSlideNext && ((swiper.isHorizontal() && kc === 39) || (swiper.isVertical() && kc === 40) || kc === 34)) {
4509 return false;
4510 }
4511 if (!swiper.allowSlidePrev && ((swiper.isHorizontal() && kc === 37) || (swiper.isVertical() && kc === 38) || kc === 33)) {
4512 return false;
4513 }
4514 if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {
4515 return undefined;
4516 }
4517 if (doc.activeElement && doc.activeElement.nodeName && (doc.activeElement.nodeName.toLowerCase() === 'input' || doc.activeElement.nodeName.toLowerCase() === 'textarea')) {
4518 return undefined;
4519 }
4520 if (swiper.params.keyboard.onlyInViewport && (kc === 33 || kc === 34 || kc === 37 || kc === 39 || kc === 38 || kc === 40)) {
4521 let inView = false;
4522 // Check that swiper should be inside of visible area of window
4523 if (swiper.$el.parents(`.${swiper.params.slideClass}`).length > 0 && swiper.$el.parents(`.${swiper.params.slideActiveClass}`).length === 0) {
4524 return undefined;
4525 }
4526 const windowWidth = win.innerWidth;
4527 const windowHeight = win.innerHeight;
4528 const swiperOffset = swiper.$el.offset();
4529 if (rtl) swiperOffset.left -= swiper.$el[0].scrollLeft;
4530 const swiperCoord = [
4531 [swiperOffset.left, swiperOffset.top],
4532 [swiperOffset.left + swiper.width, swiperOffset.top],
4533 [swiperOffset.left, swiperOffset.top + swiper.height],
4534 [swiperOffset.left + swiper.width, swiperOffset.top + swiper.height],
4535 ];
4536 for (let i = 0; i < swiperCoord.length; i += 1) {
4537 const point = swiperCoord[i];
4538 if (
4539 point[0] >= 0 && point[0] <= windowWidth
4540 && point[1] >= 0 && point[1] <= windowHeight
4541 ) {
4542 inView = true;
4543 }
4544 }
4545 if (!inView) return undefined;
4546 }
4547 if (swiper.isHorizontal()) {
4548 if (kc === 33 || kc === 34 || kc === 37 || kc === 39) {
4549 if (e.preventDefault) e.preventDefault();
4550 else e.returnValue = false;
4551 }
4552 if (((kc === 34 || kc === 39) && !rtl) || ((kc === 33 || kc === 37) && rtl)) swiper.slideNext();
4553 if (((kc === 33 || kc === 37) && !rtl) || ((kc === 34 || kc === 39) && rtl)) swiper.slidePrev();
4554 } else {
4555 if (kc === 33 || kc === 34 || kc === 38 || kc === 40) {
4556 if (e.preventDefault) e.preventDefault();
4557 else e.returnValue = false;
4558 }
4559 if (kc === 34 || kc === 40) swiper.slideNext();
4560 if (kc === 33 || kc === 38) swiper.slidePrev();
4561 }
4562 swiper.emit('keyPress', kc);
4563 return undefined;
4564 },
4565 enable() {
4566 const swiper = this;
4567 if (swiper.keyboard.enabled) return;
4568 $(doc).on('keydown', swiper.keyboard.handle);
4569 swiper.keyboard.enabled = true;
4570 },
4571 disable() {
4572 const swiper = this;
4573 if (!swiper.keyboard.enabled) return;
4574 $(doc).off('keydown', swiper.keyboard.handle);
4575 swiper.keyboard.enabled = false;
4576 },
4577};
4578
4579var keyboard = {
4580 name: 'keyboard',
4581 params: {
4582 keyboard: {
4583 enabled: false,
4584 onlyInViewport: true,
4585 },
4586 },
4587 create() {
4588 const swiper = this;
4589 Utils.extend(swiper, {
4590 keyboard: {
4591 enabled: false,
4592 enable: Keyboard.enable.bind(swiper),
4593 disable: Keyboard.disable.bind(swiper),
4594 handle: Keyboard.handle.bind(swiper),
4595 },
4596 });
4597 },
4598 on: {
4599 init() {
4600 const swiper = this;
4601 if (swiper.params.keyboard.enabled) {
4602 swiper.keyboard.enable();
4603 }
4604 },
4605 destroy() {
4606 const swiper = this;
4607 if (swiper.keyboard.enabled) {
4608 swiper.keyboard.disable();
4609 }
4610 },
4611 },
4612};
4613
4614function isEventSupported() {
4615 const eventName = 'onwheel';
4616 let isSupported = eventName in doc;
4617
4618 if (!isSupported) {
4619 const element = doc.createElement('div');
4620 element.setAttribute(eventName, 'return;');
4621 isSupported = typeof element[eventName] === 'function';
4622 }
4623
4624 if (!isSupported
4625 && doc.implementation
4626 && doc.implementation.hasFeature
4627 // always returns true in newer browsers as per the standard.
4628 // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
4629 && doc.implementation.hasFeature('', '') !== true
4630 ) {
4631 // This is the only way to test support for the `wheel` event in IE9+.
4632 isSupported = doc.implementation.hasFeature('Events.wheel', '3.0');
4633 }
4634
4635 return isSupported;
4636}
4637const Mousewheel = {
4638 lastScrollTime: Utils.now(),
4639 lastEventBeforeSnap: undefined,
4640 recentWheelEvents: [],
4641 event() {
4642 if (win.navigator.userAgent.indexOf('firefox') > -1) return 'DOMMouseScroll';
4643 return isEventSupported() ? 'wheel' : 'mousewheel';
4644 },
4645 normalize(e) {
4646 // Reasonable defaults
4647 const PIXEL_STEP = 10;
4648 const LINE_HEIGHT = 40;
4649 const PAGE_HEIGHT = 800;
4650
4651 let sX = 0;
4652 let sY = 0; // spinX, spinY
4653 let pX = 0;
4654 let pY = 0; // pixelX, pixelY
4655
4656 // Legacy
4657 if ('detail' in e) {
4658 sY = e.detail;
4659 }
4660 if ('wheelDelta' in e) {
4661 sY = -e.wheelDelta / 120;
4662 }
4663 if ('wheelDeltaY' in e) {
4664 sY = -e.wheelDeltaY / 120;
4665 }
4666 if ('wheelDeltaX' in e) {
4667 sX = -e.wheelDeltaX / 120;
4668 }
4669
4670 // side scrolling on FF with DOMMouseScroll
4671 if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) {
4672 sX = sY;
4673 sY = 0;
4674 }
4675
4676 pX = sX * PIXEL_STEP;
4677 pY = sY * PIXEL_STEP;
4678
4679 if ('deltaY' in e) {
4680 pY = e.deltaY;
4681 }
4682 if ('deltaX' in e) {
4683 pX = e.deltaX;
4684 }
4685
4686 if (e.shiftKey && !pX) { // if user scrolls with shift he wants horizontal scroll
4687 pX = pY;
4688 pY = 0;
4689 }
4690
4691 if ((pX || pY) && e.deltaMode) {
4692 if (e.deltaMode === 1) { // delta in LINE units
4693 pX *= LINE_HEIGHT;
4694 pY *= LINE_HEIGHT;
4695 } else { // delta in PAGE units
4696 pX *= PAGE_HEIGHT;
4697 pY *= PAGE_HEIGHT;
4698 }
4699 }
4700
4701 // Fall-back if spin cannot be determined
4702 if (pX && !sX) {
4703 sX = (pX < 1) ? -1 : 1;
4704 }
4705 if (pY && !sY) {
4706 sY = (pY < 1) ? -1 : 1;
4707 }
4708
4709 return {
4710 spinX: sX,
4711 spinY: sY,
4712 pixelX: pX,
4713 pixelY: pY,
4714 };
4715 },
4716 handleMouseEnter() {
4717 const swiper = this;
4718 swiper.mouseEntered = true;
4719 },
4720 handleMouseLeave() {
4721 const swiper = this;
4722 swiper.mouseEntered = false;
4723 },
4724 handle(event) {
4725 let e = event;
4726 const swiper = this;
4727 const params = swiper.params.mousewheel;
4728
4729 if (swiper.params.cssMode) {
4730 e.preventDefault();
4731 }
4732
4733 let target = swiper.$el;
4734 if (swiper.params.mousewheel.eventsTarged !== 'container') {
4735 target = $(swiper.params.mousewheel.eventsTarged);
4736 }
4737 if (!swiper.mouseEntered && !target[0].contains(e.target) && !params.releaseOnEdges) return true;
4738
4739 if (e.originalEvent) e = e.originalEvent; // jquery fix
4740 let delta = 0;
4741 const rtlFactor = swiper.rtlTranslate ? -1 : 1;
4742
4743 const data = Mousewheel.normalize(e);
4744
4745 if (params.forceToAxis) {
4746 if (swiper.isHorizontal()) {
4747 if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = data.pixelX * rtlFactor;
4748 else return true;
4749 } else if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = data.pixelY;
4750 else return true;
4751 } else {
4752 delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? -data.pixelX * rtlFactor : -data.pixelY;
4753 }
4754
4755 if (delta === 0) return true;
4756
4757 if (params.invert) delta = -delta;
4758
4759 if (!swiper.params.freeMode) {
4760 // Register the new event in a variable which stores the relevant data
4761 const newEvent = {
4762 time: Utils.now(),
4763 delta: Math.abs(delta),
4764 direction: Math.sign(delta),
4765 raw: event,
4766 };
4767
4768 // Keep the most recent events
4769 const recentWheelEvents = swiper.mousewheel.recentWheelEvents;
4770 if (recentWheelEvents.length >= 2) {
4771 recentWheelEvents.shift(); // only store the last N events
4772 }
4773 const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;
4774 recentWheelEvents.push(newEvent);
4775
4776 // If there is at least one previous recorded event:
4777 // If direction has changed or
4778 // if the scroll is quicker than the previous one:
4779 // Animate the slider.
4780 // Else (this is the first time the wheel is moved):
4781 // Animate the slider.
4782 if (prevEvent) {
4783 if (newEvent.direction !== prevEvent.direction || newEvent.delta > prevEvent.delta || newEvent.time > prevEvent.time + 150) {
4784 swiper.mousewheel.animateSlider(newEvent);
4785 }
4786 } else {
4787 swiper.mousewheel.animateSlider(newEvent);
4788 }
4789
4790 // If it's time to release the scroll:
4791 // Return now so you don't hit the preventDefault.
4792 if (swiper.mousewheel.releaseScroll(newEvent)) {
4793 return true;
4794 }
4795 } else {
4796 // Freemode or scrollContainer:
4797
4798 // If we recently snapped after a momentum scroll, then ignore wheel events
4799 // to give time for the deceleration to finish. Stop ignoring after 500 msecs
4800 // or if it's a new scroll (larger delta or inverse sign as last event before
4801 // an end-of-momentum snap).
4802 const newEvent = { time: Utils.now(), delta: Math.abs(delta), direction: Math.sign(delta) };
4803 const { lastEventBeforeSnap } = swiper.mousewheel;
4804 const ignoreWheelEvents = lastEventBeforeSnap
4805 && newEvent.time < lastEventBeforeSnap.time + 500
4806 && newEvent.delta <= lastEventBeforeSnap.delta
4807 && newEvent.direction === lastEventBeforeSnap.direction;
4808 if (!ignoreWheelEvents) {
4809 swiper.mousewheel.lastEventBeforeSnap = undefined;
4810
4811 if (swiper.params.loop) {
4812 swiper.loopFix();
4813 }
4814 let position = swiper.getTranslate() + (delta * params.sensitivity);
4815 const wasBeginning = swiper.isBeginning;
4816 const wasEnd = swiper.isEnd;
4817
4818 if (position >= swiper.minTranslate()) position = swiper.minTranslate();
4819 if (position <= swiper.maxTranslate()) position = swiper.maxTranslate();
4820
4821 swiper.setTransition(0);
4822 swiper.setTranslate(position);
4823 swiper.updateProgress();
4824 swiper.updateActiveIndex();
4825 swiper.updateSlidesClasses();
4826
4827 if ((!wasBeginning && swiper.isBeginning) || (!wasEnd && swiper.isEnd)) {
4828 swiper.updateSlidesClasses();
4829 }
4830
4831 if (swiper.params.freeModeSticky) {
4832 // When wheel scrolling starts with sticky (aka snap) enabled, then detect
4833 // the end of a momentum scroll by storing recent (N=15?) wheel events.
4834 // 1. do all N events have decreasing or same (absolute value) delta?
4835 // 2. did all N events arrive in the last M (M=500?) msecs?
4836 // 3. does the earliest event have an (absolute value) delta that's
4837 // at least P (P=1?) larger than the most recent event's delta?
4838 // 4. does the latest event have a delta that's smaller than Q (Q=6?) pixels?
4839 // If 1-4 are "yes" then we're near the end of a momuntum scroll deceleration.
4840 // Snap immediately and ignore remaining wheel events in this scroll.
4841 // See comment above for "remaining wheel events in this scroll" determination.
4842 // If 1-4 aren't satisfied, then wait to snap until 500ms after the last event.
4843 clearTimeout(swiper.mousewheel.timeout);
4844 swiper.mousewheel.timeout = undefined;
4845 const recentWheelEvents = swiper.mousewheel.recentWheelEvents;
4846 if (recentWheelEvents.length >= 15) {
4847 recentWheelEvents.shift(); // only store the last N events
4848 }
4849 const prevEvent = recentWheelEvents.length ? recentWheelEvents[recentWheelEvents.length - 1] : undefined;
4850 const firstEvent = recentWheelEvents[0];
4851 recentWheelEvents.push(newEvent);
4852 if (prevEvent && (newEvent.delta > prevEvent.delta || newEvent.direction !== prevEvent.direction)) {
4853 // Increasing or reverse-sign delta means the user started scrolling again. Clear the wheel event log.
4854 recentWheelEvents.splice(0);
4855 } else if (recentWheelEvents.length >= 15
4856 && newEvent.time - firstEvent.time < 500
4857 && firstEvent.delta - newEvent.delta >= 1
4858 && newEvent.delta <= 6
4859 ) {
4860 // We're at the end of the deceleration of a momentum scroll, so there's no need
4861 // to wait for more events. Snap ASAP on the next tick.
4862 // Also, because there's some remaining momentum we'll bias the snap in the
4863 // direction of the ongoing scroll because it's better UX for the scroll to snap
4864 // in the same direction as the scroll instead of reversing to snap. Therefore,
4865 // if it's already scrolled more than 20% in the current direction, keep going.
4866 const snapToThreshold = delta > 0 ? 0.8 : 0.2;
4867 swiper.mousewheel.lastEventBeforeSnap = newEvent;
4868 recentWheelEvents.splice(0);
4869 swiper.mousewheel.timeout = Utils.nextTick(() => {
4870 swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);
4871 }, 0); // no delay; move on next tick
4872 }
4873 if (!swiper.mousewheel.timeout) {
4874 // if we get here, then we haven't detected the end of a momentum scroll, so
4875 // we'll consider a scroll "complete" when there haven't been any wheel events
4876 // for 500ms.
4877 swiper.mousewheel.timeout = Utils.nextTick(() => {
4878 const snapToThreshold = 0.5;
4879 swiper.mousewheel.lastEventBeforeSnap = newEvent;
4880 recentWheelEvents.splice(0);
4881 swiper.slideToClosest(swiper.params.speed, true, undefined, snapToThreshold);
4882 }, 500);
4883 }
4884 }
4885
4886 // Emit event
4887 if (!ignoreWheelEvents) swiper.emit('scroll', e);
4888
4889 // Stop autoplay
4890 if (swiper.params.autoplay && swiper.params.autoplayDisableOnInteraction) swiper.autoplay.stop();
4891 // Return page scroll on edge positions
4892 if (position === swiper.minTranslate() || position === swiper.maxTranslate()) return true;
4893 }
4894 }
4895
4896 if (e.preventDefault) e.preventDefault();
4897 else e.returnValue = false;
4898 return false;
4899 },
4900 animateSlider(newEvent) {
4901 const swiper = this;
4902 // If the movement is NOT big enough and
4903 // if the last time the user scrolled was too close to the current one (avoid continuously triggering the slider):
4904 // Don't go any further (avoid insignificant scroll movement).
4905 if (newEvent.delta >= 6 && Utils.now() - swiper.mousewheel.lastScrollTime < 60) {
4906 // Return false as a default
4907 return true;
4908 }
4909 // If user is scrolling towards the end:
4910 // If the slider hasn't hit the latest slide or
4911 // if the slider is a loop and
4912 // if the slider isn't moving right now:
4913 // Go to next slide and
4914 // emit a scroll event.
4915 // Else (the user is scrolling towards the beginning) and
4916 // if the slider hasn't hit the first slide or
4917 // if the slider is a loop and
4918 // if the slider isn't moving right now:
4919 // Go to prev slide and
4920 // emit a scroll event.
4921 if (newEvent.direction < 0) {
4922 if ((!swiper.isEnd || swiper.params.loop) && !swiper.animating) {
4923 swiper.slideNext();
4924 swiper.emit('scroll', newEvent.raw);
4925 }
4926 } else if ((!swiper.isBeginning || swiper.params.loop) && !swiper.animating) {
4927 swiper.slidePrev();
4928 swiper.emit('scroll', newEvent.raw);
4929 }
4930 // If you got here is because an animation has been triggered so store the current time
4931 swiper.mousewheel.lastScrollTime = (new win.Date()).getTime();
4932 // Return false as a default
4933 return false;
4934 },
4935 releaseScroll(newEvent) {
4936 const swiper = this;
4937 const params = swiper.params.mousewheel;
4938 if (newEvent.direction < 0) {
4939 if (swiper.isEnd && !swiper.params.loop && params.releaseOnEdges) {
4940 // Return true to animate scroll on edges
4941 return true;
4942 }
4943 } else if (swiper.isBeginning && !swiper.params.loop && params.releaseOnEdges) {
4944 // Return true to animate scroll on edges
4945 return true;
4946 }
4947 return false;
4948 },
4949 enable() {
4950 const swiper = this;
4951 const event = Mousewheel.event();
4952 if (swiper.params.cssMode) {
4953 swiper.wrapperEl.removeEventListener(event, swiper.mousewheel.handle);
4954 return true;
4955 }
4956 if (!event) return false;
4957 if (swiper.mousewheel.enabled) return false;
4958 let target = swiper.$el;
4959 if (swiper.params.mousewheel.eventsTarged !== 'container') {
4960 target = $(swiper.params.mousewheel.eventsTarged);
4961 }
4962 target.on('mouseenter', swiper.mousewheel.handleMouseEnter);
4963 target.on('mouseleave', swiper.mousewheel.handleMouseLeave);
4964 target.on(event, swiper.mousewheel.handle);
4965 swiper.mousewheel.enabled = true;
4966 return true;
4967 },
4968 disable() {
4969 const swiper = this;
4970 const event = Mousewheel.event();
4971 if (swiper.params.cssMode) {
4972 swiper.wrapperEl.addEventListener(event, swiper.mousewheel.handle);
4973 return true;
4974 }
4975 if (!event) return false;
4976 if (!swiper.mousewheel.enabled) return false;
4977 let target = swiper.$el;
4978 if (swiper.params.mousewheel.eventsTarged !== 'container') {
4979 target = $(swiper.params.mousewheel.eventsTarged);
4980 }
4981 target.off(event, swiper.mousewheel.handle);
4982 swiper.mousewheel.enabled = false;
4983 return true;
4984 },
4985};
4986
4987const Pagination = {
4988 update() {
4989 // Render || Update Pagination bullets/items
4990 const swiper = this;
4991 const rtl = swiper.rtl;
4992 const params = swiper.params.pagination;
4993 if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
4994 const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
4995 const $el = swiper.pagination.$el;
4996 // Current/Total
4997 let current;
4998 const total = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
4999 if (swiper.params.loop) {
5000 current = Math.ceil((swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup);
5001 if (current > slidesLength - 1 - (swiper.loopedSlides * 2)) {
5002 current -= (slidesLength - (swiper.loopedSlides * 2));
5003 }
5004 if (current > total - 1) current -= total;
5005 if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current;
5006 } else if (typeof swiper.snapIndex !== 'undefined') {
5007 current = swiper.snapIndex;
5008 } else {
5009 current = swiper.activeIndex || 0;
5010 }
5011 // Types
5012 if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) {
5013 const bullets = swiper.pagination.bullets;
5014 let firstIndex;
5015 let lastIndex;
5016 let midIndex;
5017 if (params.dynamicBullets) {
5018 swiper.pagination.bulletSize = bullets.eq(0)[swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'](true);
5019 $el.css(swiper.isHorizontal() ? 'width' : 'height', `${swiper.pagination.bulletSize * (params.dynamicMainBullets + 4)}px`);
5020 if (params.dynamicMainBullets > 1 && swiper.previousIndex !== undefined) {
5021 swiper.pagination.dynamicBulletIndex += (current - swiper.previousIndex);
5022 if (swiper.pagination.dynamicBulletIndex > (params.dynamicMainBullets - 1)) {
5023 swiper.pagination.dynamicBulletIndex = params.dynamicMainBullets - 1;
5024 } else if (swiper.pagination.dynamicBulletIndex < 0) {
5025 swiper.pagination.dynamicBulletIndex = 0;
5026 }
5027 }
5028 firstIndex = current - swiper.pagination.dynamicBulletIndex;
5029 lastIndex = firstIndex + (Math.min(bullets.length, params.dynamicMainBullets) - 1);
5030 midIndex = (lastIndex + firstIndex) / 2;
5031 }
5032 bullets.removeClass(`${params.bulletActiveClass} ${params.bulletActiveClass}-next ${params.bulletActiveClass}-next-next ${params.bulletActiveClass}-prev ${params.bulletActiveClass}-prev-prev ${params.bulletActiveClass}-main`);
5033 if ($el.length > 1) {
5034 bullets.each((index, bullet) => {
5035 const $bullet = $(bullet);
5036 const bulletIndex = $bullet.index();
5037 if (bulletIndex === current) {
5038 $bullet.addClass(params.bulletActiveClass);
5039 }
5040 if (params.dynamicBullets) {
5041 if (bulletIndex >= firstIndex && bulletIndex <= lastIndex) {
5042 $bullet.addClass(`${params.bulletActiveClass}-main`);
5043 }
5044 if (bulletIndex === firstIndex) {
5045 $bullet
5046 .prev()
5047 .addClass(`${params.bulletActiveClass}-prev`)
5048 .prev()
5049 .addClass(`${params.bulletActiveClass}-prev-prev`);
5050 }
5051 if (bulletIndex === lastIndex) {
5052 $bullet
5053 .next()
5054 .addClass(`${params.bulletActiveClass}-next`)
5055 .next()
5056 .addClass(`${params.bulletActiveClass}-next-next`);
5057 }
5058 }
5059 });
5060 } else {
5061 const $bullet = bullets.eq(current);
5062 const bulletIndex = $bullet.index();
5063 $bullet.addClass(params.bulletActiveClass);
5064 if (params.dynamicBullets) {
5065 const $firstDisplayedBullet = bullets.eq(firstIndex);
5066 const $lastDisplayedBullet = bullets.eq(lastIndex);
5067 for (let i = firstIndex; i <= lastIndex; i += 1) {
5068 bullets.eq(i).addClass(`${params.bulletActiveClass}-main`);
5069 }
5070 if (swiper.params.loop) {
5071 if (bulletIndex >= bullets.length - params.dynamicMainBullets) {
5072 for (let i = params.dynamicMainBullets; i >= 0; i -= 1) {
5073 bullets.eq(bullets.length - i).addClass(`${params.bulletActiveClass}-main`);
5074 }
5075 bullets.eq(bullets.length - params.dynamicMainBullets - 1).addClass(`${params.bulletActiveClass}-prev`);
5076 } else {
5077 $firstDisplayedBullet
5078 .prev()
5079 .addClass(`${params.bulletActiveClass}-prev`)
5080 .prev()
5081 .addClass(`${params.bulletActiveClass}-prev-prev`);
5082 $lastDisplayedBullet
5083 .next()
5084 .addClass(`${params.bulletActiveClass}-next`)
5085 .next()
5086 .addClass(`${params.bulletActiveClass}-next-next`);
5087 }
5088 } else {
5089 $firstDisplayedBullet
5090 .prev()
5091 .addClass(`${params.bulletActiveClass}-prev`)
5092 .prev()
5093 .addClass(`${params.bulletActiveClass}-prev-prev`);
5094 $lastDisplayedBullet
5095 .next()
5096 .addClass(`${params.bulletActiveClass}-next`)
5097 .next()
5098 .addClass(`${params.bulletActiveClass}-next-next`);
5099 }
5100 }
5101 }
5102 if (params.dynamicBullets) {
5103 const dynamicBulletsLength = Math.min(bullets.length, params.dynamicMainBullets + 4);
5104 const bulletsOffset = (((swiper.pagination.bulletSize * dynamicBulletsLength) - (swiper.pagination.bulletSize)) / 2) - (midIndex * swiper.pagination.bulletSize);
5105 const offsetProp = rtl ? 'right' : 'left';
5106 bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`);
5107 }
5108 }
5109 if (params.type === 'fraction') {
5110 $el.find(`.${params.currentClass}`).text(params.formatFractionCurrent(current + 1));
5111 $el.find(`.${params.totalClass}`).text(params.formatFractionTotal(total));
5112 }
5113 if (params.type === 'progressbar') {
5114 let progressbarDirection;
5115 if (params.progressbarOpposite) {
5116 progressbarDirection = swiper.isHorizontal() ? 'vertical' : 'horizontal';
5117 } else {
5118 progressbarDirection = swiper.isHorizontal() ? 'horizontal' : 'vertical';
5119 }
5120 const scale = (current + 1) / total;
5121 let scaleX = 1;
5122 let scaleY = 1;
5123 if (progressbarDirection === 'horizontal') {
5124 scaleX = scale;
5125 } else {
5126 scaleY = scale;
5127 }
5128 $el.find(`.${params.progressbarFillClass}`).transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`).transition(swiper.params.speed);
5129 }
5130 if (params.type === 'custom' && params.renderCustom) {
5131 $el.html(params.renderCustom(swiper, current + 1, total));
5132 swiper.emit('paginationRender', swiper, $el[0]);
5133 } else {
5134 swiper.emit('paginationUpdate', swiper, $el[0]);
5135 }
5136 $el[swiper.params.watchOverflow && swiper.isLocked ? 'addClass' : 'removeClass'](params.lockClass);
5137 },
5138 render() {
5139 // Render Container
5140 const swiper = this;
5141 const params = swiper.params.pagination;
5142 if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
5143 const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
5144
5145 const $el = swiper.pagination.$el;
5146 let paginationHTML = '';
5147 if (params.type === 'bullets') {
5148 const numberOfBullets = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
5149 for (let i = 0; i < numberOfBullets; i += 1) {
5150 if (params.renderBullet) {
5151 paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
5152 } else {
5153 paginationHTML += `<${params.bulletElement} class="${params.bulletClass}"></${params.bulletElement}>`;
5154 }
5155 }
5156 $el.html(paginationHTML);
5157 swiper.pagination.bullets = $el.find(`.${params.bulletClass}`);
5158 }
5159 if (params.type === 'fraction') {
5160 if (params.renderFraction) {
5161 paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
5162 } else {
5163 paginationHTML = `<span class="${params.currentClass}"></span>`
5164 + ' / '
5165 + `<span class="${params.totalClass}"></span>`;
5166 }
5167 $el.html(paginationHTML);
5168 }
5169 if (params.type === 'progressbar') {
5170 if (params.renderProgressbar) {
5171 paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
5172 } else {
5173 paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
5174 }
5175 $el.html(paginationHTML);
5176 }
5177 if (params.type !== 'custom') {
5178 swiper.emit('paginationRender', swiper.pagination.$el[0]);
5179 }
5180 },
5181 init() {
5182 const swiper = this;
5183 const params = swiper.params.pagination;
5184 if (!params.el) return;
5185
5186 let $el = $(params.el);
5187 if ($el.length === 0) return;
5188
5189 if (
5190 swiper.params.uniqueNavElements
5191 && typeof params.el === 'string'
5192 && $el.length > 1
5193 && swiper.$el.find(params.el).length === 1
5194 ) {
5195 $el = swiper.$el.find(params.el);
5196 }
5197
5198 if (params.type === 'bullets' && params.clickable) {
5199 $el.addClass(params.clickableClass);
5200 }
5201
5202 $el.addClass(params.modifierClass + params.type);
5203
5204 if (params.type === 'bullets' && params.dynamicBullets) {
5205 $el.addClass(`${params.modifierClass}${params.type}-dynamic`);
5206 swiper.pagination.dynamicBulletIndex = 0;
5207 if (params.dynamicMainBullets < 1) {
5208 params.dynamicMainBullets = 1;
5209 }
5210 }
5211 if (params.type === 'progressbar' && params.progressbarOpposite) {
5212 $el.addClass(params.progressbarOppositeClass);
5213 }
5214
5215 if (params.clickable) {
5216 $el.on('click', `.${params.bulletClass}`, function onClick(e) {
5217 e.preventDefault();
5218 let index = $(this).index() * swiper.params.slidesPerGroup;
5219 if (swiper.params.loop) index += swiper.loopedSlides;
5220 swiper.slideTo(index);
5221 });
5222 }
5223
5224 Utils.extend(swiper.pagination, {
5225 $el,
5226 el: $el[0],
5227 });
5228 },
5229 destroy() {
5230 const swiper = this;
5231 const params = swiper.params.pagination;
5232 if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
5233 const $el = swiper.pagination.$el;
5234
5235 $el.removeClass(params.hiddenClass);
5236 $el.removeClass(params.modifierClass + params.type);
5237 if (swiper.pagination.bullets) swiper.pagination.bullets.removeClass(params.bulletActiveClass);
5238 if (params.clickable) {
5239 $el.off('click', `.${params.bulletClass}`);
5240 }
5241 },
5242};
5243
5244var pagination = {
5245 name: 'pagination',
5246 params: {
5247 pagination: {
5248 el: null,
5249 bulletElement: 'span',
5250 clickable: false,
5251 hideOnClick: false,
5252 renderBullet: null,
5253 renderProgressbar: null,
5254 renderFraction: null,
5255 renderCustom: null,
5256 progressbarOpposite: false,
5257 type: 'bullets', // 'bullets' or 'progressbar' or 'fraction' or 'custom'
5258 dynamicBullets: false,
5259 dynamicMainBullets: 1,
5260 formatFractionCurrent: (number) => number,
5261 formatFractionTotal: (number) => number,
5262 bulletClass: 'swiper-pagination-bullet',
5263 bulletActiveClass: 'swiper-pagination-bullet-active',
5264 modifierClass: 'swiper-pagination-', // NEW
5265 currentClass: 'swiper-pagination-current',
5266 totalClass: 'swiper-pagination-total',
5267 hiddenClass: 'swiper-pagination-hidden',
5268 progressbarFillClass: 'swiper-pagination-progressbar-fill',
5269 progressbarOppositeClass: 'swiper-pagination-progressbar-opposite',
5270 clickableClass: 'swiper-pagination-clickable', // NEW
5271 lockClass: 'swiper-pagination-lock',
5272 },
5273 },
5274 create() {
5275 const swiper = this;
5276 Utils.extend(swiper, {
5277 pagination: {
5278 init: Pagination.init.bind(swiper),
5279 render: Pagination.render.bind(swiper),
5280 update: Pagination.update.bind(swiper),
5281 destroy: Pagination.destroy.bind(swiper),
5282 dynamicBulletIndex: 0,
5283 },
5284 });
5285 },
5286 on: {
5287 init() {
5288 const swiper = this;
5289 swiper.pagination.init();
5290 swiper.pagination.render();
5291 swiper.pagination.update();
5292 },
5293 activeIndexChange() {
5294 const swiper = this;
5295 if (swiper.params.loop) {
5296 swiper.pagination.update();
5297 } else if (typeof swiper.snapIndex === 'undefined') {
5298 swiper.pagination.update();
5299 }
5300 },
5301 snapIndexChange() {
5302 const swiper = this;
5303 if (!swiper.params.loop) {
5304 swiper.pagination.update();
5305 }
5306 },
5307 slidesLengthChange() {
5308 const swiper = this;
5309 if (swiper.params.loop) {
5310 swiper.pagination.render();
5311 swiper.pagination.update();
5312 }
5313 },
5314 snapGridLengthChange() {
5315 const swiper = this;
5316 if (!swiper.params.loop) {
5317 swiper.pagination.render();
5318 swiper.pagination.update();
5319 }
5320 },
5321 destroy() {
5322 const swiper = this;
5323 swiper.pagination.destroy();
5324 },
5325 click(e) {
5326 const swiper = this;
5327 if (
5328 swiper.params.pagination.el
5329 && swiper.params.pagination.hideOnClick
5330 && swiper.pagination.$el.length > 0
5331 && !$(e.target).hasClass(swiper.params.pagination.bulletClass)
5332 ) {
5333 const isHidden = swiper.pagination.$el.hasClass(swiper.params.pagination.hiddenClass);
5334 if (isHidden === true) {
5335 swiper.emit('paginationShow', swiper);
5336 } else {
5337 swiper.emit('paginationHide', swiper);
5338 }
5339 swiper.pagination.$el.toggleClass(swiper.params.pagination.hiddenClass);
5340 }
5341 },
5342 },
5343};
5344
5345const Scrollbar = {
5346 setTranslate() {
5347 const swiper = this;
5348 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
5349 const { scrollbar, rtlTranslate: rtl, progress } = swiper;
5350 const {
5351 dragSize, trackSize, $dragEl, $el,
5352 } = scrollbar;
5353 const params = swiper.params.scrollbar;
5354
5355 let newSize = dragSize;
5356 let newPos = (trackSize - dragSize) * progress;
5357 if (rtl) {
5358 newPos = -newPos;
5359 if (newPos > 0) {
5360 newSize = dragSize - newPos;
5361 newPos = 0;
5362 } else if (-newPos + dragSize > trackSize) {
5363 newSize = trackSize + newPos;
5364 }
5365 } else if (newPos < 0) {
5366 newSize = dragSize + newPos;
5367 newPos = 0;
5368 } else if (newPos + dragSize > trackSize) {
5369 newSize = trackSize - newPos;
5370 }
5371 if (swiper.isHorizontal()) {
5372 $dragEl.transform(`translate3d(${newPos}px, 0, 0)`);
5373 $dragEl[0].style.width = `${newSize}px`;
5374 } else {
5375 $dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);
5376 $dragEl[0].style.height = `${newSize}px`;
5377 }
5378 if (params.hide) {
5379 clearTimeout(swiper.scrollbar.timeout);
5380 $el[0].style.opacity = 1;
5381 swiper.scrollbar.timeout = setTimeout(() => {
5382 $el[0].style.opacity = 0;
5383 $el.transition(400);
5384 }, 1000);
5385 }
5386 },
5387 setTransition(duration) {
5388 const swiper = this;
5389 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
5390 swiper.scrollbar.$dragEl.transition(duration);
5391 },
5392 updateSize() {
5393 const swiper = this;
5394 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
5395
5396 const { scrollbar } = swiper;
5397 const { $dragEl, $el } = scrollbar;
5398
5399 $dragEl[0].style.width = '';
5400 $dragEl[0].style.height = '';
5401 const trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;
5402
5403 const divider = swiper.size / swiper.virtualSize;
5404 const moveDivider = divider * (trackSize / swiper.size);
5405 let dragSize;
5406 if (swiper.params.scrollbar.dragSize === 'auto') {
5407 dragSize = trackSize * divider;
5408 } else {
5409 dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
5410 }
5411
5412 if (swiper.isHorizontal()) {
5413 $dragEl[0].style.width = `${dragSize}px`;
5414 } else {
5415 $dragEl[0].style.height = `${dragSize}px`;
5416 }
5417
5418 if (divider >= 1) {
5419 $el[0].style.display = 'none';
5420 } else {
5421 $el[0].style.display = '';
5422 }
5423 if (swiper.params.scrollbar.hide) {
5424 $el[0].style.opacity = 0;
5425 }
5426 Utils.extend(scrollbar, {
5427 trackSize,
5428 divider,
5429 moveDivider,
5430 dragSize,
5431 });
5432 scrollbar.$el[swiper.params.watchOverflow && swiper.isLocked ? 'addClass' : 'removeClass'](swiper.params.scrollbar.lockClass);
5433 },
5434 getPointerPosition(e) {
5435 const swiper = this;
5436 if (swiper.isHorizontal()) {
5437 return ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].clientX : e.clientX);
5438 }
5439 return ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].clientY : e.clientY);
5440 },
5441 setDragPosition(e) {
5442 const swiper = this;
5443 const { scrollbar, rtlTranslate: rtl } = swiper;
5444 const {
5445 $el,
5446 dragSize,
5447 trackSize,
5448 dragStartPos,
5449 } = scrollbar;
5450
5451 let positionRatio;
5452 positionRatio = ((scrollbar.getPointerPosition(e)) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top']
5453 - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);
5454 positionRatio = Math.max(Math.min(positionRatio, 1), 0);
5455 if (rtl) {
5456 positionRatio = 1 - positionRatio;
5457 }
5458
5459 const position = swiper.minTranslate() + ((swiper.maxTranslate() - swiper.minTranslate()) * positionRatio);
5460
5461 swiper.updateProgress(position);
5462 swiper.setTranslate(position);
5463 swiper.updateActiveIndex();
5464 swiper.updateSlidesClasses();
5465 },
5466 onDragStart(e) {
5467 const swiper = this;
5468 const params = swiper.params.scrollbar;
5469 const { scrollbar, $wrapperEl } = swiper;
5470 const { $el, $dragEl } = scrollbar;
5471 swiper.scrollbar.isTouched = true;
5472 swiper.scrollbar.dragStartPos = (e.target === $dragEl[0] || e.target === $dragEl)
5473 ? scrollbar.getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;
5474 e.preventDefault();
5475 e.stopPropagation();
5476
5477 $wrapperEl.transition(100);
5478 $dragEl.transition(100);
5479 scrollbar.setDragPosition(e);
5480
5481 clearTimeout(swiper.scrollbar.dragTimeout);
5482
5483 $el.transition(0);
5484 if (params.hide) {
5485 $el.css('opacity', 1);
5486 }
5487 if (swiper.params.cssMode) {
5488 swiper.$wrapperEl.css('scroll-snap-type', 'none');
5489 }
5490 swiper.emit('scrollbarDragStart', e);
5491 },
5492 onDragMove(e) {
5493 const swiper = this;
5494 const { scrollbar, $wrapperEl } = swiper;
5495 const { $el, $dragEl } = scrollbar;
5496
5497 if (!swiper.scrollbar.isTouched) return;
5498 if (e.preventDefault) e.preventDefault();
5499 else e.returnValue = false;
5500 scrollbar.setDragPosition(e);
5501 $wrapperEl.transition(0);
5502 $el.transition(0);
5503 $dragEl.transition(0);
5504 swiper.emit('scrollbarDragMove', e);
5505 },
5506 onDragEnd(e) {
5507 const swiper = this;
5508
5509 const params = swiper.params.scrollbar;
5510 const { scrollbar, $wrapperEl } = swiper;
5511 const { $el } = scrollbar;
5512
5513 if (!swiper.scrollbar.isTouched) return;
5514 swiper.scrollbar.isTouched = false;
5515 if (swiper.params.cssMode) {
5516 swiper.$wrapperEl.css('scroll-snap-type', '');
5517 $wrapperEl.transition('');
5518 }
5519 if (params.hide) {
5520 clearTimeout(swiper.scrollbar.dragTimeout);
5521 swiper.scrollbar.dragTimeout = Utils.nextTick(() => {
5522 $el.css('opacity', 0);
5523 $el.transition(400);
5524 }, 1000);
5525 }
5526 swiper.emit('scrollbarDragEnd', e);
5527 if (params.snapOnRelease) {
5528 swiper.slideToClosest();
5529 }
5530 },
5531 enableDraggable() {
5532 const swiper = this;
5533 if (!swiper.params.scrollbar.el) return;
5534 const {
5535 scrollbar, touchEventsTouch, touchEventsDesktop, params,
5536 } = swiper;
5537 const $el = scrollbar.$el;
5538 const target = $el[0];
5539 const activeListener = Support.passiveListener && params.passiveListeners ? { passive: false, capture: false } : false;
5540 const passiveListener = Support.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
5541 if (!Support.touch) {
5542 target.addEventListener(touchEventsDesktop.start, swiper.scrollbar.onDragStart, activeListener);
5543 doc.addEventListener(touchEventsDesktop.move, swiper.scrollbar.onDragMove, activeListener);
5544 doc.addEventListener(touchEventsDesktop.end, swiper.scrollbar.onDragEnd, passiveListener);
5545 } else {
5546 target.addEventListener(touchEventsTouch.start, swiper.scrollbar.onDragStart, activeListener);
5547 target.addEventListener(touchEventsTouch.move, swiper.scrollbar.onDragMove, activeListener);
5548 target.addEventListener(touchEventsTouch.end, swiper.scrollbar.onDragEnd, passiveListener);
5549 }
5550 },
5551 disableDraggable() {
5552 const swiper = this;
5553 if (!swiper.params.scrollbar.el) return;
5554 const {
5555 scrollbar, touchEventsTouch, touchEventsDesktop, params,
5556 } = swiper;
5557 const $el = scrollbar.$el;
5558 const target = $el[0];
5559 const activeListener = Support.passiveListener && params.passiveListeners ? { passive: false, capture: false } : false;
5560 const passiveListener = Support.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
5561 if (!Support.touch) {
5562 target.removeEventListener(touchEventsDesktop.start, swiper.scrollbar.onDragStart, activeListener);
5563 doc.removeEventListener(touchEventsDesktop.move, swiper.scrollbar.onDragMove, activeListener);
5564 doc.removeEventListener(touchEventsDesktop.end, swiper.scrollbar.onDragEnd, passiveListener);
5565 } else {
5566 target.removeEventListener(touchEventsTouch.start, swiper.scrollbar.onDragStart, activeListener);
5567 target.removeEventListener(touchEventsTouch.move, swiper.scrollbar.onDragMove, activeListener);
5568 target.removeEventListener(touchEventsTouch.end, swiper.scrollbar.onDragEnd, passiveListener);
5569 }
5570 },
5571 init() {
5572 const swiper = this;
5573 if (!swiper.params.scrollbar.el) return;
5574 const { scrollbar, $el: $swiperEl } = swiper;
5575 const params = swiper.params.scrollbar;
5576
5577 let $el = $(params.el);
5578 if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {
5579 $el = $swiperEl.find(params.el);
5580 }
5581
5582 let $dragEl = $el.find(`.${swiper.params.scrollbar.dragClass}`);
5583 if ($dragEl.length === 0) {
5584 $dragEl = $(`<div class="${swiper.params.scrollbar.dragClass}"></div>`);
5585 $el.append($dragEl);
5586 }
5587
5588 Utils.extend(scrollbar, {
5589 $el,
5590 el: $el[0],
5591 $dragEl,
5592 dragEl: $dragEl[0],
5593 });
5594
5595 if (params.draggable) {
5596 scrollbar.enableDraggable();
5597 }
5598 },
5599 destroy() {
5600 const swiper = this;
5601 swiper.scrollbar.disableDraggable();
5602 },
5603};
5604
5605var scrollbar = {
5606 name: 'scrollbar',
5607 params: {
5608 scrollbar: {
5609 el: null,
5610 dragSize: 'auto',
5611 hide: false,
5612 draggable: false,
5613 snapOnRelease: true,
5614 lockClass: 'swiper-scrollbar-lock',
5615 dragClass: 'swiper-scrollbar-drag',
5616 },
5617 },
5618 create() {
5619 const swiper = this;
5620 Utils.extend(swiper, {
5621 scrollbar: {
5622 init: Scrollbar.init.bind(swiper),
5623 destroy: Scrollbar.destroy.bind(swiper),
5624 updateSize: Scrollbar.updateSize.bind(swiper),
5625 setTranslate: Scrollbar.setTranslate.bind(swiper),
5626 setTransition: Scrollbar.setTransition.bind(swiper),
5627 enableDraggable: Scrollbar.enableDraggable.bind(swiper),
5628 disableDraggable: Scrollbar.disableDraggable.bind(swiper),
5629 setDragPosition: Scrollbar.setDragPosition.bind(swiper),
5630 getPointerPosition: Scrollbar.getPointerPosition.bind(swiper),
5631 onDragStart: Scrollbar.onDragStart.bind(swiper),
5632 onDragMove: Scrollbar.onDragMove.bind(swiper),
5633 onDragEnd: Scrollbar.onDragEnd.bind(swiper),
5634 isTouched: false,
5635 timeout: null,
5636 dragTimeout: null,
5637 },
5638 });
5639 },
5640 on: {
5641 init() {
5642 const swiper = this;
5643 swiper.scrollbar.init();
5644 swiper.scrollbar.updateSize();
5645 swiper.scrollbar.setTranslate();
5646 },
5647 update() {
5648 const swiper = this;
5649 swiper.scrollbar.updateSize();
5650 },
5651 resize() {
5652 const swiper = this;
5653 swiper.scrollbar.updateSize();
5654 },
5655 observerUpdate() {
5656 const swiper = this;
5657 swiper.scrollbar.updateSize();
5658 },
5659 setTranslate() {
5660 const swiper = this;
5661 swiper.scrollbar.setTranslate();
5662 },
5663 setTransition(duration) {
5664 const swiper = this;
5665 swiper.scrollbar.setTransition(duration);
5666 },
5667 destroy() {
5668 const swiper = this;
5669 swiper.scrollbar.destroy();
5670 },
5671 },
5672};
5673
5674const Zoom = {
5675 // Calc Scale From Multi-touches
5676 getDistanceBetweenTouches(e) {
5677 if (e.targetTouches.length < 2) return 1;
5678 const x1 = e.targetTouches[0].pageX;
5679 const y1 = e.targetTouches[0].pageY;
5680 const x2 = e.targetTouches[1].pageX;
5681 const y2 = e.targetTouches[1].pageY;
5682 const distance = Math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2));
5683 return distance;
5684 },
5685 // Events
5686 onGestureStart(e) {
5687 const swiper = this;
5688 const params = swiper.params.zoom;
5689 const zoom = swiper.zoom;
5690 const { gesture } = zoom;
5691 zoom.fakeGestureTouched = false;
5692 zoom.fakeGestureMoved = false;
5693 if (!Support.gestures) {
5694 if (e.type !== 'touchstart' || (e.type === 'touchstart' && e.targetTouches.length < 2)) {
5695 return;
5696 }
5697 zoom.fakeGestureTouched = true;
5698 gesture.scaleStart = Zoom.getDistanceBetweenTouches(e);
5699 }
5700 if (!gesture.$slideEl || !gesture.$slideEl.length) {
5701 gesture.$slideEl = $(e.target).closest(`.${swiper.params.slideClass}`);
5702 if (gesture.$slideEl.length === 0) gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);
5703 gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target');
5704 gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
5705 gesture.maxRatio = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
5706 if (gesture.$imageWrapEl.length === 0) {
5707 gesture.$imageEl = undefined;
5708 return;
5709 }
5710 }
5711 if (gesture.$imageEl) {
5712 gesture.$imageEl.transition(0);
5713 }
5714 swiper.zoom.isScaling = true;
5715 },
5716 onGestureChange(e) {
5717 const swiper = this;
5718 const params = swiper.params.zoom;
5719 const zoom = swiper.zoom;
5720 const { gesture } = zoom;
5721 if (!Support.gestures) {
5722 if (e.type !== 'touchmove' || (e.type === 'touchmove' && e.targetTouches.length < 2)) {
5723 return;
5724 }
5725 zoom.fakeGestureMoved = true;
5726 gesture.scaleMove = Zoom.getDistanceBetweenTouches(e);
5727 }
5728 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5729 if (Support.gestures) {
5730 zoom.scale = e.scale * zoom.currentScale;
5731 } else {
5732 zoom.scale = (gesture.scaleMove / gesture.scaleStart) * zoom.currentScale;
5733 }
5734 if (zoom.scale > gesture.maxRatio) {
5735 zoom.scale = (gesture.maxRatio - 1) + (((zoom.scale - gesture.maxRatio) + 1) ** 0.5);
5736 }
5737 if (zoom.scale < params.minRatio) {
5738 zoom.scale = (params.minRatio + 1) - (((params.minRatio - zoom.scale) + 1) ** 0.5);
5739 }
5740 gesture.$imageEl.transform(`translate3d(0,0,0) scale(${zoom.scale})`);
5741 },
5742 onGestureEnd(e) {
5743 const swiper = this;
5744 const params = swiper.params.zoom;
5745 const zoom = swiper.zoom;
5746 const { gesture } = zoom;
5747 if (!Support.gestures) {
5748 if (!zoom.fakeGestureTouched || !zoom.fakeGestureMoved) {
5749 return;
5750 }
5751 if (e.type !== 'touchend' || (e.type === 'touchend' && e.changedTouches.length < 2 && !Device.android)) {
5752 return;
5753 }
5754 zoom.fakeGestureTouched = false;
5755 zoom.fakeGestureMoved = false;
5756 }
5757 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5758 zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio);
5759 gesture.$imageEl.transition(swiper.params.speed).transform(`translate3d(0,0,0) scale(${zoom.scale})`);
5760 zoom.currentScale = zoom.scale;
5761 zoom.isScaling = false;
5762 if (zoom.scale === 1) gesture.$slideEl = undefined;
5763 },
5764 onTouchStart(e) {
5765 const swiper = this;
5766 const zoom = swiper.zoom;
5767 const { gesture, image } = zoom;
5768 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5769 if (image.isTouched) return;
5770 if (Device.android && e.cancelable) e.preventDefault();
5771 image.isTouched = true;
5772 image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
5773 image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
5774 },
5775 onTouchMove(e) {
5776 const swiper = this;
5777 const zoom = swiper.zoom;
5778 const { gesture, image, velocity } = zoom;
5779 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5780 swiper.allowClick = false;
5781 if (!image.isTouched || !gesture.$slideEl) return;
5782
5783 if (!image.isMoved) {
5784 image.width = gesture.$imageEl[0].offsetWidth;
5785 image.height = gesture.$imageEl[0].offsetHeight;
5786 image.startX = Utils.getTranslate(gesture.$imageWrapEl[0], 'x') || 0;
5787 image.startY = Utils.getTranslate(gesture.$imageWrapEl[0], 'y') || 0;
5788 gesture.slideWidth = gesture.$slideEl[0].offsetWidth;
5789 gesture.slideHeight = gesture.$slideEl[0].offsetHeight;
5790 gesture.$imageWrapEl.transition(0);
5791 if (swiper.rtl) {
5792 image.startX = -image.startX;
5793 image.startY = -image.startY;
5794 }
5795 }
5796 // Define if we need image drag
5797 const scaledWidth = image.width * zoom.scale;
5798 const scaledHeight = image.height * zoom.scale;
5799
5800 if (scaledWidth < gesture.slideWidth && scaledHeight < gesture.slideHeight) return;
5801
5802 image.minX = Math.min(((gesture.slideWidth / 2) - (scaledWidth / 2)), 0);
5803 image.maxX = -image.minX;
5804 image.minY = Math.min(((gesture.slideHeight / 2) - (scaledHeight / 2)), 0);
5805 image.maxY = -image.minY;
5806
5807 image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
5808 image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
5809
5810 if (!image.isMoved && !zoom.isScaling) {
5811 if (
5812 swiper.isHorizontal()
5813 && (
5814 (Math.floor(image.minX) === Math.floor(image.startX) && image.touchesCurrent.x < image.touchesStart.x)
5815 || (Math.floor(image.maxX) === Math.floor(image.startX) && image.touchesCurrent.x > image.touchesStart.x)
5816 )
5817 ) {
5818 image.isTouched = false;
5819 return;
5820 } if (
5821 !swiper.isHorizontal()
5822 && (
5823 (Math.floor(image.minY) === Math.floor(image.startY) && image.touchesCurrent.y < image.touchesStart.y)
5824 || (Math.floor(image.maxY) === Math.floor(image.startY) && image.touchesCurrent.y > image.touchesStart.y)
5825 )
5826 ) {
5827 image.isTouched = false;
5828 return;
5829 }
5830 }
5831 if (e.cancelable) {
5832 e.preventDefault();
5833 }
5834 e.stopPropagation();
5835
5836 image.isMoved = true;
5837 image.currentX = (image.touchesCurrent.x - image.touchesStart.x) + image.startX;
5838 image.currentY = (image.touchesCurrent.y - image.touchesStart.y) + image.startY;
5839
5840 if (image.currentX < image.minX) {
5841 image.currentX = (image.minX + 1) - (((image.minX - image.currentX) + 1) ** 0.8);
5842 }
5843 if (image.currentX > image.maxX) {
5844 image.currentX = (image.maxX - 1) + (((image.currentX - image.maxX) + 1) ** 0.8);
5845 }
5846
5847 if (image.currentY < image.minY) {
5848 image.currentY = (image.minY + 1) - (((image.minY - image.currentY) + 1) ** 0.8);
5849 }
5850 if (image.currentY > image.maxY) {
5851 image.currentY = (image.maxY - 1) + (((image.currentY - image.maxY) + 1) ** 0.8);
5852 }
5853
5854 // Velocity
5855 if (!velocity.prevPositionX) velocity.prevPositionX = image.touchesCurrent.x;
5856 if (!velocity.prevPositionY) velocity.prevPositionY = image.touchesCurrent.y;
5857 if (!velocity.prevTime) velocity.prevTime = Date.now();
5858 velocity.x = (image.touchesCurrent.x - velocity.prevPositionX) / (Date.now() - velocity.prevTime) / 2;
5859 velocity.y = (image.touchesCurrent.y - velocity.prevPositionY) / (Date.now() - velocity.prevTime) / 2;
5860 if (Math.abs(image.touchesCurrent.x - velocity.prevPositionX) < 2) velocity.x = 0;
5861 if (Math.abs(image.touchesCurrent.y - velocity.prevPositionY) < 2) velocity.y = 0;
5862 velocity.prevPositionX = image.touchesCurrent.x;
5863 velocity.prevPositionY = image.touchesCurrent.y;
5864 velocity.prevTime = Date.now();
5865
5866 gesture.$imageWrapEl.transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);
5867 },
5868 onTouchEnd() {
5869 const swiper = this;
5870 const zoom = swiper.zoom;
5871 const { gesture, image, velocity } = zoom;
5872 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5873 if (!image.isTouched || !image.isMoved) {
5874 image.isTouched = false;
5875 image.isMoved = false;
5876 return;
5877 }
5878 image.isTouched = false;
5879 image.isMoved = false;
5880 let momentumDurationX = 300;
5881 let momentumDurationY = 300;
5882 const momentumDistanceX = velocity.x * momentumDurationX;
5883 const newPositionX = image.currentX + momentumDistanceX;
5884 const momentumDistanceY = velocity.y * momentumDurationY;
5885 const newPositionY = image.currentY + momentumDistanceY;
5886
5887 // Fix duration
5888 if (velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - image.currentX) / velocity.x);
5889 if (velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - image.currentY) / velocity.y);
5890 const momentumDuration = Math.max(momentumDurationX, momentumDurationY);
5891
5892 image.currentX = newPositionX;
5893 image.currentY = newPositionY;
5894
5895 // Define if we need image drag
5896 const scaledWidth = image.width * zoom.scale;
5897 const scaledHeight = image.height * zoom.scale;
5898 image.minX = Math.min(((gesture.slideWidth / 2) - (scaledWidth / 2)), 0);
5899 image.maxX = -image.minX;
5900 image.minY = Math.min(((gesture.slideHeight / 2) - (scaledHeight / 2)), 0);
5901 image.maxY = -image.minY;
5902 image.currentX = Math.max(Math.min(image.currentX, image.maxX), image.minX);
5903 image.currentY = Math.max(Math.min(image.currentY, image.maxY), image.minY);
5904
5905 gesture.$imageWrapEl.transition(momentumDuration).transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);
5906 },
5907 onTransitionEnd() {
5908 const swiper = this;
5909 const zoom = swiper.zoom;
5910 const { gesture } = zoom;
5911 if (gesture.$slideEl && swiper.previousIndex !== swiper.activeIndex) {
5912 if (gesture.$imageEl) {
5913 gesture.$imageEl.transform('translate3d(0,0,0) scale(1)');
5914 }
5915 if (gesture.$imageWrapEl) {
5916 gesture.$imageWrapEl.transform('translate3d(0,0,0)');
5917 }
5918
5919 zoom.scale = 1;
5920 zoom.currentScale = 1;
5921
5922 gesture.$slideEl = undefined;
5923 gesture.$imageEl = undefined;
5924 gesture.$imageWrapEl = undefined;
5925 }
5926 },
5927 // Toggle Zoom
5928 toggle(e) {
5929 const swiper = this;
5930 const zoom = swiper.zoom;
5931
5932 if (zoom.scale && zoom.scale !== 1) {
5933 // Zoom Out
5934 zoom.out();
5935 } else {
5936 // Zoom In
5937 zoom.in(e);
5938 }
5939 },
5940 in(e) {
5941 const swiper = this;
5942
5943 const zoom = swiper.zoom;
5944 const params = swiper.params.zoom;
5945 const { gesture, image } = zoom;
5946
5947 if (!gesture.$slideEl) {
5948 if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
5949 gesture.$slideEl = swiper.$wrapperEl.children(`.${swiper.params.slideActiveClass}`);
5950 } else {
5951 gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);
5952 }
5953 gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target');
5954 gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
5955 }
5956 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
5957
5958 gesture.$slideEl.addClass(`${params.zoomedSlideClass}`);
5959
5960 let touchX;
5961 let touchY;
5962 let offsetX;
5963 let offsetY;
5964 let diffX;
5965 let diffY;
5966 let translateX;
5967 let translateY;
5968 let imageWidth;
5969 let imageHeight;
5970 let scaledWidth;
5971 let scaledHeight;
5972 let translateMinX;
5973 let translateMinY;
5974 let translateMaxX;
5975 let translateMaxY;
5976 let slideWidth;
5977 let slideHeight;
5978
5979 if (typeof image.touchesStart.x === 'undefined' && e) {
5980 touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX;
5981 touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY;
5982 } else {
5983 touchX = image.touchesStart.x;
5984 touchY = image.touchesStart.y;
5985 }
5986
5987 zoom.scale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
5988 zoom.currentScale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
5989 if (e) {
5990 slideWidth = gesture.$slideEl[0].offsetWidth;
5991 slideHeight = gesture.$slideEl[0].offsetHeight;
5992 offsetX = gesture.$slideEl.offset().left;
5993 offsetY = gesture.$slideEl.offset().top;
5994 diffX = (offsetX + (slideWidth / 2)) - touchX;
5995 diffY = (offsetY + (slideHeight / 2)) - touchY;
5996
5997 imageWidth = gesture.$imageEl[0].offsetWidth;
5998 imageHeight = gesture.$imageEl[0].offsetHeight;
5999 scaledWidth = imageWidth * zoom.scale;
6000 scaledHeight = imageHeight * zoom.scale;
6001
6002 translateMinX = Math.min(((slideWidth / 2) - (scaledWidth / 2)), 0);
6003 translateMinY = Math.min(((slideHeight / 2) - (scaledHeight / 2)), 0);
6004 translateMaxX = -translateMinX;
6005 translateMaxY = -translateMinY;
6006
6007 translateX = diffX * zoom.scale;
6008 translateY = diffY * zoom.scale;
6009
6010 if (translateX < translateMinX) {
6011 translateX = translateMinX;
6012 }
6013 if (translateX > translateMaxX) {
6014 translateX = translateMaxX;
6015 }
6016
6017 if (translateY < translateMinY) {
6018 translateY = translateMinY;
6019 }
6020 if (translateY > translateMaxY) {
6021 translateY = translateMaxY;
6022 }
6023 } else {
6024 translateX = 0;
6025 translateY = 0;
6026 }
6027 gesture.$imageWrapEl.transition(300).transform(`translate3d(${translateX}px, ${translateY}px,0)`);
6028 gesture.$imageEl.transition(300).transform(`translate3d(0,0,0) scale(${zoom.scale})`);
6029 },
6030 out() {
6031 const swiper = this;
6032
6033 const zoom = swiper.zoom;
6034 const params = swiper.params.zoom;
6035 const { gesture } = zoom;
6036
6037 if (!gesture.$slideEl) {
6038 if (swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual) {
6039 gesture.$slideEl = swiper.$wrapperEl.children(`.${swiper.params.slideActiveClass}`);
6040 } else {
6041 gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);
6042 }
6043 gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas, picture, .swiper-zoom-target');
6044 gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
6045 }
6046 if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
6047
6048 zoom.scale = 1;
6049 zoom.currentScale = 1;
6050 gesture.$imageWrapEl.transition(300).transform('translate3d(0,0,0)');
6051 gesture.$imageEl.transition(300).transform('translate3d(0,0,0) scale(1)');
6052 gesture.$slideEl.removeClass(`${params.zoomedSlideClass}`);
6053 gesture.$slideEl = undefined;
6054 },
6055 // Attach/Detach Events
6056 enable() {
6057 const swiper = this;
6058 const zoom = swiper.zoom;
6059 if (zoom.enabled) return;
6060 zoom.enabled = true;
6061
6062 const passiveListener = swiper.touchEvents.start === 'touchstart' && Support.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false;
6063 const activeListenerWithCapture = Support.passiveListener ? { passive: false, capture: true } : true;
6064
6065 const slideSelector = `.${swiper.params.slideClass}`;
6066
6067 // Scale image
6068 if (Support.gestures) {
6069 swiper.$wrapperEl.on('gesturestart', slideSelector, zoom.onGestureStart, passiveListener);
6070 swiper.$wrapperEl.on('gesturechange', slideSelector, zoom.onGestureChange, passiveListener);
6071 swiper.$wrapperEl.on('gestureend', slideSelector, zoom.onGestureEnd, passiveListener);
6072 } else if (swiper.touchEvents.start === 'touchstart') {
6073 swiper.$wrapperEl.on(swiper.touchEvents.start, slideSelector, zoom.onGestureStart, passiveListener);
6074 swiper.$wrapperEl.on(swiper.touchEvents.move, slideSelector, zoom.onGestureChange, activeListenerWithCapture);
6075 swiper.$wrapperEl.on(swiper.touchEvents.end, slideSelector, zoom.onGestureEnd, passiveListener);
6076 if (swiper.touchEvents.cancel) {
6077 swiper.$wrapperEl.on(swiper.touchEvents.cancel, slideSelector, zoom.onGestureEnd, passiveListener);
6078 }
6079 }
6080
6081 // Move image
6082 swiper.$wrapperEl.on(swiper.touchEvents.move, `.${swiper.params.zoom.containerClass}`, zoom.onTouchMove, activeListenerWithCapture);
6083 },
6084 disable() {
6085 const swiper = this;
6086 const zoom = swiper.zoom;
6087 if (!zoom.enabled) return;
6088
6089 swiper.zoom.enabled = false;
6090
6091 const passiveListener = swiper.touchEvents.start === 'touchstart' && Support.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false;
6092 const activeListenerWithCapture = Support.passiveListener ? { passive: false, capture: true } : true;
6093
6094 const slideSelector = `.${swiper.params.slideClass}`;
6095
6096 // Scale image
6097 if (Support.gestures) {
6098 swiper.$wrapperEl.off('gesturestart', slideSelector, zoom.onGestureStart, passiveListener);
6099 swiper.$wrapperEl.off('gesturechange', slideSelector, zoom.onGestureChange, passiveListener);
6100 swiper.$wrapperEl.off('gestureend', slideSelector, zoom.onGestureEnd, passiveListener);
6101 } else if (swiper.touchEvents.start === 'touchstart') {
6102 swiper.$wrapperEl.off(swiper.touchEvents.start, slideSelector, zoom.onGestureStart, passiveListener);
6103 swiper.$wrapperEl.off(swiper.touchEvents.move, slideSelector, zoom.onGestureChange, activeListenerWithCapture);
6104 swiper.$wrapperEl.off(swiper.touchEvents.end, slideSelector, zoom.onGestureEnd, passiveListener);
6105 if (swiper.touchEvents.cancel) {
6106 swiper.$wrapperEl.off(swiper.touchEvents.cancel, slideSelector, zoom.onGestureEnd, passiveListener);
6107 }
6108 }
6109
6110 // Move image
6111 swiper.$wrapperEl.off(swiper.touchEvents.move, `.${swiper.params.zoom.containerClass}`, zoom.onTouchMove, activeListenerWithCapture);
6112 },
6113};
6114
6115var zoom = {
6116 name: 'zoom',
6117 params: {
6118 zoom: {
6119 enabled: false,
6120 maxRatio: 3,
6121 minRatio: 1,
6122 toggle: true,
6123 containerClass: 'swiper-zoom-container',
6124 zoomedSlideClass: 'swiper-slide-zoomed',
6125 },
6126 },
6127 create() {
6128 const swiper = this;
6129 const zoom = {
6130 enabled: false,
6131 scale: 1,
6132 currentScale: 1,
6133 isScaling: false,
6134 gesture: {
6135 $slideEl: undefined,
6136 slideWidth: undefined,
6137 slideHeight: undefined,
6138 $imageEl: undefined,
6139 $imageWrapEl: undefined,
6140 maxRatio: 3,
6141 },
6142 image: {
6143 isTouched: undefined,
6144 isMoved: undefined,
6145 currentX: undefined,
6146 currentY: undefined,
6147 minX: undefined,
6148 minY: undefined,
6149 maxX: undefined,
6150 maxY: undefined,
6151 width: undefined,
6152 height: undefined,
6153 startX: undefined,
6154 startY: undefined,
6155 touchesStart: {},
6156 touchesCurrent: {},
6157 },
6158 velocity: {
6159 x: undefined,
6160 y: undefined,
6161 prevPositionX: undefined,
6162 prevPositionY: undefined,
6163 prevTime: undefined,
6164 },
6165 };
6166
6167 ('onGestureStart onGestureChange onGestureEnd onTouchStart onTouchMove onTouchEnd onTransitionEnd toggle enable disable in out').split(' ').forEach((methodName) => {
6168 zoom[methodName] = Zoom[methodName].bind(swiper);
6169 });
6170 Utils.extend(swiper, {
6171 zoom,
6172 });
6173
6174 let scale = 1;
6175 Object.defineProperty(swiper.zoom, 'scale', {
6176 get() {
6177 return scale;
6178 },
6179 set(value) {
6180 if (scale !== value) {
6181 const imageEl = swiper.zoom.gesture.$imageEl ? swiper.zoom.gesture.$imageEl[0] : undefined;
6182 const slideEl = swiper.zoom.gesture.$slideEl ? swiper.zoom.gesture.$slideEl[0] : undefined;
6183 swiper.emit('zoomChange', value, imageEl, slideEl);
6184 }
6185 scale = value;
6186 },
6187 });
6188 },
6189 on: {
6190 init() {
6191 const swiper = this;
6192 if (swiper.params.zoom.enabled) {
6193 swiper.zoom.enable();
6194 }
6195 },
6196 destroy() {
6197 const swiper = this;
6198 swiper.zoom.disable();
6199 },
6200 touchStart(e) {
6201 const swiper = this;
6202 if (!swiper.zoom.enabled) return;
6203 swiper.zoom.onTouchStart(e);
6204 },
6205 touchEnd(e) {
6206 const swiper = this;
6207 if (!swiper.zoom.enabled) return;
6208 swiper.zoom.onTouchEnd(e);
6209 },
6210 doubleTap(e) {
6211 const swiper = this;
6212 if (swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) {
6213 swiper.zoom.toggle(e);
6214 }
6215 },
6216 transitionEnd() {
6217 const swiper = this;
6218 if (swiper.zoom.enabled && swiper.params.zoom.enabled) {
6219 swiper.zoom.onTransitionEnd();
6220 }
6221 },
6222 slideChange() {
6223 const swiper = this;
6224 if (swiper.zoom.enabled && swiper.params.zoom.enabled && swiper.params.cssMode) {
6225 swiper.zoom.onTransitionEnd();
6226 }
6227 },
6228 },
6229};
6230
6231/* eslint no-underscore-dangle: "off" */
6232
6233const Autoplay = {
6234 run() {
6235 const swiper = this;
6236 const $activeSlideEl = swiper.slides.eq(swiper.activeIndex);
6237 let delay = swiper.params.autoplay.delay;
6238 if ($activeSlideEl.attr('data-swiper-autoplay')) {
6239 delay = $activeSlideEl.attr('data-swiper-autoplay') || swiper.params.autoplay.delay;
6240 }
6241 clearTimeout(swiper.autoplay.timeout);
6242 swiper.autoplay.timeout = Utils.nextTick(() => {
6243 if (swiper.params.autoplay.reverseDirection) {
6244 if (swiper.params.loop) {
6245 swiper.loopFix();
6246 swiper.slidePrev(swiper.params.speed, true, true);
6247 swiper.emit('autoplay');
6248 } else if (!swiper.isBeginning) {
6249 swiper.slidePrev(swiper.params.speed, true, true);
6250 swiper.emit('autoplay');
6251 } else if (!swiper.params.autoplay.stopOnLastSlide) {
6252 swiper.slideTo(swiper.slides.length - 1, swiper.params.speed, true, true);
6253 swiper.emit('autoplay');
6254 } else {
6255 swiper.autoplay.stop();
6256 }
6257 } else if (swiper.params.loop) {
6258 swiper.loopFix();
6259 swiper.slideNext(swiper.params.speed, true, true);
6260 swiper.emit('autoplay');
6261 } else if (!swiper.isEnd) {
6262 swiper.slideNext(swiper.params.speed, true, true);
6263 swiper.emit('autoplay');
6264 } else if (!swiper.params.autoplay.stopOnLastSlide) {
6265 swiper.slideTo(0, swiper.params.speed, true, true);
6266 swiper.emit('autoplay');
6267 } else {
6268 swiper.autoplay.stop();
6269 }
6270 if (swiper.params.cssMode && swiper.autoplay.running) swiper.autoplay.run();
6271 }, delay);
6272 },
6273 start() {
6274 const swiper = this;
6275 if (typeof swiper.autoplay.timeout !== 'undefined') return false;
6276 if (swiper.autoplay.running) return false;
6277 swiper.autoplay.running = true;
6278 swiper.emit('autoplayStart');
6279 swiper.autoplay.run();
6280 return true;
6281 },
6282 stop() {
6283 const swiper = this;
6284 if (!swiper.autoplay.running) return false;
6285 if (typeof swiper.autoplay.timeout === 'undefined') return false;
6286
6287 if (swiper.autoplay.timeout) {
6288 clearTimeout(swiper.autoplay.timeout);
6289 swiper.autoplay.timeout = undefined;
6290 }
6291 swiper.autoplay.running = false;
6292 swiper.emit('autoplayStop');
6293 return true;
6294 },
6295 pause(speed) {
6296 const swiper = this;
6297 if (!swiper.autoplay.running) return;
6298 if (swiper.autoplay.paused) return;
6299 if (swiper.autoplay.timeout) clearTimeout(swiper.autoplay.timeout);
6300 swiper.autoplay.paused = true;
6301 if (speed === 0 || !swiper.params.autoplay.waitForTransition) {
6302 swiper.autoplay.paused = false;
6303 swiper.autoplay.run();
6304 } else {
6305 swiper.$wrapperEl[0].addEventListener('transitionend', swiper.autoplay.onTransitionEnd);
6306 swiper.$wrapperEl[0].addEventListener('webkitTransitionEnd', swiper.autoplay.onTransitionEnd);
6307 }
6308 },
6309};
6310
6311var autoplay = {
6312 name: 'autoplay',
6313 params: {
6314 autoplay: {
6315 enabled: false,
6316 delay: 3000,
6317 waitForTransition: true,
6318 disableOnInteraction: true,
6319 stopOnLastSlide: false,
6320 reverseDirection: false,
6321 },
6322 },
6323 create() {
6324 const swiper = this;
6325 Utils.extend(swiper, {
6326 autoplay: {
6327 running: false,
6328 paused: false,
6329 run: Autoplay.run.bind(swiper),
6330 start: Autoplay.start.bind(swiper),
6331 stop: Autoplay.stop.bind(swiper),
6332 pause: Autoplay.pause.bind(swiper),
6333 onVisibilityChange() {
6334 if (document.visibilityState === 'hidden' && swiper.autoplay.running) {
6335 swiper.autoplay.pause();
6336 }
6337 if (document.visibilityState === 'visible' && swiper.autoplay.paused) {
6338 swiper.autoplay.run();
6339 swiper.autoplay.paused = false;
6340 }
6341 },
6342 onTransitionEnd(e) {
6343 if (!swiper || swiper.destroyed || !swiper.$wrapperEl) return;
6344 if (e.target !== this) return;
6345 swiper.$wrapperEl[0].removeEventListener('transitionend', swiper.autoplay.onTransitionEnd);
6346 swiper.$wrapperEl[0].removeEventListener('webkitTransitionEnd', swiper.autoplay.onTransitionEnd);
6347 swiper.autoplay.paused = false;
6348 if (!swiper.autoplay.running) {
6349 swiper.autoplay.stop();
6350 } else {
6351 swiper.autoplay.run();
6352 }
6353 },
6354 },
6355 });
6356 },
6357 on: {
6358 init() {
6359 const swiper = this;
6360 if (swiper.params.autoplay.enabled) {
6361 swiper.autoplay.start();
6362 document.addEventListener('visibilitychange', swiper.autoplay.onVisibilityChange);
6363 }
6364 },
6365 beforeTransitionStart(speed, internal) {
6366 const swiper = this;
6367 if (swiper.autoplay.running) {
6368 if (internal || !swiper.params.autoplay.disableOnInteraction) {
6369 swiper.autoplay.pause(speed);
6370 } else {
6371 swiper.autoplay.stop();
6372 }
6373 }
6374 },
6375 sliderFirstMove() {
6376 const swiper = this;
6377 if (swiper.autoplay.running) {
6378 if (swiper.params.autoplay.disableOnInteraction) {
6379 swiper.autoplay.stop();
6380 } else {
6381 swiper.autoplay.pause();
6382 }
6383 }
6384 },
6385 touchEnd() {
6386 const swiper = this;
6387 if (swiper.params.cssMode && swiper.autoplay.paused && !swiper.params.autoplay.disableOnInteraction) {
6388 swiper.autoplay.run();
6389 }
6390 },
6391 destroy() {
6392 const swiper = this;
6393 if (swiper.autoplay.running) {
6394 swiper.autoplay.stop();
6395 }
6396 document.removeEventListener('visibilitychange', swiper.autoplay.onVisibilityChange);
6397 },
6398 },
6399};
6400
6401// Swiper Class
6402
6403const components = [
6404 Device$1,
6405 Support$1,
6406 Browser$1,
6407 Resize,
6408 Observer$1,
6409];
6410
6411if (typeof Swiper.use === 'undefined') {
6412 Swiper.use = Swiper.Class.use;
6413 Swiper.installModule = Swiper.Class.installModule;
6414}
6415
6416Swiper.use(components);
6417
6418Swiper.use([pagination, scrollbar, autoplay, keyboard, zoom]);
6419
6420exports.Swiper = Swiper;