PageSourceSearch

https://www.holmanindustries.com.au/wp-content/themes/konte/js/scripts.js?ver=2.4.11

js holmanindustries.com.au collected 2026-10-01 12:05:09 UTC 116,040 bytes, 4,438 lines download raw bytes

1/*global konteData*/
2var konte = konte || {};
3
4(function( $ ) {
5	'use strict';
6
7	/**
8	 * The main function to init the theme
9	 */
10	konte.init = function() {
11		this.data = konteData || {};
12
13		this.preloader();
14
15		this.focusSearchField();
16		this.instantSearch();
17		this.ajaxSearch();
18		this.toggleListDropdown();
19		this.addWishlistCounter();
20		this.toggleHamburgerScreen();
21		this.toggleHamburgerMenu();
22		this.toggleVerticalMenu();
23		this.toggleOffCanvas();
24		this.calculateMenuAccessibleArea();
25		this.toggleModals();
26		this.loadMorePosts();
27		this.fetchPostTotalShare();
28
29		this.featuredContentCarousel();
30		this.postsSliderWidget();
31		this.stickySidebar();
32
33		this.closeTopbar();
34		this.stickyHeader();
35		this.pageHeaderHeight();
36		this.scrollDown();
37
38		this.closeWCMessages();
39		this.productQuantityButtons();
40		this.singleProductAjaxAddToCart();
41		this.stickyAddToCart();
42		this.cartPanel();
43		this.reviewProduct();
44		this.productLightBox();
45		this.toggleProductTabs();
46		this.productVariationSwatches();
47		this.relatedProductsCarousel();
48		this.productGalleryCarousel();
49		this.productGalleryThumbnailCarousel();
50
51		this.singleProductV1();
52		this.singleProductV2();
53		this.singleProductV3();
54		this.singleProductV4();
55		this.singleProductV5();
56		this.singleProductV6();
57		this.singleProductV7();
58
59		this.formFieldFocus();
60		this.loginTabs();
61		this.loginPanel();
62		this.loginPanelAuthenticate();
63
64		this.productsMasonry();
65		this.productsCarousel();
66		this.productThumbnailsSlider();
67		this.productThumbnailZoom();
68		this.productQuickView();
69		this.emptyQuickViewOnClose();
70		this.autoCloseQuickView();
71		this.loadMoreProducts();
72
73		this.productsQuickSearch();
74		this.productsTools();
75		this.cartWidget();
76		this.shopNotifications();
77
78		this.pageTemplateSplit();
79		this.videoBackground();
80
81		this.pageTemplateFlexPosts();
82		this.stickyScrollDown();
83		this.stickySocials();
84		this.openShareLinks();
85
86		this.popup();
87
88		this.fixVCRowsWithVerticalHeader();
89		// this.responsiveVideos();
90		this.mobileMenu();
91		this.responsiveProductGallery();
92		this.responsiveProductV3();
93
94		this.portfolioMasonry();
95		this.portfolioFilter();
96
97		this.backToTop();
98		this.lazyLoadImages();
99		this.supportJetpackLazyLoadImagesOnProductGallery();
100
101		this.updateCheckout();
102		this.mainMenuTabs();
103
104		$( document.body ).trigger( 'konte_initialized', this );
105	};
106
107	/**
108	 * Update checkout after fragments updated
109	 */
110	konte.updateCheckout = function() {
111		if ( ! $( document.body ).hasClass( 'woocommerce-checkout' ) ) {
112			return;
113		}
114
115		$( document.body ).on( 'wc_fragments_loaded wc_fragments_refreshed', function() {
116			$( document.body ).trigger( 'update_checkout' );
117		});
118	}
119
120	/**
121	 * Open quick links when focus on search field
122	 */
123	konte.focusSearchField = function() {
124		$( '.header-search .search-field' ).on( 'focus', function() {
125			var $quicklinks = $( this ).closest( '.header-search' ).find( '.quick-links' );
126
127			if ( $quicklinks.length ) {
128				$quicklinks.addClass( 'open' );
129			}
130
131			$( this ).addClass( 'focused' ).closest( '.header-search' ).addClass( 'input-focused' );
132		} );
133
134		$( document.body ).on( 'click', 'div', function( event ) {
135			var $target = $( event.target );
136
137			if ( $target.is( '.header-search' ) || $target.closest( '.header-search' ).length ) {
138				return;
139			}
140
141			var $headerSearch = $( '.header-search' );
142
143			$headerSearch.removeClass( 'input-focused' );
144			$( '.quick-links', $headerSearch ).removeClass( 'open' );
145			$( '.search-field', $headerSearch ).removeClass( 'focused' );
146		} );
147	};
148
149	/**
150	 * Instance search in the search modal.
151	 */
152	konte.instantSearch = function() {
153		var xhr = null,
154			term = '',
155			searchCache = {},
156			debounceTimeout = null,
157			$modal = $( '#search-modal' ),
158			$header = $modal.find( '.modal-header' ),
159			$content = $modal.find( '.modal-content' ),
160			$form = $modal.find( 'form' ),
161			$search = $form.find( 'input.search-field' ),
162			$result = $modal.find( '.search-result' ),
163			$button = $result.find( '.view-more a' ),
164			$quicklinks = $modal.find( '.quick-links' ),
165			post_type = $modal.find( 'input[name=post_type]' ).val();
166
167		if ( !$modal.length ) {
168			return;
169		}
170
171		// Focus on the search field when search modal opened
172		$( document.body ).on( 'konte_modal_opened', function( event, target ) {
173			if ( target.is( '#search-modal' ) ) {
174				$search.focus();
175			}
176		} );
177
178		new PerfectScrollbar( $result.find( '.searched-items' ).get( 0 ), {
179			suppressScrollX: true
180		} );
181
182		$modal.on( 'keyup', '.search-field', function( e ) {
183			var valid = false;
184
185			if ( typeof e.which === 'undefined' ) {
186				valid = true;
187			} else if ( typeof e.which === 'number' && e.which > 0 ) {
188				valid = !e.ctrlKey && !e.metaKey && !e.altKey;
189			}
190
191			if ( !valid ) {
192				return;
193			}
194
195			// if ( xhr ) {
196			// 	xhr.abort();
197			// }
198
199			$quicklinks.fadeOut( 400 );
200
201			if ( debounceTimeout ) {
202				clearTimeout( debounceTimeout );
203			}
204
205			debounceTimeout = setTimeout( function() {
206				search();
207			}, 800 );
208		} ).on( 'click', '.search-reset', function() {
209			if ( xhr ) {
210				xhr.abort();
211			}
212
213			$quicklinks.fadeIn( 400 );
214			$modal.addClass( 'reset' );
215			$result.fadeOut( function() {
216				$modal.removeClass( 'searching searched search-found search-not-found invalid-length reset' );
217				$content.removeAttr( 'style' );
218			} );
219		} ).on( 'focusout', '.search-field', function() {
220			if ( $search.val().length < 2 ) {
221				$quicklinks.fadeIn( 400 );
222				$result.fadeOut( function() {
223					$modal.removeClass( 'searching searched search-found search-not-found invalid-length' );
224					$content.removeAttr( 'style' );
225				} );
226			}
227		} );
228
229		/**
230		 * Private function for searching products
231		 */
232		function search() {
233			var keyword = $search.val(),
234				key = keyword;
235
236			if ( term === keyword ) {
237				return;
238			}
239
240			term = keyword;
241
242			if ( keyword.length < 2 ) {
243				$modal.removeClass( 'searched searching search-found search-not-found' );
244				return;
245			}
246
247			var url = $form.attr( 'action' ) + '?' + $form.serialize();
248
249			$( '.view-more-results', $result ).slideUp( 10 );
250			$modal.removeClass( 'search-found search-not-found searched' ).addClass( 'searching' );
251
252			if ( key in searchCache ) {
253				showResult( searchCache[key] );
254			} else {
255				xhr = $.post( url,
256					{
257						search_columns: 6,
258						konte_search_nonce: konte.data.product_search_nonce
259					},
260					function( response ) {
261						if ( ! response ) {
262							$modal.removeClass( 'searching' );
263							return;
264						}
265
266						var $primary = $( '#primary', response );
267
268						if ( 'product' === post_type ) {
269							var $products = $( 'ul.products', $primary );
270
271							if ( $products.length ) {
272								// Cache
273								searchCache[key] = {
274									found: true,
275									items: $products,
276									url  : url
277								};
278							} else {
279								// Cache
280								searchCache[key] = {
281									found: false,
282									text : $( '.woocommerce-info', $primary ).text()
283								};
284							}
285						} else {
286							var $posts = $( '#main article', $primary );
287
288							if ( $posts.length ) {
289								$posts.addClass( 'col-md-4' );
290
291								searchCache[key] = {
292									found: true,
293									items: $( '<div class="posts row" />' ).append( $posts ),
294									url  : url
295								};
296							} else {
297								searchCache[key] = {
298									found: false,
299									text : $( '.no-results .nothing-found-message', $primary ).text()
300								};
301							}
302						}
303
304						showResult( searchCache[key] );
305				}, 'html' );
306			}
307		}
308
309		/**
310		 * Private function for showing the search result
311		 *
312		 * @param result
313		 */
314		function showResult( result ) {
315			var extraClass = 'product' === post_type ? 'woocommerce' : '',
316				$container = $result.find( '.searched-items' );
317
318			$modal.removeClass( 'searching' );
319			$content.css( 'top', $header.outerHeight() + 65 );
320
321			if ( result.found ) {
322				var grid = result.items.clone(),
323					items = grid.children();
324
325				$modal.addClass( 'search-found' );
326				$button.attr( 'href', result.url );
327
328				$container
329					.addClass( extraClass )
330					.html( grid )
331					.append( $result.find( '.view-more' ).clone() );
332
333				// Init zoom/slider thumbnail
334				if ( 'product' === post_type ) {
335					$( document.body ).trigger( 'konte_loaded_products', [items] );
336				}
337
338				// Add animation class
339				for ( var index = 0; index < items.length; index++ ) {
340					$( items[index] ).css( 'animation-delay', index * 100 + 'ms' );
341				}
342
343				items.addClass( 'animated konteFadeInUp' );
344				$container.find( '.view-more' ).css( 'animation-delay', ++index * 100 + 'ms' ).addClass( 'animated konteFadeInUp' );
345				$result.slideDown();
346			} else {
347				$modal.addClass( 'search-not-found' );
348
349				$container.removeClass( extraClass ).html( $( '<div class="not-found" />' ).text( result.text ) );
350				$button.attr( 'href', '#' );
351
352				$result.slideDown();
353			}
354
355			$modal.addClass( 'searched' );
356			$( document.body ).trigger( 'konte_lazy_load_images' );
357		}
358	};
359
360	/**
361	 * Ajax search for header search from.
362	 */
363	konte.ajaxSearch = function() {
364		if ( ! konte.data.header_search_ajax ) {
365			return;
366		}
367
368		var debounceTimeout = null,
369			cachedResults   = {};
370
371		// Create the results container.
372		$( '<div class="header-search__results" />' ).insertAfter( '.header-search form' );
373
374		$( '.header-search input[name="s"]' ).on( 'input', function() {
375			var $input   = $( this ),
376				$search  = $input.closest( '.header-search' ),
377				$results = $search.find( '.header-search__results' ),
378				term     = $input.val();
379
380			if ( ! term ) {
381				if ( debounceTimeout ) {
382					clearTimeout( debounceTimeout );
383				}
384
385				$search.removeClass( 'ajax-loading' );
386				$results.html( '' );
387				$search.removeClass( 'show-results' );
388				return;
389			}
390
391			if ( cachedResults[ term ] ) {
392				$results.html( cachedResults[ term ] );
393				$search.addClass( 'show-results' );
394				return;
395			}
396
397			if ( debounceTimeout ) {
398				clearTimeout( debounceTimeout );
399			}
400
401			debounceTimeout = setTimeout( function() {
402				var data = $input.closest( 'form' ).serializeArray();
403
404				data.push( {name: 'action', value: 'konte_header_search'} );
405
406				$.ajax( {
407					type      : 'POST',
408					url       : konte.data.ajax_url,
409					data      : data,
410					beforeSend: function() {
411						$search.addClass( 'ajax-loading' );
412					},
413					success: function( response ) {
414						if ( ! response.success ) {
415							return;
416						}
417
418						cachedResults[ term ] = response.data;
419
420						if ( response.data ) {
421							$results.html( response.data );
422							$search.addClass( 'show-results' );
423						} else {
424							$results.html( '' );
425							$search.removeClass( 'show-results' );
426						}
427					},
428					complete: function() {
429						$search.removeClass( 'ajax-loading' );
430					},
431					dataType: 'json'
432				} );
433			}, 800 );
434		} );
435	}
436
437	/**
438	 * Toggle list dropdown
439	 */
440	konte.toggleListDropdown = function() {
441
442		$( document.body ).on( 'click', '.list-dropdown ul li', function() {
443			var $selected = $( this );
444
445			$selected.closest( '.list-dropdown' ).removeClass( 'open' ).find( '.current .selected' ).text( $selected.find( '.name' ).text() );
446		} );
447
448		if ( 'ontouchstart' in document.documentElement ) {
449			$( document.body ).on( 'click', '.list-dropdown .current', function( event ) {
450				event.preventDefault();
451
452				$( this ).closest( '.list-dropdown' ).toggleClass( 'open' );
453			} ).on( 'click', '.list-dropdown ul li', function() {
454				var $selected = $( this );
455
456				$selected.closest( '.list-dropdown' ).removeClass( 'open' ).find( '.current .selected' ).text( $selected.find( '.name' ).text() );
457			} ).on( 'click', function( event ) {
458				var $target = $( event.target );
459
460				if ( $target.is( '.list-dropdown' ) || $target.closest( '.list-dropdown' ).length ) {
461					return;
462				}
463
464				$( '.list-dropdown' ).removeClass( 'open' );
465			} );
466		}
467	};
468
469	/**
470	 * Add wishlist counter to the Account navigation
471	 */
472	konte.addWishlistCounter = function() {
473		$( '.woocommerce-MyAccount-navigation-link--wishlist, .account-link--wishlist' )
474			.append( '<span class="counter wishlist-counter">' + konte.data.wishlist_count + '</span>' );
475	};
476
477	/**
478	 * Calculate accessible area of main navigation's submenu
479	 */
480	konte.calculateMenuAccessibleArea = function() {
481		$( '.main-navigation', '#masthead' ).each( function() {
482			var $menu = $( this ),
483				$firstItem = $menu.children( 'ul' ).children( 'li:first' ),
484				accessibleGap = ( $firstItem.height() - $firstItem.children( 'a ' ).height() ) / 2;
485
486			$menu.css( { '--submenu-offset': accessibleGap.toString() + 'px' } );
487		} );
488	};
489
490	/**
491	 * Toggle hamburger full-screen
492	 */
493	konte.toggleHamburgerScreen = function() {
494		$( document.body ).on( 'click', '.header-hamburger', function( event ) {
495			event.preventDefault();
496
497			var $el = $( this ),
498				$screen = $( '#' + $el.data( 'target' ) );
499
500			if ( !$screen.length ) {
501				return;
502			}
503
504			var $menu = $( '#fullscreen-menu', $screen ),
505				$widgets = $( '.filter-widgets', $screen ),
506				$socials = $( '.social-icons', $screen ),
507				$currency = $( '.currency', $screen ),
508				$language = $( '.language', $screen ),
509				step = 100,
510				count = 0;
511
512			// Add animation if enabled.
513			if ( !$screen.hasClass( 'content-animation-none' ) ) {
514				if ( $screen.hasClass( 'content-animation-fade' ) ) {
515					step = 160;
516				}
517
518				if ( $menu.length && !$menu.data( 'delay' ) ) {
519					$( '.menu > li', $menu ).each( function() {
520						$( this ).css( 'animation-delay', count * step + 'ms' );
521						count++;
522					} );
523
524					$menu.data( 'delay', count );
525				} else if ( $widgets.length && !$widgets.data( 'delay' ) ) {
526					$( '.widget', $widgets ).each( function() {
527						$( this ).css( 'animation-delay', count * step + 'ms' );
528						count++;
529					} );
530
531					$widgets.data( 'delay', count );
532				}
533
534				count = 1;
535				if ( $socials.length && !$socials.data( 'delay' ) ) {
536					$( '.menu > li', $socials ).each( function() {
537						$( this ).css( 'animation-delay', count * step + 'ms' );
538						count++;
539					} );
540
541					$socials.data( 'delay', count );
542				}
543
544				if ( $currency.length && !$currency.data( 'delay' ) ) {
545					$currency.css( 'animation-delay', count * step + 'ms' );
546					$currency.data( 'delay', count );
547					count++;
548				}
549
550				if ( $language.length && !$language.data( 'delay' ) ) {
551					$language.css( 'animation-delay', count * step + 'ms' );
552					$language.data( 'delay', count );
553					count++;
554				}
555			}
556
557			$screen.fadeToggle( function() {
558				$( '.hamburger-menu', $screen ).addClass( 'active' );
559			} );
560			$screen.addClass( 'open' );
561		} ).on( 'click', '#hamburger-fullscreen .button-close', function( event ) {
562			event.stopPropagation();
563
564			var $el = $( this ),
565				$screen = $( '#hamburger-fullscreen' );
566
567			$el.removeClass( 'active' );
568			$screen.removeClass( 'open' );
569
570			setTimeout( function() {
571				$screen.fadeOut();
572			}, 420 );
573		} );
574
575		// Init scrollbar for full screen menu.
576		if ( typeof PerfectScrollbar !== 'undefined' ) {
577			var $hamburgerScreen = $( '#hamburger-fullscreen' );
578
579			if ( $hamburgerScreen.length ) {
580				new PerfectScrollbar( $( '.hamburger-screen-content', $hamburgerScreen ).get( 0 ) );
581			}
582		}
583	};
584
585	/**
586	 * Toggle sub-menu inside hamburger screen
587	 */
588	konte.toggleHamburgerMenu = function() {
589		var $menu = $( '#fullscreen-menu' );
590
591		if ( !$menu.length ) {
592			return;
593		}
594
595		// Open when click
596		if ( $menu.hasClass( 'click-open' ) ) {
597			$menu.on( 'click', '.menu li.menu-item-has-children > a', function( event ) {
598				event.preventDefault();
599
600				var $item = $( this ).parent();
601
602				$item.toggleClass( 'active' ).siblings().removeClass( 'active' ).children( 'ul' ).removeClass( 'open' );
603				$item.children( 'ul' ).toggleClass( 'open' );
604
605				// If this is sub-menu item
606				if ( $item.closest( 'ul' ).hasClass( 'sub-menu' ) ) {
607					$item.children( 'ul' ).slideToggle();
608					$item.siblings().find( 'ul' ).slideUp();
609				}
610			} );
611		}
612	};
613
614	/**
615	 * Toggle sub-menu of vertical header
616	 */
617	konte.toggleVerticalMenu = function() {
618		var $menu = $( '.header-vertical .main-navigation' );
619
620		if ( ! $menu.length ) {
621			return;
622		}
623
624		var dropdown = $menu.children( '.menu' ).hasClass( 'nav-menu--submenu-slidedown' );
625
626		// Open when click
627		$menu.on( 'click', 'li.menu-item-has-children > a', function( event ) {
628			var $item = $( this ).parent();
629
630			$item.toggleClass( 'active' ).siblings().removeClass( 'active' ).children( 'ul' ).removeClass( 'open' );
631			$item.children( 'ul' ).toggleClass( 'open' );
632
633			// If this is sub-menu item
634			if ( dropdown || $item.closest( 'ul' ).hasClass( 'sub-menu' ) ) {
635				$item.children( 'ul' ).slideToggle();
636				$item.siblings().find( 'ul' ).slideUp();
637
638				event.preventDefault();
639			}
640		} );
641	};
642
643	/**
644	 * Toggle off-screen panels
645	 */
646	konte.toggleOffCanvas = function() {
647		$( document.body ).on( 'click', '[data-toggle="off-canvas"]', function( event ) {
648			var target = '#' + $( this ).data( 'target' );
649
650			if ( $( target ).hasClass( 'open' ) ) {
651				konte.closeOffCanvas( target );
652			} else if ( konte.openOffCanvas( target ) ) {
653				event.preventDefault();
654			}
655		} ).on( 'click', '.offscreen-panel .button-close, .offscreen-panel .backdrop', function( event ) {
656			event.preventDefault();
657
658			konte.closeOffCanvas( this );
659		} ).on( 'keyup', function ( e ) {
660			if ( e.keyCode === 27 ) {
661				konte.closeOffCanvas();
662			}
663		} );
664	};
665
666	/**
667	 * Open off canvas panel.
668	 * @param string target Target selector.
669	 */
670	konte.openOffCanvas = function( target ) {
671		var $target = $( target );
672
673		if ( !$target.length ) {
674			return false;
675		}
676
677		$target.fadeIn();
678		$target.addClass( 'open' );
679
680		$( document.body ).addClass( 'offcanvas-opened ' + $target.attr( 'id' ) + '-opened' ).trigger( 'konte_off_canvas_opened', [$target] );
681
682		return true;
683	}
684
685	/**
686	 * Close off canvas panel.
687	 * @param DOM target
688	 */
689	konte.closeOffCanvas = function( target ) {
690		if ( !target ) {
691			$( '.offscreen-panel' ).each( function() {
692				var $panel = $( this );
693
694				if ( ! $panel.hasClass( 'open' ) ) {
695					return;
696				}
697
698				$panel.removeClass( 'open' ).fadeOut();
699				$( document.body ).removeClass( $panel.attr( 'id' ) + '-opened' );
700			} );
701		} else {
702			target = $( target ).closest( '.offscreen-panel' );
703			target.removeClass( 'open' ).fadeOut();
704
705			$( document.body ).removeClass( target.attr( 'id' ) + '-opened' );
706		}
707
708		$( document.body ).removeClass( 'offcanvas-opened' ).trigger( 'konte_off_canvas_closed', [target] );
709	}
710
711	/**
712	 * Toggle modals.
713	 */
714	konte.toggleModals = function() {
715		$( document.body ).on( 'click', '[data-toggle="modal"]', function( event ) {
716			var target = '#' + $( this ).data( 'target' );
717
718			if ( $( target ).hasClass( 'open' ) ) {
719				konte.closeModal( target );
720			} else if ( konte.openModal( target ) ) {
721				event.preventDefault();
722			}
723		} ).on( 'click', '.modal .button-close, .modal .backdrop', function( event ) {
724			event.preventDefault();
725
726			konte.closeModal( this );
727		} ).on( 'keyup', function ( e ) {
728			if ( e.keyCode === 27 ) {
729				konte.closeModal();
730			}
731		} );
732	};
733
734	/**
735	 * Open a modal.
736	 *
737	 * @param string target
738	 */
739	konte.openModal = function( target ) {
740		var $target = $( target );
741
742		if ( !$target.length ) {
743			return false;
744		}
745
746		$target.fadeIn();
747		$target.addClass( 'open' );
748
749		$( document.body ).addClass( 'modal-opened ' + $target.attr( 'id' ) + '-opened' ).trigger( 'konte_modal_opened', [$target] );
750
751		return true;
752	}
753
754	/**
755	 * Close a modal.
756	 *
757	 * @param string target
758	 */
759	konte.closeModal = function( target ) {
760		if ( !target ) {
761			$( '.modal' ).removeClass( 'open' ).fadeOut();
762
763			$( '.modal' ).each( function() {
764				var $modal = $( this );
765
766				if ( ! $modal.hasClass( 'open' ) ) {
767					return;
768				}
769
770				$modal.removeClass( 'open' ).fadeOut();
771				$( document.body ).removeClass( $modal.attr( 'id' ) + '-opened' );
772			} );
773		} else {
774			target = $( target ).closest( '.modal' );
775			target.removeClass( 'open' ).fadeOut();
776
777			$( document.body ).removeClass( target.attr( 'id' ) + '-opened' );
778		}
779
780		$( document.body ).removeClass( 'modal-opened' ).trigger( 'konte_modal_closed', [target] );
781	}
782
783	/**
784	 * Initialize the featured content carousel
785	 */
786	konte.featuredContentCarousel = function() {
787		var $featured = $( '#featured-content-carousel' ),
788			options = {
789				rtl      : !! konte.data.rtl,
790				prevArrow: '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>',
791				nextArrow: '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>'
792			};
793
794		if ( !$featured.length ) {
795			return;
796		}
797
798		if ( $featured.hasClass( 'carousel' ) ) {
799			options.infinite = false;
800			options.slidesToShow = 3;
801			options.slidesToScroll = 3;
802			options.responsive = [
803				{
804					breakpoint: 991,
805					settings  : {
806						slidesToShow  : 2,
807						slidesToScroll: 2
808					}
809				},
810				{
811					breakpoint: 767,
812					settings  : {
813						slidesToShow  : 1,
814						slidesToScroll: 1
815					}
816				}
817			];
818
819			// Lazy load
820			$featured.on( 'init reInit breakpoint', function( event, slick ) {
821				slick.$slides.each( function() {
822					loadBackgroundImage( this );
823				} );
824			} );
825		} else {
826			if ( 'fade' === $featured.data( 'effect' ) ) {
827				options.fade = true;
828			}
829
830			// Lazy load
831			$featured.on( 'beforeChange', function( event, slick, currentSlide, nextSlide ) {
832				loadBackgroundImage( slick.$slides.get( nextSlide ) );
833			} );
834
835			$featured.on( 'init reInit breakpoint', function( event, slick ) {
836				loadBackgroundImage( slick.$slides.get( slick.currentSlide ) );
837			} );
838		}
839
840		$featured.slick( options );
841
842		/**
843		 * Load background image
844		 */
845		function loadBackgroundImage( el ) {
846			var $el = $( el ).find( '.featured-item' );
847
848			if ( $el.data( 'lazy' ) ) {
849				$el.css( 'background-image', 'url(' + $el.data( 'lazy' ) + ')' );
850			}
851
852			$el.data( 'lazy_loaded', true ).removeClass( 'loading' );
853		}
854	};
855
856	/**
857	 * Ajax load more posts.
858	 */
859	konte.loadMorePosts = function() {
860		if ( $( document.body ).hasClass( 'page-template-flex-posts' ) ) {
861			return;
862		}
863
864		$( document.body ).on( 'click', '.navigation.next-posts-navigation a', function( event ) {
865			event.preventDefault();
866
867			var $el = $( this ),
868				$navigation = $el.closest( '.navigation' ),
869				url = $el.attr( 'href' );
870
871			if ( $el.hasClass( 'loading' ) ) {
872				return;
873			}
874
875			$el.addClass( 'loading' );
876
877			$.get( url, function( response ) {
878				var $content = $( '#main', response ),
879					$posts = $( '.hentry', $content ),
880					$nav = $( '.next-posts-navigation', $content );
881
882				$posts.each( function( index, post ) {
883					$( post ).css( 'animation-delay', index * 100 + 'ms' );
884				} );
885
886				// Check if posts are wrapped or not.
887				if ( $navigation.prev( '.posts-wrapper' ).length ) {
888					$posts.appendTo( $navigation.prev( '.posts-wrapper' ) );
889				} else {
890					$posts.insertBefore( $navigation );
891				}
892
893				$posts.addClass( 'animated konteFadeInUp' );
894
895				if ( $nav.length ) {
896					$el.replaceWith( $( 'a', $nav ) );
897				} else {
898					$el.removeClass( 'loading' );
899					$navigation.fadeOut();
900				}
901
902				if ( $navigation.hasClass( 'next-projects-navigation' ) ) {
903					if ( konte.data.portfolio_nav_ajax_url_change ) {
904						window.history.pushState( null, '', url );
905					}
906				} else if ( konte.data.blog_nav_ajax_url_change ) {
907					window.history.pushState( null, '', url );
908				}
909
910				$( document.body ).trigger( 'konte_posts_loaded', [$posts, true] );
911			} );
912		} );
913	};
914
915	/**
916	 * Fetch total share from ShareThis API.
917	 */
918	konte.fetchPostTotalShare = function() {
919		$( '.total-shares.fetching:visible' ).each( function() {
920			var $share = $( this ),
921				post_id = $share.data( 'post_id' );
922
923			if ( !post_id ) {
924				return;
925			}
926
927			$.post( konte.data.ajax_url, {
928				action : 'konte_get_total_shares',
929				post_id: post_id,
930				security: konte.data.share_nonce
931			}, function( response ) {
932				$share.removeClass( 'fetching' );
933
934				if ( response.success ) {
935					$( '.count', $share ).html( response.data );
936				}
937			} );
938		} );
939	};
940
941	/**
942	 * Initialize posts slider widget
943	 */
944	konte.postsSliderWidget = function() {
945		$( '.posts-slider-widget .posts-slider' ).slick( {
946			rtl           : !! konte.data.rtl,
947			adaptiveHeight: true,
948			autoplay      : true,
949			autoplaySpeed : 3000,
950			prevArrow     : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>',
951			nextArrow     : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>'
952		} );
953	};
954
955	/**
956	 * Make the sidebar sticky
957	 */
958	konte.stickySidebar = function() {
959		if ( $.fn.stick_in_parent && $( window ).width() > 767 ) {
960			$( '#secondary.sticky-sidebar' ).stick_in_parent();
961		}
962
963		// Recalculate after cart widget loaded via ajax.
964		$( document.body ).on( 'wc_fragments_refreshed post-load konte_products_loaded', function() {
965			$( document.body ).trigger( 'sticky_kit:recalc' );
966		} );
967	};
968
969	/**
970	 * Close the topbar
971	 */
972	konte.closeTopbar = function() {
973		$( document.body ).on( 'click', '.close-topbar', function( event ) {
974			event.preventDefault();
975
976			$( '#topbar' ).slideUp();
977		} );
978	};
979
980	/**
981	 * Sticky header
982	 */
983	konte.stickyHeader = function () {
984		if ( !konte.data.sticky_header || 'none' === konte.data.sticky_header ) {
985			return;
986		}
987
988		var $window = $( window ),
989			$header = $( '#masthead' ),
990			$sticker = $header,
991			$topbar = $( '#topbar' ),
992			offset = 0;
993
994		if ( $header.hasClass( 'header-v10' ) ) {
995			$sticker = $header.find( '.header-main .header-right-items' );
996		}
997
998		if ( ! $sticker.length ) {
999			return;
1000		}
1001
1002		if ( $topbar.length ) {
1003			offset += $topbar.outerHeight();
1004		}
1005
1006		if ( 'smart' === konte.data.sticky_header ) {
1007			offset += $topbar.length ? 0 : $sticker.outerHeight();
1008
1009			var stickyHeader = new Headroom( $sticker.get(0), {
1010				offset: offset
1011			});
1012
1013			stickyHeader.init();
1014		} else {
1015			sticky( offset );
1016
1017			$window.on( 'scroll', function() {
1018				sticky( offset );
1019			} );
1020		}
1021
1022		/**
1023		 * Private function for sticky header
1024		 */
1025		function sticky( topSpacing ) {
1026			if ( $sticker.hasClass( 'sticky--ignore' ) ) {
1027				return;
1028			}
1029
1030			topSpacing = topSpacing ? topSpacing : 0;
1031
1032			if ( $window.scrollTop() > topSpacing ) {
1033				$sticker.addClass( 'sticky' );
1034			} else {
1035				$sticker.removeClass( 'sticky' );
1036			}
1037		}
1038	};
1039
1040	/**
1041	 * Correct the page header's height.
1042	 */
1043	konte.pageHeaderHeight = function() {
1044		var $pageHeader = $( '.page .page-header.full-height' );
1045
1046		if ( !$pageHeader.length ) {
1047			return;
1048		}
1049
1050		var $topbar = $( '#topbar' ),
1051			$header = $( '#masthead' ),
1052			height = $( window ).height();
1053
1054		if ( $topbar.length ) {
1055			height -= $topbar.outerHeight();
1056		}
1057
1058		if ( !$header.hasClass( 'transparent' ) ) {
1059			height -= $header.outerHeight();
1060
1061			$pageHeader.css( 'marginTop', '-' + $( '#content' ).css( 'paddingTop' ) );
1062		}
1063
1064		if ( $pageHeader.hasClass( 'title-front' ) ) {
1065			$pageHeader.height( height );
1066		} else {
1067			$pageHeader.find( '.entry-thumbnail' ).height( height );
1068		}
1069	};
1070
1071	/**
1072	 * Scroll down when clicing on the anchor
1073	 */
1074	konte.scrollDown = function() {
1075		$( document.body ).on( 'click', '.scroll', function( event ) {
1076			event.preventDefault();
1077
1078			var offset = $( this ).parent().next().offset().top;
1079
1080			$( 'html, body' ).animate( {scrollTop: offset} );
1081		} );
1082	};
1083
1084	/**
1085	 * Make WC message closeable.
1086	 */
1087	konte.closeWCMessages = function() {
1088		$( document.body ).on( 'click', '.woocommerce-message .close-message, .woocommerce-error .close-message, .woocommerce-info .close-message', function( event ) {
1089			event.preventDefault();
1090
1091			$( this ).closest( 'div' ).fadeOut();
1092		} );
1093
1094		$( document.body ).on( 'click', '.wc-block-components-notice-banner__close', function( event ) {
1095			event.preventDefault();
1096
1097			$( this ).closest( '.wc-block-components-notice-banner' ).fadeOut();
1098		} );
1099	};
1100
1101	/**
1102	 * Increase/decrease product quantity
1103	 */
1104	konte.productQuantityButtons = function() {
1105		$( document.body ).on( 'click', '.quantity .increase, .quantity .decrease', function( event ) {
1106			event.preventDefault();
1107
1108			var $this = $( this ),
1109				$qty = $this.siblings( '.qty' ),
1110				current = parseFloat( $qty.val() ),
1111				min = parseFloat( $qty.attr( 'min' ) ),
1112				max = parseFloat( $qty.attr( 'max' ) ),
1113				step = parseFloat( $qty.attr( 'step' ) );
1114
1115			current = current ? current : 0;
1116			min = min ? min : 0;
1117			max = max ? max : current + 1;
1118			step = step ? step : 1;
1119
1120			if ( $this.hasClass( 'decrease' ) && current > min ) {
1121				$qty.val( current - step );
1122				$qty.trigger( 'change' );
1123			}
1124			if ( $this.hasClass( 'increase' ) && current < max ) {
1125				$qty.val( current + step );
1126				$qty.trigger( 'change' );
1127			}
1128		} );
1129	};
1130
1131	/**
1132	 * Using Ajax for add to cart button on single product page.
1133	 */
1134	konte.singleProductAjaxAddToCart = function() {
1135		if ( '1' !== konte.data.product_ajax_addtocart ) {
1136			return;
1137		}
1138
1139		$( document.body ).on( 'submit', 'form.cart', function( event ) {
1140			var $form = $( this );
1141
1142			if ( $form.closest( 'div.product' ).hasClass( 'product-type-external' ) || $form.data( 'with_ajax' ) ) {
1143				return;
1144			}
1145
1146			event.preventDefault();
1147
1148			var	$button = $form.find( '.single_add_to_cart_button' ),
1149				formData = new FormData( this );
1150
1151			// Prevent double-add by remove the param 'add-to-cart'.
1152			if ( formData.has( 'add-to-cart' ) ) {
1153				formData.delete( 'add-to-cart' );
1154			}
1155
1156			// Then we will rename it in the ajax handler function.
1157			formData.append( 'konte-add-to-cart', $form.find( '[name="add-to-cart"]' ).val() );
1158
1159			// Ajax.
1160			$.ajax( {
1161				url: woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'konte_ajax_add_to_cart' ),
1162				data: formData,
1163				method: 'POST',
1164				contentType: false,
1165				processData: false,
1166				beforeSend: function() {
1167					$button.removeClass( 'added' ).addClass( 'loading disabled' ).prop( 'disabled', true );
1168				},
1169				complete: function( response ) {
1170					$button.removeClass( 'loading disabled' ).addClass( 'added' ).prop( 'disabled', false );
1171
1172					response = response.responseJSON;
1173
1174					if ( ! response ) {
1175						return;
1176					}
1177
1178					// Reload on error.
1179					if ( response.error && response.product_url ) {
1180						window.location = response.product_url;
1181						return;
1182					}
1183
1184					// If success, trigger events.
1185					var $notices = $( response.fragments.notices_html ),
1186						isAdded = $notices.hasClass( 'woocommerce-message' ) || $notices.hasClass( 'is-success' );
1187
1188					if ( isAdded ) {
1189						// Trigger the default event to refresh fragments.
1190						$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $button ] );
1191
1192						// Trigger the fragment refresh event manually if necessary.
1193						if ( 'undefined' === typeof wc_add_to_cart_params ) {
1194							$( document.body ).trigger( 'wc_fragment_refresh' );
1195						}
1196					}
1197
1198					// Display new notices (alert bar).
1199					if ( konte.data.cart_open_after_added !== '1' || ! isAdded ) {
1200						konte.displayAlertBar( response.fragments.notices_html );
1201					}
1202
1203					// Redirect to cart option.
1204					if ( 'undefined' !== typeof wc_add_to_cart_params && wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
1205						window.location = wc_add_to_cart_params.cart_url;
1206						return;
1207					}
1208				},
1209				error: function() {
1210					// Try to submit the form without ajax on errors.
1211					$form.data( 'with_ajax', false ).trigger( 'submit' );
1212				}
1213			} );
1214		} );
1215	};
1216
1217	/**
1218	 * Display alert bar at bottom
1219	 *
1220	 * @param {String} message
1221	 * @param {Number} duration Set to 0 to permanently display the alert
1222	 */
1223	konte.displayAlertBar = function( message, duration ) {
1224		if ( ! message ) {
1225			return;
1226		}
1227
1228		if ( typeof duration !== "number" ) {
1229			duration = 5000;
1230		}
1231
1232		if ( ! konte.alertTimeout ) {
1233			konte.alertTimeout = null;
1234		}
1235
1236		// Prepare the alert bar.
1237		var $alert = $( '#konte-woocommerce-alert' );
1238
1239		if ( ! $alert.length ) {
1240			$alert = $( '<div id="konte-woocommerce-alert" class="konte-woocommerce-alert"></div>' );
1241			$( document.body ).append( $alert );
1242		}
1243
1244		// Show.
1245		$alert.html( message );
1246
1247		setTimeout( function() {
1248			$alert.addClass( 'active' );
1249		}, 100 );
1250
1251		// Close alert bar on button click.
1252		$alert.one( 'click', '.close-message, .wc-block-components-notice-banner__close', function( e ) {
1253			e.preventDefault();
1254
1255			$alert.removeClass( 'active' );
1256		} );
1257
1258		// Auto close.
1259		if ( duration ) {
1260			// Auto hide the alert bar after 5 seconds.
1261			clearTimeout( konte.alertTimeout );
1262
1263			konte.alertTimeout = setTimeout( function() {
1264				$alert.removeClass( 'active' );
1265			}, duration );
1266		}
1267	}
1268
1269	/**
1270	 * Init sticky cart form.
1271	 *
1272	 * @todo Support bundled products.
1273	 */
1274	konte.stickyAddToCart = function() {
1275		var $sticky = $( '.sticky-cart-form' );
1276
1277		if ( ! $sticky.length ) {
1278			return;
1279		}
1280
1281		// Remove wishlist and share buttons.
1282		$sticky.find( '.add-to-wishlist-button, .wcboost-wishlist-button, .wcboost-products-compare-button, .product-share' ).remove();
1283
1284		var $forms = $( 'form.cart', $sticky.closest( 'div.product' ) ),
1285			$originalForm = $forms.first(),
1286			$image = $sticky.find( '.sticky-cart-form__product-image img' ),
1287			$price = $sticky.find( '.sticky-cart-form__product-summary .price' ),
1288			$stickyHeader = $( '#masthead' ),
1289			stickyPosition = $sticky.data( 'position' ),
1290			offset = 0,
1291			doingSync = false;
1292
1293		if ( $stickyHeader.hasClass( 'header-v10' ) ) {
1294			$stickyHeader = $stickyHeader.find( '.header-main .header-right-items' );
1295		}
1296
1297		if ( konte.data.sticky_header && 'none' !== konte.data.sticky_header ) {
1298			offset = $stickyHeader.height();
1299		}
1300
1301		// Handle add-to-cart variations of 2 forms.
1302		$forms
1303			.on( 'reset_data', function() {
1304				$image.attr( 'src', $image.data( 'o_src' ) );
1305				$price.show().siblings( '.variation-price, .stock' ).remove();
1306			} )
1307			.on( 'found_variation', function( event, variation ) {
1308				if ( variation.image && variation.image.gallery_thumbnail_src && variation.image.gallery_thumbnail_src.length > 1 ) {
1309					$image.attr( 'src', variation.image.gallery_thumbnail_src );
1310				}
1311
1312				if ( variation.availability_html && variation.availability_html.length ) {
1313					$price.hide().siblings( '.stock, .variation-price' ).remove();
1314					$price.after( variation.availability_html );
1315				} else {
1316					$price.siblings( '.stock' ).remove();
1317
1318					if ( variation.price_html && variation.price_html.length ) {
1319						$price.hide().siblings( '.variation-price' ).remove();
1320						$price.after( $( variation.price_html ).addClass( 'variation-price' ) );
1321					}
1322				}
1323			} )
1324			// Sync inputs' value.
1325			.on( 'change', ':input', function() {
1326				// Avoid infinite loop.
1327				if ( doingSync ) {
1328					return;
1329				}
1330
1331				doingSync = true;
1332
1333				var $currentForm = $( this ).closest( 'form.cart' ),
1334					$targetForm = $forms.not( $currentForm );
1335
1336				$targetForm.find( ':input[name="' + this.name + '"]' ).val( this.value ).trigger( 'change' );
1337
1338				doingSync = false;
1339			} );
1340
1341		// Scroll to the grouped products form.
1342		$sticky.on( 'click', '.grouped_form .single_add_to_cart_button, .bundle_form .single_add_to_cart_button', function() {
1343			$( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 );
1344
1345			return false;
1346		} ).on( 'click', '.sticky-cart-form__mobile-button', function( event ) {
1347			event.preventDefault();
1348
1349			if ( this.dataset.product_type === 'simple' || this.dataset.product_type === 'grouped' || this.dataset.product_type === 'external' ) {
1350				$sticky.find( '.single_add_to_cart_button' ).trigger( 'click' );
1351			} else {
1352				$( 'html, body' ).animate( { scrollTop: $originalForm.offset().top - offset }, 800 );
1353			}
1354		} );
1355
1356		// Handle the scroll event.
1357		var	lastKnownScrollPosition = window.scrollY,
1358			ticking = false,
1359			rAF = window.requestAnimationFrame ||
1360				window.webkitRequestAnimationFrame ||
1361				window.mozRequestAnimationFrame ||
1362				window.msRequestAnimationFrame ||
1363				window.oRequestAnimationFrame;
1364
1365		var checkFormVisibility = function( position ) {
1366			if ( position >= ( $originalForm.offset().top + $originalForm.height() - offset ) ) {
1367				$sticky.attr( 'aria-hidden', false ).removeClass( 'sticky-cart-form--unpin' ).addClass( 'sticky-cart-form--pin' );
1368				document.body.classList.add( 'sticky-cart-form-pinned-' + stickyPosition );
1369
1370				if ( 'top' === $sticky.data( 'position' ) && konte.data.sticky_header && 'none' !== konte.data.sticky_header ) {
1371					$stickyHeader.addClass( 'sticky--ignore' );
1372				}
1373			} else {
1374				$sticky.attr( 'aria-hidden', true ).removeClass( 'sticky-cart-form--pin' ).addClass( 'sticky-cart-form--unpin' );
1375				document.body.classList.remove( 'sticky-cart-form-pinned-' + stickyPosition );
1376
1377				if ( 'top' === $sticky.data( 'position' ) && konte.data.sticky_header && 'none' !== konte.data.sticky_header ) {
1378					$stickyHeader.removeClass( 'sticky--ignore' );
1379				}
1380			}
1381		};
1382
1383		// Check and toggle the sticky add-to-cart form on scroll.
1384		document.addEventListener( 'scroll', function() {
1385			lastKnownScrollPosition = window.scrollY;
1386
1387			if ( ! ticking ) {
1388				rAF( function() {
1389					checkFormVisibility( lastKnownScrollPosition );
1390					ticking = false;
1391				} );
1392
1393				ticking = true;
1394			}
1395		} );
1396
1397		rAF( function() {
1398			checkFormVisibility( lastKnownScrollPosition );
1399			ticking = false;
1400		} );
1401
1402		// Adds extra space to the bottom if the sticky add-to-cart form at bottom.
1403		if ( 'bottom' === $sticky.data( 'position' ) ) {
1404			$( '#colophon' ).css( 'margin-bottom', $sticky.outerHeight() );
1405		}
1406	}
1407
1408	/**
1409	 * Automactically open the cart panel after a product added to cart.
1410	 * Disable window scrollbar when cart panel opened.
1411	 */
1412	konte.cartPanel = function() {
1413		var $panel = $( '#cart-panel' );
1414
1415		if ( !$panel.length ) {
1416			return;
1417		}
1418
1419		// Scrollbar for cart panel.
1420		if ( typeof PerfectScrollbar !== 'undefined' ) {
1421			new PerfectScrollbar( $panel.find( '.panel-content' ).get( 0 ) );
1422		}
1423
1424		if ( '1' === konte.data.cart_open_after_added ) {
1425			$( document.body ).on( 'added_to_cart', function() {
1426				if ( $( '#cart-panel' ).hasClass( 'open' ) ) {
1427					return;
1428				}
1429
1430				konte.closeOffCanvas( false );
1431				// Queue for opening cart panel, to avoid removing class `.offcanvas-opened`.
1432				setTimeout( function() {
1433					konte.openOffCanvas( '#cart-panel' );
1434				}, 0 );
1435			} );
1436		}
1437	};
1438
1439	/**
1440	 * Handle product reviews
1441	 */
1442	konte.reviewProduct = function() {
1443		setTimeout( function() {
1444			$( '#respond p.stars a' ).prepend( '<span class="svg-icon icon-star"><svg><use xlink:href="#star"></use></svg></span>' );
1445		}, 100 );
1446
1447		$( document.body )
1448			.on( 'click', '.add-review', function( event ) {
1449				event.preventDefault();
1450
1451				var $reviews = $( this ).closest( '#reviews' );
1452
1453				$( '#review_form_wrapper', $reviews ).fadeIn();
1454				$( '#comments', $reviews ).fadeOut();
1455			} ).on( 'click', '.cancel-review a', function( event ) {
1456			event.preventDefault();
1457
1458			var $reviews = $( this ).closest( '#reviews' );
1459
1460			$( '#review_form_wrapper', $reviews ).fadeOut();
1461			$( '#comments', $reviews ).fadeIn();
1462		} );
1463
1464		$( '#review_form' )
1465			.on( 'focus', 'input, textarea', function() {
1466				$( this ).parent().addClass( 'focused' );
1467			} )
1468			.on( 'blur', 'input, textarea', function() {
1469				if ( $( this ).val() === '' ) {
1470					$( this ).parent().removeClass( 'focused' );
1471				}
1472			} )
1473			.find( 'input, textarea' ).each( function() {
1474			if ( $( this ).val() !== '' ) {
1475				$( this ).parent().addClass( 'focused' );
1476			}
1477		} );
1478	};
1479
1480	/**
1481	 * Toggle product tabs
1482	 */
1483	konte.toggleProductTabs = function() {
1484		var $product = $( 'div.product' );
1485
1486		if ( $product.hasClass( 'layout-v6' ) || $product.hasClass( 'layout-v7' ) ) {
1487			return;
1488		}
1489
1490		$( document.body )
1491			.off( 'click', '.woocommerce-tabs.panels-offscreen .wc-tabs li a, .woocommerce-tabs.panels-offscreen ul.tabs li a' )
1492			.on( 'click', '.woocommerce-tabs.panels-offscreen .wc-tabs li a', function( event ) {
1493				event.preventDefault();
1494
1495				var $el = $( this ),
1496					$wrapper = $el.closest( '.wc-tabs-wrapper, .woocommerce-tabs' ),
1497					$tabs = $wrapper.find( '.wc-tabs, ul.tabs' ),
1498					$panels = $wrapper.find( '.panels' ),
1499					$target = $wrapper.find( $el.attr( 'href' ) );
1500
1501				$tabs.find( 'li' ).removeClass( 'active' );
1502				$el.closest( 'li' ).addClass( 'active' );
1503				$panels.find( '.panel' ).show();
1504				$panels.fadeIn();
1505				$target.addClass( 'open' );
1506
1507				$( document.body ).addClass( 'offcanvas-opened' );
1508			} )
1509			.on( 'click', '.woocommerce-tabs .backdrop, .woocommerce-tabs .button-close', function( event ) {
1510				event.preventDefault();
1511
1512				var $wrapper = $( this ).closest( '.wc-tabs-wrapper, .woocommerce-tabs' ),
1513					$panels = $wrapper.find( '.panels' ),
1514					$opened = $panels.find( '.panel.open' );
1515
1516				$opened.removeClass( 'open' );
1517				$wrapper.find( '.tabs' ).children( 'li' ).removeClass( 'active' );
1518				$panels.fadeOut();
1519
1520				// Close the review form
1521				if ( $opened.is( '#tab-reviews' ) ) {
1522					$opened.find( '#review_form_wrapper' ).fadeOut();
1523					$opened.find( '#comments' ).fadeIn();
1524				}
1525
1526				$( document.body ).removeClass( 'offcanvas-opened' );
1527			} )
1528			.on( 'keyup', function( e ) {
1529				if ( e.keyCode === 27 ) {
1530					var $wrapper = $( '.wc-tabs-wrapper, .woocommerce-tabs' ),
1531						$panels = $wrapper.find( '.panels' ),
1532						$opened = $panels.find( '.panel.open' );
1533
1534					$opened.removeClass( 'open' );
1535					$wrapper.find( '.tabs' ).children( 'li' ).removeClass( 'active' );
1536					$panels.fadeOut();
1537
1538					// Close the review form
1539					if ( $opened.is( '#tab-reviews' ) ) {
1540						$opened.find( '#review_form_wrapper' ).fadeOut();
1541						$opened.find( '#comments' ).fadeIn();
1542					}
1543
1544					$( document.body ).removeClass( 'offcanvas-opened' );
1545				}
1546			} );
1547
1548		// Remove active tab.
1549		$product.find( '.wc-tabs, ul.tabs' ).first().find( 'li.active' ).removeClass( 'active' );
1550
1551		// Auto open targeted tab (by hash).
1552		if ( window.location.hash ) {
1553			var $tabLink = $product.find( '.wc-tabs, ul.tabs' ).first().find( 'li a[href="' + window.location.hash + '"]' );
1554
1555			if ( $tabLink.length ) {
1556				$tabLink.trigger( 'click' );
1557			}
1558		}
1559	};
1560
1561	/**
1562	 * Make product full width
1563	 */
1564	konte.productFullWidth = function( $product ) {
1565		var $window = $( window );
1566
1567		// Set width of product
1568		changeProductWidth();
1569
1570		$window.on( 'resize', function() {
1571			changeProductWidth();
1572		} );
1573
1574		/**
1575		 * Change the product width
1576		 */
1577		function changeProductWidth() {
1578			var width = $window.width();
1579
1580			width -= konte.getVerticalHeaderWidth();
1581
1582			$product.width( width );
1583
1584			if ( konte.data.rtl ) {
1585				$product.css( 'marginRight', -width/2 );
1586			} else {
1587				$product.css( 'marginLeft', -width/2 );
1588			}
1589		}
1590	};
1591
1592	/**
1593	 * Open product image lightbox when click on the zoom image
1594	 */
1595	konte.productLightBox = function() {
1596		if ( typeof wc_single_product_params === 'undefined' || wc_single_product_params.photoswipe_enabled !== '1' ) {
1597			return;
1598		}
1599
1600		$( '.woocommerce-product-gallery' ).on( 'click', '.zoomImg', function() {
1601			if ( wc_single_product_params.flexslider_enabled ) {
1602				$( this ).closest( '.woocommerce-product-gallery' ).children( '.woocommerce-product-gallery__trigger' ).trigger( 'click' );
1603			} else {
1604				$( this ).prev( 'a' ).trigger( 'click' );
1605			}
1606		} );
1607	};
1608
1609	/**
1610	 * Set the product background similar to product gallery images
1611	 */
1612	konte.productBackgroundFromGallery = function( $product ) {
1613		if ( typeof BackgroundColorTheif == 'undefined' ) {
1614			return;
1615		}
1616
1617		var $gallery = $product.find( '.woocommerce-product-gallery' ),
1618			$image = $gallery.find( '.wp-post-image' ),
1619			imageColor = new BackgroundColorTheif();
1620
1621		// Change background base on main image.
1622		$image.one( 'load', function() {
1623			setTimeout( function() {
1624				changeProductBackground( $image.get( 0 ) );
1625			}, 100 );
1626		} ).each( function() {
1627			this.crossOrigin = 'Anonymous';
1628
1629			if ( this.complete ) {
1630				$( this ).trigger( 'load' );
1631			}
1632		} );
1633
1634		// Change background when slider change.
1635		setTimeout( function() {
1636			var slider = $gallery.data( 'flexslider' );
1637
1638			if ( !slider ) {
1639				return;
1640			}
1641
1642			slider.vars.before = function( slider ) {
1643				setTimeout( function() {
1644					changeProductBackground( slider.slides.filter( '.flex-active-slide' ).find( 'a img' ).get( 0 ) );
1645				}, 150 );
1646			};
1647		}, 150 );
1648
1649		// Support Jetpack images lazy loads.
1650		$gallery.on( 'jetpack-lazy-loaded-image', '.wp-post-image', function() {
1651			$( this ).one( 'load', function() {
1652				changeProductBackground( this );
1653			} );
1654		} );
1655
1656		// Change background when variation changed
1657		$gallery.on( 'woocommerce_gallery_reset_slide_position', function() {
1658			changeProductBackground( $image.get( 0 ) );
1659		} );
1660
1661		/**
1662		 * Change product backgound color
1663		 */
1664		function changeProductBackground( image ) {
1665			// Stop if this image is not loaded.
1666			if ( image.src === '' ) {
1667				return;
1668			}
1669
1670			if ( image.classList.contains( 'jetpack-lazy-image' ) ) {
1671				if ( ! image.dataset['lazyLoaded'] ) {
1672					return;
1673				}
1674			}
1675
1676			var rgb = imageColor.getBackGroundColor( image );
1677			$product.get( 0 ).style.backgroundColor = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
1678		}
1679	}
1680
1681	/**
1682	 * Add extra script for product variation swatches.
1683	 * This function will run after plugin swatches did.
1684	 */
1685	konte.productVariationSwatches = function() {
1686		$( document.body ).on( 'tawcvs_initialized', function() {
1687			var $form = $( '.variations_form' );
1688
1689			konte.modifyVariationSwatches( $form );
1690		} );
1691	};
1692
1693	/**
1694	 * Modify the product gallery carousel
1695	 */
1696	konte.productGalleryCarousel = function() {
1697		var $product = $( 'div.product' );
1698
1699		if ( !$product.length ) {
1700			return;
1701		}
1702
1703		var $gallery = $( '.woocommerce-product-gallery', $product );
1704
1705		if ( ! $gallery.length ) {
1706			return;
1707		}
1708
1709		setTimeout( function() {
1710			$gallery.each( function() {
1711				konte.addIndexToCarouselControlNav( this );
1712			} )
1713		}, 100 );
1714	};
1715
1716	/**
1717	 * Appends a span to the product gallery carousel control nav
1718	 */
1719	konte.addIndexToCarouselControlNav = function( carousel ) {
1720		$( '.flex-control-nav > li', carousel ).each( function( index, el ) {
1721			$( el ).append( $( '<span class="flex-nav-index"/>' ).text( index + 1 ) );
1722		} );
1723	}
1724
1725	/**
1726	 * Special functions for product layout v1.
1727	 * Set product background color for single product page.
1728	 * Set height of product summary equal to the gallery's.
1729	 */
1730	konte.singleProductV1 = function() {
1731		var $product = $( 'div.product.layout-v1' );
1732
1733		if ( !$product.length ) {
1734			return;
1735		}
1736
1737		// Make product fullwidth
1738		konte.productFullWidth( $product );
1739
1740		// Set top padding of product
1741		$product.css( {paddingTop: $( '#masthead' ).height()} );
1742
1743		// Change background color
1744		if ( !$product.hasClass( 'background-set' ) && konte.data.product_auto_background === '1' ) {
1745			try {
1746				konte.productBackgroundFromGallery( $product );
1747			} catch ( e ) {
1748				console.warn( e );
1749			}
1750		}
1751
1752		var $gallery = $( '.woocommerce-product-gallery', $product );
1753
1754		// Fix slider's height on resize. Do not know why the default handler of Flexslider not working.
1755		$( window ).on( 'resize', function() {
1756			var slider = $gallery.data( 'flexslider' );
1757
1758			if ( slider ) {
1759				setTimeout( function() {
1760					var setHeight = $( '.woocommerce-product-gallery__image:eq(0)', $gallery ).height();
1761
1762					$gallery.height( setHeight );
1763				}, 100 );
1764			}
1765
1766			// Update the top padding.
1767			$product.css( {paddingTop: $( '#masthead' ).height()} );
1768		} );
1769	};
1770
1771	/**
1772	 * Special functions for product layout v2.
1773	 * Enable zooming for gallery thumbnails.
1774	 * Make the summary sticky.
1775	 */
1776	konte.singleProductV2 = function() {
1777		var $product = $( 'div.product.layout-v2' );
1778
1779		if ( !$product.length ) {
1780			return;
1781		}
1782
1783		var $window = $( window ),
1784			$summary = $product.find( '.summary' ),
1785			summarySticky = false;
1786
1787		// Make product fullwidth
1788		konte.productFullWidth( $product );
1789
1790		// Init zoom for product gallery images
1791		if ( '1' === konte.data.product_image_zoom ) {
1792			$product.find( '.woocommerce-product-gallery .woocommerce-product-gallery__image' ).each( function() {
1793				konte.zoomSingleProductImage( this );
1794			} );
1795		}
1796
1797		// Sticky summary
1798		if ( $.fn.stick_in_parent && konte.data.product_sticky_summary && konte.data.product_summary_sticky_mode == 'advanced' ) {
1799			$summary.on( 'sticky_kit:bottom', function() {
1800				$( this ).parent().css( 'position', 'static' );
1801			} );
1802
1803			stickySummary();
1804
1805			$window.on( 'resize', stickySummary );
1806		}
1807
1808		/**
1809		 * Sticky summary
1810		 */
1811		function stickySummary() {
1812			var  options = {};
1813
1814			if ( konte.data.sticky_header === 'normal' ) {
1815				var offset = $('#masthead').height(),
1816					$topbar = $( '#topbar' );
1817
1818				if ( $topbar.length ) {
1819					offset += $topbar.height();
1820				}
1821
1822				options = {
1823					recalc_every: 1,
1824					offset_top: offset
1825				}
1826			}
1827
1828			if ( $window.width() > 991 ) {
1829				if ( ! summarySticky ) {
1830					$summary.stick_in_parent( options );
1831				}
1832				summarySticky = true;
1833			} else {
1834				$summary.trigger( 'sticky_kit:detach' );
1835				summarySticky = false;
1836			}
1837		}
1838	}
1839
1840	/**
1841	 * Special functions for product layout v3.
1842	 * Change the height of product gallery.
1843	 */
1844	konte.singleProductV3 = function() {
1845		var $product = $( 'div.product.layout-v3' );
1846
1847		if ( !$product.length ) {
1848			return;
1849		}
1850
1851		var $header = $( '#masthead' );
1852
1853		// Set top padding of product
1854		$product.css( {paddingTop: $header.height()} );
1855		$( '.product-toolbar' ).css( {top: $header.height()} );
1856
1857		// Change background color
1858		if ( !$product.hasClass( 'background-set' ) && konte.data.product_auto_background === '1' ) {
1859			konte.productBackgroundFromGallery( $product );
1860		}
1861
1862		// Set gallery height
1863		$( '.woocommerce-product-gallery__wrapper .woocommerce-product-gallery__image:eq(0) .wp-post-image' ).one( 'load', setGalleryHeight );
1864
1865		setTimeout( function() {
1866			setGalleryHeight();
1867		}, 200 );
1868
1869		$( window ).on( 'resize', setGalleryHeight );
1870
1871		/**
1872		 * Set gallery height
1873		 */
1874		function setGalleryHeight() {
1875			var height = $( window ).height() - $header.outerHeight() - $( '#colophon' ).outerHeight() + 19,
1876				$topbar = $( '#topbar' ),
1877				$footer = $( '.footer-main' );
1878
1879			if ( $topbar.length ) {
1880				height -= $topbar.outerHeight();
1881			}
1882
1883			if ( $footer.length ) {
1884				height -= parseFloat( $footer.css( 'padding-top' ) );
1885			}
1886
1887			$product.find( '.woocommerce-product-gallery' ).css( {
1888				maxHeight: height,
1889				height   : height
1890			} );
1891		}
1892	}
1893
1894	/**
1895	 * Special functions for product layout v4.
1896	 */
1897	konte.singleProductV4 = function() {
1898		var $product = $( 'div.product.layout-v4' );
1899
1900		if ( !$product.length ) {
1901			return;
1902		}
1903
1904		// Quantity dropdown.
1905		if ( 'dropdown' === konte.data.product_quantity_input_style ) {
1906			$product.find( '.summary .quantity .qty' ).quantityDropdown();
1907		}
1908	}
1909
1910	/**
1911	 * Special functions for product layout v5.
1912	 */
1913	konte.singleProductV5 = function() {
1914		var $product = $( 'div.product.layout-v5' ),
1915			$summary = $product.find( '.summary' ),
1916			$summaryInner = $summary.children( '.summary-inner' ),
1917			$window = $( window ),
1918			headerHeight = $( '#masthead' ).height(),
1919			summarySticky = false;
1920
1921		if ( !$product.length ) {
1922			return;
1923		}
1924
1925		// Make product fullwidth
1926		productWidth();
1927
1928		$window.on( 'resize', function() {
1929			productWidth();
1930		} );
1931
1932		// Set top padding of product
1933		$summary.css( {paddingTop: headerHeight} );
1934
1935		// Init zoom for product gallery thumbnails
1936		if ( konte.data.product_image_zoom ) {
1937			$product.find( '.product-gallery-thumbnails .woocommerce-product-gallery__image' ).each( function() {
1938				konte.zoomSingleProductImage( this );
1939			} );
1940		}
1941
1942		// Sticky summary
1943		if ( $.fn.stick_in_parent && konte.data.product_sticky_summary && konte.data.product_summary_sticky_mode == 'advanced' ) {
1944			$summaryInner.css( 'max-height', $window.height() - headerHeight );
1945
1946			$summaryInner
1947				.on( 'sticky_kit:bottom', function() {
1948					$( this ).closest( '.product-gallery-summary' ).addClass( 'summary-sticky-bottom' );
1949				} )
1950				.on( 'sticky_kit:unbottom', function() {
1951					$( this ).closest( '.product-gallery-summary' ).removeClass( 'summary-sticky-bottom' );
1952				} );
1953
1954			setTimeout( function() {
1955				stickySummary();
1956			}, 100 );
1957
1958			$window.on( 'resize', stickySummary );
1959		}
1960
1961		/**
1962		 * Set product width
1963		 */
1964		function productWidth() {
1965			var width = $window.width(),
1966				bonus = width > 1440 ? 60 : 0;
1967
1968			width -= konte.getVerticalHeaderWidth();
1969
1970			$product.width( width );
1971
1972			if ( konte.data.rtl ) {
1973				$product.css( 'margin-right', -width / 2 );
1974				$summary.css( 'padding-left', width / 2 - $( '.konte-container' ).width() / 2 + bonus );
1975			} else {
1976				$product.css( 'margin-left', -width / 2 );
1977				$summary.css( 'padding-right', width / 2 - $( '.konte-container' ).width() / 2 + bonus );
1978			}
1979		}
1980
1981		/**
1982		 * Sticky summary
1983		 */
1984		function stickySummary() {
1985			var options = { parent: $product.get(0) };
1986
1987			if (konte.data.sticky_header === 'normal') {
1988				var offset = $('#masthead').height(),
1989					$topbar = $('#topbar');
1990
1991				if ($topbar.length) {
1992					offset += $topbar.height();
1993				}
1994
1995				options = {
1996					recalc_every: 1,
1997					offset_top: offset,
1998					parent: $product.get(0)
1999				}
2000			}
2001
2002			if ( $window.width() > 991 ) {
2003				if ( ! summarySticky ) {
2004					$summaryInner.stick_in_parent( options );
2005				}
2006				summarySticky = true;
2007			} else {
2008				$summaryInner.trigger( 'sticky_kit:detach' );
2009				summarySticky = false;
2010			}
2011		}
2012	};
2013
2014	/**
2015	 * Special functions for product layout v6.
2016	 */
2017	konte.singleProductV6 = function() {
2018		var $product = $( 'div.product.layout-v6' );
2019
2020		if ( !$product.length ) {
2021			return;
2022		}
2023	};
2024
2025	/**
2026	 * Special functions for product layout v7.
2027	 */
2028	konte.singleProductV7 = function() {
2029		var $product = $( 'div.product.layout-v7' );
2030
2031		if ( !$product.length ) {
2032			return;
2033		}
2034	};
2035
2036	/**
2037	 * Init the carousel for product gallery thumbnails
2038	 *
2039	 * @param {Object} options
2040	 */
2041	konte.productGalleryThumbnailCarousel = function( options ) {
2042		var $product = $( 'div.product' );
2043
2044		if ( ! $product.length ) {
2045			return;
2046		}
2047
2048		var $gallery = $( '.woocommerce-product-gallery', $product ),
2049			$thumbnails = $gallery.find( '.flex-control-thumbs' ),
2050			options = {
2051				rtl            : !! konte.data.rtl,
2052				vertical       : false,
2053				verticalSwiping: false,
2054				swipeToSlide   : true,
2055				touchThreshold : 100,
2056				infinite       : false,
2057				slidesToShow   : 4,
2058				slidesToScroll : 1,
2059				prevArrow      : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>',
2060				nextArrow      : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>'
2061			};
2062
2063		if ( $product.hasClass( 'layout-v4' ) ) {
2064			options.vertical = true,
2065			options.verticalSwiping = true;
2066		} else if ( $product.hasClass( 'layout-v6' ) ) {
2067			options.vertical = true,
2068			options.verticalSwiping = true;
2069		} else if ( $product.hasClass( 'layout-v7' ) ) {
2070			options.adaptiveHeight = true;
2071		}
2072
2073		var isVertical = options.vertical ? true : false;
2074
2075		if ( $gallery.hasClass( 'woocommerce-product-gallery--mobile-nav-dots' ) ) {
2076			options.responsive = [
2077				{
2078					breakpoint: 991,
2079					settings: 'unslick'
2080				}
2081			];
2082		} else if ( $gallery.hasClass( 'woocommerce-product-gallery--mobile-nav-thumbnails' ) ) {
2083			options.mobileFirst = true;
2084			options.responsive = [
2085				{
2086					breakpoint: 0,
2087					settings: {
2088						variableWidth  : true,
2089						vertical       : false,
2090						verticalSwiping: false,
2091					}
2092				}
2093			];
2094
2095			var desktopOptions = {
2096				breakpoint: 992,
2097				settings: {}
2098			}
2099
2100			if ( $gallery.hasClass( 'woocommerce-product-gallery--nav-thumbnails' ) ) {
2101				desktopOptions.settings = {
2102					vertical: options.vertical,
2103					verticalSwiping: options.verticalSwiping
2104				};
2105
2106				delete options.vertical;
2107				delete options.verticalSwiping;
2108			} else {
2109				desktopOptions.settings = 'unslick';
2110			}
2111
2112			options.responsive.push( desktopOptions );
2113		}
2114
2115		var initGalleryThumbsCarousel = function() {
2116			var slidesToShow = 0;
2117
2118			if ( isVertical ) {
2119				// On mobile vertical carousel is not used.
2120				if ( options.mobileFirst && window.innerWidth < 992 ) {
2121					slidesToShow = parseInt( $gallery.width() / ( $thumbnails.find( 'li:eq(0) > img' ).width() + 10 ) );
2122				} else {
2123					slidesToShow = parseInt( $gallery.height() / ( $thumbnails.find( 'li:eq(0) > img' ).height() ) );
2124				}
2125			} else {
2126				slidesToShow = parseInt( $gallery.width() / ( $thumbnails.find( 'li:eq(0)' ).width() + 10 ) );
2127			}
2128
2129			if ( ! options.mobileFirst || window.innerWidth >= 992 || ! isVertical ) {
2130				options.slidesToShow = slidesToShow;
2131			}
2132
2133			if ( ! $thumbnails.hasClass( 'slick-initialized' ) && slidesToShow && $thumbnails.children().length > slidesToShow ) {
2134				$thumbnails.slick( options );
2135			}
2136		};
2137
2138		setTimeout( function() {
2139			// To make sure FlexSlider is initialized.
2140			if ( ! $thumbnails.length ) {
2141				$gallery = $( '.woocommerce-product-gallery', $product );
2142				$thumbnails = $gallery.find( '.flex-control-thumbs' );
2143			}
2144
2145			var firstThumb = $thumbnails.children().first().find( 'img' ).get( 0 );
2146
2147			if ( ! firstThumb ) {
2148				return;
2149			}
2150
2151			if ( firstThumb.complete ) {
2152				initGalleryThumbsCarousel();
2153			} else {
2154				firstThumb.addEventListener( 'load', initGalleryThumbsCarousel );
2155			}
2156		}, 200 );
2157
2158		$( window ).on( 'resize', function() {
2159			// With some product layouts, the gallery is replaced by a clone.
2160			// Have to update the variable accordingly to the replacement.
2161			// See more: konte.responsiveProductGallery()
2162			setTimeout( function() {
2163				if ( ! $.contains( document.documentElement, $thumbnails.get(0) ) ) {
2164					$gallery = $( '.woocommerce-product-gallery', $product );
2165					$thumbnails = $gallery.find( '.flex-control-thumbs' );
2166				}
2167
2168				initGalleryThumbsCarousel();
2169			}, 200 );
2170		} );
2171	}
2172
2173	/**
2174	 * Init slider for product gallery on mobile.
2175	 */
2176	konte.responsiveProductGallery = function() {
2177		if ( konte.data.product_gallery_slider || ! $.fn.wc_product_gallery ) {
2178			return;
2179		}
2180
2181		var $window = $( window ),
2182			$product = $( '.woocommerce div.product' ),
2183			default_flexslider_enabled = false,
2184			default_flexslider_options = {};
2185
2186		if ( ! $product.length ) {
2187			return;
2188		}
2189
2190		var $gallery = $( '.woocommerce-product-gallery', $product ),
2191			$originalGallery = $gallery.clone(),
2192			sliderActive = $gallery.find( '.flex-viewport' ).length;
2193
2194		$originalGallery.children( '.woocommerce-product-gallery__trigger' ).remove();
2195
2196		// Turn off events then we init them again later.
2197		$originalGallery.off();
2198
2199		if ( typeof wc_single_product_params !== undefined ) {
2200			default_flexslider_enabled = wc_single_product_params.flexslider_enabled;
2201			default_flexslider_options = wc_single_product_params.flexslider;
2202		}
2203
2204		initProductGallery();
2205		$window.on( 'resize', initProductGallery );
2206
2207		// Init product gallery
2208		function initProductGallery() {
2209			if ( $window.width() > 991 ) {
2210				if ( ! sliderActive ) {
2211					return;
2212				}
2213
2214				if ( typeof wc_single_product_params !== undefined ) {
2215					wc_single_product_params.flexslider_enabled = default_flexslider_enabled;
2216					wc_single_product_params.flexslider = default_flexslider_options;
2217				}
2218
2219				// Destroy is not supported at this moment.
2220				$gallery.replaceWith( $originalGallery.clone() );
2221				$gallery = $( '.woocommerce-product-gallery', $product );
2222
2223				$gallery.each( function() {
2224					$( this ).wc_product_gallery();
2225				} );
2226
2227				$( 'form.variations_form select', $product ).trigger( 'change' );
2228
2229				// Init zoom for product gallery images
2230				if ( '1' === konte.data.product_image_zoom && $product.hasClass( 'layout-v2' ) ) {
2231					$gallery.find( '.woocommerce-product-gallery__image' ).each( function() {
2232						konte.zoomSingleProductImage( this );
2233					} );
2234				}
2235
2236				sliderActive = false;
2237			} else {
2238				if ( sliderActive ) {
2239					return;
2240				}
2241
2242				if ( typeof wc_single_product_params !== undefined ) {
2243					wc_single_product_params.flexslider_enabled = true;
2244					// wc_single_product_params.flexslider.controlNav = true;
2245				}
2246
2247				$gallery.replaceWith( $originalGallery.clone() );
2248				$gallery = $( '.woocommerce-product-gallery', $product );
2249
2250				// Support Jetpack lazy load.
2251				$( document.body ).trigger( 'konte_lazy_load_images' );
2252
2253				setTimeout( function() {
2254					$gallery.each( function() {
2255						$( this ).wc_product_gallery();
2256
2257						konte.addIndexToCarouselControlNav( this );
2258					} );
2259				}, 100 );
2260
2261				$( 'form.variations_form select', $product ).trigger( 'change' );
2262
2263				sliderActive = true;
2264			}
2265		}
2266	};
2267
2268	/**
2269	 * Related & ppsell products carousel.
2270	 */
2271	konte.relatedProductsCarousel = function() {
2272		if ( typeof Swiper === 'undefined' ) {
2273			return;
2274		}
2275
2276		var $related = $( '.products.related, .products.upsells' );
2277
2278		if ( ! $related.length ) {
2279			return;
2280		}
2281
2282		var $products = $related.find( 'ul.products' );
2283
2284		$products.wrap( '<div class="konte-swiper-container swiper-container linked-products-carousel" style="opacity: 0;"></div>' );
2285		$products.after( '<div class="swiper-pagination"></div>' );
2286		$products.addClass( 'swiper-wrapper' );
2287		$products.find( 'li.product' ).addClass( 'swiper-slide' );
2288
2289		var carousel = new Swiper( '.linked-products-carousel', {
2290			loop          : false,
2291			slidesPerView : 1,
2292			slidesPerGroup: 1,
2293			spaceBetween  : 40,
2294			speed         : 800,
2295			watchOverflow : true,
2296			pagination    : {
2297				el          : '.swiper-pagination',
2298				type        : 'bullets',
2299				clickable   : true,
2300				renderBullet: function( index, className ) {
2301					return '<span class="' + className + '"><span></span></span>';
2302				}
2303			},
2304			on            : {
2305				init: function() {
2306					this.$el.css( 'opacity', 1 );
2307				}
2308			},
2309			breakpoints   : {
2310				360: {
2311					spaceBetween  : 20,
2312					slidesPerView : 2,
2313					slidesPerGroup: 2
2314				},
2315				768: {
2316					spaceBetween  : 20,
2317					slidesPerView : 2,
2318					slidesPerGroup: 2
2319				},
2320				992 : {
2321					slidesPerView : 3,
2322					slidesPerGroup: 3
2323				},
2324				1200: {
2325					slidesPerView : 4,
2326					slidesPerGroup: 4
2327				}
2328			}
2329		} );
2330	};
2331
2332	/**
2333	 * Zoom an image.
2334	 * Copy from WooCommerce single-product.js file.
2335	 */
2336	konte.zoomSingleProductImage = function( zoomTarget ) {
2337		if ( typeof wc_single_product_params == 'undefined' || !$.fn.zoom ) {
2338			return;
2339		}
2340
2341		var $target = $( zoomTarget ),
2342			width = $target.width(),
2343			zoomEnabled = false;
2344
2345		$target.each( function( index, target ) {
2346			var $image = $( target ).find( 'img' );
2347
2348			if ( $image.data( 'large_image_width' ) > width ) {
2349				zoomEnabled = true;
2350				return false;
2351			}
2352		} );
2353
2354		// Only zoom if the img is larger than its container.
2355		if ( zoomEnabled ) {
2356			var zoom_options = $.extend( {
2357				touch: false
2358			}, wc_single_product_params.zoom_options );
2359
2360			if ( 'ontouchstart' in document.documentElement ) {
2361				zoom_options.on = 'click';
2362			}
2363
2364			$target.trigger( 'zoom.destroy' );
2365			$target.zoom( zoom_options );
2366		}
2367	}
2368
2369	/**
2370	 * Add class to .form-row when inputs are focused.
2371	 */
2372	konte.formFieldFocus = function() {
2373		$( document.body )
2374			.on( 'focus', '.form-row .input-text, .wpcf7-form-control', function() {
2375				$( this ).parent().addClass( 'focused' );
2376
2377				if ( $( this ).is( '.wpcf7-form-control' ) ) {
2378					$( this ).closest( 'label' ).addClass( 'focused' );
2379				} else {
2380					$( this ).closest( '.form-row' ).addClass( 'focused' );
2381				}
2382			} )
2383			.on( 'blur', '.form-row  .input-text, .wpcf7-form-control', function() {
2384				if ( $( this ).val() === '' ) {
2385					if ( $( this ).is( '.wpcf7-form-control' ) ) {
2386						$( this ).closest( 'label' ).removeClass( 'focused' );
2387					} else {
2388						$( this ).closest( '.form-row' ).removeClass( 'focused' );
2389					}
2390				}
2391			} )
2392			.find( '.form-row .input-text, .wpcf7-form-control' ).each( function() {
2393				if ( $( this ).val() != '' ) {
2394					if ( $( this ).is( '.wpcf7-form-control' ) ) {
2395						$( this ).closest( 'label' ).addClass( 'focused' );
2396					} else {
2397						$( this ).closest( '.form-row' ).addClass( 'focused' );
2398					}
2399				}
2400			} );
2401	};
2402
2403	/**
2404	 * Login & register tabs.
2405	 */
2406	konte.loginTabs = function() {
2407		$( document.body ).on( 'click', '.login-tabs-nav .tab-nav', function( event ) {
2408			event.preventDefault();
2409
2410			var $tab = $( this ),
2411				$panels = $tab.parent().siblings( '.u-columns' );
2412
2413			if ( $tab.hasClass( 'active' ) ) {
2414				return;
2415			}
2416
2417			$tab.addClass( 'active' ).siblings().removeClass( 'active' );
2418			$panels.children().eq( $tab.index() ).addClass( 'active' ).siblings().removeClass( 'active' );
2419		} );
2420	};
2421
2422	/**
2423	 * Toggle register/login form in the login panel.
2424	 */
2425	konte.loginPanel = function() {
2426		$( document.body )
2427			.on( 'click', '#login-panel .create-account', function( event ) {
2428				event.preventDefault();
2429
2430				$( this ).closest( 'form.login' ).fadeOut( function() {
2431					$( this ).next( 'form.register' ).fadeIn();
2432				} );
2433			} ).on( 'click', '#login-panel a.login', function( event ) {
2434			event.preventDefault();
2435
2436			$( this ).closest( 'form.register' ).fadeOut( function() {
2437				$( this ).prev( 'form.login' ).fadeIn();
2438			} );
2439		} ).on( 'click', '[data-toggle="off-canvas"][data-target="login-panel"]', function() {
2440			$( '#login-panel' ).find( 'form' ).hide().filter( '.login' ).show();
2441		} );
2442	};
2443
2444	/**
2445	 * Ajax login before refresh page
2446	 */
2447	konte.loginPanelAuthenticate = function() {
2448		$( '#login-panel' ).on( 'submit', 'form.login', function authenticate( event ) {
2449			var username = $( 'input[name=username]', this ).val(),
2450				password = $( 'input[name=password]', this ).val(),
2451				remember = $( 'input[name=rememberme]', this ).is( ':checked' ),
2452				nonce = $( 'input[name=woocommerce-login-nonce]', this ).val(),
2453				$button = $( '[type=submit]', this ),
2454				$form = $( this ),
2455				$box = $form.next( '.woocommerce-error' );
2456
2457			if ( ! username ) {
2458				$( 'input[name=username]', this ).focus();
2459
2460				return false;
2461			}
2462
2463			if ( ! password ) {
2464				$( 'input[name=password]', this ).focus();
2465
2466				return false;
2467			}
2468
2469			$form.find( '.woocommerce-error' ).remove();
2470
2471			if ( $form.data( 'validated' ) ) {
2472				return true;
2473			}
2474
2475			$button.html( '<span class="spinner"></span>' );
2476
2477			if ( $box.length ) {
2478				$box.fadeOut();
2479			}
2480
2481			$.post(
2482				konte.data.ajax_url,
2483				{
2484					action: 'konte_login_authenticate',
2485					security: nonce,
2486					username: username,
2487					password: password,
2488					remember: remember
2489				},
2490				function( response ) {
2491					if ( ! response.success ) {
2492						if ( ! $box.length ) {
2493							$box = $( '<div class="woocommerce-error" role="alert"/>' );
2494
2495							$box.append( '<span class="svg-icon icon-error size-normal message-icon"><svg role="img"><use href="#error" xlink:href="#error"></use></svg></span>' )
2496								.append( '<ul class="error-message" />' )
2497								.append( '<span class="svg-icon icon-close size-normal close-message"><svg role="img"><use href="#close" xlink:href="#close"></use></svg></span>' );
2498
2499							$box.hide().prependTo( $form );
2500						}
2501
2502						$box.find( '.error-message' ).html( '<li>' + response.data + '</li>' );
2503						$box.fadeIn();
2504						$button.html( $button.attr( 'value' ) );
2505					} else {
2506						$form.data( 'validated', true ).submit();
2507						$button.html( $button.data( 'signed' ) );
2508					}
2509				}
2510			);
2511
2512			event.preventDefault();
2513		} ).on( 'click', '.woocommerce-error .close-message', function() {
2514			// Remove the error message to fix the layout issue.
2515			$( this ).closest( '.woocommerce-error' ).fadeOut( function() {
2516				$( this ).remove();
2517			} );
2518
2519			return false;
2520		} );
2521	};
2522
2523	/**
2524	 * Initialize masonry layout for the shop page.
2525	 */
2526	konte.productsMasonry = function() {
2527		var $container = $( 'ul.products.layout-masonry' ),
2528			$window = $( window );
2529
2530		if ( !$.fn.masonry || !$container.length ) {
2531			return;
2532		}
2533
2534		$container.on( 'layoutComplete', layoutMasonry );
2535
2536		initMansonry();
2537
2538		$window.on( 'resize', initMansonry );
2539
2540		$( document.body ).on( 'post-load konte_products_loaded', function( event, products, appended ) {
2541			if ( $window.width() < 992 ) {
2542				return;
2543			}
2544
2545			if ( appended ) {
2546				$container.masonry( 'appended', products ).masonry();
2547			} else {
2548				$container = $( 'ul.products.layout-masonry' );
2549
2550				$container.on( 'layoutComplete', layoutMasonry );
2551
2552				initMansonry();
2553			}
2554		} );
2555
2556		/**
2557		 * Init masonry layout
2558		 */
2559		function initMansonry() {
2560			if ( $container.children().length <= 1 ) {
2561				return;
2562			}
2563
2564			if ( $window.width() < 992 ) {
2565				$container.each( function() {
2566					var $this = $( this );
2567
2568					if ( $this.hasClass( 'masonry' ) ) {
2569						$this.masonry( 'destroy' );
2570					}
2571				} );
2572			} else {
2573				$container.each( function() {
2574					var $this = $( this ),
2575						options = {
2576							itemSelector:       'li.product',
2577							columnWidth:        'li.product:nth-child(2)',
2578							percentPosition:    true,
2579							transitionDuration: 0,
2580							isRTL:              !! konte.data.rtl
2581						};
2582
2583					if ( ! $this.hasClass( 'masonry' ) ) {
2584						$this.masonry( options );
2585
2586						$this.imagesLoaded().progress( function() {
2587							$this.masonry( 'layout' );
2588						} );
2589					}
2590				} );
2591			}
2592		}
2593
2594		/**
2595		 * Change the masonry layout as the design.
2596		 */
2597		function layoutMasonry() {
2598			var prop = konte.data.rtl ? 'right' : 'left';
2599
2600			$container
2601				.children( ':nth-child(10n+1), :nth-child(10n+6), :nth-child(10n+9)' )
2602				.css( prop, '0' )
2603				.end()
2604				.children( ':nth-child(10n+2), :nth-child(10n+4)' )
2605				.css( prop, '50%' )
2606				.end()
2607				.children( ':nth-child(10n+3), :nth-child(10n+5), :nth-child(10n+8), :nth-child(10n)' )
2608				.css( prop, '75%' )
2609				.end()
2610				.children( ':nth-child(10n+7)' )
2611				.css( prop, '25%' );
2612		}
2613	};
2614
2615	/**
2616	 * Proudcts carousel layout.
2617	 */
2618	konte.productsCarousel = function() {
2619		var $container = $( '.products-carousel' );
2620
2621		if ( !$container.length ) {
2622			return;
2623		}
2624
2625		$container.find( 'ul.products li.product' ).addClass( 'swiper-slide' );
2626
2627		var carousel = new Swiper( '.products-carousel', {
2628			loop         : false,
2629			slidesPerView: 1,
2630			spaceBetween : 40,
2631			scrollbar    : {
2632				el       : '.swiper-scrollbar',
2633				hide     : false,
2634				draggable: true
2635			},
2636			on           : {
2637				init: function() {
2638					$container.css( 'opacity', 1 );
2639				}
2640			},
2641			breakpoints  : {
2642				360 : {
2643					slidesPerView: 2
2644				},
2645				992 : {
2646					slidesPerView: 3
2647				},
2648				1200: {
2649					slidesPerView: 4
2650				}
2651			}
2652		} );
2653
2654		var xhr;
2655
2656		carousel.on( 'reachEnd', function() {
2657			var $nav = $( '.woocommerce-navigation.ajax-navigation' );
2658
2659			if ( !$nav.length ) {
2660				return;
2661			}
2662
2663			if ( xhr ) {
2664				return;
2665			}
2666
2667			var loadingHolder = document.createElement( 'li' );
2668
2669			$( loadingHolder )
2670				.addClass( 'swiper-slide loading-placeholder' )
2671				.css( {height: carousel.height - 140} )
2672				.append( '<span class="spinner"></span>' );
2673
2674			carousel.appendSlide( loadingHolder );
2675			carousel.update();
2676
2677			xhr = $.get( $nav.find( 'a' ).attr( 'href' ), function( response ) {
2678				var $content = $( '#main', response ),
2679					$list = $( 'ul.products', $content ),
2680					$products = $list.children(),
2681					$newNav = $( '.woocommerce-navigation.ajax-navigation', $content );
2682
2683				if ( $newNav.length ) {
2684					$nav.find( 'a' ).replaceWith( $( 'a', $newNav ) );
2685				} else {
2686					$nav.fadeOut( function() {
2687						$nav.remove();
2688					} );
2689				}
2690
2691				$( loadingHolder ).remove();
2692				$products.css( {opacity: 0} );
2693
2694				carousel.appendSlide( $products.addClass( 'swiper-slide' ).get() );
2695				carousel.update();
2696
2697				$products.animate( {opacity: 1} );
2698				xhr = false;
2699
2700				$( document.body ).trigger( 'konte_products_loaded', [$products, true] );
2701			} );
2702		} );
2703	};
2704
2705	/**
2706	 * Product thumbnails slider.
2707	 */
2708	konte.productThumbnailsSlider = function() {
2709		var options = {
2710			slidesToShow  : 1,
2711			slidesToScroll: 1,
2712			infinite      : false,
2713			lazyLoad      : 'ondemand',
2714			dots          : false,
2715			swipe         : false,
2716			rtl           : !! konte.data.rtl,
2717			prevArrow     : '<span class="slick-prev slick-arrow svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>',
2718			nextArrow     : '<span class="slick-next slick-arrow svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>'
2719		}
2720
2721		if ( konte.data.rtl ) {
2722			$( '.product-thumbnails--slider' ).attr( 'dir', 'rtl' );
2723		}
2724
2725		$( '.product-thumbnails--slider' ).slick( options );
2726
2727		// Filter plugins.
2728		$( document.body ).on( 'post-load', function() {
2729			if ( konte.data.rtl ) {
2730				$( '.product-thumbnails--slider', 'ul.products.hover-slider' ).attr( 'dir', 'rtl' );
2731			}
2732
2733			$( '.product-thumbnails--slider', 'ul.products.hover-slider' ).slick( options );
2734		} )
2735
2736		// Ajax product loaded.
2737		$( document.body ).on( 'konte_products_loaded', function( event, products ) {
2738			if ( konte.data.rtl ) {
2739				$( '.product-thumbnails--slider', products ).attr( 'dir', 'rtl' );
2740			}
2741
2742			$( '.product-thumbnails--slider', products ).slick( options );
2743		} );
2744	};
2745
2746	/**
2747	 * Product thumbnail zoom.
2748	 */
2749	konte.productThumbnailZoom = function() {
2750		$( '.product-thumbnail-zoom' ).each( function() {
2751			var $el = $( this );
2752
2753			$el.zoom( {
2754				url: $el.attr( 'data-zoom_image' )
2755			} );
2756		} );
2757
2758		// Filter plugins.
2759		$( document.body ).on( 'post-load', function() {
2760			$( '.product-thumbnail-zoom', 'ul.products.hover-zoom' ).each( function() {
2761				var $el = $( this );
2762
2763				$el.zoom( {
2764					url: $el.attr( 'data-zoom_image' )
2765				} );
2766			} );
2767		} );
2768
2769		// Ajax product loaded.
2770		$( document.body ).on( 'konte_products_loaded', function( event, products ) {
2771			$( '.product-thumbnail-zoom', products ).each( function() {
2772				var $el = $( this );
2773
2774				$el.zoom( {
2775					url: $el.attr( 'data-zoom_image' )
2776				} );
2777			} );
2778		} );
2779	};
2780
2781	/**
2782	 * Quick view modal.
2783	 */
2784	konte.productQuickView = function() {
2785		$( document.body ).on( 'click', '.quick_view_button', function( event ) {
2786			event.preventDefault();
2787
2788			var $el = $( this ),
2789				product_id = $el.data( 'product_id' ),
2790				$target = $( '#' + $el.data( 'target' ) ),
2791				$container = $target.find( '.woocommerce' ),
2792				ajax_url = woocommerce_params ? woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'product_quick_view' ) : konte.data.ajax_url;
2793
2794			$target.addClass( 'loading' );
2795			$container.find( '.product' ).html( '' );
2796
2797			$.post(
2798				ajax_url,
2799				{
2800					action    : 'konte_get_product_quickview',
2801					product_id: product_id,
2802					security  : konte.data.product_quickview_nonce
2803				},
2804				function( response ) {
2805					$container.find( '.product' ).replaceWith( response.data );
2806
2807					if ( response.success ) {
2808						update_quickview();
2809
2810						if ( 'modal' == $el.data( 'toggle' ) ) {
2811							update_quickview_modal();
2812						} else {
2813							update_quickview_panel();
2814						}
2815					}
2816
2817					$target.removeClass( 'loading' );
2818
2819					$( document.body ).trigger( 'konte_product_quickview_loaded', [response, product_id, konte] );
2820				}
2821			).fail( function() {
2822				window.location.herf = $el.attr( 'href' );
2823			} );
2824
2825			/**
2826			 * Update quick view common elements.
2827			 */
2828			function update_quickview() {
2829				var $product = $container.find( '.product' ),
2830					$gallery = $product.find( '.woocommerce-product-gallery' ),
2831					$variations = $product.find( '.variations_form' );
2832
2833				// Prevent clicking on gallery image link.
2834				$gallery.on( 'click', '.woocommerce-product-gallery__image a', function( event ) {
2835					event.preventDefault();
2836				} );
2837
2838				// Init flex slider.
2839				if ( $gallery.find( '.woocommerce-product-gallery__image' ).length > 1 ) {
2840					$gallery.flexslider( {
2841						selector      : '.woocommerce-product-gallery__wrapper > .woocommerce-product-gallery__image',
2842						animation     : 'slide',
2843						animationLoop : false,
2844						animationSpeed: 500,
2845						controlNav    : true,
2846						directionNav  : true,
2847						prevText      : '<span class="svg-icon icon-left icon-small"><svg width="16" height="16"><use xlink:href="#left"></use></svg></span>',
2848						nextText      : '<span class="svg-icon icon-right icon-small"><svg width="16" height="16"><use xlink:href="#right"></use></svg></span>',
2849						slideshow     : false,
2850						rtl           : !! konte.data.rtl,
2851						start         : function() {
2852							$gallery.css( 'opacity', 1 );
2853						},
2854					} );
2855				} else {
2856					$gallery.css( 'opacity', 1 );
2857				}
2858
2859				// Make videos responsive.
2860				$product.find( '.summary iframe' ).wrap( '<figure class="wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"/></div>' );
2861
2862				// Variations form.
2863				if ( $variations.length ) {
2864					$variations.wc_variation_form().find( '.variations select:eq(0)' ).change();
2865
2866					if ( $gallery.data( 'flexslider' ) ) {
2867						$variations.on( 'reset_image found_variation', function() {
2868							$gallery.flexslider( 0 );
2869						} );
2870					}
2871
2872					if ( $.fn.tawcvs_variation_swatches_form ) {
2873						$variations.tawcvs_variation_swatches_form();
2874						konte.modifyVariationSwatches( $variations );
2875					}
2876
2877					$( document.body ).trigger( 'init_variation_swatches' );
2878				}
2879			}
2880
2881			/**
2882			 * Update quick view modal's special elements.
2883			 */
2884			function update_quickview_modal() {
2885				var $product = $container.find( '.product' ),
2886					$gallery = $product.find( '.woocommerce-product-gallery' );
2887
2888				// Force height for images
2889				$gallery.find( 'img' ).css( 'height', $product.outerHeight() );
2890
2891				if ( konte.data.product_quickview_auto_background && !$product.hasClass( 'background-set' ) ) {
2892					try {
2893						$product.imagesLoaded( function() {
2894							konte.productBackgroundFromGallery( $product );
2895						} );
2896					} catch ( e ) {
2897						console.warn( e );
2898					}
2899				}
2900
2901				if ( typeof PerfectScrollbar !== 'undefined' ) {
2902					new PerfectScrollbar( $product.find( '.summary' ).get( 0 ) );
2903				}
2904			}
2905
2906			/**
2907			 * Update quick view panel's special elements.
2908			 */
2909			function update_quickview_panel() {
2910				if ( typeof PerfectScrollbar !== 'undefined' ) {
2911					new PerfectScrollbar( $container.find( '.product' ).get( 0 ) );
2912				}
2913			}
2914		} );
2915	};
2916
2917	/**
2918	 * Empty the quickview modal/panel on close to prevent sound of videos,
2919	 * or any unexpected effects.
2920	 */
2921	konte.emptyQuickViewOnClose = function() {
2922		$( document.body ).on( 'konte_off_canvas_closed konte_modal_closed', function( event, target ) {
2923			var $quickview = $( target );
2924
2925			if ( ! $quickview.is( '#quick-view-modal' ) && ! $quickview.is( '#quick-view-panel' ) ) {
2926				return;
2927			}
2928
2929			$quickview.find( '.product' ).html( '' );
2930		} );
2931	};
2932
2933	/**
2934	 * Auto-close the quick-view on successful product add to cart.
2935	 */
2936	konte.autoCloseQuickView = function() {
2937		$( document.body ).on( 'added_to_cart', function() {
2938			if ( '1' === konte.data.product_quickview_auto_close || '1' === konte.data.cart_open_after_added ) {
2939				konte.closeOffCanvas( '#quick-view-modal' );
2940				konte.closeModal( '#quick-view-modal' );
2941			}
2942		} );
2943	};
2944
2945	/**
2946	 * Modify variation swatches script.
2947	 *
2948	 * @param $form
2949	 */
2950	konte.modifyVariationSwatches = function( $form ) {
2951		// Remove class "swatches-support" if there is no swatches in this product
2952		var hasSwatches = false;
2953
2954		if ( $form.find( '.tawcvs-swatches' ).length ) {
2955			hasSwatches = true;
2956		}
2957
2958		if ( ! hasSwatches ) {
2959			$form.removeClass( 'swatches-support' );
2960		}
2961
2962		// Change alert style
2963		$form.off( 'tawcvs_no_matching_variations' );
2964		$form.on( 'tawcvs_no_matching_variations', function( event ) {
2965			event.preventDefault();
2966
2967			$form.find( '.woocommerce-variation.single_variation' ).show();
2968			if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) {
2969				$form.find( '.single_variation' ).stop( true, true ).slideDown().html( '<p class="invalid-variation-combination">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' );
2970			}
2971		} );
2972	};
2973
2974	/**
2975	 * Ajax load more products.
2976	 */
2977	konte.loadMoreProducts = function() {
2978		// Handles click load more button.
2979		$( document.body ).on( 'click', '.woocommerce-navigation.ajax-navigation a', function( event ) {
2980			event.preventDefault();
2981
2982			var $el = $( this );
2983
2984			if ( $el.hasClass( 'loading' ) ) {
2985				return;
2986			}
2987
2988			$el.addClass( 'loading' );
2989
2990			loadProducts( $( this ) );
2991		} );
2992
2993		// Infinite scroll.
2994		if ( $( document.body ).hasClass( 'woocommerce-nav-infinite' ) ) {
2995			var waiting = false,
2996				endScrollHandle;
2997
2998			$( window ).on( 'scroll', function() {
2999				if ( waiting ) {
3000					return;
3001				}
3002
3003				waiting = true;
3004
3005				// clear previous scheduled endScrollHandle
3006				clearTimeout( endScrollHandle );
3007
3008				infiniteScoll();
3009
3010				setTimeout( function() {
3011					waiting = false;
3012				}, 100 );
3013
3014				// schedule an extra execution of infiniteScoll() after 200ms
3015				// in case the scrolling stops in next 100ms.
3016				endScrollHandle = setTimeout( function() {
3017					waiting = false;
3018					infiniteScoll();
3019				}, 200 );
3020			} );
3021		}
3022
3023		/**
3024		 * Infinite scroll handler.
3025		 */
3026		function infiniteScoll() {
3027			var $navigation = $( '.woocommerce-navigation.ajax-navigation' ),
3028				$button = $( 'a', $navigation );
3029
3030			// When almost reach to the navigation.
3031			if ( konte.isVisible( $navigation ) && $button.length && !$button.hasClass( 'loading' ) ) {
3032				$button.addClass( 'loading' );
3033
3034				loadProducts( $button, function( respond ) {
3035					$button = $navigation.find( 'a' );
3036				} );
3037			}
3038		}
3039
3040		/**
3041		 * Ajax load products.
3042		 *
3043		 * @param jQuery $el Button element.
3044		 * @param function callback The callback function.
3045		 */
3046		function loadProducts( $el, callback ) {
3047			var $nav = $el.closest( '.woocommerce-navigation' ),
3048				url = $el.attr( 'href' );
3049
3050			$.get( url, function( response ) {
3051				var $content = $( '#main', response ),
3052					$list = $( 'ul.products', $content ),
3053					$products = $list.children(),
3054					$newNav = $( '.woocommerce-navigation.ajax-navigation', $content );
3055
3056				$products.each( function( index, product ) {
3057					$( product ).css( 'animation-delay', index * 100 + 'ms' );
3058				} );
3059
3060				$products.appendTo( $nav.siblings( 'ul.products' ).not('.product-categories').last() );
3061				$products.addClass( 'animated konteFadeInUp' );
3062
3063				if ( $newNav.length ) {
3064					$el.replaceWith( $( 'a', $newNav ) );
3065				} else {
3066					$nav.fadeOut( function() {
3067						$nav.remove();
3068					} );
3069				}
3070
3071				if ( 'function' === typeof callback ) {
3072					callback( response );
3073				}
3074
3075				$( document.body ).trigger( 'konte_products_loaded', [$products, true] );
3076
3077				if ( konte.data.shop_nav_ajax_url_change ) {
3078					window.history.pushState( null, '', url );
3079				}
3080			} );
3081		}
3082	};
3083
3084	/**
3085	 * Check if an element is in view-port or not
3086	 *
3087	 * @param jQuery el Targe element to check.
3088	 * @return boolean
3089	 */
3090	konte.isVisible = function( el ) {
3091		if ( el instanceof jQuery ) {
3092			el = el[0];
3093		}
3094
3095		if ( ! el ) {
3096			return false;
3097		}
3098
3099		var rect = el.getBoundingClientRect();
3100
3101		return rect.bottom > 0 &&
3102			rect.right > 0 &&
3103			rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
3104			rect.top < (window.innerHeight || document.documentElement.clientHeight);
3105	};
3106
3107	/**
3108	 * Proudcts quick search.
3109	 */
3110	konte.productsQuickSearch = function() {
3111		var $form = $( '.products-quick-search-form' );
3112
3113		if ( $.fn.select2 ) {
3114			$form.find( 'select' ).select2( {
3115				dir                    : konte.data.rtl ? 'rtl' : 'ltr',
3116				width                  : 'auto',
3117				minimumResultsForSearch: -1,
3118				dropdownCssClass       : 'products-quick-search-options',
3119				dropdownParent		   : $( '.products-quick-search-form' )
3120			} ).on( 'change', function() {
3121				$form.addClass( 'changed' );
3122			} );
3123		}
3124
3125		$form.find( 'select' ).on( 'change', function() {
3126			$form.addClass( 'changed' );
3127		} );
3128
3129		$form.on( 'submit', function( event ) {
3130			event.preventDefault();
3131
3132			var $container = $( 'ul.products.main-products' ),
3133				$inputs = $form.find( ':input:not(:checkbox):not(:button)' ),
3134				url = $form.attr( 'action' ),
3135				separator = url.indexOf( '?' ) !== -1 ? '&' : '?',
3136				params = $inputs.filter( function() {
3137					return $( this ).val() != 0;
3138				} ).serialize();
3139
3140			if ( params ) {
3141				url += separator + params;
3142			}
3143
3144			if ( $container.hasClass( 'layout-carousel' ) ) {
3145				window.location.href = url;
3146				return false;
3147			}
3148
3149			if ( !$container.length ) {
3150				$container = $( '<ul class="products"/>' );
3151				$form.closest( '.products-toolbar' ).siblings( '.woocommerce-info' ).replaceWith( $container );
3152			}
3153
3154			$form.addClass( 'filtering' );
3155			$form.find( 'select' ).prop( 'disabled', true );
3156			$container.addClass( 'loading' ).append( '<li class="loading-screen"><span class="spinner"></span></li>' );
3157
3158			$( document.body ).trigger( 'konte_quick_search_products_before_send_request', $container );
3159
3160			$.get( url, function( response ) {
3161				var $html = $( response ),
3162					$products = $html.find( '#main ul.products' ),
3163					$pagination = $container.next( 'nav' );
3164
3165				if ( !$products.length ) {
3166					$products = $html.find( '#main .woocommerce-info' );
3167					$( '.products-tools' ).addClass( 'out' );
3168
3169					$pagination.fadeOut();
3170					$container.replaceWith( $products );
3171				} else {
3172					var $nav = $products.next( 'nav' ),
3173						$order = $( 'form.woocommerce-ordering' );
3174
3175					if ( $nav.length ) {
3176						if ( $pagination.length ) {
3177							$pagination.replaceWith( $nav ).fadeIn();
3178						} else {
3179							$container.after( $nav );
3180						}
3181					} else {
3182						$pagination.fadeOut();
3183					}
3184
3185					// Modify the ordering form.
3186					$inputs.each( function() {
3187						var $input = $( this ),
3188							name = $input.attr( 'name' ),
3189							value = $input.val();
3190
3191						if ( name === 'orderby' ) {
3192							return;
3193						}
3194
3195						$order.find( 'input[name="' + name + '"]' ).remove();
3196
3197						if ( value !== '' && value != 0 ) {
3198							$( '<input type="hidden" name="' + name + '">' ).val( value ).appendTo( $order );
3199						}
3200					} );
3201
3202					// Replace the column selector.
3203					$( '.products-toolbar .columns-switcher' ).replaceWith( $html.find( '.products-toolbar .columns-switcher' ) );
3204
3205					// Replace result count.
3206					$( '.products-toolbar .woocommerce-result-count' ).replaceWith( $html.find( '.products-toolbar .woocommerce-result-count' ) );
3207
3208					// Replace tabs.
3209					$( '.products-toolbar .products-tabs' ).replaceWith( $html.find( '.products-toolbar .products-tabs' ) );
3210
3211					// Show the toolbar.
3212					$( '.products-tools' ).removeClass( 'out' );
3213
3214					$products.children().each( function( index, product ) {
3215						$( product ).css( 'animation-delay', index * 100 + 'ms' );
3216					} );
3217
3218					$container.replaceWith( $products );
3219
3220					$products.find( 'li.product' ).addClass( 'animated konteFadeInUp' );
3221
3222					$( document.body ).trigger( 'konte_products_loaded', [$products.children(), false] );
3223				}
3224
3225				$form.removeClass( 'changed filtering' );
3226				$form.find( 'select' ).prop( 'disabled', false );
3227				window.history.pushState( null, '', url );
3228
3229				$( document.body ).trigger( 'konte_products_quick_search_request_success', [$products.children()] );
3230			} );
3231		} );
3232	};
3233
3234	/**
3235	 * Handle products tools events.
3236	 */
3237	konte.productsTools = function() {
3238		var $window = $( window ),
3239			$tools = $( '.products-tools' );
3240
3241		// Products ordering.
3242		if ( $.fn.select2 ) {
3243			$tools.find( '.woocommerce-ordering select' ).select2( {
3244				dir                    : konte.data.rtl ? 'rtl' : 'ltr',
3245				width                  : 'auto',
3246				minimumResultsForSearch: -1,
3247				dropdownCssClass       : 'products-ordering',
3248				dropdownParent         : $tools.find( '.woocommerce-ordering' )
3249			} );
3250		}
3251
3252		// Products filter.
3253		var $filter = $tools.find( '#products-filter' );
3254
3255		if ( $filter.length && $filter.hasClass( 'dropdown-panel' ) ) {
3256			setDropdownFilterPosition();
3257
3258			$window.on( 'resize', setDropdownFilterPosition );
3259		}
3260
3261		// Toggle products filter.
3262		$( document.body ).on( 'click', '.products-tools .toggle-filters[data-toggle="dropdown"]', function( event ) {
3263			event.preventDefault();
3264
3265			$( $( this ).attr( 'href' ) ).fadeToggle( function() {
3266				$( this ).toggleClass( 'open' );
3267			} );
3268		} ).on( 'click', '.products-filter.dropdown-panel .button-close', function( event ) {
3269			event.preventDefault();
3270
3271			$( this ).closest( '.products-filter' ).fadeOut( function() {
3272				$( this ).removeClass( 'open' );
3273			} );
3274		} );
3275
3276		// Auto close filter when runing ajax.
3277		$( document.body ).on( 'konte_products_filter_before_send_request konte_products_filter_reseted', function() {
3278			if ( $filter.hasClass( 'offscreen-panel' ) ) {
3279				konte.closeOffCanvas( $filter );
3280			} else {
3281				$filter.fadeOut( function() {
3282					$filter.removeClass( 'open' );
3283				} );
3284			}
3285		} );
3286
3287		// Remove filtered field;
3288		$( '.products-tools .products-filter-toggle' ).on( 'click', 'a.remove-filtered', function( event ) {
3289			event.preventDefault();
3290
3291			var $el = $( this );
3292
3293			$( '.products-filter__activated a.remove-filtered[data-name="' + $el.data( 'name' ) + '"][data-value="' + $el.data( 'value' ) + '"]', '#products-filter' ).trigger( 'click' );
3294			$el.remove();
3295		} );
3296
3297		// Update filtered fields.
3298		if ( $filter.hasClass( 'dropdown-panel' ) ) {
3299			displayFilteredField( null, null );
3300			$( document.body ).on( 'konte_products_filter_widget_updated', displayFilteredField );
3301		}
3302
3303		/**
3304		 * Display filtered fields.
3305		 */
3306		function displayFilteredField( event, form ) {
3307			var $widget = form ? $( form ).closest( '.products-filter-widget' ) : $( '.products-filter-widget', '#products-filter' );
3308
3309			if ( ! $widget.length ) {
3310				return;
3311			}
3312
3313			var $toggle = $( '.products-tools .products-filter-toggle' );
3314
3315			$toggle.find( '.remove-filtered' ).remove();
3316			$widget.find( '.products-filter__activated a.remove-filtered' ).clone().appendTo( $toggle );
3317		}
3318
3319		/**
3320		 * Set the correct position of dropdown filter.
3321		 */
3322		function setDropdownFilterPosition() {
3323			var $sidebar = $( '#secondary' ),
3324				windowWidth = $window.width();
3325
3326			if ( windowWidth >= 992 ) {
3327				windowWidth -= konte.getVerticalHeaderWidth();
3328			}
3329
3330			$filter.width( windowWidth );
3331
3332			// Check if there is a sidebar
3333			var prop = 'margin-left';
3334			var value = -windowWidth / 2;
3335
3336			if ( konte.data.rtl ) {
3337				prop = 'margin-right';
3338			}
3339
3340			if ( windowWidth >= 992 ) {
3341				if ( $sidebar.length ) {
3342					if ( $( document.body ).hasClass( 'sidebar-left' ) ) {
3343						value = konte.data.rtl ? value + ($sidebar.outerWidth() / 2) : value - ($sidebar.outerWidth() / 2);
3344					} else {
3345						value = konte.data.rtl ? value - ($sidebar.outerWidth() / 2) : value + ($sidebar.outerWidth() / 2);
3346					}
3347
3348					$filter.css( prop, value );
3349				} else {
3350					$filter.css( prop, value );
3351				}
3352			} else {
3353				$filter.css( prop, value );
3354			}
3355		}
3356	};
3357
3358	/**
3359	 * Make the cart widget more flexible.
3360	 */
3361	konte.cartWidget = function() {
3362		if ( typeof woocommerce_params === 'undefined' ) {
3363			$( '.woocommerce-mini-cart-item .quantity .qty' ).prop( 'disabled', true );
3364
3365			$( document.body ).on( 'wc_fragments_refreshed removed_from_cart', function() {
3366				$( '.woocommerce-mini-cart-item .quantity .qty' ).prop( 'disabled', true );
3367			} );
3368
3369			return;
3370		}
3371
3372		var options = {
3373			onChange: function( data ) {
3374				var $row = data.$quantity.closest( '.woocommerce-mini-cart-item' ),
3375					key = $row.find( 'a.remove' ).data( 'cart_item_key' ),
3376					nonce = $row.find( '.woocommerce-mini-cart-item__qty' ).data( 'nonce' ),
3377					ajax_url = woocommerce_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'update_cart_item' );
3378
3379				if ( $.fn.block ) {
3380					$row.block( {
3381						message   : null,
3382						overlayCSS: {
3383							opacity   : 0.6,
3384							background: '#fff'
3385						}
3386					} );
3387				}
3388
3389				$.post(
3390					ajax_url, {
3391						cart_item_key: key,
3392						qty: data.current,
3393						security: nonce
3394					}, function( response ) {
3395						if ( !response || !response.fragments ) {
3396							return;
3397						}
3398
3399						if ( $.fn.unblock ) {
3400							$row.unblock();
3401						}
3402
3403						$( document.body ).trigger( 'added_to_cart', [response.fragments, response.cart_hash] );
3404
3405						// Trigger the fragment refresh event manually if necessary.
3406						if ( 'undefined' === typeof wc_add_to_cart_params ) {
3407							$( document.body ).trigger( 'wc_fragment_refresh' );
3408						}
3409					}, 'json' ).fail( function() {
3410						if ( $.fn.unblock ) {
3411							$row.unblock();
3412						}
3413
3414						return;
3415					} );
3416			}
3417		};
3418
3419		if ( $.fn.quantityDropdown ) {
3420			$( '.woocommerce-mini-cart-item .quantity .qty' ).quantityDropdown( options );
3421
3422			$( document.body ).on( 'wc_fragments_refreshed wc_fragments_loaded removed_from_cart added_to_cart', function() {
3423				$( '.woocommerce-mini-cart-item .quantity .qty' ).quantityDropdown( options );
3424			} );
3425		}
3426	};
3427
3428	/**
3429	 * Display a notification
3430	 */
3431	konte.shopNotifications = function() {
3432		if ( ! $.fn.notify ) {
3433			return;
3434		}
3435
3436		$.notify.addStyle( 'konte', {
3437			html: '<div><span class="svg-icon icon-success size-normal message-icon"><svg role="img"><use href="#success" xlink:href="#success"></use></svg></span><span data-notify-text/></div>'
3438		});
3439
3440		if ( konte.data.added_to_cart_notice ) {
3441			$( document.body ).on( 'added_to_cart', function() {
3442				$.notify( konte.data.added_to_cart_message, {
3443					position: konte.data.rtl ? 'top left' : 'top right',
3444					autoHideDelay: 2000,
3445					className: 'success',
3446					style: 'konte',
3447					showAnimation: 'fadeIn',
3448					hideAnimation: 'fadeOut'
3449				} );
3450			} );
3451		}
3452
3453		if ( konte.data.added_to_wishlist_notice ) {
3454			$( document.body ).on( 'added_to_wishlist', function() {
3455				$.notify( konte.data.added_to_wishlist_message, {
3456					autoHideDelay: 2000,
3457					className: 'success',
3458					style: 'konte',
3459					showAnimation: 'fadeIn',
3460					hideAnimation: 'fadeOut'
3461				} );
3462			} );
3463		}
3464	};
3465
3466	/**
3467	 * Scripts for page template "split.php"
3468	 */
3469	konte.pageTemplateSplit = function() {
3470		if ( !$( document.body ).hasClass( 'page-template-split' ) ) {
3471			return;
3472		}
3473
3474		var $window = $( window ),
3475			$topbar = $( '#topbar' ),
3476			ps = null;
3477
3478		// Scrollbar.
3479		if ( $window.width() >= 992 ) {
3480			ps = new PerfectScrollbar( $( '.split-page-content .entry-content' ).get( 0 ) );
3481		}
3482
3483		// Full height.
3484		$window.on( 'resize', function() {
3485			$( '.split-page.page' ).height( fullHeight() );
3486
3487			if ( $window.width() < 992 ) {
3488				if ( ps ) {
3489					ps.destroy();
3490				}
3491
3492				ps = null;
3493			} else {
3494				ps = new PerfectScrollbar( $( '.split-page-content .entry-content' ).get( 0 ) );
3495			}
3496		} );
3497
3498		$( '.split-page.page' ).height( fullHeight() );
3499
3500		/**
3501		 * Get the windown height.
3502		 */
3503		function fullHeight() {
3504			var height = $window.height();
3505
3506			if ( $topbar.length ) {
3507				height -= $topbar.outerHeight();
3508			}
3509
3510			return height;
3511		}
3512	};
3513
3514	/**
3515	 * Youtube video background.
3516	 */
3517	konte.videoBackground = function() {
3518		var $player = $( '.video-background' );
3519
3520		if ( !$player.length ) {
3521			return;
3522		}
3523
3524		var player = null;
3525		var $screen = $player.parent();
3526
3527		// Scale video function definition moved up
3528		var scaleVideo = function() {
3529			if (!player || !player.setSize || typeof player.setSize !== 'function') {
3530				return;
3531			}
3532
3533			var width = $screen.width(),
3534				pWidth,
3535				height = $screen.height(),
3536				pHeight,
3537				ratio = 16 / 9,
3538				$iframe = $screen.find('.video-background');
3539
3540			try {
3541				if (width / ratio < height) {
3542					pWidth = Math.ceil(height * ratio);
3543					player.setSize(pWidth, height);
3544					$iframe.css({
3545						left: (width - pWidth) / 2,
3546						top : 0
3547					});
3548				} else {
3549					pHeight = Math.ceil(width / ratio);
3550					player.setSize(width, pHeight);
3551					$iframe.css({
3552						left: 0,
3553						top : (height - pHeight) / 2
3554					});
3555				}
3556			} catch (e) {
3557				console.warn('Failed to scale video:', e);
3558			}
3559		};
3560
3561		// Initialize player function
3562		var initPlayer = function() {
3563			var mute = $player.data('mute');
3564
3565			player = new YT.Player($player.attr('id'), {
3566				videoId: $player.data('video_id'),
3567				events: {
3568					'onReady': function(event) {
3569						// Add a small delay before scaling
3570						setTimeout(function() {
3571							scaleVideo();
3572							$screen.find('.video-background').css('opacity', 1);
3573
3574							event.target.mute();
3575							event.target.playVideo();
3576						}, 100);
3577					},
3578					'onStateChange': function(event) {
3579						if (event.data === YT.PlayerState.ENDED) {
3580							event.target.playVideo();
3581						}
3582					}
3583				},
3584				playerVars: {
3585					autoplay: 1,
3586					loop: 1,
3587					mute: 1,
3588					autohide: 1,
3589					modestbranding: 0,
3590					rel: 0,
3591					showinfo: 0,
3592					controls: 0,
3593					disablekb: 1,
3594					enablejsapi: 1,
3595					iv_load_policy: 3,
3596					playsinline: 1
3597				}
3598			});
3599		};
3600
3601		// Debounced resize handler
3602		var resizeTimeout;
3603		$(window).on('resize', function() {
3604			clearTimeout(resizeTimeout);
3605			resizeTimeout = setTimeout(scaleVideo, 150);
3606		});
3607
3608		// Better YouTube API loading handling
3609		if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') {
3610				// Create global callback
3611				window.onYouTubeIframeAPIReady = function() {
3612					initPlayer();
3613				};
3614
3615				// Load YouTube API
3616				var tag = document.createElement('script');
3617				tag.src = 'https://www.youtube.com/iframe_api';
3618				var firstScriptTag = document.getElementsByTagName('script')[0];
3619				firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
3620		} else {
3621			// If API is already loaded, initialize directly
3622			initPlayer();
3623		}
3624	};
3625
3626	/**
3627	 * Init masonry layout for template Flex Posts.
3628	 */
3629	konte.pageTemplateFlexPosts = function() {
3630		var $posts = $( '#flex-posts' ),
3631			$window = $( window );
3632
3633		if ( !$posts.length || !$.fn.masonry ) {
3634			return;
3635		}
3636
3637		// Init masonry layout
3638		var options = {
3639			itemSelector:       '.flex_post',
3640			percentPosition:    true,
3641			transitionDuration: 0,
3642			isRTL:              !! konte.data.rtl
3643		};
3644
3645		// Add class left-item and right-item
3646		$posts.on( 'layoutComplete', function( event ) {
3647			var $items = $posts.children();
3648
3649			if ( konte.data.rtl ) {
3650				$items.filter( function() {
3651					return parseInt( $( this ).get( 0 ).style.right ) === 0;
3652				} ).removeClass( 'left-item' ).addClass( 'right-item' );
3653
3654				$items.filter( function() {
3655					return $( this ).get( 0 ).style.right === '50%';
3656				} ).removeClass( 'right-item' ).addClass( 'left-item' );
3657			} else {
3658				$items.filter( function() {
3659					return parseInt( $( this ).get( 0 ).style.left ) === 0;
3660				} ).removeClass( 'right-item' ).addClass( 'left-item' );
3661
3662				$items.filter( function() {
3663					return $( this ).get( 0 ).style.left === '50%';
3664				} ).removeClass( 'left-item' ).addClass( 'right-item' );
3665			}
3666		} );
3667
3668		initFlexPostsMasonry();
3669
3670		$window.on( 'resize', initFlexPostsMasonry );
3671
3672		// Support Jetpack lazy loads.
3673		var layoutHandle;
3674
3675		$posts.on( 'jetpack-lazy-loaded-image', 'img', function() {
3676			if ( ! $posts.hasClass( 'masonry' ) ) {
3677				initFlexPostsMasonry();
3678			}
3679
3680			clearTimeout( layoutHandle );
3681
3682			layoutHandle = setTimeout( function() {
3683				$posts.masonry( 'layout' );
3684			}, 100 );
3685		} );
3686
3687		// Ajax load more posts
3688		$( 'body.page-template-flex-posts' ).on( 'click', '.navigation.next-posts-navigation a', function( event ) {
3689			event.preventDefault();
3690
3691			var $el = $( this ),
3692				url = $el.attr( 'href' );
3693
3694			if ( $el.hasClass( 'loading' ) ) {
3695				return;
3696			}
3697
3698			$el.addClass( 'loading' );
3699
3700			$.get( url, function( response ) {
3701				var $content = $( '#main', response ),
3702					$_posts = $( '.flex_post', $content ),
3703					$nav = $( '.next-posts-navigation', $content );
3704
3705				$_posts.addClass( 'animated' ).appendTo( $posts );
3706				;
3707				$posts.masonry( 'appended', $_posts ).masonry();
3708
3709				$_posts.imagesLoaded().progress( function() {
3710					$posts.masonry( 'layout' );
3711				} );
3712
3713				if ( $nav.length ) {
3714					$el.replaceWith( $( 'a', $nav ) );
3715				} else {
3716					$el.removeClass( 'loading' ).closest( '.next-posts-navigation' ).fadeOut();
3717				}
3718
3719				window.history.pushState( null, '', url );
3720
3721				if ( typeof trigger !== undefined ) {
3722					$_posts.attr( 'data-scroll', '' );
3723					trigger.bind( $_posts.get() );
3724				}
3725
3726				$( document.body ).trigger( 'konte_flex_posts_loaded', [$_posts] );
3727			} );
3728		} );
3729
3730		if ( typeof ScrollTrigger !== undefined ) {
3731			$posts.children().attr( 'data-scroll', '' ).addClass( 'animated' );
3732
3733			var trigger = new ScrollTrigger( {
3734				toggle: {
3735					visible: 'konteFadeInUp',
3736					hidden : ''
3737				},
3738				offset: {
3739					x: 0,
3740					y: -20
3741				},
3742				once  : true
3743			}, document.body, window );
3744		}
3745
3746		/**
3747		 * Init flex posts masonry
3748		 */
3749		function initFlexPostsMasonry() {
3750			if ( $window.width() >= 992 ) {
3751				if ( $posts.hasClass( 'masonry' ) ) {
3752					return;
3753				}
3754
3755				$posts.masonry( options );
3756
3757				// Layout Masonry after each image loads.
3758				$posts.imagesLoaded().progress( function() {
3759					$posts.masonry( 'layout' );
3760				} );
3761			} else {
3762				if ( ! $posts.hasClass( 'masonry' ) ) {
3763					return;
3764				}
3765
3766				$posts.masonry( 'destroy' );
3767			}
3768		}
3769	};
3770
3771	/**
3772	 * Scroll down arrow sticky.
3773	 * This arrow appears on flex posts template and portfolio page.
3774	 */
3775	konte.stickyScrollDown = function() {
3776		var $window = $( window ),
3777			$arrow = $( '.sticky-scrolldown' ),
3778			waiting = false,
3779			endScrollHandle,
3780			offset = $( '#masthead' ).height();
3781
3782		if ( !$arrow.length ) {
3783			return;
3784		}
3785
3786		$arrow.on( 'click', function() {
3787			$( 'html, body' ).animate( {scrollTop: $window.scrollTop() + $window.height()}, 800 );
3788		} );
3789
3790		toggleArrow();
3791
3792		$window.on( 'scroll', function() {
3793			if ( waiting ) {
3794				return;
3795			}
3796
3797			if ( $window.width() < 1440 ) {
3798				return;
3799			}
3800
3801			waiting = true;
3802
3803			// clear previous scheduled endScrollHandle
3804			clearTimeout( endScrollHandle );
3805
3806			toggleArrow();
3807
3808			setTimeout( function() {
3809				waiting = false;
3810			}, 100 );
3811
3812			// schedule an extra execution of toggleArrow() after 200ms
3813			// in case the scrolling stops in next 100ms.
3814			endScrollHandle = setTimeout( function() {
3815				waiting = false;
3816				toggleArrow();
3817			}, 200 );
3818		} );
3819
3820		/**
3821		 * Toggle social icons on footer.
3822		 */
3823		function toggleArrow() {
3824			if ( $window.scrollTop() >= offset ) {
3825				$arrow.fadeOut();
3826			} else {
3827				$arrow.fadeIn();
3828			}
3829		}
3830	};
3831
3832	/**
3833	 * Sticky social icon on page template Flex Posts.
3834	 */
3835	konte.stickySocials = function() {
3836		var $footer = $( '#colophon' ),
3837			$socials = $( '#sticky-socials' ),
3838			$window = $( window ),
3839			waiting = false,
3840			endScrollHandle;
3841
3842		if ( !$socials.length ) {
3843			return;
3844		}
3845
3846		toggleSocials();
3847
3848		$window.on( 'scroll', function() {
3849			if ( waiting ) {
3850				return;
3851			}
3852
3853			if ( $window.width() < 1440 ) {
3854				return;
3855			}
3856
3857			waiting = true;
3858
3859			// clear previous scheduled endScrollHandle
3860			clearTimeout( endScrollHandle );
3861
3862			toggleSocials();
3863
3864			setTimeout( function() {
3865				waiting = false;
3866			}, 100 );
3867
3868			// schedule an extra execution of toggleSocials() after 200ms
3869			// in case the scrolling stops in next 100ms.
3870			endScrollHandle = setTimeout( function() {
3871				waiting = false;
3872				toggleSocials();
3873			}, 200 );
3874		} );
3875
3876		/**
3877		 * Toggle social icons on footer.
3878		 */
3879		function toggleSocials() {
3880			if ( $window.scrollTop() + $window.height() >= $footer.offset().top - 200 ) {
3881				$socials.fadeOut();
3882			} else {
3883				$socials.fadeIn();
3884			}
3885		}
3886	};
3887
3888	/**
3889	 * Open share links in a new popup window
3890	 */
3891	konte.openShareLinks = function() {
3892		var $window = $( window );
3893
3894		$( document.body ).on( 'click', '.social-share-link', function( event ) {
3895			if ( $window.width() <= 1024 ) {
3896				return;
3897			}
3898
3899			event.preventDefault();
3900
3901			popupShare( $( this ).attr( 'href' ), '', 500, 550 );
3902		} );
3903
3904		/**
3905		 * Open new window at middle of screen
3906		 */
3907		function popupShare( url, title, w, h ) {
3908			// Fixes dual-screen position
3909			var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : window.screenX,
3910				dualScreenTop = window.screenTop != undefined ? window.screenTop : window.screenY,
3911
3912				width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width,
3913				height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height,
3914
3915				systemZoom = width / window.screen.availWidth,
3916				left = (width - w) / 2 / systemZoom + dualScreenLeft,
3917				top = (height - h) / 2 / systemZoom + dualScreenTop;
3918
3919			var newWindow = window.open(url, title, 'scrollbars=yes, width=' + w / systemZoom + ', height=' + h / systemZoom + ', top=' + top + ', left=' + left);
3920
3921			// Puts focus on the newWindow
3922			if ( window.focus ) {
3923				newWindow.focus();
3924			}
3925		}
3926	};
3927
3928	/**
3929	 * Fix full width row of WPB with vertical header.
3930	 */
3931	konte.fixVCRowsWithVerticalHeader = function() {
3932		if ( !$( document.body ).hasClass( 'header-vertical' ) ) {
3933			return;
3934		}
3935
3936		$( document ).on( 'vc-full-width-row-single', function( event, data ) {
3937			var width = konte.getVerticalHeaderWidth();
3938
3939			data.el.css( {
3940				width: data.width - width,
3941				left : data.offset + width
3942			} );
3943
3944			if ( konte.data.rtl ) {
3945				data.el.css( {
3946					right: data.offset + width
3947				} );
3948			} else {
3949				data.el.css( {
3950					left: data.offset + width
3951				} );
3952			}
3953		} );
3954	};
3955
3956	/**
3957	 * Get the width of vertical header.
3958	 */
3959	konte.getVerticalHeaderWidth = function() {
3960		var width = 0;
3961
3962		if ( $( document.body ).hasClass( 'header-vertical' ) ) {
3963			var $header = $( '#masthead' );
3964
3965			if ( $header.hasClass( 'header-v10' ) ) {
3966				$header = $header.find( '.header-main .header-left-items' );
3967			}
3968
3969			if ( $header.is( ':visible' ) ) {
3970				width = $header.outerWidth();
3971			}
3972
3973			return width;
3974		}
3975
3976		return width;
3977	};
3978
3979	/**
3980	 * Responsive video
3981	 */
3982	konte.responsiveVideos = function() {
3983		if ( !$.fn.fitVids ) {
3984			return;
3985		}
3986
3987		$( '.entry-content' ).fitVids();
3988	};
3989
3990	/**
3991	 * Open popup.
3992	 */
3993	konte.popup = function() {
3994		if ( ! konte.data.popup ) {
3995			return;
3996		}
3997
3998		var days = parseInt( konte.data.popup_frequency ),
3999			delay = parseInt( konte.data.popup_visible_delay );
4000
4001		if ( days > 0 && document.cookie.match( /^(.*;)?\s*konte_popup\s*=\s*[^;]+(.*)?$/ ) ) {
4002			return;
4003		}
4004
4005		delay = Math.max( delay, 0 );
4006		delay = 'delay' === konte.data.popup_visible ? delay : 0;
4007
4008		$( window ).on( 'load', function() {
4009			setTimeout( function() {
4010				konte.openModal( '#popup-modal' );
4011			}, delay * 1000 );
4012		} );
4013
4014		$( document.body ).on( 'konte_modal_closed', function( event, modal ) {
4015			if ( !$( modal ).closest( '.modal' ).hasClass( 'popup-modal' ) ) {
4016				return;
4017			}
4018
4019			var date = new Date(),
4020				value = date.getTime();
4021
4022			date.setTime( date.getTime() + (days * 24 * 60 * 60 * 1000) );
4023
4024			document.cookie = 'konte_popup=' + value + ';expires=' + date.toGMTString() + ';path=/';
4025		} );
4026
4027		// Support close popup with a helper class.
4028		$( document.body ).on( 'click', '.popup-modal .close-popup-trigger', function() {
4029			konte.closeModal( '.popup-modal' );
4030		} );
4031	};
4032
4033	/**
4034	 * Preloader.
4035	 */
4036	konte.preloader = function() {
4037		var $preloader = $( '#preloader' );
4038
4039		if ( ! $preloader.length ) {
4040			return;
4041		}
4042
4043		var ignorePreloader = false;
4044
4045		$( document.body ).on( 'click', 'a[href^=mailto], a[href^=tel]', function() {
4046			ignorePreloader = true;
4047		} );
4048
4049		$( window ).on( 'beforeunload', function( event ) {
4050			if ( ! ignorePreloader ) {
4051				$preloader.fadeIn();
4052			}
4053
4054			ignorePreloader = false;
4055		} );
4056
4057		setTimeout( function() {
4058			$preloader.fadeOut();
4059		}, 200 );
4060
4061		window.onpageshow = function( event ) {
4062			if ( event.persisted ) {
4063				setTimeout( function() {
4064					$preloader.fadeOut();
4065				}, 200 );
4066			}
4067		};
4068	};
4069
4070	/**
4071	 * Handle mobile menu toggle.
4072	 */
4073	konte.mobileMenu = function() {
4074		var $mobileMenu = $( '#mobile-menu' );
4075
4076		$mobileMenu.find( '' )
4077
4078		// Add class 'open' to current menu item.
4079		$mobileMenu.find( '.menu > .menu-item-has-children, .menu > li > ul > .menu-item-has-children' ).filter( function() {
4080			return $( this ).hasClass( 'current-menu-item' ) || $( this ).hasClass( 'current-menu-ancestor' );
4081		} ).addClass( 'open' );
4082
4083		// Toggle submenu.
4084		$mobileMenu.on( 'click', '.menu-item-has-children > a', function( event ) {
4085			var $li = $( this ).parent();
4086
4087			if ( $li.hasClass( 'open' ) && $li.hasClass( 'clicked' ) && '#' !== $( this ).attr( 'href' ) ) {
4088				return true;
4089			}
4090
4091			event.stopPropagation();
4092			event.preventDefault();
4093
4094			$li.addClass( 'clicked' );
4095
4096			$li.toggleClass( 'open' ).children( 'ul' ).slideToggle();
4097			$li.siblings( '.open' ).removeClass( 'open clicked' ).children( 'ul' ).slideUp();
4098		} ).on( 'click', '.menu-item-has-children > .toggle', function( event ) {
4099			event.stopPropagation();
4100			event.preventDefault();
4101
4102			var $li = $( this ).parent();
4103
4104			$li.toggleClass( 'open' ).children( 'ul' ).slideToggle();
4105			$li.siblings( '.open' ).removeClass( 'open' ).children( 'ul' ).slideUp();
4106		} );
4107
4108		// Close other panels.
4109		$mobileMenu.on( 'click', '[data-toggle="off-canvas"], [data-toggle="modal"]', function() {
4110			if ( 'mobile-menu' !== $( this ).data( 'target' ) ) {
4111				konte.closeModal();
4112				konte.closeOffCanvas();
4113			}
4114		} );
4115	};
4116
4117	/**
4118	 * Responsive for single product v3.
4119	 */
4120	konte.responsiveProductV3 = function() {
4121		var $window = $( window ),
4122			$product = $( '.woocommerce div.product.layout-v3' );
4123
4124		if ( !$product.length ) {
4125			return;
4126		}
4127
4128		updateLayout();
4129
4130		$window.on( 'resize', updateLayout );
4131
4132		// Change tabs position
4133		function updateLayout() {
4134			if ( $window.width() < 1200 ) {
4135				$( '.woocommerce-product-cart form.cart', $product ).insertBefore( $( '.summary > .product_meta', $product ) );
4136			} else {
4137				$( '.summary > form.cart', $product ).appendTo( $( '.woocommerce-product-cart', $product ) );
4138			}
4139		}
4140	}
4141
4142	/**
4143	 * Portfolio mansonry
4144	 */
4145	konte.portfolioMasonry = function() {
4146		var $portfolio = $( '.portfolio-projects--masonry' );
4147
4148		if ( ! $portfolio.length || ! $.fn.masonry ) {
4149			return;
4150		}
4151
4152		// Init masonry layout
4153		var $window = $( window ),
4154			options = {
4155				itemSelector:       '.portfolio',
4156				percentPosition:    true,
4157				transitionDuration: 0,
4158				isRTL:              !! konte.data.rtl
4159			};
4160
4161		initPortfolioMasonry();
4162
4163		$window.on( 'resize', initPortfolioMasonry );
4164
4165		// Layout items when using ajax load.
4166		$( document.body ).on( 'konte_posts_loaded', function( event, $posts, append ) {
4167			if ( $window.width() < 767 ) {
4168				return;
4169			}
4170
4171			if ( append ) {
4172				$portfolio.masonry( 'appended', $posts );
4173			} else {
4174				$portfolio.masonry( 'reloadItems' );
4175			}
4176
4177			setTimeout( function() {
4178				$portfolio.masonry( 'layout' );
4179			}, $posts.length * 50 + 50 );
4180
4181			$posts.imagesLoaded().progress( function() {
4182				$portfolio.masonry( 'layout' );
4183			} );
4184		} );
4185
4186		// Support Jetpack lazy loads.
4187		var layoutHandle;
4188
4189		$portfolio.on( 'jetpack-lazy-loaded-image', 'img', function() {
4190			if ( ! $portfolio.hasClass( 'masonry' ) ) {
4191				initPortfolioMasonry();
4192			}
4193
4194			clearTimeout( layoutHandle );
4195
4196			layoutHandle = setTimeout( function() {
4197				$portfolio.masonry( 'layout' );
4198			}, 100 );
4199		} );
4200
4201		/**
4202		 * Init portfolio masonry
4203		 */
4204		function initPortfolioMasonry() {
4205			if ( $window.width() >= 767 ) {
4206				if ( $portfolio.hasClass( 'masonry' ) ) {
4207					$portfolio.masonry( 'layout' );
4208				}
4209
4210				$portfolio.masonry( options );
4211
4212				// Layout Masonry after each image loads.
4213				$portfolio.imagesLoaded().progress( function() {
4214					$portfolio.masonry( 'layout' );
4215				} );
4216			} else {
4217				if ( ! $portfolio.hasClass( 'masonry' ) ) {
4218					return;
4219				}
4220
4221				$portfolio.masonry( 'destroy' );
4222			}
4223		}
4224	};
4225
4226	/**
4227	 * Ajax filter portfolio
4228	 */
4229	konte.portfolioFilter = function() {
4230		var $filter = $( '.portfolio-filter' ),
4231			$portfolio = $( '.portfolio-projects' ),
4232			$nav = $portfolio.siblings( '.navigation' );
4233
4234		if ( ! $filter.length || ! $portfolio.length ) {
4235			return;
4236		}
4237
4238		$filter.on( 'click', 'a', function( event ) {
4239			event.preventDefault();
4240
4241			var $link = $( this ),
4242				$active = $link.siblings( '.active' ),
4243				url = $link.attr( 'href' );
4244
4245			if ( $link.hasClass( 'active' ) ) {
4246				return;
4247			}
4248
4249			$link.addClass( 'active' );
4250			$active.removeClass( 'active' );
4251
4252			$portfolio.fadeIn().addClass( 'loading' ).append( '<div class="loading-screen"><span class="spinner"></span></div>' );
4253
4254			$.get( url, function( response ) {
4255				var $_portfolio = $( '.portfolio-projects', response ),
4256					$_projects = $( '.hentry', $_portfolio ),
4257					$_nav = $_portfolio.siblings( '.navigation' );
4258
4259				$portfolio.html( '' ).removeClass( 'loading' );
4260
4261				// If there is no project.
4262				if ( ! $_portfolio.length ) {
4263					$portfolio.fadeOut();
4264					$nav.fadeOut();
4265
4266					return;
4267				}
4268
4269				$_projects.each( function( index, project ) {
4270					$( project ).css( 'animation-delay', index * 100 + 'ms' );
4271				} );
4272
4273				$portfolio.append( $_projects );
4274
4275				$_projects.addClass( 'animated konteFadeInUp' );
4276
4277				if ( $_nav.length ) {
4278					if ( $nav.length ) {
4279						$nav.html( $_nav.html() ).fadeIn();
4280					} else {
4281						$portfolio.after( $_nav );
4282						$nav = $_nav;
4283					}
4284				} else {
4285					$nav.fadeOut();
4286				}
4287
4288				window.history.pushState( null, '', url );
4289				$( document.body ).trigger( 'konte_posts_loaded', [$_projects, false] );
4290			} ).fail( function() {
4291				$link.removeClass( 'active' );
4292				$active.addClass( 'active' );
4293
4294				$portfolio.children( '.loading-screen' ).remove();
4295				$portfolio.removeClass( 'loading' );
4296			} );
4297		} );
4298	};
4299
4300	/**
4301	 * Back to top icon
4302	 */
4303	konte.backToTop = function () {
4304		var $button = $( '#gotop' ),
4305			$window = $( window ),
4306			waiting = false,
4307			endScrollHandle;
4308
4309		$button.on( 'click', function ( e ) {
4310			e.preventDefault();
4311
4312			$( 'html, body' ).animate( {scrollTop: 0}, 800 );
4313		} );
4314
4315		if ( $button.length ) {
4316			toggleButton();
4317
4318			$window.on( 'scroll', function() {
4319				if ( waiting ) {
4320					return;
4321				}
4322
4323				waiting = true;
4324
4325				// clear previous scheduled endScrollHandle
4326				clearTimeout( endScrollHandle );
4327
4328				toggleButton();
4329
4330				setTimeout( function() {
4331					waiting = false;
4332				}, 100 );
4333
4334				// schedule an extra execution of toggleArrow() after 200ms
4335				// in case the scrolling stops in next 100ms.
4336				endScrollHandle = setTimeout( function() {
4337					waiting = false;
4338					toggleButton();
4339				}, 200 );
4340			} );
4341		}
4342
4343		/**
4344		 * Toggle the button when scrolling
4345		 */
4346		function toggleButton() {
4347			if ( $window.scrollTop() < $window.height() * 1.5 ) {
4348				$button.fadeOut();
4349			} else {
4350				$button.fadeIn();
4351			}
4352		}
4353	};
4354
4355	/**
4356	 * Support lazy load events
4357	 */
4358	konte.lazyLoadImages = function() {
4359		var lazyLoadImagesEvent;
4360
4361		$( document.body ).on( 'post-load konte_posts_loaded konte_products_loaded konte_products_quick_search_request_success konte_flex_posts_loaded konte_product_quickview_loaded konte_lazy_load_images', function() {
4362			try {
4363				lazyLoadImagesEvent = new Event( 'jetpack-lazy-images-load', {
4364					bubbles: true,
4365					cancelable: true
4366				} );
4367			} catch ( e ) {
4368				lazyLoadImagesEvent = document.createEvent( 'Event' )
4369				lazyLoadImagesEvent.initEvent( 'jetpack-lazy-images-load', true, true );
4370			}
4371
4372			setTimeout( function() {
4373				document.body.dispatchEvent( lazyLoadImagesEvent );
4374			}, 100 );
4375		} );
4376	};
4377
4378	/**
4379	 * Update the height of product gallery with Jetpack lazy loads.
4380	 */
4381	konte.supportJetpackLazyLoadImagesOnProductGallery = function() {
4382		$( 'div.product' ).each( function() {
4383			var $product = $( this );
4384
4385			if ( $product.hasClass( 'layout-v2' ) || $product.hasClass( 'layout-v5' ) ) {
4386				return;
4387			}
4388
4389			// Trigger resize event after main image loads to correct the gallery size.
4390			$( '.woocommerce-product-gallery', $product ).one( 'jetpack-lazy-loaded-image load', '.wp-post-image', function() {
4391				var $image = $( this );
4392
4393				if ( $image ) {
4394					setTimeout( function() {
4395						var setHeight = $image.closest( '.woocommerce-product-gallery__image' ).height();
4396						var $viewport = $image.closest( '.flex-viewport' );
4397
4398						if ( ! $viewport.length ) {
4399							$viewport = $image.closest( '.woocommerce-product-gallery' );
4400						}
4401
4402						if ( setHeight && $viewport.length ) {
4403							$viewport.height( setHeight );
4404						}
4405					}, 100 );
4406				}
4407			} );
4408		} );
4409
4410	}
4411
4412	/**
4413	 * Support mega menu tabs.
4414	 */
4415	konte.mainMenuTabs = function() {
4416		$( '.main-navigation' ).on( 'click', '.menu-item--tab, .menu-item--tab a', function( event ) {
4417			event.preventDefault();
4418			event.stopPropagation();
4419
4420			var $tab = $( this ).closest( '.menu-item--tab' );
4421
4422			if ( $tab.hasClass( 'active' ) ) {
4423				return;
4424			}
4425
4426			$tab.addClass( 'active' ).attr( 'aria-selected', 'true' ).siblings().removeClass( 'active' ).attr( 'aria-selected', 'false' );
4427
4428			$tab.closest( '.menu-item-mega' ).find( '#' + $tab.attr( 'aria-controls' ) ).addClass( 'active' ).siblings().removeClass( 'active' );
4429		} );
4430	}
4431
4432	/**
4433	 * Fire when document ready
4434	 */
4435	$( function() {
4436		konte.init();
4437	} );
4438})( 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.