PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 1.8.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v1.8.2
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
merchant / assets / js / carousel.js

carousel.js in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 1.8.2, at assets/js/carousel.js

916 lines 35.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Siema v1.5.1
3 * Lightweight and simple carousel in pure JavaScript
4 * https://pawelgrzybek.github.io/siema/
5 *
6 * Copyright (c) 2017 Paweł Grzybek (https://pawelgrzybek.com/)
7 *
8 * Released under the MIT License
9 *
10 * Modified by aThemes
11 *
12 * @cc_on
13 */
14
15 'use strict';
16
17 function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
18 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
19 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
20 function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
21 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
22 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
23 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
24 function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
25 function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
26 var Siema = /*#__PURE__*/function () {
27 /**
28 * Create a Siema.
29 * @param {Object} options - Optional settings object.
30 */
31 function Siema(options) {
32 var _this2 = this;
33 _classCallCheck(this, Siema);
34 // Merge defaults with user's settings
35 this.config = Siema.mergeSettings(options);
36
37 // Resolve parent selector's type
38 this.parentSelector = typeof this.config.parentSelector === 'string' ? document.querySelector(this.config.parentSelector) : this.config.parentSelector;
39
40 // Resolve selector's type
41 this.selector = typeof this.config.selector === 'string' ? document.querySelector(this.config.selector) : this.config.selector;
42 if (this.parentSelector) {
43 this.selector = this.parentSelector.querySelector('.merchant-carousel-stage');
44 }
45
46 // Early throw if selector doesn't exists
47 if (this.selector === null) {
48 throw new Error('Something wrong with your selector 😭');
49 }
50 if (this.parentSelector.getAttribute('data-initialized') === 'true') {
51 return false;
52 }
53
54 // update perPage number dependable of user value
55 this.resolveSlidesNumber();
56
57 // Create global references
58 this.selectorWidth = this.selector.offsetWidth;
59 this.innerElements = [].slice.call(this.selector.children);
60 this.currentSlide = this.config.loop ? this.config.startIndex % this.innerElements.length : Math.max(0, Math.min(this.config.startIndex, this.innerElements.length - this.perPage));
61 this.transformProperty = Siema.webkitOrNot();
62
63 // Bind all event handlers for referencability
64 ['resizeHandler', 'touchstartHandler', 'touchendHandler', 'touchmoveHandler', 'mousedownHandler', 'mouseupHandler', 'mouseleaveHandler', 'mousemoveHandler', 'clickHandler', 'navNextHandler', 'navPrevHandler'].forEach(function (method) {
65 _this2[method] = _this2[method].bind(_this2);
66 });
67
68 // Build markup and apply required styling to elements
69 this.init();
70 }
71
72 /**
73 * Overrides default settings with custom ones.
74 * @param {Object} options - Optional settings object.
75 * @returns {Object} - Custom Siema settings.
76 */
77 _createClass(Siema, [{
78 key: "attachEvents",
79 value:
80 /**
81 * Attaches listeners to required events.
82 */
83 function attachEvents() {
84 // Resize element on window resize
85 window.addEventListener('resize', this.resizeHandler);
86
87 // If element is draggable / swipable, add event handlers
88 if (this.config.draggable) {
89 // Keep track pointer hold and dragging distance
90 this.pointerDown = false;
91 this.drag = {
92 startX: 0,
93 endX: 0,
94 startY: 0,
95 letItGo: null,
96 preventClick: false
97 };
98
99 // Touch events
100 this.selector.addEventListener('touchstart', this.touchstartHandler);
101 this.selector.addEventListener('touchend', this.touchendHandler);
102 this.selector.addEventListener('touchmove', this.touchmoveHandler);
103
104 // Mouse events
105 this.selector.addEventListener('mousedown', this.mousedownHandler);
106 this.selector.addEventListener('mouseup', this.mouseupHandler);
107 this.selector.addEventListener('mouseleave', this.mouseleaveHandler);
108 this.selector.addEventListener('mousemove', this.mousemoveHandler);
109
110 // Click
111 this.selector.addEventListener('click', this.clickHandler);
112
113 // Navigation
114 this.parentSelector.querySelector('.merchant-carousel-nav-next').addEventListener('click', this.navNextHandler);
115 this.parentSelector.querySelector('.merchant-carousel-nav-prev').addEventListener('click', this.navPrevHandler);
116 }
117 }
118 }, {
119 key: "detachEvents",
120 value:
121 /**
122 * Detaches listeners from required events.
123 */
124 function detachEvents() {
125 window.removeEventListener('resize', this.resizeHandler);
126 this.selector.removeEventListener('touchstart', this.touchstartHandler);
127 this.selector.removeEventListener('touchend', this.touchendHandler);
128 this.selector.removeEventListener('touchmove', this.touchmoveHandler);
129 this.selector.removeEventListener('mousedown', this.mousedownHandler);
130 this.selector.removeEventListener('mouseup', this.mouseupHandler);
131 this.selector.removeEventListener('mouseleave', this.mouseleaveHandler);
132 this.selector.removeEventListener('mousemove', this.mousemoveHandler);
133 this.selector.removeEventListener('click', this.clickHandler);
134 this.parentSelector.querySelector('.merchant-carousel-nav-next').removeEventListener('click', this.navNextHandler);
135 this.parentSelector.querySelector('.merchant-carousel-nav-prev').removeEventListener('click', this.navPrevHandler);
136 }
137
138 /**
139 * Builds the markup and attaches listeners to required events.
140 */
141 }, {
142 key: "init",
143 value: function init() {
144 // build navigation
145 this.buildNavigation();
146 this.attachEvents();
147
148 // hide everything out of selector's boundaries
149 this.selector.style.overflow = 'hidden';
150
151 // rtl or ltr
152 this.selector.style.direction = this.config.rtl ? 'rtl' : 'ltr';
153
154 // build a frame and slide to a currentSlide
155 this.buildSliderFrame();
156 this.config.onInit.call(this);
157 this.parentSelector.querySelector('.merchant-carousel-stage').classList.add('show');
158 if (this.parentSelector !== null) {
159 this.parentSelector.setAttribute('data-initialized', true);
160 }
161 }
162 }, {
163 key: "buildNavigation",
164 value: function buildNavigation() {
165 var next = document.createElement('a'),
166 nextSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg"),
167 prev = document.createElement('a'),
168 prevSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
169
170 // Next button
171 next.role = 'button';
172 next.href = '#';
173 next.className = 'merchant-carousel-nav merchant-carousel-nav-next';
174 nextSVG.setAttribute('width', 18);
175 nextSVG.setAttribute('height', 18);
176 nextSVG.setAttribute('viewBox', '0 0 10 16');
177 nextSVG.setAttribute('fill', 'none');
178 nextSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
179 nextSVG.setAttribute('class', 'stroke-based');
180 nextSVG.innerHTML = '<path d="M1.5 14.667L8.16667 8.00033L1.5 1.33366" stroke="#242021" stroke-width="1.5"></path>';
181 next.append(nextSVG);
182 this.parentSelector.querySelector('.merchant-carousel-wrapper').append(next);
183
184 // Prev button
185 prev.role = 'button';
186 prev.href = '#';
187 prev.className = 'merchant-carousel-nav merchant-carousel-nav-prev';
188 prevSVG.setAttribute('width', 18);
189 prevSVG.setAttribute('height', 18);
190 prevSVG.setAttribute('viewBox', '0 0 10 16');
191 prevSVG.setAttribute('fill', 'none');
192 prevSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
193 prevSVG.setAttribute('class', 'stroke-based');
194 prevSVG.innerHTML = '<path d="M8.5 1.33301L1.83333 7.99967L8.5 14.6663" stroke="#242021" stroke-width="1.5"></path>';
195 prev.append(prevSVG);
196 this.parentSelector.querySelector('.merchant-carousel-wrapper').append(prev);
197 }
198
199 /**
200 * Build a sliderFrame and slide to a current item.
201 */
202 }, {
203 key: "buildSliderFrame",
204 value: function buildSliderFrame() {
205 if (this.innerElements.length <= this.perPage) {
206 this.parentSelector.classList.add('no-nav');
207 this.parentSelector.querySelector('.merchant-carousel-nav-next').remove();
208 this.parentSelector.querySelector('.merchant-carousel-nav-prev').remove();
209 return false;
210 }
211 var widthItem = (this.selectorWidth + this.config.margin) / this.perPage;
212 var itemsToBuild = this.config.loop ? this.innerElements.length + 2 * this.perPage : this.innerElements.length;
213
214 // Create frame and apply styling
215 this.sliderFrame = document.createElement('div');
216 this.sliderFrame.style.width = widthItem * itemsToBuild + 'px';
217 this.enableTransition();
218 if (this.config.draggable) {
219 this.selector.style.cursor = '-webkit-grab';
220 }
221
222 // Create a document fragment to put slides into it
223 var docFragment = document.createDocumentFragment();
224
225 // Loop through the slides, add styling and add them to document fragment
226 if (this.config.loop) {
227 for (var i = this.innerElements.length - this.perPage; i < this.innerElements.length; i++) {
228 var element = this.buildSliderFrameItem(this.innerElements[i].cloneNode(true));
229 docFragment.appendChild(element);
230 }
231 }
232 for (var _i = 0; _i < this.innerElements.length; _i++) {
233 var element = this.buildSliderFrameItem(this.innerElements[_i]);
234 docFragment.appendChild(element);
235 }
236 if (this.config.loop) {
237 for (var _i2 = 0; _i2 < this.perPage; _i2++) {
238 var element = this.buildSliderFrameItem(this.innerElements[_i2].cloneNode(true));
239 docFragment.appendChild(element);
240 }
241 }
242
243 // Add fragment to the frame
244 this.sliderFrame.appendChild(docFragment);
245
246 // Clear selector (just in case something is there) and insert a frame
247 this.selector.innerHTML = '';
248 this.selector.appendChild(this.sliderFrame);
249
250 // Go to currently active slide after initial build
251 this.slideToCurrent();
252 }
253 }, {
254 key: "buildSliderFrameItem",
255 value: function buildSliderFrameItem(elm) {
256 var elementContainer = document.createElement('div');
257 elementContainer.style.cssFloat = this.config.rtl ? 'right' : 'left';
258 elementContainer.style.float = this.config.rtl ? 'right' : 'left';
259 elementContainer.style.width = (this.config.loop ? 100 / (this.innerElements.length + this.perPage * 2) : 100 / this.innerElements.length) + '%';
260 elementContainer.style.marginRight = this.config.margin + 'px';
261 elementContainer.appendChild(elm);
262 return elementContainer;
263 }
264
265 /**
266 * Determinates slides number accordingly to clients viewport.
267 */
268 }, {
269 key: "resolveSlidesNumber",
270 value: function resolveSlidesNumber() {
271 if (typeof this.config.perPage === 'number') {
272 this.perPage = this.config.perPage;
273 } else if (_typeof(this.config.perPage) === 'object') {
274 this.perPage = 1;
275 for (var viewport in this.config.perPage) {
276 if (window.innerWidth >= viewport) {
277 this.perPage = this.config.perPage[viewport];
278 }
279 }
280 }
281 }
282
283 /**
284 * Go to previous slide.
285 * @param {number} [howManySlides=1] - How many items to slide backward.
286 * @param {function} callback - Optional callback function.
287 */
288 }, {
289 key: "prev",
290 value: function prev() {
291 var howManySlides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
292 var callback = arguments.length > 1 ? arguments[1] : undefined;
293 // early return when there is nothing to slide
294 if (this.innerElements.length <= this.perPage) {
295 return;
296 }
297 var beforeChange = this.currentSlide;
298 if (this.config.loop) {
299 var isNewIndexClone = this.currentSlide - howManySlides < 0;
300 if (isNewIndexClone) {
301 this.disableTransition();
302 var mirrorSlideIndex = this.currentSlide + this.innerElements.length;
303 var mirrorSlideIndexOffset = this.perPage;
304 var moveTo = mirrorSlideIndex + mirrorSlideIndexOffset;
305 var offset = (this.config.rtl ? 1 : -1) * moveTo * (this.selectorWidth / this.perPage);
306 var dragDistance = this.config.draggable ? this.drag.endX - this.drag.startX : 0;
307 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat(offset + dragDistance, "px, 0, 0)");
308 this.currentSlide = mirrorSlideIndex - howManySlides;
309 } else {
310 this.currentSlide = this.currentSlide - howManySlides;
311 }
312 } else {
313 this.currentSlide = Math.max(this.currentSlide - howManySlides, 0);
314 }
315 if (beforeChange !== this.currentSlide) {
316 this.slideToCurrent(this.config.loop);
317 this.config.onChange.call(this);
318 if (callback) {
319 callback.call(this);
320 }
321 }
322 }
323
324 /**
325 * Go to next slide.
326 * @param {number} [howManySlides=1] - How many items to slide forward.
327 * @param {function} callback - Optional callback function.
328 */
329 }, {
330 key: "next",
331 value: function next() {
332 var howManySlides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
333 var callback = arguments.length > 1 ? arguments[1] : undefined;
334 // early return when there is nothing to slide
335 if (this.innerElements.length <= this.perPage) {
336 return;
337 }
338 var beforeChange = this.currentSlide;
339 if (this.config.loop) {
340 var isNewIndexClone = this.currentSlide + howManySlides > this.innerElements.length - this.perPage;
341 if (isNewIndexClone) {
342 this.disableTransition();
343 var mirrorSlideIndex = this.currentSlide - this.innerElements.length;
344 var mirrorSlideIndexOffset = this.perPage;
345 var moveTo = mirrorSlideIndex + mirrorSlideIndexOffset;
346 var offset = (this.config.rtl ? 1 : -1) * moveTo * (this.selectorWidth / this.perPage);
347 var dragDistance = this.config.draggable ? this.drag.endX - this.drag.startX : 0;
348 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat(offset + dragDistance, "px, 0, 0)");
349 this.currentSlide = mirrorSlideIndex + howManySlides;
350 } else {
351 this.currentSlide = this.currentSlide + howManySlides;
352 }
353 } else {
354 this.currentSlide = Math.min(this.currentSlide + howManySlides, this.innerElements.length - this.perPage);
355 }
356 if (beforeChange !== this.currentSlide) {
357 this.slideToCurrent(this.config.loop);
358 this.config.onChange.call(this);
359 if (callback) {
360 callback.call(this);
361 }
362 }
363 }
364
365 /**
366 * Disable transition on sliderFrame.
367 */
368 }, {
369 key: "disableTransition",
370 value: function disableTransition() {
371 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
372 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
373 }
374
375 /**
376 * Enable transition on sliderFrame.
377 */
378 }, {
379 key: "enableTransition",
380 value: function enableTransition() {
381 if (typeof this.sliderFrame === 'undefined') {
382 return false;
383 }
384 this.sliderFrame.style.webkitTransition = "all ".concat(this.config.duration, "ms ").concat(this.config.easing);
385 this.sliderFrame.style.transition = "all ".concat(this.config.duration, "ms ").concat(this.config.easing);
386 }
387
388 /**
389 * Go to slide with particular index
390 * @param {number} index - Item index to slide to.
391 * @param {function} callback - Optional callback function.
392 */
393 }, {
394 key: "goTo",
395 value: function goTo(index, callback) {
396 if (this.innerElements.length <= this.perPage) {
397 return;
398 }
399 var beforeChange = this.currentSlide;
400 this.currentSlide = this.config.loop ? index % this.innerElements.length : Math.min(Math.max(index, 0), this.innerElements.length - this.perPage);
401 if (beforeChange !== this.currentSlide) {
402 this.slideToCurrent();
403 this.config.onChange.call(this);
404 if (callback) {
405 callback.call(this);
406 }
407 }
408 }
409
410 /**
411 * Moves sliders frame to position of currently active slide
412 */
413 }, {
414 key: "slideToCurrent",
415 value: function slideToCurrent(enableTransition) {
416 var _this = this;
417 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
418 var offset = (this.config.rtl ? 1 : -1) * currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
419 if (typeof this.sliderFrame === 'undefined') {
420 return false;
421 }
422 if (enableTransition) {
423 requestAnimationFrame(function () {
424 requestAnimationFrame(function () {
425 _this.enableTransition();
426 _this.sliderFrame.style[_this.transformProperty] = 'translate3d(' + offset + 'px, 0, 0)';
427 });
428 });
429 } else {
430 this.enableTransition();
431 this.sliderFrame.style[this.transformProperty] = 'translate3d(' + offset + 'px, 0, 0)';
432 }
433 }
434
435 /**
436 * Recalculate drag /swipe event and reposition the frame of a slider
437 */
438 }, {
439 key: "updateAfterDrag",
440 value: function updateAfterDrag() {
441 var movement = (this.config.rtl ? -1 : 1) * (this.drag.endX - this.drag.startX);
442 var movementDistance = Math.abs(movement);
443 var howManySliderToSlide = this.config.multipleDrag ? Math.ceil(movementDistance / (this.selectorWidth / this.perPage)) : 1;
444 var slideToNegativeClone = movement > 0 && this.currentSlide - howManySliderToSlide < 0;
445 var slideToPositiveClone = movement < 0 && this.currentSlide + howManySliderToSlide > this.innerElements.length - this.perPage;
446 if (movement > 0 && movementDistance > this.config.threshold && this.innerElements.length > this.perPage) {
447 this.prev(howManySliderToSlide);
448 } else if (movement < 0 && movementDistance > this.config.threshold && this.innerElements.length > this.perPage) {
449 this.next(howManySliderToSlide);
450 }
451 this.slideToCurrent(slideToNegativeClone || slideToPositiveClone);
452 }
453
454 /**
455 * When window resizes, resize slider components as well
456 */
457 }, {
458 key: "resizeHandler",
459 value: function resizeHandler() {
460 // update perPage number dependable of user value
461 this.resolveSlidesNumber();
462
463 // relcalculate currentSlide
464 // prevent hiding items when browser width increases
465 if (this.currentSlide + this.perPage > this.innerElements.length) {
466 this.currentSlide = this.innerElements.length <= this.perPage ? 0 : this.innerElements.length - this.perPage;
467 }
468 this.selectorWidth = this.selector.offsetWidth;
469 this.buildSliderFrame();
470 }
471
472 /**
473 * Clear drag after touchend and mouseup event
474 */
475 }, {
476 key: "clearDrag",
477 value: function clearDrag() {
478 this.drag = {
479 startX: 0,
480 endX: 0,
481 startY: 0,
482 letItGo: null,
483 preventClick: this.drag.preventClick
484 };
485 }
486
487 /**
488 * touchstart event handler
489 */
490 }, {
491 key: "touchstartHandler",
492 value: function touchstartHandler(e) {
493 // Prevent dragging / swiping on inputs, selects and textareas
494 var ignoreSiema = ['TEXTAREA', 'OPTION', 'INPUT', 'SELECT'].indexOf(e.target.nodeName) !== -1;
495 if (ignoreSiema) {
496 return;
497 }
498 e.stopPropagation();
499 this.pointerDown = true;
500 this.drag.startX = e.touches[0].pageX;
501 this.drag.startY = e.touches[0].pageY;
502 }
503
504 /**
505 * touchend event handler
506 */
507 }, {
508 key: "touchendHandler",
509 value: function touchendHandler(e) {
510 e.stopPropagation();
511 this.pointerDown = false;
512 this.enableTransition();
513 if (this.drag.endX) {
514 this.updateAfterDrag();
515 }
516 this.clearDrag();
517 }
518
519 /**
520 * touchmove event handler
521 */
522 }, {
523 key: "touchmoveHandler",
524 value: function touchmoveHandler(e) {
525 e.stopPropagation();
526 if (this.drag.letItGo === null) {
527 this.drag.letItGo = Math.abs(this.drag.startY - e.touches[0].pageY) < Math.abs(this.drag.startX - e.touches[0].pageX);
528 }
529 if (this.pointerDown && this.drag.letItGo) {
530 e.preventDefault();
531 this.drag.endX = e.touches[0].pageX;
532 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
533 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
534 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
535 var currentOffset = currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
536 var dragOffset = this.drag.endX - this.drag.startX;
537 var offset = this.config.rtl ? currentOffset + dragOffset : currentOffset - dragOffset;
538 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat((this.config.rtl ? 1 : -1) * offset, "px, 0, 0)");
539 }
540 }
541
542 /**
543 * mousedown event handler
544 */
545 }, {
546 key: "mousedownHandler",
547 value: function mousedownHandler(e) {
548 // Prevent dragging / swiping on inputs, selects and textareas
549 var ignoreSiema = ['TEXTAREA', 'OPTION', 'INPUT', 'SELECT'].indexOf(e.target.nodeName) !== -1;
550 if (ignoreSiema) {
551 return;
552 }
553 e.preventDefault();
554 e.stopPropagation();
555 this.pointerDown = true;
556 this.drag.startX = e.pageX;
557 }
558
559 /**
560 * mouseup event handler
561 */
562 }, {
563 key: "mouseupHandler",
564 value: function mouseupHandler(e) {
565 e.stopPropagation();
566 this.pointerDown = false;
567 this.selector.style.cursor = '-webkit-grab';
568 this.enableTransition();
569 if (this.drag.endX) {
570 this.updateAfterDrag();
571 }
572 this.clearDrag();
573 }
574
575 /**
576 * mousemove event handler
577 */
578 }, {
579 key: "mousemoveHandler",
580 value: function mousemoveHandler(e) {
581 e.preventDefault();
582 if (this.pointerDown) {
583 // if dragged element is a link
584 // mark preventClick prop as a true
585 // to detemine about browser redirection later on
586 if (typeof e.target.closest('a') !== 'null') {
587 this.drag.preventClick = true;
588 }
589 if (typeof this.sliderFrame === 'undefined') {
590 return false;
591 }
592 this.drag.endX = e.pageX;
593 this.selector.style.cursor = '-webkit-grabbing';
594 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
595 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
596 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
597 var currentOffset = currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
598 var dragOffset = this.drag.endX - this.drag.startX;
599 var offset = this.config.rtl ? currentOffset + dragOffset : currentOffset - dragOffset;
600 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat((this.config.rtl ? 1 : -1) * offset, "px, 0, 0)");
601 }
602 }
603
604 /**
605 * mouseleave event handler
606 */
607 }, {
608 key: "mouseleaveHandler",
609 value: function mouseleaveHandler(e) {
610 if (this.pointerDown) {
611 this.pointerDown = false;
612 this.selector.style.cursor = '-webkit-grab';
613 this.drag.endX = e.pageX;
614 this.drag.preventClick = false;
615 this.enableTransition();
616 this.updateAfterDrag();
617 this.clearDrag();
618 }
619 }
620
621 /**
622 * click event handler
623 */
624 }, {
625 key: "clickHandler",
626 value: function clickHandler(e) {
627 // if the dragged element is a link
628 // prevent browsers from folowing the link
629 if (this.drag.preventClick) {
630 e.preventDefault();
631 }
632 this.drag.preventClick = false;
633 }
634 }, {
635 key: "navNextHandler",
636 value: function navNextHandler(e) {
637 e.preventDefault();
638 this.next(1);
639 }
640 }, {
641 key: "navPrevHandler",
642 value: function navPrevHandler(e) {
643 e.preventDefault();
644 this.prev(1);
645 }
646
647 /**
648 * Remove item from carousel.
649 * @param {number} index - Item index to remove.
650 * @param {function} callback - Optional callback to call after remove.
651 */
652 }, {
653 key: "remove",
654 value: function remove(index, callback) {
655 if (index < 0 || index >= this.innerElements.length) {
656 throw new Error('Item to remove doesn\'t exist 😭');
657 }
658
659 // Shift sliderFrame back by one item when:
660 // 1. Item with lower index than currenSlide is removed.
661 // 2. Last item is removed.
662 var lowerIndex = index < this.currentSlide;
663 var lastItem = this.currentSlide + this.perPage - 1 === index;
664 if (lowerIndex || lastItem) {
665 this.currentSlide--;
666 }
667 this.innerElements.splice(index, 1);
668
669 // build a frame and slide to a currentSlide
670 this.buildSliderFrame();
671 if (callback) {
672 callback.call(this);
673 }
674 }
675
676 /**
677 * Insert item to carousel at particular index.
678 * @param {HTMLElement} item - Item to insert.
679 * @param {number} index - Index of new new item insertion.
680 * @param {function} callback - Optional callback to call after insert.
681 */
682 }, {
683 key: "insert",
684 value: function insert(item, index, callback) {
685 if (index < 0 || index > this.innerElements.length + 1) {
686 throw new Error('Unable to inset it at this index 😭');
687 }
688 if (this.innerElements.indexOf(item) !== -1) {
689 throw new Error('The same item in a carousel? Really? Nope 😭');
690 }
691
692 // Avoid shifting content
693 var shouldItShift = index <= this.currentSlide > 0 && this.innerElements.length;
694 this.currentSlide = shouldItShift ? this.currentSlide + 1 : this.currentSlide;
695 this.innerElements.splice(index, 0, item);
696
697 // build a frame and slide to a currentSlide
698 this.buildSliderFrame();
699 if (callback) {
700 callback.call(this);
701 }
702 }
703
704 /**
705 * Prepernd item to carousel.
706 * @param {HTMLElement} item - Item to prepend.
707 * @param {function} callback - Optional callback to call after prepend.
708 */
709 }, {
710 key: "prepend",
711 value: function prepend(item, callback) {
712 this.insert(item, 0);
713 if (callback) {
714 callback.call(this);
715 }
716 }
717
718 /**
719 * Append item to carousel.
720 * @param {HTMLElement} item - Item to append.
721 * @param {function} callback - Optional callback to call after append.
722 */
723 }, {
724 key: "append",
725 value: function append(item, callback) {
726 this.insert(item, this.innerElements.length + 1);
727 if (callback) {
728 callback.call(this);
729 }
730 }
731
732 /**
733 * Removes listeners and optionally restores to initial markup
734 * @param {boolean} restoreMarkup - Determinants about restoring an initial markup.
735 * @param {function} callback - Optional callback function.
736 */
737 }, {
738 key: "destroy",
739 value: function destroy() {
740 var restoreMarkup = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
741 var callback = arguments.length > 1 ? arguments[1] : undefined;
742 this.detachEvents();
743 this.selector.style.cursor = 'auto';
744 if (restoreMarkup) {
745 var slides = document.createDocumentFragment();
746 for (var i = 0; i < this.innerElements.length; i++) {
747 slides.appendChild(this.innerElements[i]);
748 }
749 this.selector.innerHTML = '';
750 this.selector.appendChild(slides);
751 this.selector.removeAttribute('style');
752 }
753 if (callback) {
754 callback.call(this);
755 }
756 }
757 }], [{
758 key: "mergeSettings",
759 value: function mergeSettings(options) {
760 var settings = {
761 selector: '.siema',
762 duration: 200,
763 easing: 'ease-out',
764 perPage: 1,
765 startIndex: 0,
766 draggable: true,
767 multipleDrag: true,
768 threshold: 20,
769 loop: false,
770 rtl: false,
771 onInit: function onInit() {},
772 onChange: function onChange() {}
773 };
774 var userSttings = options;
775 for (var attrname in userSttings) {
776 settings[attrname] = userSttings[attrname];
777 }
778 return settings;
779 }
780
781 /**
782 * Determine if browser supports unprefixed transform property.
783 * Google Chrome since version 26 supports prefix-less transform
784 * @returns {string} - Transform property supported by client.
785 */
786 }, {
787 key: "webkitOrNot",
788 value: function webkitOrNot() {
789 var style = document.documentElement.style;
790 if (typeof style.transform === 'string') {
791 return 'transform';
792 }
793 return 'WebkitTransform';
794 }
795 }]);
796 return Siema;
797 }();
798 /**
799 * Merchant Carousel
800 *
801 */
802 var merchant = merchant || {};
803 merchant.carousel = {
804 domReady: function domReady(fn) {
805 if (typeof fn !== 'function') {
806 return;
807 }
808 if (document.readyState === 'interactive' || document.readyState === 'complete') {
809 return fn();
810 }
811 document.addEventListener('DOMContentLoaded', fn, false);
812 },
813 init: function init() {
814 this.build();
815 this.events();
816 },
817 build: function build() {
818 if (document.querySelector('.merchant-carousel') === null && document.querySelector('.has-cross-sells-carousel') === null && document.querySelector('.merchant-woocommerce-mini-cart__cross-sell') === null) {
819 return false;
820 }
821 var carouselEls = document.querySelectorAll('.merchant-carousel, #masthead .cross-sells, .merchant-side-mini-cart .cross-sells, .cart-collaterals .cross-sells');
822 var _iterator = _createForOfIteratorHelper(carouselEls),
823 _step;
824 try {
825 for (_iterator.s(); !(_step = _iterator.n()).done;) {
826 var carouselEl = _step.value;
827 if (carouselEl.querySelector('.merchant-carousel-stage') === null) {
828 carouselEl.querySelector('.products').classList.add('merchant-carousel-stage');
829 }
830 if (carouselEl.getAttribute('data-initialized') !== 'true') {
831 var perPage = carouselEl.getAttribute('data-per-page');
832 if (perPage === null) {
833 var stageClassList = carouselEl.querySelector('.products').classList.value;
834 [1, 2, 3, 4, 5].forEach(function (columns) {
835 if (stageClassList.indexOf('columns-' + columns) > 0) {
836 perPage = columns;
837 }
838 });
839 }
840
841 // Mount carousel wrapper
842 var wrapper = document.createElement('div'),
843 stage = carouselEl.querySelector('.merchant-carousel-stage');
844 wrapper.className = 'merchant-carousel-wrapper';
845 wrapper.innerHTML = stage.outerHTML;
846 stage.remove();
847 carouselEl.append(wrapper);
848
849 // Margin
850 var margin = 30;
851 if (typeof merchant_carousel !== 'undefined') {
852 margin = parseInt(merchant_carousel.margin_desktop);
853 } else if (carouselEl.closest('.merchant-woocommerce-mini-cart__cross-sell') !== null) {
854 margin = 15;
855 }
856
857 // Initialize
858 var carousel = new Siema({
859 parentSelector: carouselEl,
860 selector: '.merchant-carousel-stage',
861 duration: 200,
862 easing: 'ease-out',
863 perPage: perPage !== null ? {
864 0: 1,
865 768: 2,
866 1025: parseInt(perPage)
867 } : 2,
868 startIndex: 0,
869 draggable: true,
870 multipleDrag: false,
871 threshold: 20,
872 loop: true,
873 rtl: false,
874 // autoplay: true, TO DO
875 margin: margin,
876 onInit: function onInit() {
877 window.dispatchEvent(new Event('merchant.carousel.initialized'));
878 }
879 });
880 }
881 }
882 } catch (err) {
883 _iterator.e(err);
884 } finally {
885 _iterator.f();
886 }
887 },
888 events: function events() {
889 var _this = this;
890 if (typeof jQuery !== 'undefined') {
891 var onpageload = true;
892 jQuery(document.body).on('wc_fragment_refresh added_to_cart removed_from_cart', function () {
893 setTimeout(function () {
894 var mini_cart = document.getElementById('site-header-cart'),
895 mini_cart_list = mini_cart.querySelector('.cart_list');
896 if (mini_cart_list !== null) {
897 if (mini_cart_list.children.length > 2) {
898 mini_cart.classList.remove('mini-cart-has-no-scroll');
899 mini_cart.classList.add('mini-cart-has-scroll');
900 } else {
901 mini_cart.classList.remove('mini-cart-has-scroll');
902 mini_cart.classList.add('mini-cart-has-no-scroll');
903 }
904 }
905 _this.build();
906 onpageload = false;
907 }, onpageload ? 1000 : 0);
908 });
909 }
910 }
911 };
912
913 // Initialize.
914 merchant.carousel.domReady(function () {
915 merchant.carousel.init();
916 });