PageSourceSearch

https://www.awwaart.com/wp-content/themes/sober/js/script.js?ver=3.6.7

js awwaart.com collected 2026-10-08 21:03:23 UTC 73,936 bytes, 2,737 lines download raw bytes

1(function ( $ ) {
2	'use strict';
3
4	var sober = sober || {};
5
6	sober.init = function () {
7		this.$window = $( window );
8		this.$body = $( document.body );
9		this.$sideMenu = $( '.side-menu' );
10
11		this.data = soberData || {};
12
13		this.closeTopbar();
14		this.menuHover();
15		this.toggleSideMenu();
16		this.toggleModal();
17		this.toggleTabs();
18		this.focusInputs();
19		this.productsTabs();
20		this.sortProducts();
21		this.productQuantity();
22		this.productImagesLightbox();
23		this.stickyProductSummary();
24		this.sideProductsCarousel();
25		this.productImageSlider();
26		this.productImageZoom();
27		this.stickUpSells();
28		this.checkBox();
29		this.formatGallery();
30		this.backToTop();
31		this.toggleProductFilter();
32		this.productQuickView();
33		this.instanceSearch();
34		this.fakeScrollbar();
35		this.setCSSVars();
36		this.stickyHeader();
37		this.navAjax();
38		this.portfolioFilter();
39		this.productVariationSwatches();
40		this.productGalleryZoom();
41		this.productGallerySlider();
42		this.productFullWidth();
43		this.productBackground();
44		this.relatedProductsCarousel();
45		this.upsellProductsCarousel();
46		this.singeProductAjaxAddToCart();
47		this.stickyAddToCart();
48		this.openCartModalAfterAdd();
49		this.pageHeaderParallax();
50		this.responsive();
51		this.preload();
52		this.popup();
53		this.addedToCartNotice();
54		// this.checkoutTerms();
55		// this.fixVC();
56		this.loginModalAuthenticate();
57		this.lazyLoadImages();
58		this.closeNotices();
59
60		this.$body.trigger( 'sober_init', [sober] );
61	};
62
63	/**
64	 * Check if a node is blocked for processing.
65	 *
66	 * @param {object} $node
67	 * @return {bool} True if the DOM Element is UI Blocked, false if not.
68	 */
69	sober.isBlocked = function ( $node ) {
70		return $node.is( '.processing' ) || $node.parents( '.processing' ).length;
71	};
72
73	/**
74	 * Block a node visually for processing.
75	 *
76	 * @param {object} $node
77	 */
78	sober.block = function ( $node ) {
79		if ( !sober.isBlocked( $node ) ) {
80			$node.addClass( 'processing' ).block( {
81				message   : null,
82				overlayCSS: {
83					background: '#fff',
84					opacity   : 0.6
85				}
86			} );
87		}
88	};
89
90	/**
91	 * Unblock a node after processing is complete.
92	 *
93	 * @param {object} $node
94	 */
95	sober.unblock = function ( $node ) {
96		$node.removeClass( 'processing' ).unblock();
97	};
98
99	/**
100	 * Check if an element is in view-port or not
101	 *
102	 * @param el
103	 * @returns {boolean}
104	 */
105	sober.isVisible = function ( el ) {
106		if ( el instanceof jQuery ) {
107			el = el[0];
108		}
109
110		var rect = el.getBoundingClientRect();
111
112		return rect.bottom > 0 &&
113			rect.right > 0 &&
114			rect.left < ( window.innerWidth || document.documentElement.clientWidth ) &&
115			rect.top < ( window.innerHeight || document.documentElement.clientHeight );
116	};
117
118	/**
119	 * Post format gallery with carousel slider
120	 */
121	sober.formatGallery = function () {
122		$( '.entry-gallery' ).addClass( 'owl-carousel' ).owlCarousel( {
123			singleItem: true,
124			items     : 1,
125			navSpeed  : 800,
126			nav       : true,
127			dots      : false,
128			autoplay  : true,
129			dotsSpeed : 1000,
130			rtl       : sober.data.isRTL === "1",
131			navText   : ['<svg viewBox="0 0 20 20"><use xlink:href="#left-arrow"></use></svg>', '<svg viewBox="0 0 20 20"><use xlink:href="#right-arrow"></use></svg>']
132		} );
133	};
134
135	/**
136	 * Style checkboxes
137	 */
138	sober.checkBox = function () {
139		// Checkbox: Ship to a different address
140		$( '#ship-to-different-address' ).find( '.input-checkbox' ).on( 'change', function () {
141			if ( $( this ).is( ':checked' ) ) {
142				$( this ).parent().find( '.checkbox' ).addClass( 'checked' );
143			} else {
144				$( this ).parent().find( '.checkbox' ).removeClass( 'checked' );
145			}
146		} ).trigger( 'change' );
147	};
148
149	/**
150	 * Load ajax on shop page and blog
151	 */
152	sober.navAjax = function () {
153		// Blog & Portfolio
154		sober.$body.on( 'click', '.ajax-navigation a', function ( e ) {
155			e.preventDefault();
156
157			var $button = $( this ),
158				$nav = $button.parent(),
159				$main = $( '#main' ),
160				url = $button.attr( 'href' );
161
162			if ( $nav.hasClass( 'loading' ) ) {
163				return;
164			}
165
166			$nav.addClass( 'loading' );
167
168			$.get(
169				url,
170				function ( response ) {
171					var $response = $( response ),
172						nextTitle = $response.find( 'title' ).text();
173
174					if ( $nav.hasClass( 'posts-navigation' ) ) {
175						var $content = $( $response.find( '#main' ).html() );
176						$content.hide();
177
178						$main.append( $content );
179						$content.fadeIn( 1000 );
180						$nav.remove();
181					} else if ( $nav.hasClass( 'portfolio-navigation' ) ) {
182						var $items = $response.find( '.portfolio-items .portfolio' ),
183							$link = $response.find( '.ajax-navigation a' );
184
185						if ( $items.length ) {
186							$items.imagesLoaded( function () {
187								$main.find( '.portfolio-items' ).isotope( 'insert', $items );
188							} );
189							$nav.removeClass( 'loading' );
190
191							if ( $link.length ) {
192								$nav.html( $link );
193							} else {
194								$nav.fadeOut();
195							}
196						}
197					}
198
199					window.history.pushState( null, nextTitle, url );
200					sober.$body.trigger( 'post-load' );
201				}
202			);
203		} );
204
205		// Shop
206		if ( 'ajax' === sober.data.shop_nav_type || 'infinity' === sober.data.shop_nav_type ) {
207			sober.$body.on( 'click', '.woocommerce-pagination .next', function ( e ) {
208				e.preventDefault();
209
210				var $button = $( this ),
211					$nav = $button.closest( '.woocommerce-pagination' ),
212					url = $button.attr( 'href' );
213
214				if ( $button.hasClass( 'loading' ) ) {
215					return;
216				}
217
218				$button.addClass( 'loading' );
219
220				load_products( url, function ( response ) {
221					var $pagination = $( response ).find( '.woocommerce-pagination' );
222
223					if ( $pagination.length ) {
224						$nav.html( $pagination.html() );
225					} else {
226						$nav.html( '' );
227					}
228				} );
229			} );
230		}
231
232		// Infinity Shop
233		if ( 'infinity' === sober.data.shop_nav_type ) {
234			var $nav = $( '.woocommerce-pagination' ),
235				$button = $nav.find( '.next' );
236
237			if ( $button.length ) {
238				// Use this variable to control scroll event handle for better performance
239				var waiting = false,
240					endScrollHandle;
241
242				sober.$window.on( 'scroll', function () {
243					if ( waiting ) {
244						return;
245					}
246
247					$nav = $( '.woocommerce-pagination' );
248					$button = $( '.next', $nav );
249					waiting = true;
250
251					// clear previous scheduled endScrollHandle
252					clearTimeout( endScrollHandle );
253
254					infiniteScoll();
255
256					setTimeout( function () {
257						waiting = false;
258					}, 100 );
259
260					// schedule an extra execution of infiniteScoll() after 200ms
261					// in case the scrolling stops in next 100ms
262					endScrollHandle = setTimeout( function () {
263						waiting = false;
264						infiniteScoll();
265					}, 200 );
266				} );
267			}
268
269			var infiniteScoll = function () {
270				// When almost reach to nav and new next button is exists
271				if ( sober.isVisible( $nav ) && $button.length ) {
272					if ( $button.hasClass( 'loading' ) ) {
273						return;
274					}
275
276					$button.addClass( 'loading' );
277
278					load_products( $button.attr( 'href' ), function ( response ) {
279						var $pagination = $( response ).find( '.woocommerce-pagination' );
280
281						if ( $pagination.length ) {
282							$nav.html( $pagination.html() );
283
284							// Re-select because DOM has been changed
285							$button = $nav.find( '.next' );
286						} else {
287							$nav.html( '' );
288							$button.length = 0;
289						}
290					} );
291				}
292			}
293		}
294
295		/**
296		 * Private function for ajax loading product
297		 *
298		 * @param url
299		 * @param callback
300		 */
301		function load_products( url, callback ) {
302			// 'ul.products' can be replace by the filter widget,
303			// so we have to query it again every call.
304			var $holder = $( 'ul.products', '#primary' );
305
306			$.get(
307				url,
308				function ( response ) {
309					var $primary = $( response ).find( '#primary' ),
310						$_products = $primary.find( 'ul.products' ).children();
311
312					if ( 'isotope' === sober.data.tab_behaviour ) {
313						$_products.imagesLoaded( function() {
314							var i = 0;
315
316							$_products.each( function( index, product ) {
317								setTimeout( function() {
318									$holder.isotope( 'insert', product );
319									sober.$body.trigger( 'sober_products_loaded', [product] );
320								}, index * 100 );
321
322								i++;
323							} );
324
325							setTimeout( function() {
326								$holder.isotope( 'layout' );
327							}, i * 100 );
328						} );
329					} else {
330						$_products.each( function( index, product ) {
331							$( product ).css( 'animation-delay', index * 100 + 'ms' );
332						} );
333
334						$_products.addClass( 'soberFadeInUp soberAnimation' );
335						$_products.appendTo( $holder );
336
337						if ( $_products.length ) {
338							sober.$body.trigger( 'sober_products_loaded', [$_products] );
339						}
340					}
341
342					if ( 'function' === typeof callback ) {
343						callback( response );
344					}
345
346					window.history.pushState( null, '', url );
347				}
348			);
349		}
350	};
351
352	/**
353	 * Close topbar
354	 */
355	sober.closeTopbar = function () {
356		$( '#topbar' ).on( 'click', '.close', function ( e ) {
357			e.preventDefault();
358
359			var $topbar = $( this ).closest( '#topbar' );
360
361			if ( sober.data.sticky_header !== 'none' ) {
362				$topbar.css({ position: 'absolute', top: 0, left: 0, width: '100%' }).slideUp();
363				$( '#masthead' ).animate( {top: 0} );
364
365				var offsetTop = $topbar.css( 'margin-bottom' );
366
367				$( '#page' ).css( {paddingTop: offsetTop} );
368			} else {
369				$topbar.slideUp();
370			}
371		} );
372	};
373
374	/**
375	 * Main navigation sub-menu hover
376	 */
377	sober.menuHover = function () {
378		var animations = {
379			none : ['show', 'hide'],
380			fade : ['fadeIn', 'fadeOut'],
381			slide: ['slideDown', 'slideUp']
382		};
383
384		var animation = sober.data.menu_animation ? animations[sober.data.menu_animation] : 'fade';
385
386		$( '.site-navigation li, .topbar-menu li' ).on( 'mouseenter', function () {
387			var $li = $( this );
388
389			if ( ! $li.hasClass( 'mega-sub-menu' ) ) {
390				$li.addClass( 'active' ).children( '.sub-menu' ).stop( true, true )[animation[0]]();
391			}
392		} ).on( 'mouseleave', function () {
393			var $li = $( this );
394
395			if ( ! $li.hasClass( 'mega-sub-menu' ) ) {
396				$( this ).removeClass( 'active' ).children( '.sub-menu' ).stop( true, true ).delay( 100 )[animation[1]]();
397			}
398		} );
399	};
400
401	/**
402	 *  Toggle modal
403	 */
404	sober.toggleModal = function () {
405		sober.$body.on( 'click', '[data-toggle="modal"]', function ( e ) {
406			e.preventDefault();
407
408			var $el = $( this ),
409				$target = $( '#' + $el.data( 'target' ) ),
410				tab = $el.data( 'tab' );
411
412			if ( !$target.length ) {
413				return;
414			}
415
416			sober.openModal( $target, tab );
417		} );
418
419		sober.$body.on( 'click', '.close-modal, .sober-modal-backdrop', function ( e ) {
420			e.preventDefault();
421
422			sober.closeModal();
423		} );
424
425		// Close when press escape button
426		$( document ).on( 'keyup', function ( e ) {
427			if ( e.keyCode === 27 ) {
428				sober.closeModal();
429			}
430		} );
431	};
432
433	/**
434	 * Open modal
435	 *
436	 * @param $modal
437	 * @param tab
438	 */
439	sober.openModal = function ( $modal, tab ) {
440		$modal = $modal instanceof jQuery ? $modal : $( $modal );
441
442		if ( ! $modal.length ) {
443			return;
444		}
445
446		sober.$body.addClass( 'modal-open' );
447		$modal.fadeIn();
448		$modal.addClass( 'open' );
449
450		if ( tab ) {
451			var $tab = $modal.find( '.tab-nav' ).filter( '[data-tab="' + tab + '"]' );
452
453			$tab.trigger( 'click' );
454		}
455	};
456
457	/**
458	 * Close modal
459	 */
460	sober.closeModal = function () {
461		sober.$body.removeClass( 'modal-open' );
462
463		var $opened = $( '.sober-modal.open' );
464
465		$opened.fadeOut( function () {
466			$( this ).removeClass( 'open' );
467		} );
468
469		sober.$body.trigger( 'sober_modal_closed', [$opened] );
470	};
471
472	/**
473	 * Toggle side menu and its' child items
474	 */
475	sober.toggleSideMenu = function () {
476		// Toggle side menu
477		sober.$body.on( 'click', '.toggle-nav', function () {
478			var target = '#' + $( this ).data( 'target' );
479
480			$( target ).toggleClass( 'open' );
481			sober.$body.toggleClass( 'side-menu-opened' );
482		} );
483
484		// Close when click to backdrop
485		sober.$body.on( 'click', '.side-menu-backdrop', function () {
486			$( '.side-menu' ).removeClass( 'open' );
487			sober.$body.removeClass( 'side-menu-opened' );
488		} );
489
490		// Add class 'open' to current menu item
491		sober.$sideMenu.find( '.menu > .menu-item-has-children, .menu > ul > .menu-item-has-children' ).filter( function () {
492			return $( this ).hasClass( 'current-menu-item' ) || $( this ).hasClass( 'current-menu-ancestor' );
493		} ).addClass( 'open' );
494
495		// Toggle sub-menu
496		sober.$sideMenu.on( 'click', '.menu > .menu-item-has-children > a, .menu > ul > .menu-item-has-children > a', function ( e ) {
497			var $li = $( this ).parent();
498
499			if ( $li.hasClass( 'open' ) && $li.hasClass( 'clicked' ) ) {
500				return true;
501			}
502
503			e.stopPropagation();
504			e.preventDefault();
505
506			$li.addClass( 'clicked' );
507
508			$li.toggleClass( 'open' ).children( 'ul' ).slideToggle();
509			$li.siblings( '.open' ).removeClass( 'open' ).children( 'ul' ).slideUp();
510		} ).on( 'click', '.menu > .menu-item-has-children > .toggle, .menu > ul > .menu-item-has-children > .toggle', function( e ) {
511			e.stopPropagation();
512			e.preventDefault();
513
514			var $li = $( this ).parent();
515
516			$li.toggleClass( 'open' ).children( 'ul' ).slideToggle();
517			$li.siblings( '.open' ).removeClass( 'open' ).children( 'ul' ).slideUp();
518		} );
519	};
520
521	/**
522	 * Focusing inputs and adds 'active' class
523	 */
524	sober.focusInputs = function () {
525
526		$( '.woocommerce-account, .woocommerce-checkout' ).on( 'focus', '.input-text', function () {
527			$( this ).closest( '.form-row' ).addClass( 'active' );
528		} ).on( 'focusout', '.input-text', function () {
529			if ( $( this ).val() === '' ) {
530				$( this ).closest( '.form-row' ).removeClass( 'active' );
531			}
532		} ).find( '.input-text' ).each( function () {
533			if ( $( this ).val() !== '' ) {
534				$( this ).closest( '.form-row' ).addClass( 'active' );
535			}
536		} );
537
538
539		$( '#commentform' ).on( 'focus', ':input', function () {
540			$( this ).closest( 'p' ).addClass( 'active' );
541		} ).on( 'focusout', ':input', function () {
542			if ( $( this ).val() === '' ) {
543				$( this ).closest( 'p' ).removeClass( 'active' );
544			}
545		} ).find( ':input' ).each( function () {
546			if ( $( this ).val() !== '' ) {
547				$( this ).closest( 'p' ).addClass( 'active' );
548			}
549		} );
550
551	};
552
553	/**
554	 * Toggle tabs
555	 */
556	sober.toggleTabs = function () {
557		sober.$body.on( 'click', '.tabs-nav .tab-nav', function () {
558			var $tab = $( this ),
559				tab = $tab.data( 'tab' );
560
561			if ( $tab.hasClass( 'active' ) ) {
562				return;
563			}
564
565			$tab.addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
566			$tab.closest( '.tabs-nav' ).next( '.tab-panels' )
567				.children( '[data-tab="' + tab + '"]' ).addClass( 'active' )
568				.siblings( '.active' ).removeClass( 'active' );
569		} )
570	};
571
572	/**
573	 * Handle product tabs on product catalog pages
574	 */
575	sober.productsTabs = function() {
576		var $tabs = $( '.shop-toolbar .products-filter' );
577
578		if ( ! $tabs.length ) {
579			return;
580		}
581
582		if ( 'isotope' == sober.data.tab_behaviour ) {
583			sober.isotopeProductTabs();
584		} else if ( 'ajax' == sober.data.tab_behaviour ) {
585			sober.ajaxProductTabs();
586		} else {
587			$tabs.on( 'click', 'li', function() {
588				$( this ).addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
589			} );
590		}
591
592		// Reset the active tab when using ajax filter
593		sober.$body.on( 'soo_filter_request_success sober_products_filter_request_success', function() {
594			$( 'li:first', '.products-filter' ).addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
595		} );
596	};
597
598	/**
599	 * Make products filterable with Isotope
600	 */
601	sober.isotopeProductTabs = function() {
602		var $container = $( '.woocommerce.archive .site-content ul.products' );
603
604		var isotopeOptions = {
605				itemSelector      : '.product',
606				transitionDuration: 700,
607				layoutMode        : 'fitRows',
608				isOriginLeft      : !(sober.data.isRTL === '1'),
609				hiddenStyle: {
610					opacity: 0,
611					transform: 'translate3d(0,50px,0)'
612				},
613				visibleStyle: {
614					opacity: 1,
615					transform: 'none'
616				}
617			};
618
619		$container.isotope( isotopeOptions );
620
621		$container.imagesLoaded().progress( function() {
622			$container.isotope( 'layout' );
623		} );
624
625		// Support Jetpack lazy load.
626		$container.on( 'jetpack-lazy-loaded-image', 'img', function() {
627			if ( ! $container.data( 'isotope' ) ) {
628				return;
629			}
630
631			$( this ).imagesLoaded( function() {
632				$container.isotope( 'layout' );
633			} );
634		} );
635
636		// Fix issue of hover style "slider".
637		$( '.product-images__slider', $container ).on( 'initialized.owl.carousel', function() {
638			$container.isotope( 'layout' );
639		} );
640
641		// Tabs.
642		$( '.shop-toolbar .products-filter' ).on( 'click', 'li', function( e ) {
643			e.preventDefault();
644			e.stopPropagation();
645
646			var $this = $( this ),
647				selector = $this.attr( 'data-filter' );
648
649			if ( $this.hasClass( 'active' ) ) {
650				return;
651			}
652
653			$this.addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
654			$this.closest( '.shop-toolbar' ).next( 'ul.products' ).isotope( {
655				filter: selector
656			} );
657		} );
658
659		// Reset the active tab when using ajax filter
660		sober.$body.on( 'soo_filter_request_success sober_products_filter_request_success', function() {
661			setTimeout( function() {
662				$( 'ul.products', '#primary' ).imagesLoaded( function() {
663					$( this.elements ).isotope( isotopeOptions );
664				} );
665			}, 100 );
666		} );
667	};
668
669	/**
670	 * Ajax product tabs on product catalog pages
671	 */
672	sober.ajaxProductTabs = function() {
673		$( '.shop-toolbar__tabs' ).on( 'click', 'li', function( e ) {
674			e.preventDefault();
675			e.stopPropagation();
676
677			var $this = $( this ),
678				$grid = $this.closest( '.shop-toolbar' ).next( 'ul.products' ),
679				$nav = $grid.next( '.woocommerce-pagination' ),
680				url = $this.children( 'a' ).attr( 'href' );
681
682			if ( $this.hasClass( 'active' ) ) {
683				return;
684			}
685
686			// Reset the filter data
687			$( ':input', '.soo-product-filter-widget' )
688				.not( ':button, :submit, :reset' )
689				.val( '' )
690				.removeAttr( 'checked' )
691				.removeAttr( 'selected' );
692
693			$( '.selected', '.soo-product-filter-widget' ).removeClass( 'selected' );
694
695			$( '.filter-slider', '.soo-product-filter-widget' ).each( function() {
696				var $slider = $( this ),
697					options = $slider.slider( 'option' );
698
699				$slider.slider( 'values', [options.min, options.max] );
700
701				sober.$body.trigger( 'soo_price_filter_create', [options.min, options.max, $slider] );
702			} );
703
704			// Prepare grid if we are at no-products page
705			if ( ! $grid.length ) {
706				$this.closest( '.shop-toolbar' ).next( '.woocommerce-info' ).replaceWith( '<ul class="products"/>' );
707				$grid = $this.closest( '.shop-toolbar' ).next( 'ul.products' );
708			}
709
710			$this.addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
711			$grid.addClass( 'loading' );
712			$grid.append( '<li class="loading-overlay"><span class="loading-icon">\n' +
713				'<span class="bubble"><span class="dot"></span></span>\n' +
714				'<span class="bubble"><span class="dot"></span></span>\n' +
715				'<span class="bubble"><span class="dot"></span></span>\n' +
716				'</span></li>' );
717			$nav.fadeOut();
718
719			$.get( url, function( response ) {
720				var $primary = $( response ).find( '#primary' ),
721					$products = $( 'ul.products', $primary ).children(),
722					$info = $( '.woocommerce-info', $primary ),
723					$button = $( '.woocommerce-pagination', $primary );
724
725				if ( $products.length ) {
726					$( '.woocommerce-result-count' ).html( $( '.woocommerce-result-count', $primary ).html() );
727
728					$products.addClass( 'soberFadeInUp soberAnimation' );
729
730					$products.each( function( index ) {
731						$( this ).css( 'animation-delay', index * 100 + 'ms' );
732					} );
733
734					$grid.html( $products ).removeClass( 'loading' );
735
736					// Replace button
737					if ( $button.length ) {
738						if ( $nav.length ) {
739							$nav.html( $button.html() ).fadeIn();
740						} else {
741							$nav = $button;
742							$nav.insertAfter( $grid );
743						}
744					} else {
745						$nav.html( '' ).fadeOut();
746					}
747
748					sober.$body.trigger( 'sober_products_loaded', [$products] );
749
750					// Update the filter form.
751					$( '.shop-toolbar .filter-widgets .sober-products-filter-widget' ).each( function() {
752						var $widget = $( this ),
753							widgetId = $widget.attr( 'id' ),
754							$newWidget = $( '#' + widgetId, response );
755
756						if ( ! $newWidget.length ) {
757							return;
758						}
759
760						$( '.filters', $widget ).html( $( '.filters', $newWidget ).html() );
761						$( '.products-filter__activated', $widget ).html( $( '.products-filter__activated', $newWidget ).html() );
762
763						$( document.body ).trigger( 'sober_products_filter_widget_updated', [$widget.find( 'form' ).get(0)] );
764					} );
765				} else {
766					$( '.woocommerce-result-count' ).html( '' );
767					$grid.html( '' ).removeClass( 'loading' ).append( $( '<li class="no-result-message" />' ).append( $info ) );
768					$nav.html( '' ).fadeOut();
769				}
770
771				window.history.pushState( null, '', url );
772			} );
773		} );
774	};
775
776	/**
777	 * Use select2 to styling the dropdown of the product order select
778	 */
779	sober.sortProducts = function() {
780		if ( ! $.fn.select2 ) {
781			return;
782		}
783
784		$( '.woocommerce-ordering select' ).select2( {
785			minimumResultsForSearch: -1,
786			width: 'auto',
787			dropdownAutoWidth: true,
788			dropdownCssClass: 'woocommerce-ordering-select2-dropdown',
789		} );
790	};
791
792	/**
793	 * Change product quantity
794	 */
795	sober.productQuantity = function () {
796		sober.$body.on( 'click', '.quantity .increase, .quantity .decrease', function ( e ) {
797			e.preventDefault();
798
799			var $this = $( this ),
800				$qty = $this.siblings( '.qty' ),
801				current = parseFloat( $qty.val() ),
802				min = parseFloat( $qty.attr( 'min' ) ),
803				max = parseFloat( $qty.attr( 'max' ) ),
804				step = parseFloat( $qty.attr( 'step' ) );
805
806			if ( true === $qty.prop( 'readonly' ) ) {
807				return;
808			}
809
810			current = current ? current : 0;
811			min = min ? min : 0;
812			max = max ? max : current + 1;
813			step = step ? step : 1;
814
815			if ( $this.hasClass( 'decrease' ) && current > min ) {
816				$qty.val( current - step );
817				$qty.trigger( 'change' );
818			}
819			if ( $this.hasClass( 'increase' ) && current < max ) {
820				$qty.val( current + step );
821				$qty.trigger( 'change' );
822			}
823		} );
824	};
825
826	/**
827	 * Make up sells products be sticky
828	 */
829	sober.stickUpSells = function () {
830		if ( !sober.$body.hasClass( 'product-style-3' ) ) {
831			return;
832		}
833
834		var $topbar = $( '#topbar' ),
835			$header = $( '#masthead' ),
836			$upsells = $( '.side-products' );
837
838		if ( !$upsells.length ) {
839			return;
840		}
841
842		var $primary = $( '#primary' );
843
844		var offset = $topbar.length ? $topbar.outerHeight() : 0;
845		offset += $header.length ? $header.outerHeight() : 0;
846
847		$( window ).on( 'scroll', function () {
848			if ( $( document ).scrollTop() >= offset ) {
849				$upsells.addClass( 'sticky' );
850
851				if ( !$upsells.data( 'wrap' ) ) {
852					$upsells.wrap( '<div id="upsells-wrap" class="upsells-wrap"/>' );
853					$upsells.data( 'wrap', true );
854				}
855			} else {
856				$upsells.removeClass( 'sticky' );
857
858				if ( $upsells.data( 'wrap' ) ) {
859					$upsells.unwrap();
860					$upsells.data( 'wrap', false );
861				}
862			}
863
864			if ( $( window ).scrollTop() >= $primary.offset().top + $primary.outerHeight() - window.innerHeight ) {
865				var $wrap = $( '#upsells-wrap' );
866
867				$wrap.addClass( 'sticky-bottom' ).css( 'top', function () {
868					return $( window ).scrollTop() - $primary.offset().top;
869				} );
870
871				if ( $wrap.outerHeight() <= $upsells.outerHeight() ) {
872					$wrap.addClass( 'reach-bottom' );
873				} else {
874					$wrap.removeClass( 'reach-bottom' );
875				}
876			} else {
877				$( '#upsells-wrap' ).removeClass( 'sticky-bottom' ).css( 'top', 0 );
878			}
879		} ).trigger( 'scroll' );
880	};
881
882	/**
883	 * Prepare and init carousel for up sell products.
884	 * This carousel is placed on product style v3.
885	 */
886	sober.sideProductsCarousel = function () {
887		if ( !sober.$body.hasClass( 'product-style-3' ) ) {
888			return;
889		}
890
891		var $sideProducts = $( '.side-products' );
892
893		if ( !$sideProducts.length ) {
894			return;
895		}
896
897		if ( $sideProducts.find( 'li.product' ).length > 4 ) {
898			$sideProducts.find( 'ul.products' ).addClass( 'owl-carousel' ).owlCarousel( {
899				rtl          : sober.data.isRTL === "1",
900				owl2row      : true,
901				owl2rowTarget: 'product',
902				dots         : true,
903				nav          : true,
904				navText      : ['<svg viewBox="0 0 20 20"><use xlink:href="#left-arrow"></use></svg>', '<svg viewBox="0 0 20 20"><use xlink:href="#right-arrow"></use></svg>'],
905				items        : 2,
906				responsive   : {
907					0   : {
908						items: 1
909					},
910					992 : {
911						items: 1
912					},
913					1200: {
914						items: 2
915					}
916				}
917			} );
918		}
919	};
920
921	/**
922	 * Show photoSwipe lightbox for product images
923	 */
924	sober.productImagesLightbox = function () {
925		if ( '1' !== sober.data.lightbox ) {
926			return;
927		}
928
929		var $product = $( 'div.product' ),
930			$gallery = $( 'div.images', $product ),
931			$slides = $( '.woocommerce-product-gallery__slider .woocommerce-product-gallery__image', $gallery );
932
933		if ( !$gallery.length ) {
934			return;
935		}
936
937		$gallery.on( 'click', '.woocommerce-product-gallery__slider .woocommerce-product-gallery__image a', function ( e ) {
938			e.preventDefault();
939
940			var items = getGalleryItems(),
941				$target = $( e.target ),
942				$clicked = $target.closest( '.owl-item' ),
943				options = {
944					index              : $clicked.length ? $clicked.index() : $target.closest( '.woocommerce-product-gallery__image' ).index(),
945					history            : false,
946					bgOpacity          : 0.85,
947					showHideOpacity    : true,
948					mainClass          : 'pswp--minimal-dark',
949					captionEl          : true,
950					fullscreenEl       : false,
951					shareEl            : false,
952					tapToClose         : true,
953					tapToToggleControls: false
954				};
955
956			var lightBox = new PhotoSwipe( $( '.pswp' ).get(0), window.PhotoSwipeUI_Default, items, options );
957
958			if ( $gallery.hasClass( 'woocommerce-product-gallery--has-video' ) ) {
959				// Pause the current player.
960				$gallery.find( 'video' ).each( function() {
961					this.player.pause();
962				} );
963
964				// Stop videos inside oembed iframes.
965				$gallery.find( '.sober-product-video__content > iframe' ).each( function() {
966					this.src = this.src;
967				} );
968
969				lightBox.listen( 'afterChange', function() {
970					window.wp.mediaelement.initialize();
971
972					var $container = $( lightBox.currItem.container ),
973						$video = $container.children( '.wp-video-shortcode' ),
974						videoRatio = $video.width() / $video.height();
975
976					var viewport = lightBox.viewportSize,
977						videoHeight = viewport.y * 0.6,
978						videoWidth = videoHeight * videoRatio;
979
980					if ( lightBox.currItem.isVideo ) {
981						$container.find( 'video' ).each( function() {
982							this.muted = false;
983							this.controls = false;
984							this.player.play();
985						} );
986
987						// Set Video Size
988						sober.$window.on( 'resize.sober_gallery_video', function() {
989							$container
990								.children( '.wp-video-shortcode' )
991								.css({
992									'max-width' : videoWidth,
993									'max-height': videoHeight,
994									'top'       : ( viewport.y - videoHeight ) / 2,
995									'left'      : ( viewport.x - videoWidth ) / 2
996								});
997						} ).trigger( 'resize' );
998					} else {
999						$( lightBox.container ).find( 'video' ).each( function() {
1000							this.player.pause();
1001						} );
1002
1003						// Handle oembed iframe.
1004						$( lightBox.container ).find( '.pswp__zoom-wrap > iframe' ).each( function() {
1005							this.src = this.src;
1006						} );
1007					}
1008				} );
1009
1010				lightBox.listen( 'close', function() {
1011					// Re-play gallery videos.
1012					if ( $product.hasClass( 'layout-style-6' ) || $product.hasClass( 'layout-style-1' ) ) {
1013						$gallery.find( 'video' ).each( function() {
1014							this.player.play();
1015						} );
1016					}
1017
1018					// Pause all videos inside the lightbox.
1019					$( lightBox.container ).find( 'video' ).each( function() {
1020						if ( this.player ) {
1021							this.player.pause();
1022						}
1023					} );
1024
1025					// Stop videos inside oembed iframes.
1026					$( lightBox.container ).find( '.pswp__zoom-wrap > iframe' ).each( function() {
1027						this.src = this.src;
1028					} );
1029
1030					// Detach listener resize.sober_gallery_video.
1031					sober.$window.off( 'resize.sober_gallery_video' );
1032				} );
1033			}
1034
1035			lightBox.init();
1036		} );
1037
1038		/**
1039		 * Private function to get gallery items
1040		 * @returns {Array}
1041		 */
1042		function getGalleryItems() {
1043			var items = [];
1044
1045			if ( $slides.length > 0 ) {
1046				$slides.each( function( i, el ) {
1047					var $el = $( el ),
1048						img = $el.find( 'img' ),
1049						large_image_src = img.attr( 'data-large_image' ),
1050						large_image_w   = img.attr( 'data-large_image_width' ),
1051						large_image_h   = img.attr( 'data-large_image_height' ),
1052						item;
1053
1054					if ( $el.hasClass( 'sober-product-video' ) ) {
1055						var $video = $el.find( 'video.wp-video-shortcode' );
1056
1057						$video = $video.length > 0 ? $video : $el.find( '.sober-product-video__content iframe' );
1058
1059						if ( $video.length ) {
1060							item            = {
1061								html   : $video.get(0).outerHTML.replace( 'muted', '' ),
1062								isVideo: true,
1063							};
1064						}
1065					} else {
1066						item            = {
1067							src    : large_image_src,
1068							w      : large_image_w,
1069							h      : large_image_h,
1070							title  : img.attr( 'data-caption' ) ? img.attr( 'data-caption' ): '',
1071							isVideo: false
1072						};
1073					}
1074					items.push( item );
1075				} );
1076			}
1077
1078			return items;
1079		}
1080	};
1081
1082	/**
1083	 * Make product summary be sticky when use product layout 1
1084	 */
1085	sober.stickyProductSummary = function () {
1086		if ( ! $.fn.stick_in_parent ) {
1087			return;
1088		}
1089
1090		stickyProductSummary();
1091
1092		sober.$window.on( 'resize', stickyProductSummary );
1093
1094		function stickyProductSummary() {
1095			if ( sober.$window.width() > 768 ) {
1096				$( 'div.product .sticky-summary' ).stick_in_parent( {
1097					parent: '.product-summary'
1098				} );
1099			} else {
1100				$( 'div.product .sticky-summary' ).trigger( 'sticky_kit:detach' );
1101			}
1102		}
1103	};
1104
1105	/**
1106	 * Back to top icon
1107	 */
1108	sober.backToTop = function () {
1109		sober.$body.on( 'click', '#gotop', function ( e ) {
1110			e.preventDefault();
1111
1112			$( 'html, body' ).animate( {scrollTop: 0}, 'slow' );
1113		} );
1114	};
1115
1116	/**
1117	 * Toggle product filter widgets
1118	 */
1119	sober.toggleProductFilter = function () {
1120		sober.$body.on( 'click', '.toggle-filter', function ( e ) {
1121			e.preventDefault();
1122
1123			$( this ).next( '.filter-widgets' ).fadeIn( function () {
1124				$( this ).addClass( 'active' );
1125			} );
1126		} ).on( 'click', '.filter-widgets button.close', function () {
1127			$( this ).closest( '.filter-widgets' ).fadeOut( function () {
1128				$( this ).removeClass( 'active' );
1129			} );
1130		} );
1131
1132	};
1133
1134	/**
1135	 * Toggle product quick view
1136	 */
1137	sober.productQuickView = function () {
1138		if ( !sober.$body.hasClass( 'product-quickview-enable' ) ) {
1139			return;
1140		}
1141
1142		var target = 'ul.products .woocommerce-LoopProduct-link';
1143
1144		switch ( sober.data.quickview ) {
1145			case 'buy_button':
1146				target = 'ul.products .sober-loop-atc-button';
1147				break;
1148
1149			case 'view_button':
1150				target = 'ul.products .quick_view_button';
1151				break;
1152
1153			case 'title':
1154				target = 'ul.products h3 a';
1155				break;
1156		}
1157
1158		sober.$body.on( 'click', target, function ( e ) {
1159			if ( sober.$window.width() <= 768 ) {
1160				return;
1161			}
1162
1163			e.preventDefault();
1164
1165			var $a = $( this ),
1166				product_id = $a.data( 'product_id' ) ? $a.data( 'product_id' ) : $a.closest( '.product' ).find( '.sober-loop-atc-button' ).data( 'product_id' ),
1167				url = $a.data( 'url' ) ? $a.data( 'url' ) : $a.attr( 'href' ),
1168				ajax_url = woocommerce_params ? woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'product_quick_view' ) : sober.data.ajaxurl,
1169				$modal = $( '#quick-view-modal' ),
1170				$product = $modal.find( '.product' ),
1171				$button = $modal.find( '.modal-header .close-modal' ).first().clone();
1172
1173			// Incase no product_id found.
1174			if ( ! product_id ) {
1175				var inClass = $a.closest( '.product' ).get( 0 ).classList.value.match( /post-\d*/ );
1176
1177				if ( inClass ) {
1178					product_id = parseInt( inClass[0].replace( 'post-', '' ) );
1179				}
1180			}
1181
1182			$product.hide().html( '' ).addClass( 'invisible' );
1183			$modal.addClass( 'loading' );
1184			sober.openModal( $modal );
1185
1186			$.post( ajax_url, {
1187				action    : 'sober_get_product_quickview',
1188				product_id: product_id,
1189			}, function ( response ) {
1190				var $_product = $( response.data );
1191
1192				$_product.find( 'h1.product_title' ).wrapInner( '<a href="' + url + '"></a>' );
1193				$product.show().html( $_product ).prepend( $button );
1194
1195				var $gallery = $product.find( '.images' ),
1196					$variations = $product.find( '.variations_form' ),
1197					$carousel = $gallery.find( '.woocommerce-product-gallery__slider' );
1198
1199				// Force height for images
1200				$carousel.find( 'img' ).css( 'height', $product.outerHeight() );
1201
1202				// Play the gallery video.
1203				if ( $gallery.hasClass( 'woocommerce-product-gallery--has-video' ) ) {
1204					var $video = $carousel.find( 'video' );
1205
1206					if ( $video.length ) {
1207						$video.mediaelementplayer();
1208
1209						var player = $video.get(0).player;
1210
1211						$carousel.on( 'initialized.owl.carousel translated.owl.carousel', function( event ) {
1212							var $currentSlide = $carousel.find( '.owl-item:eq(' + event.item.index + ')' );
1213
1214							if ( $currentSlide.children( '.woocommerce-product-gallery__image' ).hasClass( 'sober-product-video' ) ) {
1215								player.play();
1216							} else {
1217								player.pause();
1218							}
1219						} );
1220					}
1221				}
1222
1223				if ( $carousel.children().length > 1 ) {
1224					$carousel.addClass( 'owl-carousel' ).owlCarousel( {
1225						rtl       : sober.data.isRTL === "1",
1226						items     : 1,
1227						smartSpeed: 500,
1228						dots      : false,
1229						nav       : true,
1230						navText   : ['<svg width="20" height="20"><use xlink:href="#left-arrow"></use></svg>', '<svg width="20" height="20"><use xlink:href="#right-arrow"></use></svg>'],
1231					} );
1232				}
1233
1234				$gallery.css( 'opacity', 1 );
1235
1236				$carousel.on( 'click', '.woocommerce-product-gallery__image a', function( event ) {
1237					event.preventDefault();
1238				} );
1239
1240				$variations.wc_variation_form().find( '.variations select:eq(0)' ).change();
1241
1242				if ( $.fn.tawcvs_variation_swatches_form ) {
1243					$variations.tawcvs_variation_swatches_form();
1244					sober.modifyVariationSwatches( $variations );
1245				}
1246
1247				$variations.on( 'reset_image found_variation', function() {
1248					$carousel.trigger( 'to.owl.carousel', [0] );
1249				} );
1250
1251				$modal.removeClass( 'loading' );
1252				$product.removeClass( 'invisible' );
1253
1254				if ( $product.find( '.bundle_form .bundle_data' ).length && typeof jQuery.fn.wc_pb_bundle_form === 'function' ) {
1255					$product.find( '.bundle_form .bundle_data' ).wc_pb_bundle_form();
1256				}
1257
1258				if ( typeof SimpleScrollbar !== 'undefined' ) {
1259					SimpleScrollbar.initEl( $_product.find( '.summary' ).get( 0 ) );
1260				}
1261
1262				sober.$body.trigger( 'sober_quickview_opened', [$_product, $modal, sober] );
1263				sober.$body.trigger( 'init_variation_swatches' );
1264			} ).fail( function() {
1265				window.location.herf = url;
1266			} );
1267
1268			if ( 'buy_button' === sober.data.quickview ) {
1269				return false; // Prevent ajax add to cart
1270			}
1271		} );
1272
1273		sober.$body.on( 'sober_modal_closed', function( e, $modal ) {
1274			if ( $modal.hasClass( 'quick-view-modal' ) )  {
1275				$modal.find( '.product' ).html( '' );
1276			}
1277		} );
1278	};
1279
1280	/**
1281	 * Product instance search
1282	 */
1283	sober.instanceSearch = function () {
1284		var xhr = null,
1285			term = '',
1286			searchCache = {},
1287			initialized = {},
1288			debounceTimeout = null,
1289			$modal = $( '#search-modal' ),
1290			$form = $modal.find( 'form' ),
1291			$search = $form.find( 'input.search-field' ),
1292			$results = $modal.find( '.search-results' ),
1293			$button = $results.find( '.search-results-button' ),
1294			post_type = $modal.find( 'input[name=post_type]' ).val();
1295
1296		// Focus on the search field when search modal opened
1297		sober.$body.on( 'click', '[data-toggle="modal"][data-target="search-modal"]', function() {
1298			$search.focus();
1299		} );
1300
1301		$modal.on( 'keyup', '.search-field', function ( e ) {
1302			var valid = false;
1303
1304			if ( typeof e.which === 'undefined' ) {
1305				valid = true;
1306			} else if ( typeof e.which === 'number' && e.which > 0 ) {
1307				valid = !e.ctrlKey && !e.metaKey && !e.altKey;
1308			}
1309
1310			if ( !valid ) {
1311				return;
1312			}
1313
1314			if ( xhr ) {
1315				xhr.abort();
1316			}
1317
1318			clearTimeout( debounceTimeout );
1319
1320			debounceTimeout = setTimeout( function() { search( true ) }, 500 );
1321		} ).on( 'change', '.product-cats input', function () {
1322			if ( xhr ) {
1323				xhr.abort();
1324			}
1325
1326			clearTimeout( debounceTimeout );
1327
1328			debounceTimeout = setTimeout( function() { search( false ) }, 500 );
1329		} ).on( 'click', '.search-reset', function () {
1330			if ( xhr ) {
1331				xhr.abort();
1332			}
1333
1334			$modal.addClass( 'reset' );
1335			$results.find( '.results-container, .view-more-results' ).slideUp( function () {
1336				$modal.removeClass( 'searching searched found-products found-no-product invalid-length reset' );
1337			} );
1338		} ).on( 'focusout', '.search-field', function () {
1339			if ( $search.val().length < 2 ) {
1340				$results.find( '.results-container, .view-more-results' ).slideUp( function () {
1341					$modal.removeClass( 'searching searched found-products found-no-product invalid-length' );
1342				} );
1343			}
1344		} );
1345
1346		/**
1347		 * Private function for searching products
1348		 */
1349		function search( typing ) {
1350			var keyword = $search.val(),
1351				$category = $form.find( '.product-cats input:checked' ),
1352				category = $category.length ? $category.val() : '',
1353				key = keyword + '[' + category + ']';
1354
1355			if ( term === keyword && typing ) {
1356				return;
1357			}
1358
1359			term = keyword;
1360
1361			if ( keyword.length < 2 ) {
1362				$modal.removeClass( 'searching found-products found-no-product' ).addClass( 'invalid-length' );
1363				return;
1364			}
1365
1366			var url = $form.attr( 'action' ) + '?' + $form.serialize();
1367
1368			$button.removeClass( 'soberFadeInUp' );
1369			$( '.view-more-results', $results ).slideUp( 10 );
1370			$modal.removeClass( 'found-products found-no-product' ).addClass( 'searching' );
1371
1372			if ( key in searchCache ) {
1373				showResult( searchCache[key] );
1374			} else {
1375				xhr = $.get( url, function ( response ) {
1376					var $content = $( '#primary', response );
1377
1378					if ( 'product' === post_type ) {
1379						var $products = $( 'ul.products', $content );
1380
1381						if ( $products.length ) {
1382							$products.children( '.last' ).nextAll().remove();
1383
1384							// Cache
1385							searchCache[key] = {
1386								found: true,
1387								items: $products,
1388								url  : url
1389							};
1390						} else {
1391							// Cache
1392							searchCache[key] = {
1393								found: false,
1394								text : $( '.woocommerce-info', $content ).text()
1395							};
1396						}
1397					} else if ( 'post' === post_type ) {
1398						var $posts = $( '#main article:lt(3)', $content );
1399
1400						if ( $posts.length ) {
1401							$posts.addClass( 'col-md-4' );
1402
1403							searchCache[key] = {
1404								found: true,
1405								items: $( '<div class="posts row" />' ).append( $posts ),
1406								url  : url
1407							};
1408						} else {
1409							searchCache[key] = {
1410								found: false,
1411								text : $( '.no-results .page-header-none', $content ).text()
1412							};
1413						}
1414					}
1415
1416					showResult( searchCache[key] );
1417
1418					$modal.addClass( 'searched' );
1419				}, 'html' );
1420			}
1421		}
1422
1423		/**
1424		 * Private function for showing the search result
1425		 *
1426		 * @param result
1427		 */
1428		function showResult( result ) {
1429			var extraClass = 'product' === post_type ? 'woocommerce' : 'sober-post-grid';
1430
1431			$modal.removeClass( 'searching' );
1432
1433			if ( result.found ) {
1434				var grid = result.items.clone(),
1435					items = grid.children();
1436
1437				$modal.addClass( 'found-products' );
1438
1439				$results.find( '.results-container' ).addClass( extraClass ).html( grid );
1440
1441				// Add animation class
1442				for ( var index = 0; index < items.length; index++ ) {
1443					$( items[index] ).css( 'animation-delay', index * 100 + 'ms' );
1444				}
1445				items.addClass( 'soberFadeInUp soberAnimation' );
1446
1447				$button.attr( 'href', result.url ).css( 'animation-delay', index * 100 + 'ms' ).addClass( 'soberFadeInUp soberAnimation' );
1448
1449				$results.find( '.results-container, .view-more-results' ).slideDown( 300, function () {
1450					$modal.removeClass( 'invalid-length' );
1451				} );
1452
1453				// Init zoom/slider thumbnail
1454				if ( 'product' === post_type ) {
1455					sober.$body.trigger( 'sober_products_loaded', [$results] );
1456				} else {
1457					sober.$body.trigger( 'post-load' );
1458				}
1459			} else {
1460				$modal.addClass( 'found-no-product' );
1461
1462				$results.find( '.results-container' ).removeClass( extraClass ).html( $( '<div class="not-found text-center" />' ).text( result.text ) );
1463				$button.attr( 'href', '#' );
1464
1465				$results.find( '.view-more-results' ).slideUp( 300 );
1466				$results.find( '.results-container' ).slideDown( 300, function () {
1467					$modal.removeClass( 'invalid-length' );
1468				} );
1469			}
1470
1471			$modal.addClass( 'searched' );
1472		}
1473	};
1474
1475	/**
1476	 * Init simple scrollbar
1477	 */
1478	sober.fakeScrollbar = function () {
1479		var el = document.querySelector( '#primary-menu.side-menu' );
1480
1481		if ( el && typeof SimpleScrollbar !== 'undefined' ) {
1482			SimpleScrollbar.initEl( el );
1483		}
1484	};
1485
1486	/**
1487	 * Set CSS vars
1488	 */
1489	sober.setCSSVars = function() {
1490		var css = '',
1491			$topbar = $( '#topbar' ),
1492			$header = $( '#masthead' );
1493
1494		if ( $topbar.length ) {
1495			css += '--topbar-height: ' + $topbar.outerHeight() + 'px;';
1496		}
1497
1498		if ( $header.length ) {
1499			css += '--header-height: ' + $header.outerHeight() + 'px;';
1500		}
1501
1502		if ( css ) {
1503			css = ':root{' + css + '}';
1504			$( document.head ).append( '<style id="sober-custom-css-vars">' + css + '</style>' );
1505		}
1506	}
1507
1508	/**
1509	 * Sticky header
1510	 */
1511	sober.stickyHeader = function () {
1512		if ( !sober.data.sticky_header || 'none' === sober.data.sticky_header ) {
1513			return;
1514		}
1515
1516		var header = document.getElementById( 'masthead' );
1517		var topbar = document.getElementById( 'topbar' );
1518		var adminbar = document.getElementById( 'wpadminbar' );
1519		var offset = 0;
1520
1521		if ( ! header ) {
1522			return;
1523		}
1524
1525		// Prepare for white header
1526		prepareForWhiteHeader();
1527		calculateOffset();
1528
1529		sober.$window.on( 'resize', function() {
1530			prepareForWhiteHeader();
1531			calculateOffset();
1532		} );
1533
1534		// Init sticky header.
1535		if ( 'smart' === sober.data.sticky_header && typeof Headroom !== 'undefined' ) {
1536			var stickyHeader = new Headroom( header, {
1537				offset  : offset,
1538				onTop   : function () {
1539					setTimeout( function () {
1540						header.classList.remove( 'headroom--animation' );
1541					}, 500 );
1542				},
1543				onNotTop: function () {
1544					setTimeout( function () {
1545						header.classList.add( 'headroom--animation' );
1546					}, 10 );
1547				}
1548			} );
1549
1550			stickyHeader.init();
1551		} else if ( 'normal' === sober.data.sticky_header ) {
1552			sticky();
1553
1554			sober.$window.on( 'scroll', function () {
1555				sticky();
1556			} );
1557		}
1558
1559		/**
1560		 * Private function for sticky header
1561		 */
1562		function sticky() {
1563			if ( sober.$window.scrollTop() >= offset ) {
1564				header.classList.add( 'sticky' );
1565			} else {
1566				header.classList.remove( 'sticky' );
1567			}
1568		}
1569
1570		function calculateOffset() {
1571			offset = topbar ? topbar.clientHeight : 1;
1572
1573			if ( sober.$window.width() < 783 && adminbar ) {
1574				offset += adminbar.clientHeight;
1575			}
1576		}
1577
1578		/**
1579		 * Add empty spacing for white header.
1580		 */
1581		function prepareForWhiteHeader() {
1582			var needPrepare = sober.$body.hasClass( 'header-white' ) || sober.$body.hasClass( 'header-dark' ) || sober.$body.hasClass( 'header-custom' );
1583
1584			if ( ! needPrepare ) {
1585				needPrepare = ( sober.$body.hasClass( 'no-page-header' ) && !sober.$body.hasClass( 'page-title-hidden' ) && !sober.$body.hasClass( 'page-template-homepage' ) && ! sober.$body.hasClass( 'product-style-5' ) );
1586			}
1587
1588			if ( sober.$body.hasClass( 'page-template-full-screen' ) ) {
1589				needPrepare = false;
1590			}
1591
1592			if ( needPrepare ) {
1593				if ( topbar ) {
1594					topbar.style.marginBottom = header.clientHeight + 'px';
1595				} else {
1596					document.getElementById( 'page' ).style.paddingTop = header.clientHeight + 'px';
1597				}
1598			}
1599		}
1600	};
1601
1602	/**
1603	 * Initialize isotope for portfolio items
1604	 */
1605	sober.portfolioFilter = function () {
1606		var $items = $( '.portfolio-items:not(.sober-portfolio__row)' );
1607
1608		if ( ! $items.length ) {
1609			return;
1610		}
1611
1612		var options = {
1613			itemSelector      : '.portfolio',
1614			transitionDuration: 700,
1615			isOriginLeft      : !(sober.data.isRTL === '1')
1616		};
1617
1618		if ( $items.hasClass( 'portfolio-fullwidth' ) ) {
1619			options.masonry = {
1620				columnWidth: '.col-md-3'
1621			};
1622		}
1623
1624		if ( $items.hasClass( 'portfolio-classic' ) ) {
1625			options.layoutMode = 'fitRows';
1626		}
1627
1628		$items.isotope( options );
1629
1630		$items.imagesLoaded().always( function() {
1631			$items.isotope( 'layout' );
1632		} );
1633
1634		// Support Jetpack lazy load.
1635		$items.on( 'jetpack-lazy-loaded-image', 'img', function() {
1636			$items.isotope( 'layout' );
1637		} );
1638
1639		var $filter = $( '.portfolio-filter' );
1640
1641		$filter.on( 'click', 'li', function ( e ) {
1642			e.preventDefault();
1643
1644			var $this = $( this ),
1645				selector = $this.attr( 'data-filter' );
1646
1647			if ( $this.hasClass( 'active' ) ) {
1648				return;
1649			}
1650
1651			$this.addClass( 'active' ).siblings( '.active' ).removeClass( 'active' );
1652			$this.closest( '.portfolio-filter' ).next( '.portfolio-items' ).isotope( {
1653				filter: selector
1654			} );
1655		} );
1656	};
1657
1658	/**
1659	 * Add extra script for product variation swatches
1660	 * This function will run after plugin swatches did
1661	 */
1662	sober.productVariationSwatches = function () {
1663		sober.$body.on( 'tawcvs_initialized', function () {
1664			var $form = $( '.variations_form' );
1665
1666			sober.modifyVariationSwatches( $form );
1667		} );
1668	};
1669
1670	/**
1671	 * Modify variation swatches
1672	 * This function is used in sober.productVariationSwatches and sober.productQuickView
1673	 *
1674	 * @param $form
1675	 */
1676	sober.modifyVariationSwatches = function ( $form ) {
1677		var $variables = $form.find( '.variations .variable' );
1678
1679		// Remove class "swatches-support" if there is no swatches in this product
1680		var hasSwatches = false;
1681		$variables.each( function() {
1682			if ( $( this ).hasClass( 'swatches' ) ) {
1683				hasSwatches = true;
1684			}
1685		} );
1686
1687		if ( ! hasSwatches ) {
1688			$form.removeClass( 'swatches-support' );
1689		}
1690
1691		// Add class for the last even variation
1692		if ( $variables.length % 2 ) {
1693			$variables.last().addClass( 'wide-variable' );
1694		}
1695
1696		// Change alert style
1697		$form.off( 'tawcvs_no_matching_variations' );
1698		$form.on( 'tawcvs_no_matching_variations', function () {
1699			event.preventDefault();
1700
1701			$form.find( '.woocommerce-variation.single_variation' ).show();
1702			if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) {
1703				$form.find( '.single_variation' ).stop( true, true ).slideDown( 500 ).html( '<p class="invalid-variation-combination">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' );
1704			}
1705		} );
1706	};
1707
1708	/**
1709	 * Init the zoom function for product gallery
1710	 */
1711	sober.productGalleryZoom = function() {
1712		sober.initZoom( '.woocommerce-product-gallery__slider .woocommerce-product-gallery__image' );
1713
1714		$( '.woocommerce-product-gallery--with-images' ).on( 'woocommerce_gallery_init_zoom', function() {
1715			var $target = $( '.woocommerce-product-gallery__image', this ).first().trigger( 'zoom.destroy' );
1716			sober.initZoom( $target );
1717		} ).on( 'click', '.zoomImg', function() {
1718			$( this ).prev( 'a' ).trigger( 'click' );
1719		} );
1720	};
1721
1722	/**
1723	 * Init zoom function on selected image
1724	 *
1725	 * @param zoomTarget
1726	 */
1727	sober.initZoom = function( zoomTarget ) {
1728		if ( ! sober.data.zoom || ! $.fn.zoom ) {
1729			return;
1730		}
1731
1732		var $zoomTarget = $( zoomTarget ),
1733			galleryWidth = $zoomTarget.width(),
1734			zoomEnabled  = false;
1735
1736		$zoomTarget.each( function( index, target ) {
1737			var image = $( target ).find( 'img' );
1738
1739			if ( image.data( 'large_image_width' ) > galleryWidth ) {
1740				zoomEnabled = true;
1741				return false;
1742			}
1743		} );
1744
1745		// But only zoom if the img is larger than its container.
1746		if ( zoomEnabled ) {
1747			var zoom_options = {
1748				touch: false
1749			};
1750
1751			if ( 'ontouchstart' in window ) {
1752				zoom_options.on = 'click';
1753			}
1754
1755			$zoomTarget.trigger( 'zoom.destroy' );
1756			$zoomTarget.zoom( zoom_options );
1757		}
1758	};
1759
1760	/**
1761	 * Init product gallery as a slider
1762	 */
1763	sober.productGallerySlider = function() {
1764		var $product = $( '.woocommerce div.product' ),
1765			$gallery = $( 'div.images', $product ),
1766			$carousel = $( '.woocommerce-product-gallery__slider', $gallery ),
1767			$thumbnails = $( '.thumbnails', $gallery );
1768
1769		// Play the gallery video.
1770		if ( $gallery.hasClass( 'woocommerce-product-gallery--has-video' ) ) {
1771			var $video = $carousel.find( 'video' );
1772
1773			if ( $video.length ) {
1774				var player = $video.get(0).player;
1775
1776				if ( $product.hasClass( 'layout-style-6' ) || $product.hasClass( 'layout-style-1' ) ) {
1777					player.play();
1778				} else {
1779					$carousel.on( 'initialized.owl.carousel translated.owl.carousel', function( event ) {
1780						var $currentSlide = $carousel.find( '.owl-item:eq(' + event.item.index + ')' );
1781
1782						if ( $currentSlide.children( '.woocommerce-product-gallery__image' ).hasClass( 'sober-product-video' ) ) {
1783							player.play();
1784						} else {
1785							player.pause();
1786						}
1787					} );
1788				}
1789			}
1790		}
1791
1792		// Init the carousel.
1793		if ( $carousel.children().length > 1 ) {
1794			var carouselOptions = {
1795				rtl       : sober.data.isRTL === "1",
1796				dots      : true,
1797				items     : 1,
1798				loop      : false,
1799				autoHeight: !! sober.data.product_gallery_autoheight
1800			};
1801
1802			if ( $product.hasClass( 'layout-style-5' ) ) {
1803				carouselOptions.autoHeight = false;
1804				carouselOptions.animateOut = 'fadeOut';
1805			}
1806
1807			if ( $product.hasClass( 'layout-style-4' ) ) {
1808				if ( ! $product.hasClass( 'product-type-variable' ) ) {
1809					carouselOptions.loop = true;
1810					carouselOptions.startPosition = 0;
1811				} else {
1812					carouselOptions.startPosition = ( $carousel.children().length > 2 ? 1 : 0 );
1813				}
1814
1815				carouselOptions.items = 2;
1816				carouselOptions.margin = 30;
1817				carouselOptions.center = true;
1818				carouselOptions.nav = true;
1819				carouselOptions.navText = ['<svg viewBox="0 0 20 20"><use xlink:href="#left-arrow"></use></svg>', '<svg viewBox="0 0 20 20"><use xlink:href="#right-arrow"></use></svg>'];
1820				carouselOptions.responsive = {
1821					0: {
1822						items: 1,
1823						nav: false
1824					},
1825					768: {
1826						items: 2,
1827						nav: true
1828					}
1829				};
1830				carouselOptions.onInitialized = function() {
1831					sober.initZoom( '.woocommerce-product-gallery__slider .woocommerce-product-gallery__image' );
1832				};
1833			}
1834
1835			// Toggle carousel for mobile
1836			if ( $product.hasClass( 'layout-style-1' ) || $product.hasClass( 'layout-style-6' ) ) {
1837				carouselOptions.margin = 10;
1838
1839				if ( sober.$window.width() < 992 ) {
1840					if ( ! $carousel.hasClass( 'owl-carousel' ) ) {
1841						$carousel.addClass( 'owl-carousel' ).owlCarousel( carouselOptions );
1842					}
1843				} else {
1844					$carousel.trigger( 'destroy.owl.carousel' ).removeClass( 'owl-carousel' );
1845				}
1846			} else if ( ! $carousel.hasClass( 'owl-loaded' ) ) {
1847				// Run the carousel.
1848				$carousel.addClass( 'owl-carousel' ).owlCarousel( carouselOptions );
1849			}
1850		}
1851
1852		// Show it
1853		$gallery.css( 'opacity', 1 );
1854
1855		// Use thumbnails as pagination
1856		$gallery.on( 'click', '.thumbnails .woocommerce-product-gallery__image a', function( event ) {
1857			event.preventDefault();
1858
1859			var $image = $( this ).closest( '.woocommerce-product-gallery__image' );
1860
1861			$carousel.trigger( 'to.owl.carousel', [$image.index()] );
1862		} );
1863
1864		// Change the active state of thumbnails.
1865		$carousel.on( 'translated.owl.carousel', function( event ) {
1866			$thumbnails.children().removeClass( 'active' ).eq( event.item.index ).addClass( 'active' );
1867		} );
1868
1869		// Variation form changed
1870		$( '.variations_form:not(.yith-wcpb-bundle-form)', $product ).on( 'reset_image found_variation', function() {
1871			$carousel.trigger( 'to.owl.carousel', [0] );
1872		} ).on( 'reset_image', function() {
1873			$thumbnails.children( ':eq(0)' ).find( 'img' ).wc_reset_variation_attr( 'src' );
1874		} ).on( 'found_variation', function( event, variation ) {
1875			$thumbnails.children( ':eq(0)' ).find( 'img' ).wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src ? variation.image.gallery_thumbnail_src : variation.image.thumb_src );
1876		} );
1877	};
1878
1879	/**
1880	 * change product width to be full-width
1881	 */
1882	sober.productFullWidth = function() {
1883		var $product = $( '.woocommerce div.product' );
1884
1885		if ( ! $product.length ) {
1886			return;
1887		}
1888
1889		var $gallerySummary = $product.find( '.product-summary' ),
1890			$toolbar = $product.find( '.product-toolbar' ),
1891			$header = $( '#masthead' );
1892
1893		// Set width of product
1894		if ( $product.hasClass( 'layout-style-5' ) || $product.hasClass( 'layout-style-6' ) ) {
1895			setProductWidth();
1896
1897			sober.$window.on( 'resize load', function() {
1898				setProductWidth();
1899			} );
1900		}
1901
1902		// Set top spacing
1903		if ( $product.hasClass( 'layout-style-5' ) ) {
1904			setTopSpacing();
1905
1906			sober.$window.on( 'resize load', function() {
1907				setTopSpacing();
1908			} );
1909		}
1910
1911		/**
1912		 * Change the product width
1913		 */
1914		function setProductWidth() {
1915			var width = sober.$window.width();
1916
1917			$gallerySummary.width( width );
1918			$toolbar.width( width );
1919
1920			if ( sober.data.isRTL ) {
1921				$gallerySummary.css( 'marginRight', -width/2 );
1922				$toolbar.css( 'marginRight', -width/2 );
1923			} else {
1924				$gallerySummary.css( 'marginLeft', -width/2 );
1925				$toolbar.css( 'marginLeft', -width/2 );
1926			}
1927		}
1928
1929		function setTopSpacing() {
1930			$gallerySummary.css( 'paddingTop', $header.outerHeight() );
1931		}
1932	};
1933
1934	/**
1935	 * Set product background
1936	 */
1937	sober.productBackground = function() {
1938		if ( typeof BackgroundColorTheif == 'undefined' ) {
1939			return;
1940		}
1941
1942		if ( ! sober.data.product_gallery_autobg ) {
1943			return;
1944		}
1945
1946		var $product = $( '.woocommerce div.product' );
1947
1948		if ( ! $product.hasClass( 'layout-style-5' ) ) {
1949			return;
1950		}
1951
1952		var	$gallery = $product.find( 'div.images' ),
1953			$carousel = $gallery.find( '.woocommerce-product-gallery__slider' ),
1954			$image = $gallery.find( '.wp-post-image' ),
1955			imageColor = new BackgroundColorTheif();
1956
1957		// Change background base on main image.
1958		if ( ! $product.hasClass( 'background-set' ) ) {
1959			$image.one( 'load', function() {
1960				setTimeout( function() {
1961					changeProductBackground( $image.get( 0 ) );
1962				}, 100 );
1963			} ).each( function() {
1964				if ( this.complete ) {
1965					$( this ).trigger( 'load' );
1966				}
1967			} );
1968
1969			// Support Jetpack images lazy loads.
1970			$gallery.on( 'jetpack-lazy-loaded-image', '.wp-post-image', function() {
1971				$( this ).one( 'load', function() {
1972					changeProductBackground( this );
1973				} );
1974			} );
1975		}
1976
1977		// Change background when slider change.
1978		if ( ! $product.hasClass( 'background-set-all' ) ) {
1979			$carousel.on( 'translate.owl.carousel', function( event ) {
1980				setTimeout( function() {
1981					changeProductBackground( $carousel.find( '.owl-item' ).eq( event.item.index ).find( 'img' ).get( 0 ) );
1982				}, 150 );
1983			} );
1984
1985			// Change background when variation changed
1986			$gallery.on( 'woocommerce_gallery_reset_slide_position', function() {
1987				changeProductBackground( $image.get( 0 ) );
1988			} );
1989		}
1990
1991		/**
1992		 * Change product backgound color
1993		 */
1994		function changeProductBackground( image ) {
1995			// Stop if this image is not loaded.
1996			if ( typeof image === 'undefined' || image.src === '' ) {
1997				return;
1998			}
1999
2000			if ( image.classList.contains( 'jetpack-lazy-image' ) ) {
2001				if ( ! image.dataset['lazyLoaded'] ) {
2002					return;
2003				}
2004			}
2005
2006			var rgb = imageColor.getBackGroundColor( image );
2007			$product.find( '.product-summary' ).get( 0 ).style.backgroundColor = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
2008		}
2009	};
2010
2011	/**
2012	 * Display related products as a carousel
2013	 */
2014	sober.relatedProductsCarousel = function() {
2015		if ( ! sober.data.related_products_carousel ) {
2016			return;
2017		}
2018
2019		var $relatedProducts = $( '.related.products ul.products' );
2020
2021		if ( ! $relatedProducts.length ) {
2022			return;
2023		}
2024
2025		var columns = 4;
2026
2027		if ( sober.$body.hasClass( 'product-style-1' ) || sober.$body.hasClass( 'product-style-2' ) ) {
2028			columns = 5;
2029		}
2030
2031		$relatedProducts.addClass( 'owl-carousel' ).owlCarousel( {
2032			rtl   : sober.data.isRTL === "1",
2033			items : columns,
2034			loop  : false,
2035			dots: true,
2036			nav: false,
2037			responsive: {
2038				0: {
2039					items: 1
2040				},
2041				320: {
2042					items: 2
2043				},
2044				768: {
2045					items: 3
2046				},
2047				1024: {
2048					items: 4
2049				},
2050				1366: {
2051					items: columns
2052				}
2053			}
2054		} );
2055	};
2056
2057	/**
2058	 * Display upsell products as a carousel.
2059	 * This is a normal carousel for all product layouts except layout v3.
2060	 */
2061	sober.upsellProductsCarousel = function() {
2062		if ( ! sober.data.upsell_products_carousel ) {
2063			return;
2064		}
2065
2066		var $upsellProducts = $( '.upsells.products ul.products' );
2067
2068		if ( ! $upsellProducts.length ) {
2069			return;
2070		}
2071
2072		var columns = 4;
2073
2074		if ( sober.$body.hasClass( 'product-style-1' ) || sober.$body.hasClass( 'product-style-2' ) ) {
2075			columns = 5;
2076		}
2077
2078		$upsellProducts.addClass( 'owl-carousel' ).owlCarousel( {
2079			rtl   : sober.data.isRTL === "1",
2080			items : columns,
2081			loop  : false,
2082			dots: true,
2083			nav: false,
2084			responsive: {
2085				0: {
2086					items: 1
2087				},
2088				320: {
2089					items: 2
2090				},
2091				768: {
2092					items: 3
2093				},
2094				1024: {
2095					items: 4
2096				},
2097				1366: {
2098					items: columns
2099				}
2100			}
2101		} );
2102	};
2103
2104	/**
2105	 * Zoom product image when hover
2106	 */
2107	sober.productImageZoom = function() {
2108		$( '.product-thumbnail-zoom' ).each( function () {
2109			var $el = $( this );
2110
2111			$el.zoom( {
2112				url: $el.attr( 'data-zoom_image' )
2113			} );
2114		} );
2115
2116		sober.$body.on( 'soo_filter_request_success', function() {
2117			$( '.product-thumbnail-zoom', '.archive.woocommerce #primary ul.products' ).each( function () {
2118				var $el = $( this );
2119
2120				$el.zoom( {
2121					url: $el.attr( 'data-zoom_image' )
2122				} );
2123			} );
2124		} );
2125
2126		sober.$body.on( 'sober_products_loaded', function( event, products ) {
2127			$( products ).imagesLoaded( function() {
2128				var $thumbnails = $( '.product-thumbnail-zoom', products );
2129
2130				if ( $thumbnails.length ) {
2131					$thumbnails.each( function() {
2132						var $el = $( this );
2133
2134						$el.zoom( {
2135							url: $el.attr( 'data-zoom_image' )
2136						} );
2137					} );
2138				}
2139			} );
2140		} );
2141	};
2142
2143	/**
2144	 * Display product thumbnail images as slider
2145	 */
2146	sober.productImageSlider = function() {
2147		var $products = $( 'ul.products' );
2148
2149		$products.each( function() {
2150			if ( ! $( this ).parents().is( '.side-products' ) ) {
2151				sober.initProductThumbnailSlider( this );
2152			}
2153		} );
2154
2155		// Fix problem with the product carousel element
2156		$( '.sober-product-carousel' ).on( 'initialized.owl.carousel', function() {
2157			$( '.product-images__slider' ).trigger( 'refresh.owl.carousel' );
2158		} );
2159
2160		// Fix problem with Soo Filter
2161		sober.$body.on( 'soo_filter_request_success', function() {
2162			sober.initProductThumbnailSlider( $( '.archive.woocommerce #primary ul.products' ) );
2163		} );
2164
2165		sober.$body.on( 'sober_products_loaded', function( event, products ) {
2166			sober.initProductThumbnailSlider( products );
2167		} );
2168	};
2169
2170	/**
2171	 * Init product thumbnail slider
2172	 */
2173	sober.initProductThumbnailSlider = function( products ) {
2174		$( products ).imagesLoaded( function() {
2175			$( '.product-images__slider', products ).owlCarousel( {
2176				items: 1,
2177				lazyLoad: true,
2178				dots: false,
2179				nav: true,
2180				loop: !! sober.data.product_card_slider_loop,
2181				rtl: sober.data.isRTL === "1",
2182				navText: ['<svg viewBox="0 0 14 20"><use xlink:href="#left"></use></svg>', '<svg viewBox="0 0 14 20"><use xlink:href="#right"></use></svg>']
2183			} ).on( 'resize.owl.carousel initialized.owl.carousel', function() {
2184				$( '.woocommerce.archive .site-content ul.products' ).isotope( 'layout' );
2185			} );
2186		} );
2187	};
2188
2189	/**
2190	 * Ajaxify add to cart button on single product page
2191	 */
2192	sober.singeProductAjaxAddToCart = function () {
2193		if ( 'yes' !== sober.data.single_ajax_add_to_cart ) {
2194			return;
2195		}
2196
2197		var alertTimeout = null;
2198
2199		sober.$body.on( 'submit', 'form.cart', function( event ) {
2200			var $form = $( this );
2201
2202			if ( $form.closest( 'div.product' ).hasClass( 'product-type-external' ) || $form.data( 'with_ajax' ) ) {
2203				return;
2204			}
2205
2206			event.preventDefault();
2207
2208			var	$button = $form.find( '.single_add_to_cart_button' ),
2209				formData = new FormData( this );
2210
2211			// Prevent double-add by remove the param 'add-to-cart'.
2212			if ( formData.has( 'add-to-cart' ) ) {
2213				formData.delete( 'add-to-cart' );
2214			}
2215
2216			// Then we will rename it in the ajax handler function.
2217			formData.append( 'sober-add-to-cart', $form.find( '[name="add-to-cart"]' ).val() );
2218
2219			// Ajax.
2220			$.ajax( {
2221				url: woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'sober_ajax_add_to_cart' ),
2222				data: formData,
2223				method: 'POST',
2224				contentType: false,
2225				processData: false,
2226				beforeSend: function() {
2227					$button.removeClass( 'added' ).addClass( 'loading disabled' ).prop( 'disabled', true );
2228				},
2229				complete: function( response ) {
2230					$button.removeClass( 'loading disabled' ).addClass( 'added' ).prop( 'disabled', false );
2231
2232					response = response.responseJSON;
2233
2234					if ( ! response ) {
2235						return;
2236					}
2237
2238					// Reload on error.
2239					if ( response.error && response.product_url ) {
2240						window.location = response.product_url;
2241						return;
2242					}
2243
2244					// Redirect to cart option.
2245					if ( 'undefined' !== typeof wc_add_to_cart_params && wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
2246						window.location = wc_add_to_cart_params.cart_url;
2247						return;
2248					}
2249
2250					// Trigger the default event to refresh fragments.
2251					sober.$body.trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $button ] );
2252
2253					// Trigger the fragment refresh event manually if necessary.
2254					if ( 'undefined' === typeof wc_add_to_cart_params ) {
2255						sober.$body.trigger( 'wc_fragment_refresh' );
2256					}
2257
2258					// Display new notices (alert bar).
2259					if ( sober.data.open_cart_modal_after_add !== '1' && response.fragments.notices_html ) {
2260						var $alert = $( '.sober-alert-bar' );
2261
2262						if ( ! $alert.length ) {
2263							$alert = $( '<div class="sober-alert-bar"></div>' );
2264							sober.$body.append( $alert );
2265						}
2266
2267						$alert.html( response.fragments.notices_html );
2268						setTimeout( function() {
2269							$alert.addClass( 'active' );
2270						}, 100 );
2271
2272						// Auto hide the alert bar after 5 seconds. Apply for success actions only.
2273						if ( $alert.find( '.woocommerce-message' ).length ) {
2274							clearTimeout( alertTimeout );
2275							alertTimeout = setTimeout( function() {
2276								$alert.removeClass( 'active' );
2277							}, 5000 );
2278						}
2279					}
2280				},
2281				error: function() {
2282					// Try to submit the form without ajax on errors.
2283					$form.data( 'with_ajax', false ).trigger( 'submit' );
2284				}
2285			} );
2286		} );
2287
2288		// Close alert bar
2289		sober.$body.on( 'click', '.sober-alert-bar .close', function ( e ) {
2290			e.preventDefault();
2291
2292			$( this ).closest( '.sober-alert-bar' ).removeClass( 'active' );
2293		} );
2294	};
2295
2296	/**
2297	 * Init sticky cart form.
2298	 *
2299	 * @todo Support bundled products.
2300	 */
2301	sober.stickyAddToCart = function() {
2302		var $sticky = $( '.sticky-cart-form' );
2303
2304		if ( ! $sticky.length ) {
2305			return;
2306		}
2307
2308		// Remove wishlist and share buttons.
2309		$sticky.find( '.wcboost-wishlist-button, .add-to-wishlist-button, .product-share' ).remove();
2310
2311		var $forms = $( 'form.cart', $sticky.closest( 'div.product' ) ),
2312			$originalForm = $forms.first(),
2313			$image = $sticky.find( '.sticky-cart-form__product-image img' ),
2314			$price = $sticky.find( '.sticky-cart-form__product-summary .price' ),
2315			$stickyHeader = $( '#masthead' ),
2316			offset = 0,
2317			doingSync = false;
2318
2319		if ( $stickyHeader.hasClass( 'header-v10' ) ) {
2320			$stickyHeader = $stickyHeader.find( '.header-main .header-right-items' );
2321		}
2322
2323		if ( sober.data.sticky_header && 'none' !== sober.data.sticky_header ) {
2324			offset = $stickyHeader.height();
2325		}
2326
2327		// Handle add-to-cart variations of 2 forms.
2328		$forms
2329			.on( 'reset_data', function() {
2330				$image.attr( 'src', $image.data( 'o_src' ) );
2331				$price.show().siblings( '.variation-price, .stock' ).remove();
2332			} )
2333			.on( 'found_variation', function( event, variation ) {
2334				if ( variation.image && variation.image.gallery_thumbnail_src && variation.image.gallery_thumbnail_src.length > 1 ) {
2335					$image.attr( 'src', variation.image.gallery_thumbnail_src );
2336				}
2337
2338				if ( variation.availability_html && variation.availability_html.length ) {
2339					$price.hide().siblings( '.stock, .variation-price' ).remove();
2340					$price.after( variation.availability_html );
2341				} else {
2342					$price.siblings( '.stock' ).remove();
2343
2344					if ( variation.price_html && variation.price_html.length ) {
2345						$price.hide().siblings( '.variation-price' ).remove();
2346						$price.after( $( variation.price_html ).addClass( 'variation-price' ) );
2347					}
2348				}
2349			} )
2350			// Sync inputs' value.
2351			.on( 'change', ':input', function() {
2352				// Avoid infinite loop.
2353				if ( doingSync ) {
2354					return;
2355				}
2356
2357				doingSync = true;
2358
2359				var $currentForm = $( this ).closest( 'form.cart' ),
2360					$targetForm = $forms.not( $currentForm );
2361
2362				$targetForm.find( ':input[name="' + this.name + '"]' ).val( this.value ).trigger( 'change' );
2363
2364				doingSync = false;
2365			} );
2366
2367		// Scroll to the grouped products form.
2368		$sticky.on( 'click', '.grouped_form .single_add_to_cart_button, .bundle_form .single_add_to_cart_button', function() {
2369			$( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 );
2370
2371			return false;
2372		} ).on( 'click', '.sticky-cart-form__mobile-button', function( event ) {
2373			event.preventDefault();
2374
2375			if ( this.dataset.product_type === 'simple' || this.dataset.product_type === 'grouped' || this.dataset.product_type === 'external' ) {
2376				$sticky.find( '.single_add_to_cart_button' ).trigger( 'click' );
2377			} else {
2378				$( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 );
2379			}
2380		} );
2381
2382		// Handle the scroll event.
2383		var	lastKnownScrollPosition = window.scrollY,
2384			ticking = false,
2385			rAF = window.requestAnimationFrame ||
2386				window.webkitRequestAnimationFrame ||
2387				window.mozRequestAnimationFrame ||
2388				window.msRequestAnimationFrame ||
2389				window.oRequestAnimationFrame;
2390
2391		var checkFormVisibility = function( position ) {
2392			if ( position >= ( $originalForm.offset().top + $originalForm.height() - offset ) ) {
2393				$sticky.attr( 'aria-hidden', false ).removeClass( 'sticky-cart-form--unpin' ).addClass( 'sticky-cart-form--pin' );
2394
2395				if ( 'top' === $sticky.data( 'position' ) && sober.data.sticky_header && 'none' !== sober.data.sticky_header ) {
2396					$stickyHeader.addClass( 'sticky--ignore' );
2397				}
2398			} else {
2399				$sticky.attr( 'aria-hidden', true ).removeClass( 'sticky-cart-form--pin' ).addClass( 'sticky-cart-form--unpin' );
2400
2401				if ( 'top' === $sticky.data( 'position' ) && sober.data.sticky_header && 'none' !== sober.data.sticky_header ) {
2402					$stickyHeader.removeClass( 'sticky--ignore' );
2403				}
2404			}
2405		};
2406
2407		// Check and toggle the sticky add-to-cart form on scroll.
2408		document.addEventListener( 'scroll', function() {
2409			lastKnownScrollPosition = window.scrollY;
2410
2411			if ( ! ticking ) {
2412				rAF( function() {
2413					checkFormVisibility( lastKnownScrollPosition );
2414					ticking = false;
2415				} );
2416
2417				ticking = true;
2418			}
2419		} );
2420
2421		rAF( function() {
2422			checkFormVisibility( lastKnownScrollPosition );
2423			ticking = false;
2424		} );
2425	}
2426
2427	/**
2428	 * Open the cart modal after successful addition
2429	 */
2430	sober.openCartModalAfterAdd = function () {
2431		if ( sober.data.open_cart_modal_after_add !== '1' ) {
2432			return;
2433		}
2434
2435		sober.$body.on( 'added_to_cart', function () {
2436			if ( $( '#cart-modal' ).hasClass( 'open' ) ) {
2437				return;
2438			}
2439
2440			sober.closeModal();
2441			sober.openModal( '#cart-modal', 'cart' );
2442		} );
2443	};
2444
2445	/**
2446	 * Init parallax for page header elements
2447	 */
2448	sober.pageHeaderParallax = function () {
2449		if ( typeof Rellax === 'undefined' ) {
2450			return;
2451		}
2452
2453		var $title = $( '.page-header .page-title' ),
2454			$breadcrumb = $( '.page-header .breadcrumb' );
2455
2456		if ( 'up' === sober.data.page_header_parallax ) {
2457			if ( $title.length ) {
2458				new Rellax( '.page-header .page-title', {speed: 1} );
2459			}
2460			if ( $breadcrumb.length ) {
2461				new Rellax( '.page-header .breadcrumb', {speed: 2} );
2462			}
2463		} else if ( 'down' === sober.data.page_header_parallax ) {
2464			if ( $title.length ) {
2465				new Rellax( '.page-header .page-title', {speed: -2} );
2466			}
2467			if ( $breadcrumb.length ) {
2468				new Rellax( '.page-header .breadcrumb', {speed: -1} );
2469			}
2470		}
2471	};
2472
2473	/**
2474	 * Add page preloader
2475	 */
2476	sober.preload = function () {
2477		var $preloader = $( '#preloader' );
2478
2479		if ( ! $preloader.length ) {
2480			return;
2481		}
2482
2483		var ignorePreloader = false;
2484
2485		sober.$body.on( 'click', 'a[href^=mailto], a[href^=tel]', function() {
2486			ignorePreloader = true;
2487		} );
2488
2489		sober.$window.on( 'beforeunload', function() {
2490			if ( ! ignorePreloader ) {
2491				$preloader.fadeIn( 'slow' );
2492			}
2493
2494			ignorePreloader = false;
2495		} );
2496
2497		$preloader.fadeOut( 800 );
2498
2499		window.onpageshow = function( event ) {
2500			if ( event.persisted ) {
2501				$preloader.fadeOut( 800 );
2502			}
2503		};
2504	};
2505
2506	/**
2507	 * Call functions for responsiveness
2508	 */
2509	sober.responsive = function () {
2510		// Initialize fitvids
2511		sober.responsiveVideos();
2512
2513		// Init/destroy product image carousel for product style 1
2514		sober.$window.on( 'resize', sober.productGallerySlider );
2515
2516		// Close the filter panel on success.
2517		sober.$body.on( 'sober_products_filter_request_success', function() {
2518			if ( sober.$window.width() < 768 ) {
2519				sober.closeProductFilter();
2520			}
2521		} )
2522	};
2523
2524	/**
2525	 * Responsive videos
2526	 */
2527	sober.responsiveVideos = function () {
2528		sober.$body.fitVids();
2529	};
2530
2531	/**
2532	 * Close the filter p
2533	 */
2534	sober.closeProductFilter = function() {
2535		$( '.shop-toolbar .filter-widgets.active' ).fadeOut( function () {
2536			$( this ).removeClass( 'active' );
2537		} );
2538	}
2539
2540	/**
2541	 * Open popup
2542	 */
2543	sober.popup = function() {
2544		var days = parseInt( sober.data.popup_frequency ),
2545			delay = parseInt( sober.data.popup_visible_delay );
2546
2547		if ( days > 0 && document.cookie.match( /^(.*;)?\s*sober_popup\s*=\s*[^;]+(.*)?$/ ) ) {
2548			return;
2549		}
2550
2551		delay = Math.max( delay, 0 );
2552		delay = 'delay' === sober.data.popup_visible ? delay : 0;
2553
2554		sober.$window.on( 'load', function() {
2555			setTimeout( function() {
2556				sober.openModal( '#popup' );
2557			}, delay * 1000 );
2558		} );
2559
2560		sober.$body.on( 'sober_modal_closed', function (event, modal) {
2561			if ( ! modal.hasClass( 'sober-popup' ) ) {
2562				return;
2563			}
2564
2565			var date = new Date(),
2566				value = date.getTime();
2567
2568			date.setTime( date.getTime() + (days * 24 * 60 * 60 * 1000) );
2569
2570			document.cookie = 'sober_popup=' + value + ';expires=' + date.toGMTString() + ';path=/';
2571		} );
2572
2573		// Support third party to close the popup.
2574		sober.$body.on( 'click', '.sober-popup .close-popup-trigger', function() {
2575			sober.closeModal();
2576		} );
2577	};
2578
2579	/**
2580	 * Show a notification after added a product to cart successfully
2581	 */
2582	sober.addedToCartNotice = function() {
2583		if ( ! sober.data.added_to_cart_notice || ! $.fn.notify ) {
2584			return;
2585		}
2586
2587		$.notify.addStyle( 'sober', {
2588			html: '<div><svg viewBox="0 0 20 20" class="message-icon"><use xlink:href="#success" href="#success"></use></svg><span data-notify-text/></div>'
2589		});
2590
2591		$( document ).on( 'added_to_cart', function() {
2592			$.notify( sober.data.l10n.added_to_cart_notice, {
2593				autoHideDelay: 2000,
2594				className: 'success',
2595				style: 'sober',
2596				showAnimation: 'fadeIn',
2597				hideAnimation: 'fadeOut'
2598			} );
2599		} );
2600	};
2601
2602	/**
2603	 * Turn off the event handler for terms and conditions link
2604	 */
2605	sober.checkoutTerms = function() {
2606		sober.$body.off( 'click', 'a.woocommerce-terms-and-conditions-link' );
2607	};
2608
2609	/**
2610	 * Fix row full width in RTL
2611	 */
2612	sober.fixVC = function() {
2613		if ( sober.data.isRTL !== '1' ) {
2614			return;
2615		}
2616
2617		$( document ).on( 'vc-full-width-row-single', function( event, data ) {
2618			data.el.css( {
2619				left: 'auto',
2620				right: data.offset
2621			} );
2622		} );
2623	};
2624
2625	/**
2626	 * Ajax login before refresh page
2627	 */
2628	sober.loginModalAuthenticate = function() {
2629		$( '#login-modal' ).on( 'submit', '.woocommerce-form-login', function( e ) {
2630			var username = $( 'input[name=username]', this ).val(),
2631				password = $( 'input[name=password]', this ).val(),
2632				remember = $( 'input[name=rememberme]', this ).is( ':checked' ),
2633				nonce = $( 'input[name=woocommerce-login-nonce]', this ).val(),
2634				$button = $( '[type=submit]', this ),
2635				$form = $( this ),
2636				$box = $form.next( '.woocommerce-error' );
2637
2638			if ( ! username ) {
2639				$( 'input[name=username]', this ).focus();
2640
2641				return false;
2642			}
2643
2644			if ( ! password ) {
2645				$( 'input[name=password]', this ).focus();
2646
2647				return false;
2648			}
2649
2650			if ( $form.data( 'validated' ) ) {
2651				return true;
2652			}
2653
2654			$button.addClass( 'loading' );
2655
2656			if ( $box.length ) {
2657				$box.fadeOut();
2658			}
2659
2660			$.post(
2661				sober.data.ajaxurl,
2662				{
2663					action: 'sober_login_authenticate',
2664					username: username,
2665					password: password,
2666					remember: remember,
2667					security: nonce,
2668				},
2669				function( response ) {
2670					if ( ! response.success ) {
2671						if ( ! $box.length ) {
2672							$box = $( '<div class="woocommerce-error sober-message-box danger"/>' );
2673
2674							$box.append( '<svg viewBox="0 0 20 20" class="message-icon"><use xlink:href="#warning"></use></svg>' )
2675								.append( '<div class="box-content"></div>' )
2676								.append( '<a class="close" href="#"><svg viewBox="0 0 14 14"><use xlink:href="#close-delete-small"></use></svg></a>' );
2677
2678							$box.hide().insertAfter( $form );
2679						}
2680
2681						$box.find( '.box-content' ).html( response.data );
2682						$box.fadeIn();
2683						$button.removeClass( 'loading' );
2684					} else {
2685						// Need a valid data to pass the login from validation.
2686						$button.before( '<input type="hidden" name="login" value="' + $button.attr( 'value' ) + '" />' );
2687						$form.data( 'validated', true ).submit();
2688					}
2689				}
2690			);
2691
2692			e.preventDefault();
2693		} );
2694	};
2695
2696	/**
2697	 * Support lazy load images
2698	 */
2699	sober.lazyLoadImages = function() {
2700		sober.$body.on( 'post-load sober_products_loaded soo_filter_request_success sober_quickview_opened', function() {
2701			// Create a custom event for Jetpack lazy loads
2702			var lazyLoadImagesEvent;
2703
2704			try {
2705				lazyLoadImagesEvent = new Event( 'jetpack-lazy-images-load', {
2706					bubbles: true,
2707					cancelable: true,
2708				} );
2709			} catch ( e ) {
2710				lazyLoadImagesEvent = document.createEvent( 'Event' );
2711				lazyLoadImagesEvent.initEvent( 'jetpack-lazy-images-load', true, true );
2712			}
2713
2714			setTimeout( function() {
2715				document.body.dispatchEvent( lazyLoadImagesEvent );
2716			}, 100 );
2717		} );
2718	};
2719
2720	/**
2721	 * Close WC notices
2722	 */
2723	sober.closeNotices = function() {
2724		sober.$body.on( 'click', '.wc-block-components-notice-banner__close', function( event ) {
2725			event.preventDefault();
2726
2727			$( this ).closest( '.wc-block-components-notice-banner' ).fadeOut( 'slow' );
2728		} );
2729	}
2730
2731	/**
2732	 * Document ready
2733	 */
2734	$( function () {
2735		sober.init();
2736	} );
2737})( jQuery );

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.