UNPKG

16.4 kBJavaScriptView Raw
1/* eslint no-param-reassign: "off" */
2import { getDocument } from 'ssr-window';
3import $ from '../shared/dom.js';
4import { extend, now, deleteProps } from '../shared/utils.js';
5import { getSupport } from '../shared/get-support.js';
6import { getDevice } from '../shared/get-device.js';
7import { getBrowser } from '../shared/get-browser.js';
8import Resize from './modules/resize/resize.js';
9import Observer from './modules/observer/observer.js';
10import eventsEmitter from './events-emitter.js';
11import update from './update/index.js';
12import translate from './translate/index.js';
13import transition from './transition/index.js';
14import slide from './slide/index.js';
15import loop from './loop/index.js';
16import grabCursor from './grab-cursor/index.js';
17import events from './events/index.js';
18import breakpoints from './breakpoints/index.js';
19import classes from './classes/index.js';
20import images from './images/index.js';
21import checkOverflow from './check-overflow/index.js';
22import defaults from './defaults.js';
23import moduleExtendParams from './moduleExtendParams.js';
24const prototypes = {
25 eventsEmitter,
26 update,
27 translate,
28 transition,
29 slide,
30 loop,
31 grabCursor,
32 events,
33 breakpoints,
34 checkOverflow,
35 classes,
36 images
37};
38const extendedDefaults = {};
39
40class Swiper {
41 constructor(...args) {
42 let el;
43 let params;
44
45 if (args.length === 1 && args[0].constructor && Object.prototype.toString.call(args[0]).slice(8, -1) === 'Object') {
46 params = args[0];
47 } else {
48 [el, params] = args;
49 }
50
51 if (!params) params = {};
52 params = extend({}, params);
53 if (el && !params.el) params.el = el;
54
55 if (params.el && $(params.el).length > 1) {
56 const swipers = [];
57 $(params.el).each(containerEl => {
58 const newParams = extend({}, params, {
59 el: containerEl
60 });
61 swipers.push(new Swiper(newParams));
62 });
63 return swipers;
64 } // Swiper Instance
65
66
67 const swiper = this;
68 swiper.__swiper__ = true;
69 swiper.support = getSupport();
70 swiper.device = getDevice({
71 userAgent: params.userAgent
72 });
73 swiper.browser = getBrowser();
74 swiper.eventsListeners = {};
75 swiper.eventsAnyListeners = [];
76 swiper.modules = [...swiper.__modules__];
77
78 if (params.modules && Array.isArray(params.modules)) {
79 swiper.modules.push(...params.modules);
80 }
81
82 const allModulesParams = {};
83 swiper.modules.forEach(mod => {
84 mod({
85 swiper,
86 extendParams: moduleExtendParams(params, allModulesParams),
87 on: swiper.on.bind(swiper),
88 once: swiper.once.bind(swiper),
89 off: swiper.off.bind(swiper),
90 emit: swiper.emit.bind(swiper)
91 });
92 }); // Extend defaults with modules params
93
94 const swiperParams = extend({}, defaults, allModulesParams); // Extend defaults with passed params
95
96 swiper.params = extend({}, swiperParams, extendedDefaults, params);
97 swiper.originalParams = extend({}, swiper.params);
98 swiper.passedParams = extend({}, params); // add event listeners
99
100 if (swiper.params && swiper.params.on) {
101 Object.keys(swiper.params.on).forEach(eventName => {
102 swiper.on(eventName, swiper.params.on[eventName]);
103 });
104 }
105
106 if (swiper.params && swiper.params.onAny) {
107 swiper.onAny(swiper.params.onAny);
108 } // Save Dom lib
109
110
111 swiper.$ = $; // Extend Swiper
112
113 Object.assign(swiper, {
114 enabled: swiper.params.enabled,
115 el,
116 // Classes
117 classNames: [],
118 // Slides
119 slides: $(),
120 slidesGrid: [],
121 snapGrid: [],
122 slidesSizesGrid: [],
123
124 // isDirection
125 isHorizontal() {
126 return swiper.params.direction === 'horizontal';
127 },
128
129 isVertical() {
130 return swiper.params.direction === 'vertical';
131 },
132
133 // Indexes
134 activeIndex: 0,
135 realIndex: 0,
136 //
137 isBeginning: true,
138 isEnd: false,
139 // Props
140 translate: 0,
141 previousTranslate: 0,
142 progress: 0,
143 velocity: 0,
144 animating: false,
145 // Locks
146 allowSlideNext: swiper.params.allowSlideNext,
147 allowSlidePrev: swiper.params.allowSlidePrev,
148 // Touch Events
149 touchEvents: function touchEvents() {
150 const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
151 const desktop = ['pointerdown', 'pointermove', 'pointerup'];
152 swiper.touchEventsTouch = {
153 start: touch[0],
154 move: touch[1],
155 end: touch[2],
156 cancel: touch[3]
157 };
158 swiper.touchEventsDesktop = {
159 start: desktop[0],
160 move: desktop[1],
161 end: desktop[2]
162 };
163 return swiper.support.touch || !swiper.params.simulateTouch ? swiper.touchEventsTouch : swiper.touchEventsDesktop;
164 }(),
165 touchEventsData: {
166 isTouched: undefined,
167 isMoved: undefined,
168 allowTouchCallbacks: undefined,
169 touchStartTime: undefined,
170 isScrolling: undefined,
171 currentTranslate: undefined,
172 startTranslate: undefined,
173 allowThresholdMove: undefined,
174 // Form elements to match
175 focusableElements: swiper.params.focusableElements,
176 // Last click time
177 lastClickTime: now(),
178 clickTimeout: undefined,
179 // Velocities
180 velocities: [],
181 allowMomentumBounce: undefined,
182 isTouchEvent: undefined,
183 startMoving: undefined
184 },
185 // Clicks
186 allowClick: true,
187 // Touches
188 allowTouchMove: swiper.params.allowTouchMove,
189 touches: {
190 startX: 0,
191 startY: 0,
192 currentX: 0,
193 currentY: 0,
194 diff: 0
195 },
196 // Images
197 imagesToLoad: [],
198 imagesLoaded: 0
199 });
200 swiper.emit('_swiper'); // Init
201
202 if (swiper.params.init) {
203 swiper.init();
204 } // Return app instance
205
206
207 return swiper;
208 }
209
210 enable() {
211 const swiper = this;
212 if (swiper.enabled) return;
213 swiper.enabled = true;
214
215 if (swiper.params.grabCursor) {
216 swiper.setGrabCursor();
217 }
218
219 swiper.emit('enable');
220 }
221
222 disable() {
223 const swiper = this;
224 if (!swiper.enabled) return;
225 swiper.enabled = false;
226
227 if (swiper.params.grabCursor) {
228 swiper.unsetGrabCursor();
229 }
230
231 swiper.emit('disable');
232 }
233
234 setProgress(progress, speed) {
235 const swiper = this;
236 progress = Math.min(Math.max(progress, 0), 1);
237 const min = swiper.minTranslate();
238 const max = swiper.maxTranslate();
239 const current = (max - min) * progress + min;
240 swiper.translateTo(current, typeof speed === 'undefined' ? 0 : speed);
241 swiper.updateActiveIndex();
242 swiper.updateSlidesClasses();
243 }
244
245 emitContainerClasses() {
246 const swiper = this;
247 if (!swiper.params._emitClasses || !swiper.el) return;
248 const cls = swiper.el.className.split(' ').filter(className => {
249 return className.indexOf('swiper') === 0 || className.indexOf(swiper.params.containerModifierClass) === 0;
250 });
251 swiper.emit('_containerClasses', cls.join(' '));
252 }
253
254 getSlideClasses(slideEl) {
255 const swiper = this;
256 return slideEl.className.split(' ').filter(className => {
257 return className.indexOf('swiper-slide') === 0 || className.indexOf(swiper.params.slideClass) === 0;
258 }).join(' ');
259 }
260
261 emitSlidesClasses() {
262 const swiper = this;
263 if (!swiper.params._emitClasses || !swiper.el) return;
264 const updates = [];
265 swiper.slides.each(slideEl => {
266 const classNames = swiper.getSlideClasses(slideEl);
267 updates.push({
268 slideEl,
269 classNames
270 });
271 swiper.emit('_slideClass', slideEl, classNames);
272 });
273 swiper.emit('_slideClasses', updates);
274 }
275
276 slidesPerViewDynamic(view = 'current', exact = false) {
277 const swiper = this;
278 const {
279 params,
280 slides,
281 slidesGrid,
282 slidesSizesGrid,
283 size: swiperSize,
284 activeIndex
285 } = swiper;
286 let spv = 1;
287
288 if (params.centeredSlides) {
289 let slideSize = slides[activeIndex].swiperSlideSize;
290 let breakLoop;
291
292 for (let i = activeIndex + 1; i < slides.length; i += 1) {
293 if (slides[i] && !breakLoop) {
294 slideSize += slides[i].swiperSlideSize;
295 spv += 1;
296 if (slideSize > swiperSize) breakLoop = true;
297 }
298 }
299
300 for (let i = activeIndex - 1; i >= 0; i -= 1) {
301 if (slides[i] && !breakLoop) {
302 slideSize += slides[i].swiperSlideSize;
303 spv += 1;
304 if (slideSize > swiperSize) breakLoop = true;
305 }
306 }
307 } else {
308 // eslint-disable-next-line
309 if (view === 'current') {
310 for (let i = activeIndex + 1; i < slides.length; i += 1) {
311 const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
312
313 if (slideInView) {
314 spv += 1;
315 }
316 }
317 } else {
318 // previous
319 for (let i = activeIndex - 1; i >= 0; i -= 1) {
320 const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
321
322 if (slideInView) {
323 spv += 1;
324 }
325 }
326 }
327 }
328
329 return spv;
330 }
331
332 update() {
333 const swiper = this;
334 if (!swiper || swiper.destroyed) return;
335 const {
336 snapGrid,
337 params
338 } = swiper; // Breakpoints
339
340 if (params.breakpoints) {
341 swiper.setBreakpoint();
342 }
343
344 swiper.updateSize();
345 swiper.updateSlides();
346 swiper.updateProgress();
347 swiper.updateSlidesClasses();
348
349 function setTranslate() {
350 const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;
351 const newTranslate = Math.min(Math.max(translateValue, swiper.maxTranslate()), swiper.minTranslate());
352 swiper.setTranslate(newTranslate);
353 swiper.updateActiveIndex();
354 swiper.updateSlidesClasses();
355 }
356
357 let translated;
358
359 if (swiper.params.freeMode && swiper.params.freeMode.enabled) {
360 setTranslate();
361
362 if (swiper.params.autoHeight) {
363 swiper.updateAutoHeight();
364 }
365 } else {
366 if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
367 translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
368 } else {
369 translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
370 }
371
372 if (!translated) {
373 setTranslate();
374 }
375 }
376
377 if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
378 swiper.checkOverflow();
379 }
380
381 swiper.emit('update');
382 }
383
384 changeDirection(newDirection, needUpdate = true) {
385 const swiper = this;
386 const currentDirection = swiper.params.direction;
387
388 if (!newDirection) {
389 // eslint-disable-next-line
390 newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
391 }
392
393 if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
394 return swiper;
395 }
396
397 swiper.$el.removeClass(`${swiper.params.containerModifierClass}${currentDirection}`).addClass(`${swiper.params.containerModifierClass}${newDirection}`);
398 swiper.emitContainerClasses();
399 swiper.params.direction = newDirection;
400 swiper.slides.each(slideEl => {
401 if (newDirection === 'vertical') {
402 slideEl.style.width = '';
403 } else {
404 slideEl.style.height = '';
405 }
406 });
407 swiper.emit('changeDirection');
408 if (needUpdate) swiper.update();
409 return swiper;
410 }
411
412 mount(el) {
413 const swiper = this;
414 if (swiper.mounted) return true; // Find el
415
416 const $el = $(el || swiper.params.el);
417 el = $el[0];
418
419 if (!el) {
420 return false;
421 }
422
423 el.swiper = swiper;
424
425 const getWrapperSelector = () => {
426 return `.${(swiper.params.wrapperClass || '').trim().split(' ').join('.')}`;
427 };
428
429 const getWrapper = () => {
430 if (el && el.shadowRoot && el.shadowRoot.querySelector) {
431 const res = $(el.shadowRoot.querySelector(getWrapperSelector())); // Children needs to return slot items
432
433 res.children = options => $el.children(options);
434
435 return res;
436 }
437
438 return $el.children(getWrapperSelector());
439 }; // Find Wrapper
440
441
442 let $wrapperEl = getWrapper();
443
444 if ($wrapperEl.length === 0 && swiper.params.createElements) {
445 const document = getDocument();
446 const wrapper = document.createElement('div');
447 $wrapperEl = $(wrapper);
448 wrapper.className = swiper.params.wrapperClass;
449 $el.append(wrapper);
450 $el.children(`.${swiper.params.slideClass}`).each(slideEl => {
451 $wrapperEl.append(slideEl);
452 });
453 }
454
455 Object.assign(swiper, {
456 $el,
457 el,
458 $wrapperEl,
459 wrapperEl: $wrapperEl[0],
460 mounted: true,
461 // RTL
462 rtl: el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl',
463 rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
464 wrongRTL: $wrapperEl.css('display') === '-webkit-box'
465 });
466 return true;
467 }
468
469 init(el) {
470 const swiper = this;
471 if (swiper.initialized) return swiper;
472 const mounted = swiper.mount(el);
473 if (mounted === false) return swiper;
474 swiper.emit('beforeInit'); // Set breakpoint
475
476 if (swiper.params.breakpoints) {
477 swiper.setBreakpoint();
478 } // Add Classes
479
480
481 swiper.addClasses(); // Create loop
482
483 if (swiper.params.loop) {
484 swiper.loopCreate();
485 } // Update size
486
487
488 swiper.updateSize(); // Update slides
489
490 swiper.updateSlides();
491
492 if (swiper.params.watchOverflow) {
493 swiper.checkOverflow();
494 } // Set Grab Cursor
495
496
497 if (swiper.params.grabCursor && swiper.enabled) {
498 swiper.setGrabCursor();
499 }
500
501 if (swiper.params.preloadImages) {
502 swiper.preloadImages();
503 } // Slide To Initial Slide
504
505
506 if (swiper.params.loop) {
507 swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit, false, true);
508 } else {
509 swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
510 } // Attach events
511
512
513 swiper.attachEvents(); // Init Flag
514
515 swiper.initialized = true; // Emit
516
517 swiper.emit('init');
518 swiper.emit('afterInit');
519 return swiper;
520 }
521
522 destroy(deleteInstance = true, cleanStyles = true) {
523 const swiper = this;
524 const {
525 params,
526 $el,
527 $wrapperEl,
528 slides
529 } = swiper;
530
531 if (typeof swiper.params === 'undefined' || swiper.destroyed) {
532 return null;
533 }
534
535 swiper.emit('beforeDestroy'); // Init Flag
536
537 swiper.initialized = false; // Detach events
538
539 swiper.detachEvents(); // Destroy loop
540
541 if (params.loop) {
542 swiper.loopDestroy();
543 } // Cleanup styles
544
545
546 if (cleanStyles) {
547 swiper.removeClasses();
548 $el.removeAttr('style');
549 $wrapperEl.removeAttr('style');
550
551 if (slides && slides.length) {
552 slides.removeClass([params.slideVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass].join(' ')).removeAttr('style').removeAttr('data-swiper-slide-index');
553 }
554 }
555
556 swiper.emit('destroy'); // Detach emitter events
557
558 Object.keys(swiper.eventsListeners).forEach(eventName => {
559 swiper.off(eventName);
560 });
561
562 if (deleteInstance !== false) {
563 swiper.$el[0].swiper = null;
564 deleteProps(swiper);
565 }
566
567 swiper.destroyed = true;
568 return null;
569 }
570
571 static extendDefaults(newDefaults) {
572 extend(extendedDefaults, newDefaults);
573 }
574
575 static get extendedDefaults() {
576 return extendedDefaults;
577 }
578
579 static get defaults() {
580 return defaults;
581 }
582
583 static installModule(mod) {
584 if (!Swiper.prototype.__modules__) Swiper.prototype.__modules__ = [];
585 const modules = Swiper.prototype.__modules__;
586
587 if (typeof mod === 'function' && modules.indexOf(mod) < 0) {
588 modules.push(mod);
589 }
590 }
591
592 static use(module) {
593 if (Array.isArray(module)) {
594 module.forEach(m => Swiper.installModule(m));
595 return Swiper;
596 }
597
598 Swiper.installModule(module);
599 return Swiper;
600 }
601
602}
603
604Object.keys(prototypes).forEach(prototypeGroup => {
605 Object.keys(prototypes[prototypeGroup]).forEach(protoMethod => {
606 Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
607 });
608});
609Swiper.use([Resize, Observer]);
610export default Swiper;
\No newline at end of file