PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.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 2.3.2, at assets/js/carousel.js

938 lines 36.2 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(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
18 function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
19 function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
20 function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
21 function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
22 function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
23 function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
24 function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
25 function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
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 return _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 var _this$parentSelector$, _this$parentSelector$2;
207 this.parentSelector.classList.add('no-nav');
208 (_this$parentSelector$ = this.parentSelector.querySelector('.merchant-carousel-nav-next')) === null || _this$parentSelector$ === void 0 || _this$parentSelector$.remove();
209 (_this$parentSelector$2 = this.parentSelector.querySelector('.merchant-carousel-nav-prev')) === null || _this$parentSelector$2 === void 0 || _this$parentSelector$2.remove();
210 return false;
211 }
212 var widthItem = (this.selectorWidth + this.config.margin) / this.perPage;
213 var itemsToBuild = this.config.loop ? this.innerElements.length + 2 * this.perPage : this.innerElements.length;
214
215 // Create frame and apply styling
216 this.sliderFrame = document.createElement('div');
217 this.sliderFrame.style.width = widthItem * itemsToBuild + 'px';
218 this.enableTransition();
219 if (this.config.draggable) {
220 this.selector.style.cursor = '-webkit-grab';
221 }
222
223 // Create a document fragment to put slides into it
224 var docFragment = document.createDocumentFragment();
225
226 // Loop through the slides, add styling and add them to document fragment
227 if (this.config.loop) {
228 for (var i = this.innerElements.length - this.perPage; i < this.innerElements.length; i++) {
229 var element = this.buildSliderFrameItem(this.innerElements[i].cloneNode(true));
230 docFragment.appendChild(element);
231 }
232 }
233 for (var _i = 0; _i < this.innerElements.length; _i++) {
234 var element = this.buildSliderFrameItem(this.innerElements[_i]);
235 docFragment.appendChild(element);
236 }
237 if (this.config.loop) {
238 for (var _i2 = 0; _i2 < this.perPage; _i2++) {
239 var element = this.buildSliderFrameItem(this.innerElements[_i2].cloneNode(true));
240 docFragment.appendChild(element);
241 }
242 }
243
244 // Add fragment to the frame
245 this.sliderFrame.appendChild(docFragment);
246
247 // Clear selector (just in case something is there) and insert a frame
248 this.selector.innerHTML = '';
249 this.selector.appendChild(this.sliderFrame);
250
251 // Go to currently active slide after initial build
252 this.slideToCurrent();
253 }
254 }, {
255 key: "buildSliderFrameItem",
256 value: function buildSliderFrameItem(elm) {
257 var elementContainer = document.createElement('div');
258 elementContainer.style.cssFloat = this.config.rtl ? 'right' : 'left';
259 elementContainer.style.float = this.config.rtl ? 'right' : 'left';
260 elementContainer.style.width = (this.config.loop ? 100 / (this.innerElements.length + this.perPage * 2) : 100 / this.innerElements.length) + '%';
261 elementContainer.style.marginRight = this.config.margin + 'px';
262 elementContainer.appendChild(elm);
263 return elementContainer;
264 }
265
266 /**
267 * Determinates slides number accordingly to clients viewport.
268 */
269 }, {
270 key: "resolveSlidesNumber",
271 value: function resolveSlidesNumber() {
272 if (typeof this.config.perPage === 'number') {
273 this.perPage = this.config.perPage;
274 } else if (_typeof(this.config.perPage) === 'object') {
275 this.perPage = 1;
276 for (var viewport in this.config.perPage) {
277 if (window.innerWidth >= viewport) {
278 this.perPage = this.config.perPage[viewport];
279 }
280 }
281 }
282 }
283
284 /**
285 * Go to previous slide.
286 * @param {number} [howManySlides=1] - How many items to slide backward.
287 * @param {function} callback - Optional callback function.
288 */
289 }, {
290 key: "prev",
291 value: function prev() {
292 var howManySlides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
293 var callback = arguments.length > 1 ? arguments[1] : undefined;
294 // early return when there is nothing to slide
295 if (this.innerElements.length <= this.perPage) {
296 return;
297 }
298 var beforeChange = this.currentSlide;
299 if (this.config.loop) {
300 var isNewIndexClone = this.currentSlide - howManySlides < 0;
301 if (isNewIndexClone) {
302 this.disableTransition();
303 var mirrorSlideIndex = this.currentSlide + this.innerElements.length;
304 var mirrorSlideIndexOffset = this.perPage;
305 var moveTo = mirrorSlideIndex + mirrorSlideIndexOffset;
306 var offset = (this.config.rtl ? 1 : -1) * moveTo * (this.selectorWidth / this.perPage);
307 var dragDistance = this.config.draggable ? this.drag.endX - this.drag.startX : 0;
308 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat(offset + dragDistance, "px, 0, 0)");
309 this.currentSlide = mirrorSlideIndex - howManySlides;
310 } else {
311 this.currentSlide = this.currentSlide - howManySlides;
312 }
313 } else {
314 this.currentSlide = Math.max(this.currentSlide - howManySlides, 0);
315 }
316 if (beforeChange !== this.currentSlide) {
317 this.slideToCurrent(this.config.loop);
318 this.config.onChange.call(this);
319 if (callback) {
320 callback.call(this);
321 }
322 }
323 }
324
325 /**
326 * Go to next slide.
327 * @param {number} [howManySlides=1] - How many items to slide forward.
328 * @param {function} callback - Optional callback function.
329 */
330 }, {
331 key: "next",
332 value: function next() {
333 var howManySlides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
334 var callback = arguments.length > 1 ? arguments[1] : undefined;
335 // early return when there is nothing to slide
336 if (this.innerElements.length <= this.perPage) {
337 return;
338 }
339 var beforeChange = this.currentSlide;
340 if (this.config.loop) {
341 var isNewIndexClone = this.currentSlide + howManySlides > this.innerElements.length - this.perPage;
342 if (isNewIndexClone) {
343 this.disableTransition();
344 var mirrorSlideIndex = this.currentSlide - this.innerElements.length;
345 var mirrorSlideIndexOffset = this.perPage;
346 var moveTo = mirrorSlideIndex + mirrorSlideIndexOffset;
347 var offset = (this.config.rtl ? 1 : -1) * moveTo * (this.selectorWidth / this.perPage);
348 var dragDistance = this.config.draggable ? this.drag.endX - this.drag.startX : 0;
349 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat(offset + dragDistance, "px, 0, 0)");
350 this.currentSlide = mirrorSlideIndex + howManySlides;
351 } else {
352 this.currentSlide = this.currentSlide + howManySlides;
353 }
354 } else {
355 this.currentSlide = Math.min(this.currentSlide + howManySlides, this.innerElements.length - this.perPage);
356 }
357 if (beforeChange !== this.currentSlide) {
358 this.slideToCurrent(this.config.loop);
359 this.config.onChange.call(this);
360 if (callback) {
361 callback.call(this);
362 }
363 }
364 }
365
366 /**
367 * Disable transition on sliderFrame.
368 */
369 }, {
370 key: "disableTransition",
371 value: function disableTransition() {
372 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
373 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
374 }
375
376 /**
377 * Enable transition on sliderFrame.
378 */
379 }, {
380 key: "enableTransition",
381 value: function enableTransition() {
382 if (typeof this.sliderFrame === 'undefined') {
383 return false;
384 }
385 this.sliderFrame.style.webkitTransition = "all ".concat(this.config.duration, "ms ").concat(this.config.easing);
386 this.sliderFrame.style.transition = "all ".concat(this.config.duration, "ms ").concat(this.config.easing);
387 }
388
389 /**
390 * Go to slide with particular index
391 * @param {number} index - Item index to slide to.
392 * @param {function} callback - Optional callback function.
393 */
394 }, {
395 key: "goTo",
396 value: function goTo(index, callback) {
397 if (this.innerElements.length <= this.perPage) {
398 return;
399 }
400 var beforeChange = this.currentSlide;
401 this.currentSlide = this.config.loop ? index % this.innerElements.length : Math.min(Math.max(index, 0), this.innerElements.length - this.perPage);
402 if (beforeChange !== this.currentSlide) {
403 this.slideToCurrent();
404 this.config.onChange.call(this);
405 if (callback) {
406 callback.call(this);
407 }
408 }
409 }
410
411 /**
412 * Moves sliders frame to position of currently active slide
413 */
414 }, {
415 key: "slideToCurrent",
416 value: function slideToCurrent(enableTransition) {
417 var _this = this;
418 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
419 var offset = (this.config.rtl ? 1 : -1) * currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
420 if (typeof this.sliderFrame === 'undefined') {
421 return false;
422 }
423 if (enableTransition) {
424 requestAnimationFrame(function () {
425 requestAnimationFrame(function () {
426 _this.enableTransition();
427 _this.sliderFrame.style[_this.transformProperty] = 'translate3d(' + offset + 'px, 0, 0)';
428 });
429 });
430 } else {
431 this.enableTransition();
432 this.sliderFrame.style[this.transformProperty] = 'translate3d(' + offset + 'px, 0, 0)';
433 }
434 }
435
436 /**
437 * Recalculate drag /swipe event and reposition the frame of a slider
438 */
439 }, {
440 key: "updateAfterDrag",
441 value: function updateAfterDrag() {
442 var movement = (this.config.rtl ? -1 : 1) * (this.drag.endX - this.drag.startX);
443 var movementDistance = Math.abs(movement);
444 var howManySliderToSlide = this.config.multipleDrag ? Math.ceil(movementDistance / (this.selectorWidth / this.perPage)) : 1;
445 var slideToNegativeClone = movement > 0 && this.currentSlide - howManySliderToSlide < 0;
446 var slideToPositiveClone = movement < 0 && this.currentSlide + howManySliderToSlide > this.innerElements.length - this.perPage;
447 if (movement > 0 && movementDistance > this.config.threshold && this.innerElements.length > this.perPage) {
448 this.prev(howManySliderToSlide);
449 } else if (movement < 0 && movementDistance > this.config.threshold && this.innerElements.length > this.perPage) {
450 this.next(howManySliderToSlide);
451 }
452 this.slideToCurrent(slideToNegativeClone || slideToPositiveClone);
453 }
454
455 /**
456 * When window resizes, resize slider components as well
457 */
458 }, {
459 key: "resizeHandler",
460 value: function resizeHandler() {
461 // update perPage number dependable of user value
462 this.resolveSlidesNumber();
463
464 // relcalculate currentSlide
465 // prevent hiding items when browser width increases
466 if (this.currentSlide + this.perPage > this.innerElements.length) {
467 this.currentSlide = this.innerElements.length <= this.perPage ? 0 : this.innerElements.length - this.perPage;
468 }
469 this.selectorWidth = this.selector.offsetWidth;
470 this.buildSliderFrame();
471 }
472
473 /**
474 * Clear drag after touchend and mouseup event
475 */
476 }, {
477 key: "clearDrag",
478 value: function clearDrag() {
479 this.drag = {
480 startX: 0,
481 endX: 0,
482 startY: 0,
483 letItGo: null,
484 preventClick: this.drag.preventClick
485 };
486 }
487
488 /**
489 * touchstart event handler
490 */
491 }, {
492 key: "touchstartHandler",
493 value: function touchstartHandler(e) {
494 // Prevent dragging / swiping on inputs, selects and textareas
495 var ignoreSiema = ['TEXTAREA', 'OPTION', 'INPUT', 'SELECT'].indexOf(e.target.nodeName) !== -1;
496 if (ignoreSiema) {
497 return;
498 }
499 e.stopPropagation();
500 this.pointerDown = true;
501 this.drag.startX = e.touches[0].pageX;
502 this.drag.startY = e.touches[0].pageY;
503 }
504
505 /**
506 * touchend event handler
507 */
508 }, {
509 key: "touchendHandler",
510 value: function touchendHandler(e) {
511 e.stopPropagation();
512 this.pointerDown = false;
513 this.enableTransition();
514 if (this.drag.endX) {
515 this.updateAfterDrag();
516 }
517 this.clearDrag();
518 }
519
520 /**
521 * touchmove event handler
522 */
523 }, {
524 key: "touchmoveHandler",
525 value: function touchmoveHandler(e) {
526 e.stopPropagation();
527 if (this.drag.letItGo === null) {
528 this.drag.letItGo = Math.abs(this.drag.startY - e.touches[0].pageY) < Math.abs(this.drag.startX - e.touches[0].pageX);
529 }
530 if (this.pointerDown && this.drag.letItGo) {
531 e.preventDefault();
532 this.drag.endX = e.touches[0].pageX;
533 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
534 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
535 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
536 var currentOffset = currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
537 var dragOffset = this.drag.endX - this.drag.startX;
538 var offset = this.config.rtl ? currentOffset + dragOffset : currentOffset - dragOffset;
539 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat((this.config.rtl ? 1 : -1) * offset, "px, 0, 0)");
540 }
541 }
542
543 /**
544 * mousedown event handler
545 */
546 }, {
547 key: "mousedownHandler",
548 value: function mousedownHandler(e) {
549 // Prevent dragging / swiping on inputs, selects and textareas
550 var ignoreSiema = ['TEXTAREA', 'OPTION', 'INPUT', 'SELECT'].indexOf(e.target.nodeName) !== -1;
551 if (ignoreSiema) {
552 return;
553 }
554 e.preventDefault();
555 e.stopPropagation();
556 this.pointerDown = true;
557 this.drag.startX = e.pageX;
558 }
559
560 /**
561 * mouseup event handler
562 */
563 }, {
564 key: "mouseupHandler",
565 value: function mouseupHandler(e) {
566 e.stopPropagation();
567 this.pointerDown = false;
568 this.selector.style.cursor = '-webkit-grab';
569 this.enableTransition();
570 if (this.drag.endX) {
571 this.updateAfterDrag();
572 }
573 this.clearDrag();
574 }
575
576 /**
577 * mousemove event handler
578 */
579 }, {
580 key: "mousemoveHandler",
581 value: function mousemoveHandler(e) {
582 e.preventDefault();
583 if (this.pointerDown) {
584 // if dragged element is a link
585 // mark preventClick prop as a true
586 // to detemine about browser redirection later on
587 if (typeof e.target.closest('a') !== 'null') {
588 this.drag.preventClick = true;
589 }
590 if (typeof this.sliderFrame === 'undefined') {
591 return false;
592 }
593 this.drag.endX = e.pageX;
594 this.selector.style.cursor = '-webkit-grabbing';
595 this.sliderFrame.style.webkitTransition = "all 0ms ".concat(this.config.easing);
596 this.sliderFrame.style.transition = "all 0ms ".concat(this.config.easing);
597 var currentSlide = this.config.loop ? this.currentSlide + this.perPage : this.currentSlide;
598 var currentOffset = currentSlide * ((this.selectorWidth + this.config.margin) / this.perPage);
599 var dragOffset = this.drag.endX - this.drag.startX;
600 var offset = this.config.rtl ? currentOffset + dragOffset : currentOffset - dragOffset;
601 this.sliderFrame.style[this.transformProperty] = "translate3d(".concat((this.config.rtl ? 1 : -1) * offset, "px, 0, 0)");
602 }
603 }
604
605 /**
606 * mouseleave event handler
607 */
608 }, {
609 key: "mouseleaveHandler",
610 value: function mouseleaveHandler(e) {
611 if (this.pointerDown) {
612 this.pointerDown = false;
613 this.selector.style.cursor = '-webkit-grab';
614 this.drag.endX = e.pageX;
615 this.drag.preventClick = false;
616 this.enableTransition();
617 this.updateAfterDrag();
618 this.clearDrag();
619 }
620 }
621
622 /**
623 * click event handler
624 */
625 }, {
626 key: "clickHandler",
627 value: function clickHandler(e) {
628 // if the dragged element is a link
629 // prevent browsers from folowing the link
630 if (this.drag.preventClick) {
631 e.preventDefault();
632 }
633 this.drag.preventClick = false;
634 }
635 }, {
636 key: "navNextHandler",
637 value: function navNextHandler(e) {
638 e.preventDefault();
639 this.next(1);
640 }
641 }, {
642 key: "navPrevHandler",
643 value: function navPrevHandler(e) {
644 e.preventDefault();
645 this.prev(1);
646 }
647
648 /**
649 * Remove item from carousel.
650 * @param {number} index - Item index to remove.
651 * @param {function} callback - Optional callback to call after remove.
652 */
653 }, {
654 key: "remove",
655 value: function remove(index, callback) {
656 if (index < 0 || index >= this.innerElements.length) {
657 throw new Error('Item to remove doesn\'t exist 😭');
658 }
659
660 // Shift sliderFrame back by one item when:
661 // 1. Item with lower index than currenSlide is removed.
662 // 2. Last item is removed.
663 var lowerIndex = index < this.currentSlide;
664 var lastItem = this.currentSlide + this.perPage - 1 === index;
665 if (lowerIndex || lastItem) {
666 this.currentSlide--;
667 }
668 this.innerElements.splice(index, 1);
669
670 // build a frame and slide to a currentSlide
671 this.buildSliderFrame();
672 if (callback) {
673 callback.call(this);
674 }
675 }
676
677 /**
678 * Insert item to carousel at particular index.
679 * @param {HTMLElement} item - Item to insert.
680 * @param {number} index - Index of new new item insertion.
681 * @param {function} callback - Optional callback to call after insert.
682 */
683 }, {
684 key: "insert",
685 value: function insert(item, index, callback) {
686 if (index < 0 || index > this.innerElements.length + 1) {
687 throw new Error('Unable to inset it at this index 😭');
688 }
689 if (this.innerElements.indexOf(item) !== -1) {
690 throw new Error('The same item in a carousel? Really? Nope 😭');
691 }
692
693 // Avoid shifting content
694 var shouldItShift = index <= this.currentSlide > 0 && this.innerElements.length;
695 this.currentSlide = shouldItShift ? this.currentSlide + 1 : this.currentSlide;
696 this.innerElements.splice(index, 0, item);
697
698 // build a frame and slide to a currentSlide
699 this.buildSliderFrame();
700 if (callback) {
701 callback.call(this);
702 }
703 }
704
705 /**
706 * Prepernd item to carousel.
707 * @param {HTMLElement} item - Item to prepend.
708 * @param {function} callback - Optional callback to call after prepend.
709 */
710 }, {
711 key: "prepend",
712 value: function prepend(item, callback) {
713 this.insert(item, 0);
714 if (callback) {
715 callback.call(this);
716 }
717 }
718
719 /**
720 * Append item to carousel.
721 * @param {HTMLElement} item - Item to append.
722 * @param {function} callback - Optional callback to call after append.
723 */
724 }, {
725 key: "append",
726 value: function append(item, callback) {
727 this.insert(item, this.innerElements.length + 1);
728 if (callback) {
729 callback.call(this);
730 }
731 }
732
733 /**
734 * Removes listeners and optionally restores to initial markup
735 * @param {boolean} restoreMarkup - Determinants about restoring an initial markup.
736 * @param {function} callback - Optional callback function.
737 */
738 }, {
739 key: "destroy",
740 value: function destroy() {
741 var restoreMarkup = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
742 var callback = arguments.length > 1 ? arguments[1] : undefined;
743 this.detachEvents();
744 this.selector.style.cursor = 'auto';
745 if (restoreMarkup) {
746 var slides = document.createDocumentFragment();
747 for (var i = 0; i < this.innerElements.length; i++) {
748 slides.appendChild(this.innerElements[i]);
749 }
750 this.selector.innerHTML = '';
751 this.selector.appendChild(slides);
752 this.selector.removeAttribute('style');
753 }
754 if (callback) {
755 callback.call(this);
756 }
757 }
758 }], [{
759 key: "mergeSettings",
760 value: function mergeSettings(options) {
761 var settings = {
762 selector: '.siema',
763 duration: 200,
764 easing: 'ease-out',
765 perPage: 1,
766 startIndex: 0,
767 draggable: true,
768 multipleDrag: true,
769 threshold: 20,
770 loop: false,
771 rtl: false,
772 onInit: function onInit() {},
773 onChange: function onChange() {}
774 };
775 var userSttings = options;
776 for (var attrname in userSttings) {
777 settings[attrname] = userSttings[attrname];
778 }
779 return settings;
780 }
781
782 /**
783 * Determine if browser supports unprefixed transform property.
784 * Google Chrome since version 26 supports prefix-less transform
785 * @returns {string} - Transform property supported by client.
786 */
787 }, {
788 key: "webkitOrNot",
789 value: function webkitOrNot() {
790 var style = document.documentElement.style;
791 if (typeof style.transform === 'string') {
792 return 'transform';
793 }
794 return 'WebkitTransform';
795 }
796 }]);
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 var that = this;
812 document.addEventListener('DOMContentLoaded', function () {
813 that.init(); // Required for some themes
814 });
815 jQuery(document).on('photoSliderTriggered', function () {
816 that.init();
817 });
818 },
819 init: function init() {
820 this.build();
821 this.events();
822 },
823 build: function build() {
824 if (document.querySelector('.merchant-carousel') === null && document.querySelector('.has-cross-sells-carousel') === null && document.querySelector('.merchant-woocommerce-mini-cart__cross-sell') === null) {
825 return false;
826 }
827 var carouselEls = document.querySelectorAll('.merchant-carousel, #masthead .cross-sells, .merchant-side-mini-cart .cross-sells, .cart-collaterals .cross-sells');
828 var _iterator = _createForOfIteratorHelper(carouselEls),
829 _step;
830 try {
831 for (_iterator.s(); !(_step = _iterator.n()).done;) {
832 var carouselEl = _step.value;
833 if (carouselEl.querySelector('.merchant-carousel-stage') === null) {
834 carouselEl.querySelector('.products').classList.add('merchant-carousel-stage');
835 }
836 if (carouselEl.getAttribute('data-initialized') !== 'true') {
837 var perPage = carouselEl.getAttribute('data-per-page');
838 if (perPage === null) {
839 var stageClassList = carouselEl.querySelector('.products').classList.value;
840 [1, 2, 3, 4, 5].forEach(function (columns) {
841 if (stageClassList.indexOf('columns-' + columns) > 0) {
842 perPage = columns;
843 }
844 });
845 }
846 var loop = carouselEl.getAttribute('data-loop') !== '0';
847
848 // Mount carousel wrapper
849 var wrapper = document.createElement('div'),
850 stage = carouselEl.querySelector('.merchant-carousel-stage');
851 wrapper.className = 'merchant-carousel-wrapper';
852 wrapper.innerHTML = stage.outerHTML;
853 stage.remove();
854 carouselEl.append(wrapper);
855
856 // Margin
857 var margin = 30;
858 if (typeof merchant_carousel !== 'undefined') {
859 margin = parseInt(merchant_carousel.margin_desktop);
860 } else if (carouselEl.closest('.merchant-woocommerce-mini-cart__cross-sell') !== null) {
861 margin = 15;
862 }
863
864 // Initialize
865 var carousel = new Siema({
866 parentSelector: carouselEl,
867 selector: '.merchant-carousel-stage',
868 duration: 200,
869 easing: 'ease-out',
870 perPage: perPage !== null ? {
871 0: 1,
872 768: 2,
873 1025: parseInt(perPage)
874 } : 2,
875 startIndex: 0,
876 draggable: true,
877 multipleDrag: false,
878 threshold: 20,
879 loop: loop,
880 rtl: false,
881 // autoplay: true, TO DO
882 margin: margin,
883 onInit: function onInit() {
884 var _this$innerElements;
885 window.dispatchEvent(new Event('merchant.carousel.initialized'));
886
887 // Fix for theme that has lazy-load but not working
888 this === null || this === void 0 || (_this$innerElements = this.innerElements) === null || _this$innerElements === void 0 || _this$innerElements.forEach(function (item) {
889 var img = item.querySelector('img');
890 var src = img === null || img === void 0 ? void 0 : img.getAttribute('src');
891 if (src !== null && src !== void 0 && src.startsWith('data')) {
892 img.src = img === null || img === void 0 ? void 0 : img.getAttribute('data-src');
893 }
894 });
895 }
896 });
897 }
898 }
899 } catch (err) {
900 _iterator.e(err);
901 } finally {
902 _iterator.f();
903 }
904 },
905 events: function events() {
906 var _this = this;
907 if (typeof jQuery !== 'undefined') {
908 var onpageload = true;
909 jQuery(document.body).on('wc_fragment_refresh added_to_cart removed_from_cart', function () {
910 setTimeout(function () {
911 var mini_cart = document.getElementById('site-header-cart'),
912 mini_cart_list = mini_cart === null || mini_cart === void 0 ? void 0 : mini_cart.querySelector('.cart_list');
913 if (mini_cart_list !== null) {
914 if ((mini_cart_list === null || mini_cart_list === void 0 ? void 0 : mini_cart_list.children.length) > 2) {
915 mini_cart === null || mini_cart === void 0 || mini_cart.classList.remove('mini-cart-has-no-scroll');
916 mini_cart === null || mini_cart === void 0 || mini_cart.classList.add('mini-cart-has-scroll');
917 } else {
918 mini_cart === null || mini_cart === void 0 || mini_cart.classList.remove('mini-cart-has-scroll');
919 mini_cart === null || mini_cart === void 0 || mini_cart.classList.add('mini-cart-has-no-scroll');
920 }
921 }
922 _this.build();
923 onpageload = false;
924 }, onpageload ? 1000 : 0);
925 });
926 }
927 }
928 };
929
930 // Initialize.
931 merchant.carousel.domReady(function () {
932 var _merchant$carousel;
933 merchant === null || merchant === void 0 || (_merchant$carousel = merchant.carousel) === null || _merchant$carousel === void 0 || _merchant$carousel.init();
934 });
935 jQuery(document).on('photoSliderTriggered', function () {
936 var _merchant$carousel2;
937 merchant === null || merchant === void 0 || (_merchant$carousel2 = merchant.carousel) === null || _merchant$carousel2 === void 0 || _merchant$carousel2.init();
938 });