UNPKG

esnext-slider

Version:

Slim modular ESnext carousel/slider library

946 lines (882 loc) 32.3 kB
import 'intersection-observer'; import {easeInOutQuart, supportsPassive, supportsHidden} from './utils.js'; export default class Slider { constructor(settings = {}) { if (settings.node && settings.node instanceof HTMLElement) { this.$slider = [settings.node]; } else { this.$slider = document.querySelectorAll(settings.node ? settings.node : '.slider') } if (this.$slider.length === 0) { return; } if (this.$slider.length > 1) { let sliders = []; [...this.$slider].forEach(slider => { settings.node = slider; sliders.push(new Slider(settings)); }); return sliders; } this.$slider = this.$slider[0]; this.settings = { node: undefined, block: 'slider', element: { track: 'track', slide: 'slide', pagination: 'pagination', dots: 'dots', dot: 'dot', button: 'button' }, modifier: { active: 'active', visible: 'visible', next: 'next', prev: 'prev', dot: 'dot', clone: 'clone', edge: 'edge', horizontal: 'horizontal', vertical: 'vertical', play: 'play', pause: 'pause', disabled: 'disabled' }, clones: 3, transition: 250, multiplyTransition: true, ease: easeInOutQuart, align: 'left', mode: 'horizontal', initialSlide: 0, slidesToSlide: 1, autoplay: { direction: '>', mode: 'bounce', duration: 3800, pauseOnInteraction: true }, swipeToSlide: true, swipeThreshold: 60, dragToSlide: true, focusOnClick: true, pagination: true, prev: true, next: true, play: true, loop: false, rewind: false, syncedSliders: [], intersection: { root: this.$slider, rootMargin: '0px', threshold: [0, 0.01] }, l10n: { prev: 'Previous slide', next: 'Next slide', start: 'Start autoplay', pause: 'Pause autoplay', goto: 'Go to slide %d', active: 'Go to current slide', nav: 'Go to slider pagination' } }; this.settings = Object.assign({}, this.settings, settings); this.$track = false; this.$pagination = false; this.$dots = false; this.$prev = false; this.$next = false; this.$play = false; this.trackSize = 0; this.referenceSize = 0; this.$$clones = []; this.$$slides = []; this.$$slidesAndClones = []; this.currentSlide = false; this.fps = { then: 0, interval: 1000 / 60, tolerance: .1 }; this.slideAnimation = { then: 0, start: 0, distance: 0, calculated: 0, transition: 0, rafId: null }; this.intersectionObserver = null; if (this.settings.play) { this.autoplay = { play: this.settings.play !== false, stop: false, direction: this.settings.autoplay.direction, timeout: null }; } this.drag = { active: false, dragging: false, disableFocusOnClick: false, start: 0, distance: 0, track: 0 }; this.onArrowKeys = this.onArrowKeys.bind(this); this.onResize = this.onResize.bind(this); this.onEdgeJump = this.onEdgeJump.bind(this); this.onTransitionEnd = this.onTransitionEnd.bind(this); this.onIntersection = this.onIntersection.bind(this); this.onSlide = this.onSlide.bind(this); this.onSlideClick = this.onSlideClick.bind(this); this.onDragStart = this.onDragStart.bind(this); this.onDrag = this.onDrag.bind(this); this.onDragEnd = this.onDragEnd.bind(this); this.onDragSlideEnd = this.onDragSlideEnd.bind(this); this.onAutoplay = this.onAutoplay.bind(this); this.onToggleAutoplay = this.onToggleAutoplay.bind(this); this.onVisibilityChange = this.onVisibilityChange.bind(this); this.to = this.to.bind(this); this.prev = this.prev.bind(this); this.next = this.next.bind(this); this.init = this.init.bind(this); this.destroy = this.destroy.bind(this); this.public = { $$slides: this.$$slides, settings: this.settings, to: this.to, prev: this.prev, next: this.next, reInit: this.init, destroy: this.destroy }; this.$slider.slider = this.public; this.init(); return this.public; } __element(element) { return `${this.settings.block}__${this.settings.element[element]}`; } __initElement(element, type = 'div') { this[`$${element}`] = this.$slider.querySelector(`.${this.__element(element)}`); if (!this[`$${element}`]) { this[`$${element}`] = document.createElement(type); this[`$${element}`].classList.add(this.__element(element)); } } __initSlides() { [...this.$slider.querySelectorAll(`.${this.__element('slide')}`)].forEach($slide => { this.trackSize += $slide[this.__offsetSize()]; $slide.style[this.__size()] = `${$slide[this.__offsetSize()]}px`; $slide.setAttribute('tabindex', '-1'); $slide.setAttribute('aria-hidden', true); $slide.setAttribute('data-slide', this.$$slides.length); this.$track.appendChild($slide); this.$$slides.push($slide); this.$$slidesAndClones.push($slide); }); } __initClones() { let slidesCount = this.$$slides.length; for (let i = 0; i < this.settings.clones; i++) { this.__initClone(this.$$slides[i % slidesCount]); this.__initClone(this.$$slides[Math.abs(slidesCount - (i + 1)) % slidesCount], 'prepend'); } } __initClone($node, method = 'appendChild') { this.trackSize += $node[this.__offsetSize()]; let $clone = $node.cloneNode(true); let slideId = parseInt(this.$$clones.length / 2, 10); $clone.classList.add(`${this.__element('slide')}--${this.settings.modifier.clone}`); $clone.setAttribute('data-slide', method === 'appendChild' ? this.$$slides.length + slideId : -1 - slideId); this.currentSlide = -1 - slideId; this.$track[method]($clone); this.$$clones.push($clone); this.$$slidesAndClones[method === 'appendChild' ? 'push' : 'unshift']($clone); } __resetTrackSize() { this.trackSize = 0; this.$track.removeAttribute('style'); this.$track.style.display = 'block'; } __setTrackSize(referenceSize) { this.$track.removeAttribute('style'); this.$track.style[this.__size()] = `${this.trackSize}px`; this.referenceSize = referenceSize; } __offsetSize() { return this.settings.mode === 'horizontal' ? 'offsetWidth' : 'offsetHeight'; } __offsetDirection() { return this.settings.mode === 'horizontal' ? 'offsetLeft' : 'offsetTop'; } __size() { return this.settings.mode === 'horizontal' ? 'width' : 'height'; } __axis() { return this.settings.mode === 'horizontal' ? 'X' : 'Y'; } onIntersection(entries, observer) { entries.forEach(entry => { if (entry.isIntersecting) { if (entry.intersectionRatio >= 0.01) { this.__changeVisibility(entry.target); } } else { if (entry.intersectionRatio === 0.0) { this.__changeVisibility(entry.target, 'remove'); } } }); } __initObserver() { this.intersectionObserver = new IntersectionObserver(this.onIntersection, this.settings.intersection); [...this.$$slidesAndClones].forEach($slide => { this.intersectionObserver.observe($slide); }); } __initSwipeToSlide() { if (this.settings.swipeToSlide) { this.$slider.addEventListener('touchstart', this.onDragStart, supportsPassive ? {passive: true} : false); this.$slider.addEventListener('touchmove', this.onDrag, supportsPassive ? {passive: true} : false); this.$slider.addEventListener('touchend', this.onDragEnd); } } __initDragToSlide() { if (this.settings.dragToSlide) { let slideClass = `.${this.__element('slide')}`; [... this.$slider.querySelectorAll(`${slideClass} a, ${slideClass} img`)].forEach(item => item.draggable = false); this.$slider.addEventListener('mousedown', this.onDragStart); this.$slider.addEventListener('mousemove', this.onDrag); this.$slider.addEventListener('mouseup', this.onDragEnd); document.documentElement.addEventListener('mouseout', this.onDragEnd); } } __initFocusOnClick() { if (this.settings.focusOnClick) { [...this.$$slidesAndClones].forEach($slide => { $slide.addEventListener('click', this.onSlideClick); }); } } __initAutoplay() { if (this.settings.play) { this.onAutoplay(false); if (this.settings.autoplay.pauseOnInteraction) { this.$track.addEventListener('mouseenter', this.onToggleAutoplay); this.$track.addEventListener('mouseleave', this.onToggleAutoplay); } if (supportsHidden) { document.addEventListener(supportsHidden.event, this.onVisibilityChange, false); } this.__initPaginationItem('button', 'button', this.$slider, this.settings.modifier.play); let playClass = `${this.__element('button')}--${this.settings.modifier.play}`, pauseClass = `${this.__element('button')}--${this.settings.modifier.pause}`, sliderClass = `${this.settings.block}--${this.settings.modifier.pause}`; this.$play.classList.add(this.__element('button'), playClass); this.$play.title = this.settings.l10n.pause; this.$play.addEventListener('click', () => { this.autoplay.stop = !this.autoplay.stop; if (this.autoplay.stop) { this.$play.classList.add(pauseClass); this.$play.classList.remove(playClass); this.$play.title = this.settings.l10n.start; } else { this.$play.classList.add(playClass); this.$play.classList.remove(pauseClass); this.$play.title = this.settings.l10n.pause; } this.__resetAutoplay(); }); this.$slider.addEventListener('pause', () => { this.$slider.classList.add(sliderClass); this.$play.classList.add(pauseClass); this.$play.classList.remove(playClass); }); this.$slider.addEventListener('play', () => { this.$slider.classList.remove(sliderClass); this.$play.classList.add(playClass); this.$play.classList.remove(pauseClass); }); } } __initPaginationItem(item, type, $parent, modifier = false) { let node = modifier ? modifier : item; if (this.settings[node] instanceof HTMLElement) { this[`$${node}`] = this.settings[node]; } else { let className = this.__element(item) + (modifier ? `--${modifier}` : ''); this[`$${node}`] = $parent.querySelector(`.${className}`); if (!this[`$${node}`]) { this[`$${node}`] = document.createElement(type); if (this.settings.l10n[node]) { this[`$${node}`].title = this.settings.l10n[node]; } $parent[node === 'pagination' ? 'prepend' : 'appendChild'](this[`$${node}`]); } } } __setActiveDot($current) { let className = `${this.__element('dot')}--${this.settings.modifier.active}`; let $previous = this.$dots.querySelector(`.${className}`); if ($previous) { $previous.classList.remove(className); } if ($current) { $current.classList.add(className); } } __initPagination() { if (!(this.settings.pagination || this.settings.prev || this.settings.next)) { return; } this.__initPaginationItem('pagination', 'nav', this.$slider); this.$pagination.classList.add(this.__element('pagination')); let disabledButtonClass = `${this.__element('button')}--${this.settings.modifier.disabled}`; if (this.settings.prev) { this.__initPaginationItem('button', 'button', this.$pagination, this.settings.modifier.prev); this.$prev.classList.add(`${this.__element('button')}`, `${this.__element('button')}--${this.settings.modifier.prev}`); this.$prev.addEventListener('click', this.prev); this.$slider.addEventListener('afterslide', (e) => { if (!this.settings.rewind && !this.settings.loop && e.detail.current === 0) { this.$prev.classList.add(disabledButtonClass); } else { this.$prev.classList.remove(disabledButtonClass); } }); } if (this.settings.pagination) { this.__initPaginationItem('dots', 'ol', this.$pagination); this.$dots.classList.add(`${this.__element('dots')}`); let className = `${this.__element('dot')}--${this.settings.modifier.active}`; let $lis = [...this.$dots.querySelectorAll(`.${this.__element('dot')}`)]; [...this.$$slides].forEach(($slide, index) => { let $li = $lis[index] || document.createElement('li'); $li.classList.add(this.__element('dot')); if (index === this.settings.initialSlide) { this.__setActiveDot($li); } this.$dots.appendChild($li); let $button = $li.querySelector(`.${this.__element('button')}`) || document.createElement('button'); $button.classList.add(`${this.__element('button')}`, `${this.__element('button')}--${this.settings.modifier.dot}`); $button.title = $button.title || this.settings.l10n.goto.replace('%d', index + 1); $li.appendChild($button); $button.addEventListener('click', () => { this.__setActiveDot($li); this.to(index); }); }); this.$slider.addEventListener('afterslide', (e) => { this.__setActiveDot([...this.$dots.children][e.detail.current]); }); this.$slider.addEventListener('beforeslide', (e) => { this.__setActiveDot(e.detail.next !== null ? [...this.$dots.children][e.detail.next] : null); }); } if (this.settings.next) { this.__initPaginationItem('button', 'button', this.$pagination, this.settings.modifier.next); this.$next.classList.add(`${this.__element('button')}`, `${this.__element('button')}--${this.settings.modifier.next}`); this.$next.addEventListener('click', this.next); this.$slider.addEventListener('afterslide', (e) => { if (!this.settings.rewind && !this.settings.loop && e.detail.current === this.$$slides.length - 1) { this.$next.classList.add(disabledButtonClass); } else { this.$next.classList.remove(disabledButtonClass); } }); } } __initKeyboard() { this.$slider.addEventListener('keydown', this.onArrowKeys); } onArrowKeys (event) { let direction = null; if (event.keyCode === 37 || event.keyCode === 38) { direction = this.settings.slidesToSlide*-1; } if (event.keyCode === 39 || event.keyCode === 40) { direction = this.settings.slidesToSlide; } this.__slide(direction) } init() { this.$slider.dispatchEvent(new CustomEvent('init', { detail: { slider: this, current: this.currentSlide } })); window.addEventListener('resize', this.onResize); this.__initElement('track'); this.$track.setAttribute('aria-live', 'polite'); this.$slider.appendChild(this.$track); this.$slider.classList.remove(`${this.settings.block}--${this.settings.modifier.disabled}`); this.$slider.classList.add(`${this.settings.block}--${this.settings.modifier[this.settings.mode]}`,`${this.settings.block}--${this.settings.modifier.active}`); this.__resetTrackSize(); this.__initSlides(); if (this.$$slides.length < 1) { this.destroy(); } else if (this.settings.loop) { this.__initClones(); } this.__setTrackSize(this.$slider[this.__offsetSize()]); this.__initPagination(); this.__initObserver(); this.__initSwipeToSlide(); this.__initDragToSlide(); this.__initFocusOnClick(); this.__initAutoplay(); this.__initKeyboard(); let direction = (this.settings.loop ? this.settings.clones + this.settings.initialSlide : this.settings.initialSlide ); this.$track.addEventListener('slideend', this.onTransitionEnd); this.__slide(direction, false); return this.public; } __slide(direction = null, transition = true) { if (direction === null || !this.$track) { return; } let slide = this.currentSlide + direction; let maxSlide = this.$$slides.length - 1; if (this.settings.rewind && !this.settings.loop) { if (slide < 0) { slide = maxSlide; direction = maxSlide; } else if (slide > maxSlide) { slide = 0; direction = -maxSlide; } } let $slide = this.$track.querySelector(`[data-slide="${slide}"]`); if (!$slide) { return; } let isEdgeSlide = slide < 0 || slide > maxSlide; if (transition) { if (isEdgeSlide) { this.$track.addEventListener('slideend', this.onEdgeJump); } let next = this.__relativeSlide(slide); this.slideAnimation.transition = this.settings.multiplyTransition ? this.settings.transition * Math.abs(direction) : this.settings.transition; this.$slider.dispatchEvent(new CustomEvent('beforeslide', { detail: { slider: this, current: this.currentSlide, next, isEdgeSlide } })); } this.__setActiveSlide(slide); this.__slideDistance(this.__offsetByAlignment($slide[this.__offsetDirection()]), transition ? this.settings.transition * Math.abs(direction) : 0); } __setActiveSlide(slide) { this.currentSlide = slide; let $slide = this.$slider.querySelector(`[data-slide="${slide}"]`); if (!$slide) { return; } let activeClass = `${this.__element('slide')}--${this.settings.modifier.active}`; let previousSlide = this.$slider.querySelector(`.${activeClass}`); if (previousSlide) { previousSlide.classList.remove(activeClass); } $slide.classList.add(activeClass); $slide.setAttribute('aria-hidden', false); } __slideEnd() { this.slideAnimation.start = parseInt(this.slideAnimation.start + this.slideAnimation.distance, 10); this.slideAnimation.distance = 0; this.$track.style.transform = `translate${this.__axis()}(${this.slideAnimation.start}px)`; this.__resetAutoplay(); if (this.slideAnimation.transition > 0) { this.$track.dispatchEvent(new CustomEvent('slideend')); this.slideAnimation.transition = 0; } } __slideDistance(distance, transition) { if (this.slideAnimation.start !== parseInt(this.slideAnimation.start + this.slideAnimation.distance, 10)) { cancelAnimationFrame(this.slideAnimation.rafId); let isEdgeSlide = this.currentSlide < 0 || this.currentSlide > (this.$$slides.length - 1); if (isEdgeSlide) { this.onEdgeJump(); return; } else { this.slideAnimation.start = parseInt(this.$track.style.transform.replace(/[^-\d.]/g, ''), 10); this.$track.style.transform = `translate${this.__axis()}(${this.slideAnimation.start}px)`; } } distance = this.__applyMinMaxDistance(distance); this.slideAnimation.then = this.slideAnimation.time = performance.now(); this.slideAnimation.distance = distance - this.slideAnimation.start; this.slideAnimation.transition = transition; if (transition === 0) { return this.__slideEnd(); } this.onSlide(); } __applyMinMaxDistance(distance) { if (!this.settings.loop && this.settings.align !== 'center') { if (distance > 0) { return 0; } let maxDistance = (this.$track[this.__offsetSize()] - this.$slider[this.__offsetSize()]) * -1; if (distance < maxDistance) { return maxDistance; } } return distance; } onSlide() { let now = performance.now(); const DELTA = now - this.slideAnimation.then; if (DELTA >= this.fps.interval - this.fps.tolerance) { this.slideAnimation.then += DELTA; this.slideAnimation.calculated = this.settings.ease(now - this.slideAnimation.time, this.slideAnimation.start, this.slideAnimation.distance, this.slideAnimation.transition); if ((now - this.slideAnimation.time) >= this.slideAnimation.transition) { cancelAnimationFrame(this.slideAnimation.rafId); return this.__slideEnd(); } this.$track.style.transform = `translate${this.__axis()}(${parseInt(this.slideAnimation.calculated, 10)}px)`; this.$slider.dispatchEvent(new CustomEvent('whileslide', { detail: { slider: this, direction: this.slideAnimation.calculated > this.slideAnimation.start ? '<' : '>', distance: this.slideAnimation.distance, distancePassed: Math.abs(parseInt(this.slideAnimation.start - this.slideAnimation.calculated,10)), transition: this.slideAnimation.transition, transitionPassed: parseInt(now - this.slideAnimation.time,10) } })); } this.slideAnimation.rafId = requestAnimationFrame(this.onSlide); } __offsetByAlignment(offset) { let align = this.settings.align; let $slide = this.$track.querySelector(`[data-slide="${this.currentSlide}"]`); if (align === 'left' || align === 'top') { return offset * -1; } if (align === 'center') { return offset * -1 + (this.$slider[this.__offsetSize()] / 2 - $slide[this.__offsetSize()] / 2); } if (align === 'right' || align === 'bottom') { return offset * -1 + (this.$slider[this.__offsetSize()] - $slide[this.__offsetSize()]); } } __changeVisibility(element, method = 'add') { let visibilityClass = `${this.__element('slide')}--${this.settings.modifier.visible}`; if (element) { element.classList[method](visibilityClass); element.setAttribute('aria-hidden', true); element.setAttribute('tabindex', method === 'add' ? 0 : -1); } } __relativeSlide(slideOrCloneId) { let cloneFactor = parseInt(this.$$clones.length / this.$$slides.length, 10) + 1; return (slideOrCloneId + this.$$slides.length * cloneFactor) % this.$$slides.length } to(slide, transition = true) { if (this.currentSlide === slide) { return this.public; } let direction = (this.currentSlide - slide) * -1; this.__slide(direction, transition); this.__stopAutoplay(); return this.public; } next() { this.__slide(this.settings.slidesToSlide); this.__stopAutoplay(); return this.public; } prev() { this.__slide(-this.settings.slidesToSlide); this.__stopAutoplay(); return this.public; } onResize() { let now = performance.now(); const DELTA = now - this.fps.then; if (DELTA >= this.fps.interval - this.fps.tolerance) { this.fps.then = now - DELTA % this.fps.interval; let referenceSize = this.$slider[this.__offsetSize()]; if (referenceSize === this.referenceSize) { return; } this.__resetTrackSize(); setTimeout(() => { this.$$slidesAndClones.forEach($slide => this.__resizeSlide($slide)); setTimeout(() => { this.__setTrackSize(referenceSize) setTimeout(() => { this.__slide(0, false); }, 0); }, 0); },0); } } __resizeSlide($node) { $node.style[this.__size()] = null; let slideSize = $node[this.__offsetSize()]; this.trackSize += slideSize; $node.style[this.__size()] = `${slideSize}px` } onEdgeJump() { this.$track.removeEventListener('slideend', this.onEdgeJump); this.__edgeJump(); } __edgeJump() { this.$slider.dispatchEvent(new CustomEvent('edgejump', { detail: { slider: this, direction: this.currentSlide < 0 ? '<' : '>' } })); let edgeClass = `${this.__element('track')}--${this.settings.modifier.edge}`; this.$track.classList.add(edgeClass); let distanceFactor = parseInt(Math.abs(this.currentSlide < 0 ? this.currentSlide + 1 : this.currentSlide - 1) / this.$$slides.length, 10) + 1; let distanceToOriginal = this.currentSlide < 0 ? this.$$slides.length : -this.$$slides.length; distanceToOriginal *= distanceFactor; let visibleClass = `${this.__element('slide')}--${this.settings.modifier.visible}`; let visibleSlides = this.$$slidesAndClones.reduce((accumulator, $slide) => { if ($slide.classList.contains(visibleClass)) { accumulator.push($slide); $slide.classList.remove(visibleClass) } return accumulator; }, []); visibleSlides.forEach($slide => { let index = parseInt($slide.dataset.slide, 10); let otherEdgeSlide = this.$slider.querySelector(`[data-slide="${index + distanceToOriginal}"]`); if (otherEdgeSlide) { otherEdgeSlide.classList.add(`${this.__element('slide')}--${this.settings.modifier.visible}`); } }); this.__slide(distanceToOriginal, false); setTimeout(() => { this.$track.classList.remove(edgeClass); },0) } onTransitionEnd() { let isEdgeSlide = this.currentSlide < 0 || this.currentSlide >= this.$$slides.length; this.$slider.dispatchEvent(new CustomEvent('afterslide', { detail: { slider: this, current: this.__relativeSlide(this.currentSlide), isEdgeSlide } })); } onDragStart() { this.drag.active = true; this.drag.start = false; this.drag.distance = 0; this.drag.track = parseInt(this.$track.style.transform.replace(/[^-\d.]/g, ''), 10); } onDrag(e) { if (!this.drag.active) { return; } let property = `screen${this.__axis()}`; if (typeof e.touches === 'object' && e.touches.length > 0) { e[property] = e.touches[0][property]; } if (this.drag.start === false) { this.drag.start = e[property]; this.__stopAutoplay(); this.$slider.dispatchEvent(new CustomEvent('beforeslide', { detail: { slider: this, current: this.currentSlide, next: null, isEdgeSlide: null } })); } this.drag.distance = this.drag.start - e[property]; if (Math.abs(this.drag.distance) >= this.settings.swipeThreshold || this.drag.dragging) { this.$track.style.transform = `translate${this.__axis()}(${this.drag.track - this.drag.distance}px)`; this.drag.dragging = true; this.drag.disableFocusOnClick = true; this.$slider.dispatchEvent(new CustomEvent('whiledrag', { detail: { slider: this, direction: this.drag.distance < 0 ? '<' : '>', distance: Math.abs(this.drag.distance), origin: this.drag.track } })); } } onDragEnd() { this.drag.active = false; if (!this.drag.dragging) { return; } this.drag.dragging = false; this.slideAnimation.start = this.drag.track - this.drag.distance; let forward = this.drag.distance > 0 ? true : false; let distance = false; let currentSlide = false; this.$$slidesAndClones.forEach($slide => { if (forward && distance !== false) { return; } let offset = this.__currentSlideOffset($slide); if (forward && this.slideAnimation.start > offset) { distance = offset; } else if (!forward && this.slideAnimation.start < offset) { distance = offset; currentSlide = this.currentSlide; } }); if (false !== currentSlide) { this.currentSlide = currentSlide } else if (false === distance) { let $slide; if (forward) { $slide = this.$$slidesAndClones[this.$$slidesAndClones.length - 1] } else { $slide = this.$$slidesAndClones[0] } distance = this.__currentSlideOffset($slide); } this.__setActiveSlide(this.currentSlide); this.$track.addEventListener('slideend', this.onDragSlideEnd); this.__slideDistance(distance, this.settings.transition); return false; } onDragSlideEnd() { this.$track.removeEventListener('slideend', this.onDragSlideEnd); let isEdgeSlide = this.currentSlide < 0 || this.currentSlide > (this.$$slides.length - 1); this.__resetAutoplay(); if (isEdgeSlide) { this.__edgeJump(); } } onSlideClick(e) { if (this.drag.disableFocusOnClick) { this.drag.disableFocusOnClick = false; return; } let targetSlide = parseInt(e.currentTarget.dataset.slide, 10) this.to(targetSlide); } __currentSlideOffset($slide) { this.currentSlide = parseInt($slide.dataset.slide, 10); return this.__offsetByAlignment($slide[this.__offsetDirection()]); } __stopAutoplay() { if (this.settings.play) { clearTimeout(this.autoplay.timeout); } } __resetAutoplay() { if (!this.settings.play) { return; } clearTimeout(this.autoplay.timeout); if (this.autoplay.play && !this.autoplay.stop) { this.onAutoplay(false); } } onAutoplay(slideOnInit = true) { if (slideOnInit) { let direction = this.autoplay.direction === '>' ? this.settings.slidesToSlide : this.settings.slidesToSlide * -1; if (this.settings.autoplay.mode === 'rewind') { if ((this.currentSlide + direction) < 0) { direction += this.$$slides.length; } else if ((this.currentSlide + direction) > (this.$$slides.length - 1)) { direction -= this.$$slides.length; } } if (this.settings.autoplay.mode === 'bounce') { if ((this.currentSlide + direction) < 0) { this.autoplay.direction = '>'; direction *= -1; } else if ((this.currentSlide + direction) > (this.$$slides.length - 1)) { this.autoplay.direction = '<'; direction *= -1; } } this.__slide(direction); } this.autoplay.timeout = setTimeout(this.onAutoplay, this.settings.autoplay.duration); } onToggleAutoplay(e) { if (e.type.toLowerCase() === 'click') { this.autoplay.play = this.autoplay.stop = !this.autoplay.stop; if (this.autoplay.stop) { this.__stopAutoplay(); } } else if (!this.autoplay.stop) { this.autoplay.play = !this.autoplay.play; this.$slider.dispatchEvent(new CustomEvent(this.autoplay.play ? 'play' : 'pause')); } this.__resetAutoplay(); } onVisibilityChange() { if (document[supportsHidden.property]) { this.autoplay.stop = true; } else { this.autoplay.stop = false; } this.__resetAutoplay(); } destroy() { if (this.autoplay) { this.autoplay.stop = true; clearTimeout(this.autoplay.timeout); this.$play.parentNode.removeChild(this.$play); } window.removeEventListener('resize', this.onResize); this.$$slides.forEach($slide => { $slide.classList.remove(`${this.__element('slide')}--${this.settings.modifier.active}`); $slide.removeAttribute('style'); $slide.removeAttribute('tabindex'); $slide.removeAttribute('aria-hidden'); $slide.removeAttribute('data-slide'); this.$slider.appendChild($slide); }); this.$$clones.forEach($clone => $clone.remove()); this.__resetElement(this.$pagination); this.__resetElement(this.$prev); this.__resetElement(this.$next); this.__resetElement(this.$track); this.__resetElement(this.$dots); if (supportsHidden) { document.removeEventListener(supportsHidden.event, this.onVisibilityChange, false); } this.$slider.classList.add(`${this.settings.block}--${this.settings.modifier.disabled}`); this.$$slidesAndClones = []; this.$$slides = []; this.$$clones = []; this.$slider.classList.remove(`${this.settings.block}--${this.settings.modifier.active}`); let $sliderClone = this.$slider.cloneNode(true); this.$slider.dispatchEvent(new CustomEvent('destroy', { detail: { slider: this, $slider: $sliderClone } })); this.$slider.parentNode.replaceChild($sliderClone, this.$slider); if (this.$slider === this.settings.intersection.root) { this.settings.intersection.root = $sliderClone; } this.settings.node = this.$slider = $sliderClone; return this.public; } __resetElement(attribute) { let $el = this[attribute]; if (typeof $el === 'HTMLElement' && $el.hasOwnProperty('parentNode')) { $el.parentNode.removeChild($el); $el = false; } } }