UNPKG

8.77 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.translate = translate;
7exports.infiniteIndex = infiniteIndex;
8exports.clampNumber = clampNumber;
9exports["default"] = slidy;
10var LINEAR_ANIMATION = 'linear';
11var VALID_SWIPE_DISTANCE = 50;
12var TRANSITION_END = 'transitionend';
13var abs = Math.abs;
14var EVENT_OPTIONS = {
15 passive: false
16};
17
18function translate(to, moveX, percentatge) {
19 if (percentatge === void 0) {
20 percentatge = 100;
21 }
22
23 var translation = to * percentatge * -1;
24 var x = moveX ? "calc(" + translation + "% - " + moveX + "px)" : translation + "%";
25 return "translate3d(" + x + ", 0, 0)";
26}
27
28function infiniteIndex(index, end) {
29 if (index < 0) return end - 1;else if (index >= end) return 0;else return index;
30}
31
32function clampNumber(x, minValue, maxValue) {
33 return Math.min(Math.max(x, minValue), maxValue);
34}
35
36function getTouchCoordinatesFromEvent(e) {
37 return e.targetTouches ? e.targetTouches[0] : e.touches[0];
38}
39/**
40 *
41 * @param {number} duration
42 * @param {string} ease
43 * @param {number} index
44 * @param {number} x
45 * @param {number} percentatge
46 */
47
48
49function getTranslationCSS(duration, ease, index, x, percentatge) {
50 var easeCssText = ease !== '' ? "transition-timing-function: " + ease + ";" : '';
51 var durationCssText = duration ? "transition-duration: " + duration + "ms;" : '';
52 return "" + easeCssText + durationCssText + "transform: " + translate(index, x, percentatge) + ";";
53}
54
55function cleanContainer(container) {
56 // remove all the elements except the last one as it seems to be old data in the HTML
57 // that's specially useful for dynamic content
58 while (container.childElementCount > 1) {
59 container !== null && container.removeChild(container.lastChild);
60 } // tell that the clean is done
61
62
63 return true;
64}
65
66function slidy(containerDOMEl, options) {
67 var doAfterSlide = options.doAfterSlide,
68 doBeforeSlide = options.doBeforeSlide,
69 ease = options.ease,
70 infiniteLoop = options.infiniteLoop,
71 initialSlide = options.initialSlide,
72 numOfSlides = options.numOfSlides,
73 onNext = options.onNext,
74 onPrev = options.onPrev,
75 slidesDOMEl = options.slidesDOMEl,
76 slideSpeed = options.slideSpeed;
77 var items = options.items; // if frameDOMEl is null, then we do nothing
78
79 if (containerDOMEl === null) return; // initialize some variables
80
81 var index = initialSlide;
82 var isScrolling = false;
83 var transitionEndCallbackActivated = false; // event handling
84
85 var deltaX = 0;
86 var deltaY = 0;
87 var touchOffsetX = 0;
88 var touchOffsetY = 0;
89 /**
90 * translates to a given position in a given time in milliseconds
91 *
92 * @param {number} duration time in milliseconds for the transistion
93 * @param {string} ease easing css property
94 * @param {number} x Number of pixels to fine tuning translation
95 */
96
97 function _translate(duration, ease, x) {
98 if (ease === void 0) {
99 ease = '';
100 }
101
102 if (x === void 0) {
103 x = 0;
104 }
105
106 var percentatge = 100 / numOfSlides;
107 slidesDOMEl.style.cssText = getTranslationCSS(duration, ease, index, x, percentatge);
108 }
109 /**
110 * slide function called by prev, next & touchend
111 *
112 * determine nextIndex and slide to next postion
113 * under restrictions of the defined options
114 *
115 * @param {boolean} direction 'true' for right, 'false' for left
116 */
117
118
119 function slide(direction) {
120 var movement = direction === true ? 1 : -1; // calculate the nextIndex according to the movement
121
122 var nextIndex = index + 1 * movement;
123 /**
124 * If the slider has the infiniteLoop option
125 * nextIndex will start from the start when arrives to the end
126 * and vice versa
127 */
128
129 if (infiniteLoop) nextIndex = infiniteIndex(nextIndex, items); // nextIndex should be between 0 and items minus 1
130
131 nextIndex = clampNumber(nextIndex, 0, items - 1);
132 goTo(nextIndex);
133 }
134
135 function onTransitionEnd() {
136 if (transitionEndCallbackActivated === true) {
137 _translate(0);
138
139 transitionEndCallbackActivated = false;
140 }
141 }
142
143 function onTouchstart(e) {
144 var coords = getTouchCoordinatesFromEvent(e);
145 isScrolling = undefined;
146 touchOffsetX = coords.pageX;
147 touchOffsetY = coords.pageY;
148 }
149
150 function onTouchmove(e) {
151 // ensure swiping with one touch and not pinching
152 if (e.touches.length > 1 || e.scale && e.scale !== 1) return;
153 var coords = getTouchCoordinatesFromEvent(e);
154 deltaX = coords.pageX - touchOffsetX;
155 deltaY = coords.pageY - touchOffsetY;
156
157 if (typeof isScrolling === 'undefined') {
158 isScrolling = abs(deltaX) < abs(deltaY);
159 if (!isScrolling) document.ontouchmove = function (e) {
160 return e.preventDefault();
161 };
162 return;
163 }
164
165 if (!isScrolling) {
166 e.preventDefault();
167
168 _translate(0, LINEAR_ANIMATION, deltaX * -1);
169 }
170 }
171
172 function onTouchend() {
173 // hack the document to block scroll
174 document.ontouchmove = function () {
175 return true;
176 };
177
178 if (!isScrolling) {
179 /**
180 * is valid if:
181 * -> swipe distance is greater than the specified valid swipe distance
182 * -> swipe distance is more then a third of the swipe area
183 * @isValidSlide {Boolean}
184 */
185 var isValid = abs(deltaX) > VALID_SWIPE_DISTANCE;
186 /**
187 * is out of bounds if:
188 * -> index is 0 and deltaX is greater than 0
189 * -> index is the last slide and deltaX is smaller than 0
190 * @isOutOfBounds {Boolean}
191 */
192
193 var direction = deltaX < 0;
194 var isOutOfBounds = direction === false && index === 0 || direction === true && index === items - 1;
195 /**
196 * If the swipe is valid and we're not out of bounds
197 * -> Slide to the direction
198 * otherwise: go back to the previous slide with a linear animation
199 */
200
201 isValid === true && isOutOfBounds === false ? slide(direction) : _translate(slideSpeed, LINEAR_ANIMATION);
202 } // reset variables with the initial values
203
204
205 deltaX = deltaY = touchOffsetX = touchOffsetY = 0;
206 }
207 /**
208 * public
209 * setup function
210 */
211
212
213 function _setup() {
214 slidesDOMEl.addEventListener(TRANSITION_END, onTransitionEnd);
215 containerDOMEl.addEventListener('touchstart', onTouchstart, EVENT_OPTIONS);
216 containerDOMEl.addEventListener('touchmove', onTouchmove, EVENT_OPTIONS);
217 containerDOMEl.addEventListener('touchend', onTouchend, EVENT_OPTIONS);
218
219 if (index !== 0) {
220 _translate(0);
221 }
222 }
223 /**
224 * public
225 * clean content of the slider
226 */
227
228
229 function clean() {
230 return cleanContainer(slidesDOMEl);
231 }
232 /**
233 * public
234 * @param {number} nextIndex Index number to go to
235 */
236
237
238 function goTo(nextIndex) {
239 // if the nextIndex and the current is the same, we don't need to do the slide
240 if (nextIndex === index) return; // if the nextIndex is possible according to number of items, then use it
241
242 if (nextIndex <= items) {
243 // execute the callback from the options before sliding
244 doBeforeSlide({
245 currentSlide: index,
246 nextSlide: nextIndex
247 }); // execute the internal callback
248
249 nextIndex > index ? onNext(nextIndex) : onPrev(nextIndex);
250 index = nextIndex;
251 } // translate to the next index by a defined duration and ease function
252
253
254 _translate(slideSpeed, ease); // execute the callback from the options after sliding
255
256
257 slidesDOMEl.addEventListener(TRANSITION_END, function cb(e) {
258 doAfterSlide({
259 currentSlide: index
260 });
261 e.currentTarget.removeEventListener(e.type, cb);
262 });
263 }
264 /**
265 * public
266 * prev function: called on clickhandler
267 */
268
269
270 function prev(e) {
271 e.preventDefault();
272 e.stopPropagation();
273 slide(false);
274 }
275 /**
276 * public
277 * next function: called on clickhandler
278 */
279
280
281 function next(e) {
282 e.preventDefault();
283 e.stopPropagation();
284 slide(true);
285 }
286 /**
287 * public
288 * @param {number} newItems Number of items in the slider for dynamic content
289 */
290
291
292 function updateItems(newItems) {
293 items = newItems;
294 }
295 /**
296 * public
297 * destroy function: called to gracefully destroy the slidy instance
298 */
299
300
301 function destroy() {
302 // remove all touch listeners
303 containerDOMEl.removeEventListener('touchstart', onTouchstart, EVENT_OPTIONS);
304 containerDOMEl.removeEventListener('touchmove', onTouchmove, EVENT_OPTIONS);
305 containerDOMEl.removeEventListener('touchend', onTouchend, EVENT_OPTIONS); // remove transition listeners
306
307 slidesDOMEl.removeEventListener(TRANSITION_END, onTransitionEnd);
308 } // trigger initial setup
309
310
311 _setup(); // expose public api
312
313
314 return {
315 clean: clean,
316 destroy: destroy,
317 goTo: goTo,
318 next: next,
319 prev: prev,
320 slide: slide,
321 updateItems: updateItems
322 };
323}
\No newline at end of file