1import debounce from './debounce.js'; 2 3export class Slide { 4 constructor(slide, wrapper) { 5 this.slide = document.querySelector(slide) 6 this.wrapper = document.querySelector(wrapper); 7 this.dist = { finalPosition: 0, startX: 0, movement: 0 } 8 this.activeClass = 'active'; 9 this.changeEvent = new Event('changeEvent'); 10 } 11 12 transition(active) { 13 this.slide.style.transition = active ? 'transform .3s' : ''; 14 } 15 16 moveSlide(distX) { 17 this.dist.movePosition = distX; 18 this.slide.style.transform = `translate(${distX}px)`; 19 } 20 21 updatePosition(clientX) { 22 this.dist.movement = (this.dist.startX - clientX) * 1.6; 23 return this.dist.finalPosition - this.dist.movement; 24 } 25 26 onStart(event) { 27 let movetype; 28 if (event.type === 'mousedown') { 29 event.preventDefault(); 30 this.dist.startX = event.clientX; 31 movetype = 'mousemove'; 32 } else { 33 this.dist.startX = event.changedTouches[0].clientX; 34 movetype = 'touchmove'; 35 } 36 this.wrapper.addEventListener(movetype, this.onMove); 37 this.transition(false); 38 } 39 40 onMove(event) { 41 const pointerPosition = (event.type === 'mousemove') ? event.clientX : event.changedTouches[0].clientX; 42 const finalPosition = this.updatePosition(pointerPosition); 43 this.moveSlide(finalPosition); 44 } 45 46 onEnd(event) { 47 const movetype = (event.type === 'mouseup') ? 'mousemove' : 'touchmove'; 48 this.wrapper.removeEventListener(movetype, this.onMove); 49 this.dist.finalPosition = this.dist.movePosition; 50 this.transition(true); 51 this.changeSlideOnEnd(); 52 } 53 54 changeSlideOnEnd() { 55 if (this.dist.movement > 120 && this.index.next !== undefined) { 56 this.activeNextSlide(); 57 } else if (this.dist.movement < -120 && this.index.prev !== undefined) { 58 this.activePrevSlide(); 59 } else { 60 this.changeSlide(this.index.active); 61 } 62 } 63 64 addSlideEvents() { 65 this.wrapper.addEventListener('mousedown', this.onStart); 66 this.wrapper.addEventListener('touchstart', this.onStart, {passive: true}); 67 this.wrapper.addEventListener('mouseup', this.onEnd); 68 this.wrapper.addEventListener('touchend', this.onEnd); 69 } 70 71 // Slides config 72 73 slidePosition(slide) { 74 const margin = (this.wrapper.offsetWidth - slide.offsetWidth) / 2; 75 return -(slide.offsetLeft - margin); 76 } 77 78 slidesConfig() { 79 this.slideArray = [...this.slide.children].map((element) => { 80 const position = this.slidePosition(element); 81 return { position, element }; 82 }); 83 } 84 85 slidesIndexNav(index) { 86 const last = this.slideArray.length - 1; 87 this.index = { 88 prev: index ? index - 1 : undefined, 89 active: index, 90 next: index === last ? undefined : index + 1, 91 } 92 } 93 94 changeSlide(index) { 95 const activeSlide = this.slideArray[index]; 96 this.moveSlide(activeSlide.position); 97 this.slidesIndexNav(index); 98 this.dist.finalPosition = activeSlide.position; 99 this.changeActiveClass(); 100 this.wrapper.dispatchEvent(this.changeEvent); 101 } 102 103 changeActiveClass() { 104 this.slideArray.forEach(item => item.element.classList.remove(this.activeClass)); 105 this.slideArray[this.index.active].element.classList.add(this.activeClass); 106 } 107 108 activePrevSlide() { 109 if (this.index.prev !== undefined) this.changeSlide(this.index.prev); 110 } 111 112 activeNextSlide() { 113 if (this.index.next !== undefined) this.changeSlide(this.index.next); 114 } 115 116 onResize() { 117 setTimeout(() => { 118 this.slidesConfig(); 119 this.changeSlide(this.index.active); 120 }, 1000); 121 } 122 123 addResizeEvent() { 124 window.addEventListener('resize', this.onResize); 125 } 126 127 bindEvents() { 128 this.onStart = this.onStart.bind(this); 129 this.onMove = this.onMove.bind(this); 130 this.onEnd = this.onEnd.bind(this); 131 132 this.activePrevSlide = this.activePrevSlide.bind(this); 133 this.activeNextSlide = this.activeNextSlide.bind(this); 134 135 this.onResize = debounce(this.onResize.bind(this), 200); 136 } 137 138 init() { 139 this.bindEvents(); 140 this.transition(true); 141 this.addSlideEvents(); 142 this.slidesConfig(); 143 this.addResizeEvent(); 144 this.changeSlide(0); 145 return this; 146 } 147} 148 149export default class SlideNav extends Slide { 150 constructor(slide, wrapper) { 151 super(slide, wrapper); 152 this.bindControlEvents(); 153 } 154 155 addArrow(prev, next) { 156 this.prevElement = document.querySelector(prev); 157 this.nextElement = document.querySelector(next); 158 this.addArrowEvent(); 159 } 160 161 addArrowEvent() { 162 this.prevElement.addEventListener('click', this.activePrevSlide); 163 this.nextElement.addEventListener('click', this.activeNextSlide); 164 } 165 166 createControl() { 167 const control = document.createElement('ul'); 168 control.dataset.control = 'slide'; 169 this.slideArray.forEach((item, index) => { 170 control.innerHTML += `<li><a href="#slide${index + 1}">${index + 1}</a></li>`; 171 }); 172 this.wrapper.appendChild(control); 173 return control; 174 } 175 176 eventControl(item, index) { 177 item.addEventListener('click', (event) => { 178 event.preventDefault(); 179 this.changeSlide(index); 180 }); 181 this.wrapper.addEventListener('changeEvent', this.activeControlItem); 182 } 183 184 activeControlItem() { 185 this.controlArray.forEach(item => item.classList.remove(this.activeClass)); 186 this.controlArray[this.index.active].classList.add(this.activeClass); 187 } 188 189 addControl(customControl) { 190 this.control = document.querySelector(customControl) || this.createControl(); 191 this.controlArray = [...this.control.children]; 192 193 this.activeControlItem(); 194 this.controlArray.forEach(this.eventControl); 195 } 196 197 bindControlEvents() { 198 this.eventControl = this.eventControl.bind(this); 199 this.activeControlItem = this.activeControlItem.bind(this); 200 } 201}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.