PageSourceSearch

https://diamant-strass-dmc.com/wp-content/plugins/woocommerce-side…/assets/js/xoo-wsc-main.js?ver=4.9.1

js diamant-strass-dmc.com collected 2026-10-04 02:17:13 UTC 45,091 bytes, 1,915 lines download raw bytes

1jQuery(document).ready(function($){
2
3	var isCartPage 		= xoo_wsc_params.isCart == '1',
4		isCheckoutPage 	= xoo_wsc_params.isCheckout == '1';
5
6
7	var get_wcurl = function( endpoint ) {
8		return xoo_wsc_params.wc_ajax_url.toString().replace(
9			'%%endpoint%%',
10			endpoint
11		);
12	};
13
14
15	var Notice = {
16
17		timeout: null,
18
19		markupTimeout: null,
20
21		$cartNoticeCont: function(){
22			return $('.xoo-wsc-markup').find('.xoo-wsc-notice-container');
23		},
24
25		$markupNoticeCont: function(){
26			return $('.xoo-wsc-markup-notices')
27		},
28
29		add: function( notice, type = 'success', clearPrevious = true ){
30
31			if( clearPrevious ){
32				Notice.$cartNoticeCont().html('');
33			}
34
35			var noticeHTML = type === 'success' ? xoo_wsc_params.html.successNotice.toString().replace( '%s%', notice ) : xoo_wsc_params.html.errorNotice.toString().replace( '%s%', notice );
36
37			Notice.$cartNoticeCont().html( noticeHTML );
38
39		},
40
41
42		setHTML: function(noticeHTML){
43			Notice.$cartNoticeCont().add( Notice.$markupNoticeCont() ).html(noticeHTML);
44		},
45
46		showNotification: function(){
47
48			if( !cart.isOpen() ){
49				Notice.showMarkupNotice();
50				return;
51			}
52
53			Notice.$cartNoticeCont().slideDown();
54			
55			clearTimeout(Notice.timeout);
56
57			Notice.timeout = setTimeout(function(){
58				Notice.$cartNoticeCont().slideUp('slow');
59			}, xoo_wsc_params.notificationTime );
60
61		},
62
63
64		hideNotification: function(){
65			Notice.$cartNoticeCont().hide();
66		},
67
68		hideMarkupNotice: function(){
69			Notice.$markupNoticeCont().removeClass('xoo-wsc-active');
70		},
71
72
73		showMarkupNotice: function(){
74
75			var $markupNotice = Notice.$markupNoticeCont();
76
77			var $noticeCont = $markupNotice.find('.xoo-wsc-notice-container .xoo-wsc-notices');
78
79			if( !$noticeCont.length || $noticeCont.children().length === 0 ) return;
80
81			setTimeout(function(){$markupNotice.addClass('xoo-wsc-active')},10);
82			
83			clearTimeout(Notice.markupTimeout);
84
85			Notice.markupTimeout = setTimeout(function(){
86				$markupNotice.removeClass('xoo-wsc-active');
87			},xoo_wsc_params.notificationTime )
88		}
89	}
90
91	var masonryInitialised = {};
92
93	function initMasonryLayout( type = '' ){
94
95		var layouts = {
96			saveLater: {'.xoo-wsc-savl-column': '.xoo-wsc-savl-prod-cont'},
97			cart: {'.xoo-wsc-pattern-card': '.xoo-wsc-product-cont'},
98			suggested: {'.xoo-wsc-sp-column ul.xoo-wsc-sp-slider': '.xoo-wsc-sp-prod-cont'}
99		};
100
101		var initLayouts = {};
102
103		if( type ){
104			if( Array.isArray( type ) ){
105				$.each( type, function(index, type_val ){
106					initLayouts[ type_val ] = layouts[ type_val ];
107				} )
108			}
109			else{
110				initLayouts[type] = layouts[type];
111			}
112			
113		}else{
114			initLayouts = layouts;
115		}
116
117
118		$.each( initLayouts, function(type, layout){
119
120			if( masonryInitialised[type] &&  document.body.contains( masonryInitialised[type][0] ) ) return true;
121
122			$.each( layout, function(cont, childClass){
123				if( $(cont).length && $(cont).is(':visible') ){
124					$(cont).masonry({
125						// options
126						itemSelector: childClass,
127						columnWidth: childClass, /* Each column takes 50% */
128						percentPosition: true
129					});
130					masonryInitialised[type] = $(cont);
131				}
132			})
133		})
134
135		
136	}
137
138
139	var QuickView  = {
140
141		init: function(){
142			$( document.body ).on( 'found_variation', '.xoo-wsc-qv-container .variations_form', QuickView.onVariationSelect );
143			$( document.body ).on( 'reset_data hide_variation', '.xoo-wsc-qv-container .variations_form', QuickView.onVariationReset );
144		},
145
146		load: function(){
147
148			var $form = $( document.body ).find('.xoo-wsc-qv-container .variations_form');
149
150			if( !$form.length ) return;
151
152			$form.each(function () {
153				$(this).wc_variation_form();
154				$(this).find('.variations select').change();
155			});
156
157		},
158
159		onVariationSelect: function( event, variation ){
160
161			if( !variation || !variation.image || !variation.image.src ) return;
162
163			const $container 	= $( this ).closest('.xoo-wsc-qv-container');
164			const $img 			= $container.find('.xoo-qv-product-image');
165
166	        QuickView.storeOriginalImageAttrs( $container );
167
168			$img.attr({
169				src    : variation.image.src,
170				alt    : variation.image.alt || '',
171				width  : variation.image.src_w || '',
172				height : variation.image.src_h || ''
173			});
174
175			if( variation.image.srcset ){
176				$img.attr( 'srcset', variation.image.srcset );
177			}
178			else{
179				$img.removeAttr( 'srcset' );
180			}
181
182			if( variation.image.sizes ){
183				$img.attr( 'sizes', variation.image.sizes );
184			}
185			else{
186				$img.removeAttr( 'sizes' );
187			}
188
189		},
190
191		onVariationReset: function(){
192			const $img = $( this ).closest('.xoo-wsc-qv-container').find('.xoo-qv-product-image');
193			QuickView.resetImage( $img );
194		},
195
196		storeOriginalImageAttrs: function( $container ){
197
198	        const $img = $container.find('.xoo-qv-product-image');
199
200	        if( !$img.length || $img.data('xoo-originalized') ) return;
201
202			[ 'src', 'srcset', 'sizes', 'alt', 'width', 'height' ].forEach(function( attr ){
203
204				$img.attr( 'data-o_' + attr, $img.attr( attr ) || '' );
205
206			});
207
208			$img.data('xoo-originalized', true);
209	    },
210
211	    resetImage: function( $img ){
212
213	    	[ 'src', 'srcset', 'sizes', 'alt', 'width', 'height' ].forEach(function( attr ){
214
215				const original = $img.attr( 'data-o_' + attr );
216
217				if( original ){
218					$img.attr( attr, original );
219				}
220				else{
221					$img.removeAttr( attr );
222				}
223
224			});
225
226	    }
227
228	}
229
230	QuickView.init();
231
232	class Container{
233
234		static eventHandlerCalled = false;
235
236		constructor( $modal, container ){
237			this.$modal 			= $modal;
238			this.container 			= container || 'cart';
239		}
240
241
242		isOpen(){
243			return this.$modal.hasClass('xoo-wsc-'+this.container+'-active');
244		}
245
246		eventHandlers(){
247			$(document.body).on( 'wc_fragments_loaded updated_checkout', this.onCartUpdate.bind(this) );	
248		}
249
250		onCartUpdate(){
251			this.unblock();
252			Notice.showNotification();
253		}
254
255		setAjaxData( data, noticeSection ){
256
257			var ajaxData = {
258				container: this.container,
259				noticeSection: this.container,
260				isCheckout: isCheckoutPage,
261				isCart: isCartPage
262			}
263
264
265			if( typeof data === 'object' ){
266
267				$.extend( ajaxData, data );
268
269			}
270			else{
271
272				var serializedData = data;
273
274				$.each( ajaxData, function( key, value ){
275					serializedData += ( '&'+key+'='+value );
276				} )
277		
278				ajaxData = serializedData;
279
280			}
281
282			return ajaxData;
283		}
284
285
286		toggle( type ){
287
288			var $activeEls 	= this.$modal.add( 'body' ).add('html'),
289				activeClass = 'xoo-wsc-'+ this.container +'-active';
290
291			if( type === 'show' ){
292				$activeEls.addClass(activeClass);
293			}
294			else if( type === 'hide' ){
295				$activeEls.removeClass(activeClass);
296				Notice.hideNotification();
297			}
298			else{
299				$activeEls.toggleClass(activeClass);
300			}
301
302
303			$(document.body).trigger( 'xoo_wsc_' + this.container + '_toggled', [ type ] );
304
305		}
306
307
308		block(){
309			this.$modal.addClass('xoo-wsc-loading');
310		}
311
312		unblock(){
313			this.$modal.removeClass('xoo-wsc-loading');
314		}
315
316
317		refreshMyFragments(){
318
319			if( xoo_wsc_params.refreshCart === "yes" && typeof wc_cart_fragments_params !== 'undefined' ){
320				$( document.body ).trigger( 'wc_fragment_refresh' );
321				return;
322			}
323
324			this.block();
325
326			$.ajax({
327				url: get_wcurl( 'xoo_wsc_refresh_fragments' ),
328				type: 'POST',
329				context: this,
330				data: {},
331				success: function( response ){
332					this.updateFragments(response);
333					$( document.body ).trigger( 'wc_fragments_refreshed' );
334				},
335				complete: function(){
336					this.unblock();
337				}
338			})
339
340		}
341
342
343		updateCartCheckoutPage(){
344
345			//Refresh checkout page
346			if( isCheckoutPage ){
347				if( $( 'form.checkout' ).length === 0 ){
348					location.reload();
349					return;
350				}
351				$(document.body).trigger("update_checkout");
352			}
353
354			//Refresh Cart page
355			if( isCartPage ){
356				$(document.body).trigger("wc_update_cart");
357			}
358
359		}
360
361		updateFragments( response ){
362
363			if( response.fragments ){
364
365				$( document.body ).trigger( 'xoo_wsc_before_loading_fragments', [ response ] );
366
367				this.block();
368
369				//Set fragments
370		   		$.each( response.fragments, function( key, value ) {
371					$( key ).replaceWith( value );
372				});
373
374		   		if( typeof wc_cart_fragments_params !== 'undefined' && ( 'sessionStorage' in window && window.sessionStorage !== null ) ){
375
376		   			sessionStorage.setItem( wc_cart_fragments_params.fragment_name, JSON.stringify( response.fragments ) );
377					localStorage.setItem( wc_cart_fragments_params.cart_hash_key, response.cart_hash );
378					sessionStorage.setItem( wc_cart_fragments_params.cart_hash_key, response.cart_hash );
379
380					if ( response.cart_hash ) {
381						sessionStorage.setItem( 'wc_cart_created', ( new Date() ).getTime() );
382					}
383
384				}
385
386				$( document.body ).trigger( 'wc_fragments_loaded' );
387
388				this.unblock();
389
390			}
391
392			if( xoo_wsc_params.refreshCart === "yes" && typeof wc_cart_fragments_params !== 'undefined' ){
393				this.block();
394				$( document.body ).trigger( 'wc_fragment_refresh' );
395				return;
396			}
397
398		}
399
400	}
401
402
403	class Cart extends Container{
404
405		static isWCAjaxAddToCart = false;
406
407		constructor( $modal ){
408
409			super( $modal, 'cart' );
410
411			this.baseQty 				= 1;
412			this.qtyUpdateDelay 		= null;
413			this.bodyPosition 			= false;
414			this.cartLoaded 			= false;
415			this.blockAddedToCartCalled = false;
416			this.barsData 				= {};
417			this.barsWidth 				= {};
418
419			this.refreshFragmentsOnPageLoad();
420			this.eventHandlers();
421			this.initSlider();
422			this.toggleBasket();
423
424		}
425
426
427		refreshFragmentsOnPageLoad(){
428			if( xoo_wsc_params.fetchCart === 'page_load' ){
429				setTimeout(function(){
430					this.refreshMyFragments();
431				}.bind(this), xoo_wsc_params.fetchDelay )
432			}
433		}
434
435		eventHandlers(){
436
437			super.eventHandlers();
438
439			this.$modal.on( 'click', '.xoo-wsc-chng', this.toggleQty.bind(this) );
440			this.$modal.on( 'change', '.xoo-wsc-qty', this.changeInputQty.bind(this) );
441			this.$modal.on( 'click', '.xoo-wsc-undo-item', this.undoItem.bind(this) );
442			this.$modal.on( 'focusin', '.xoo-wsc-qty', this.saveQtyFocus.bind(this) );
443			this.$modal.on( 'click', '.xoo-wsc-smr-del', this.deleteIconClick.bind(this) );
444			this.$modal.on( 'click', '.xoo-wsch-close, .xoo-wsc-opac, .xoo-wsc-cart-close', this.closeCartOnClick.bind(this) );
445			this.$modal.on( 'click', '.xoo-wsc-basket', this.toggleCart.bind(this) );
446
447			$( document.body ).on( 'click', '.xoo-wsc-ecl', this.emptyCart.bind(this) );
448
449			$(document.body).on( 'xoo_wsc_cart_updated', this.updateCartCheckoutPage.bind(this) );
450			$(document.body).on( 'click', 'a.added_to_cart, .xoo-wsc-cart-trigger', this.openCart.bind(this) );
451			$(document.body).on( 'added_to_cart ', this.addedToCart.bind(this) );
452
453			if( xoo_wsc_params.ajaxAddToCart === 'yes' ){
454				$(document.body).on( 'submit', 'form.cart', this.addToCartFormSubmit.bind(this) );
455			}
456
457			if( typeof wc_cart_fragments_params === 'undefined' ){
458				$( window ).on( 'pageshow' , this.onPageShow.bind(this) );
459			}
460
461			if( xoo_wsc_params.triggerClass ){
462				$(document.body).on( 'click', '.'+xoo_wsc_params.triggerClass, this.openCart.bind(this) );
463			}
464
465
466
467			if( isCheckoutPage || isCartPage ){
468				$(document.body).on( 'updated_shipping_method', this.refreshMyFragments.bind(this) );
469			}
470
471			$(document.body).on( 'wc-blocks_added_to_cart', this.blockAddedToCart.bind(this) );
472
473			$(document.body).on( 'adding_to_cart', this.checkIfWCAjaxAddToCart.bind(this) );
474
475			//Animate shipping bar
476			$(document.body).on( 'xoo_wsc_before_loading_fragments adding_to_cart wc_fragment_refresh', this.storeProgressBarWidth.bind(this) );
477
478			//$(document.body).on( 'wc_fragments_loaded', this.checkIfWCAjaxAddToCartUnset.bind(this) );
479
480			initMasonryLayout( ['cart', 'suggested' ] );
481
482			if( xoo_wsc_params.autoOpenCart === 'yes' && xoo_wsc_params.addedToCart === 'yes'){
483				this.openCart();
484			}
485
486
487			this.$modal.on( 'click', '.xoo-wsc-save', this.saveForLater.bind(this) );
488
489		}
490
491
492		saveForLater(e){
493
494			if( xoo_wsc_params.saveForLaterNeedsLogin ) return;
495
496			var $product 		= $(e.currentTarget).closest('.xoo-wsc-product'),
497				cartKey 		= $product.data('key'),
498				formData 		= {
499					cart_key: cartKey,
500				}
501
502				this.block();
503				this.saveScrollPosition();
504			
505			
506			$.ajax({
507				url: get_wcurl( 'xoo_wsc_save_for_later' ),
508				type: 'POST',
509				context: this,
510				data: this.setAjaxData(formData),
511				success: function(response){
512
513					this.updateFragments( response );
514
515					$(document.body).trigger( 'xoo_wsc_added_to_save_list', [response, cartKey] );
516					$(document.body).trigger( 'xoo_wsc_cart_updated', [response] );
517
518					this.setScrollPosition();
519					this.unblock();
520
521					var $saveLaterIcon = this.$modal.find('.xoo-wsch-savelater');
522
523					if( $saveLaterIcon.length ){
524						$saveLaterIcon.addClass('xoo-wsc-shake-animate');
525						setTimeout(function(){
526							$saveLaterIcon.removeClass('xoo-wsc-shake-animate');
527						},1200);
528					}
529
530				}
531
532			})
533
534		}
535
536		checkIfWCAjaxAddToCartUnset(){
537			this.isWCAjaxAddToCart = false;
538		}
539
540		checkIfWCAjaxAddToCart(e, $button, data){
541
542			Cart.isWCAjaxAddToCart = true;
543
544			if( ( !(data instanceof FormData) || !data.has('action') || !data.get('action') === 'xoo_wsc_add_to_cart' ) && $button.hasClass('ajax_add_to_cart') ){
545				this.isWCAjaxAddToCart = true;
546			}
547		}
548
549
550		toggleCart(e){
551			if( this.isOpen() ){
552				this.closeCartOnClick(e);
553			}
554			else{
555				this.openCart(e);
556			}
557			
558		}
559
560
561		openCart(e){
562			if( e ){
563				e.preventDefault();
564				e.stopImmediatePropagation();
565			}
566
567			if( !this.cartLoaded && xoo_wsc_params.fetchCart === 'cart_open' ){
568				this.refreshMyFragments();
569				this.cartLoaded = true;
570			}
571
572			this.toggle('show');
573			this.animateProgressBar();
574			Notice.hideMarkupNotice();
575
576		}
577
578		addToCartFormSubmit(e){
579
580			var $form = $(e.currentTarget);
581
582			if( $form.closest('.product').hasClass('product-type-external') || $form.siblings('.xoo-wsc-disable-atc').length ) return;
583
584			var $button  		= e.originalEvent && e.originalEvent.submitter ? $(e.originalEvent.submitter) : $form.find( 'button[type="submit"]'),
585				formData 		= new FormData($form.get(0)),
586				productData  	= $form.serializeArray(),
587				hasProductId 	= false;
588
589			//Check for woocommerce custom quantity code 
590			//https://docs.woocommerce.com/document/override-loop-template-and-show-quantities-next-to-add-to-cart-buttons/
591			$.each( productData, function( key, form_item ){
592				if( form_item.name === 'productID' || form_item.name === 'add-to-cart' ){
593					if( form_item.value ){
594						hasProductId = true;
595						return false;
596					}
597				}
598			})
599
600			//If no product id found , look for the form action URL
601			if( !hasProductId && $form.attr('action') ){
602				var is_url = $form.attr('action').match(/add-to-cart=([0-9]+)/),
603					productID = is_url ? is_url[1] : false; 
604			}
605
606			// Add submitted button value
607	        if( $button.attr('name') && $button.attr('value') ){
608	            formData.append( $button.attr('name'), $button.attr('value') );
609	        }
610
611	        if( productID ){
612	        	formData.append( 'add-to-cart', productID );
613	        }
614
615	        formData.append( 'action', 'xoo_wsc_add_to_cart' );
616
617	        var doAjaxAddToCart = true;
618
619	        
620        	$.each( xoo_wsc_params.skipAjaxForData, function( key, value ){
621        		if( formData.has(key) && ( !value || formData.get(key) == value ) ){
622        			doAjaxAddToCart = false;
623        			return false;
624        		}
625        	} )
626	        
627
628	        if( doAjaxAddToCart ){
629	        	e.preventDefault();
630	        	this.addToCartAjax( $button, formData );//Ajax add to cart
631	        }
632			
633		}
634
635
636		addToCartAjax( $button, formData ){
637
638			var cart = this;
639
640			this.block();
641
642			$button.addClass('loading');
643
644			// Trigger event.
645			$( document.body ).trigger( 'adding_to_cart', [ $button, formData ] );
646
647			//formData.append('noticeSection', 'slider');
648
649			$.ajax({
650				url: get_wcurl( 'xoo_wsc_add_to_cart' ),
651				type: 'POST',
652				context: this,
653				cache: false,
654			    contentType: false,
655			    processData: false,
656				data: formData,
657			    success: function(response){
658
659					if(response.fragments){
660						// Trigger event so themes can refresh other areas.
661						$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $button ] );
662					}else if(response.notice ){
663						Notice.setHTML(response.notice);
664						Notice.showNotification();
665					}
666					else{
667						//window.location.reload();
668					}
669
670			    },
671			    complete: function(){
672			    	this.unblock();
673			    	$button.removeClass('loading').addClass('added');
674			    }
675			})
676		}
677
678		addedToCart( e, response, hash, $button ){
679
680			$(document.body).trigger( 'xoo_wsc_cart_updated', [response] );
681	
682			var _this = this;
683
684			this.flyToCart( $button, function(){
685				if( xoo_wsc_params.autoOpenCart === "yes" ){
686					setTimeout(function(){
687						_this.openCart();	
688					},20 )
689				}
690			} );
691		}
692
693
694		blockAddedToCart(){
695
696			if( !Cart.isWCAjaxAddToCart && !this.blockAddedToCartCalled ){
697
698				this.refreshMyFragments();
699				
700				var _this = this;
701
702				if( xoo_wsc_params.autoOpenCart === "yes" ){
703					setTimeout(function(){
704						_this.openCart();	
705					},20 )
706				}
707
708				this.blockAddedToCartCalled = true;
709
710				setTimeout( function(){
711					_this.blockAddedToCartCalled = false;
712				}, 200 );
713
714				Cart.isWCAjaxAddToCart = false;
715
716			}
717
718
719						
720		}
721
722
723		flyToCart( $atcEL, callback ){
724
725			var $basket = this.$modal.find('.xoo-wsc-basket').length ? this.$modal.find('.xoo-wsc-basket') : $(document.body).find('.xoo-wsc-sc-cont');
726
727			if( !$basket.length || xoo_wsc_params.flyToCart !== 'yes' || !$atcEL || !$atcEL.length ){
728				callback();
729				return;
730			}
731
732			var customDragImgClass 	= xoo_wsc_params.productFlyClass,
733				$dragIMG 			= null,
734				$product 			= $atcEL.closest('.product');
735
736
737			//If has product container
738			if( $product.length ){
739
740				$product = $($product[0]);
741
742				var $productGallery = $product.find('.woocommerce-product-gallery');
743
744				if( customDragImgClass && $product.find( customDragImgClass ).length ){
745					$dragIMG = $product.find( customDragImgClass );
746				}
747				else if( $product.find( 'img[data-xooWscFly="fly"]' ).length ){
748					if( $productGallery.length ){
749						$dragIMG = $productGallery.find( '.flex-active-slide img[data-xooWscFly="fly"]' ).length ? $productGallery.find( '.flex-active-slide img[data-xooWscFly="fly"]' ) : $productGallery.find( 'img[data-xooWscFly="fly"]' )
750					}
751					else{
752						$dragIMG = $product.find( 'img[data-xooWscFly="fly"]' );
753					}
754				}
755				else if( $productGallery.length ){
756					$dragIMG = $productGallery;
757				}
758				else{
759					$dragIMG = $product;
760				}
761
762			}
763			else if( customDragImgClass ){
764				var moveUp = 4;
765				for ( var i = moveUp; i >= 0; i-- ) {
766					var $foundImg = $atcEL.parent().find( customDragImgClass );
767					if( $foundImg.length ){
768						$dragIMG = $foundImg;
769						return false;
770					}
771				}
772			}
773
774
775			if( !$dragIMG || !$dragIMG.length ){
776				callback();
777				return;
778			}
779
780			$dragIMG = $dragIMG.eq(0);
781
782			var $imgclone = $dragIMG
783				.clone()
784	    		.offset({
785		            top: $dragIMG.offset().top,
786		            left: $dragIMG.offset().left
787		        })
788	        	.addClass( 'xoo-wsc-fly-animating' )
789	            .appendTo( $('body') )
790	            .animate({
791	            	'top': $basket.offset().top - 20,
792		            'left': $basket.offset().left - 20,
793		            'width': 75,
794		            'height': 75
795		        }, parseInt( xoo_wsc_params.flyToCartTime ), 'easeInOutExpo' );
796	        
797	        setTimeout(function () {
798	        	callback()
799	        }, parseInt( xoo_wsc_params.flyToCartTime ) );
800
801	        $imgclone.animate({
802	        	'width': 0,
803	        	'height': 0
804	        }, function () {
805	        	$(this).detach();
806	        });
807
808		}
809
810
811		toggleQty(e){
812
813			var $toggler 	= $(e.currentTarget),
814				$input 		= $toggler.siblings('.xoo-wsc-qty');
815
816			if( !$input.length ) return;
817
818			var baseQty = this.baseQty = parseFloat( $input.val() ),
819				step 	= parseFloat( $input.attr('step') ),
820				action 	= $toggler.hasClass( 'xoo-wsc-plus' ) ? 'add' : 'less',
821				newQty 	= action === 'add' ? baseQty + step : baseQty - step;
822
823			
824			$input.val(newQty).trigger('change');
825
826		}
827
828		changeInputQty(e){
829
830			Notice.hideNotification();
831
832			var $_this	= this,
833 				$input 	= $(e.currentTarget),
834				newQty 	= parseFloat( $input.val() ),
835				step 	= parseFloat( $input.attr('step') ),
836				min 	= parseFloat( $input.attr('min') ),
837				max 	= parseFloat( $input.attr('max') ),
838				invalid = false,
839				message = false;
840
841			//Validation
842			
843			if( isNaN( newQty )  || newQty < 0 || newQty < min  ){
844				invalid = true;
845			}
846			else if( newQty > max ){
847				invalid = true;
848				message = xoo_wsc_params.strings.maxQtyError.replace( '%s%', max );
849			}
850			else if( !Number.isInteger(newQty/step ) ){
851				invalid = true;
852				message = xoo_wsc_params.strings.stepQtyError.replace( '%s%', step );
853			}
854			
855			//Set back to default quantity
856			if( invalid ){
857				$input.val( this.baseQty );
858				if( message ){
859					Notice.add( message, 'error' );
860					Notice.showNotification();
861				}
862				return;
863			}
864
865			//Update
866			$input.val( newQty );
867
868			clearTimeout( this.qtyUpdateDelay );
869
870			this.qtyUpdateDelay = setTimeout(function(){
871				$_this.updateItemQty( $input.parents('.xoo-wsc-product').data('key'), newQty )
872			}, xoo_wsc_params.qtyUpdateDelay );
873			
874			
875		}
876
877
878		saveScrollPosition(){
879			this.bodyPosition = this.$modal.find('.xoo-wsc-body').length ? this.$modal.find('.xoo-wsc-body').scrollTop() : false;
880		}
881
882		setScrollPosition(){
883			if( this.bodyPosition !== false ){
884				this.$modal.find( '.xoo-wsc-body' ).scrollTop( this.bodyPosition );
885				this.bodyPosition = false; //reset
886			}
887		}
888
889		updateItemQty( cart_key, qty ){
890
891			if( !cart_key || qty === undefined ) return;
892
893			this.block();
894			
895			this.saveScrollPosition();
896
897			var formData = {
898				cart_key: cart_key,
899				qty: qty
900			}
901
902			$.ajax({
903				url: get_wcurl( 'xoo_wsc_update_item_quantity' ),
904				type: 'POST',
905				context: this,
906				data: this.setAjaxData(formData),
907				success: function(response){
908					this.updateFragments( response );
909					$(document.body).trigger( 'xoo_wsc_quantity_updated', [response] );
910					$(document.body).trigger( 'xoo_wsc_cart_updated', [response] );
911					this.setScrollPosition();
912					this.unblock();
913				}
914
915			})
916		}
917
918
919		closeCartOnClick(e){
920			e.preventDefault();
921			if( drawer.isOpen() ){
922				drawer.toggle('hide');
923				setTimeout( function(){
924					cart.toggle( 'hide' )
925				}, 500 );
926			}
927			else{
928				cart.toggle('hide');
929			}
930
931		}
932
933
934		saveQtyFocus(e){
935			this.baseQty = $(e.currentTarget).val();
936		}
937
938
939		onPageShow(e){
940			if ( e.originalEvent.persisted ) {
941				this.refreshMyFragments();
942				$( document.body ).trigger( 'wc_fragment_refresh' );
943			}
944		}
945
946		deleteIconClick(e){
947			this.updateItemQty( $( e.currentTarget ).parents('.xoo-wsc-product').data('key'), 0 );
948		}
949
950		undoItem(e){
951
952			var $undo 		= $(e.currentTarget),
953				formData 	= {
954					cart_key: $undo.data('key')
955				}
956
957			this.block();
958
959			$.ajax({
960				url: get_wcurl('xoo_wsc_undo_item'),
961				type: 'POST',
962				context: this,
963				data: this.setAjaxData(formData),
964				success: function(response){
965					this.updateFragments( response );
966					$(document.body).trigger( 'xoo_wsc_item_restored', [response] );
967					$(document.body).trigger( 'xoo_wsc_cart_updated', [response] );
968					this.unblock();
969				}
970
971			})
972		}
973
974		storeProgressBarWidth( e ){
975
976			var $bars 	= $(document.body).find( '.xoo-wsc-bar-cont' ),
977				self 	= this;
978
979			if( !$bars.length ) return;
980
981			$.each( $bars, function( index, el ){
982
983				var $bar 	= $(el),
984					$filled = $bar.find('.xoo-wsc-bar-filled'),
985					id 		= $bar.attr('id');
986
987				self.barsWidth[ id ] 		= $filled.prop('style').width;
988				self.barsData[ id ] 		= $bar.data('bardata')
989
990			} );
991
992			
993		}
994
995		onCartUpdate(){
996			super.onCartUpdate();
997			this.cartLoaded = true;
998			this.initAnimateProgressBar = true;
999			if( this.isOpen() ){
1000				this.animateProgressBar();
1001			}
1002			this.initSlider();
1003			this.toggleBasket();
1004			initMasonryLayout( ['cart','suggested'] );
1005		}
1006
1007
1008		
1009		toggleBasket(){
1010
1011			var $basket 	= $('.xoo-wsc-basket'),
1012				show 		= xoo_wsc_params.showBasket,
1013				hasProducts = this.$modal.find('.xoo-wsc-product').length;
1014
1015			if( show === "always_show" ){
1016				$basket.show();	
1017			}
1018			else if( show === "hide_empty" ){
1019				if( hasProducts ){
1020					$basket.show();
1021				}
1022				else{
1023					$basket.hide();
1024				}
1025			}
1026			else{
1027				$basket.hide();
1028			}
1029
1030			var $shortcode = $('.xoo-wsc-sc-cont');
1031
1032			if( $shortcode.length && xoo_wsc_params.menuCartHideOnEmpty.length ){
1033
1034				var shortcodeEls = xoo_wsc_params.shortcodeEls;
1035
1036				$.each( xoo_wsc_params.menuCartHideOnEmpty, function( index, val ){
1037
1038					if( shortcodeEls[val] ){
1039						if( hasProducts ){
1040							$(shortcodeEls[val]).show();
1041						}
1042						else{
1043							$(shortcodeEls[val]).hide();
1044						}
1045					}
1046
1047				})
1048
1049			}
1050			
1051		}
1052
1053		animateProgressBar(){
1054
1055			if( isCartPage || isCheckoutPage || !this.initAnimateProgressBar ) return;
1056
1057			var $bars  	= $(document.body).find( '.xoo-wsc-bar-cont' ),
1058				self 	= this;
1059
1060			if( !$bars.length ) return;
1061
1062			$.each( $bars, function( index, el ){
1063
1064				var $bar 	= $(el),
1065					$filled = $bar.find('.xoo-wsc-bar-filled'),
1066					id 		= $bar.attr('id');
1067
1068				if( !self.barsWidth[ id ] ) return true;
1069
1070				var newWidth = $filled.prop('style').width;
1071
1072				$filled
1073					.width( self.barsWidth[ id ] )
1074					.animate({ width: newWidth }, 400, 'linear');
1075
1076			} );
1077
1078			this.checkPointAchievedAnimate();
1079
1080			this.initAnimateProgressBar = false;
1081		}
1082
1083		checkPointAchievedAnimate(){
1084
1085			var $bars 	= $(document.body).find( '.xoo-wsc-bar-cont' ),
1086				self 	= this;
1087
1088			if( !this.barsData || !$bars.length ) return;
1089
1090
1091			$.each( $bars, function( index, el ){
1092
1093				var $bar 		= $(el),
1094					$filled 	= $bar.find('.xoo-wsc-bar-filled'),
1095					id 			= $bar.attr('id'),
1096					barData 	= $bar.data('bardata'),
1097					pastBarData = self.barsData[ id ];
1098
1099				if( !pastBarData ) return true;
1100
1101				var pastPointsReached 	= [],
1102					newPointsReached 	= [],
1103					allPointsReached 	= false;
1104
1105				$.each( pastBarData.points, function( point_index, point ){
1106					if( point.reached == true ){
1107						pastPointsReached.push('id_'+point_index);
1108					}
1109				} )
1110
1111				$.each( barData.points, function( point_index, point ){
1112					if( point.reached == true && !pastPointsReached.includes('id_'+point_index)  ){
1113						newPointsReached.push('id_'+point_index);
1114					}
1115
1116					if( point.reached == true && (point_index + 1) === barData.points.length  ){
1117						allPointsReached = true;
1118					}
1119				} )
1120
1121
1122
1123				if( newPointsReached.length ){
1124					setTimeout( function(){
1125						Celebrate.Celebrate( $bar, allPointsReached && xoo_wsc_params.bar.fullCelebration !== 'none' ? xoo_wsc_params.bar.fullCelebration : xoo_wsc_params.bar.singleCelebration );
1126					}, 200 );
1127				}
1128
1129				self.barsData[id] = barData;
1130
1131
1132			})
1133
1134			
1135		}
1136
1137
1138		emptyCart(){
1139
1140			this.block();
1141
1142			$.ajax({
1143				url: get_wcurl( 'xoo_wsc_empty_cart' ),
1144				type: 'POST',
1145				context: this,
1146				data: {},
1147			    success: function(response){
1148			    	
1149					this.updateFragments( response );
1150					// Trigger event.
1151					$( document.body ).trigger( 'xoo_wsc_cart_emptied' );
1152					$(document.body).trigger( 'xoo_wsc_cart_updated', [response] );
1153			    },
1154			    complete: function(){
1155			    	this.unblock();
1156			    }
1157			})
1158		}
1159
1160
1161		initSlider(){
1162
1163			if( typeof $.fn.lightSlider !== 'function' || xoo_wsc_params.spSlide.enable !== 'yes' ) return;
1164
1165			$('ul.xoo-wsc-sp-slider').each( function( index, el ){
1166				var $el = $(el);
1167
1168				if( $(this).parents('.xoo-wsc-drawer').length ) return;
1169
1170				$el.lightSlider(xoo_wsc_params.spSlide);
1171
1172			} );
1173			
1174		}
1175
1176	}
1177
1178
1179	class Drawer extends Container{
1180
1181		constructor( $modal ){
1182
1183			super( $modal, 'drawer' );
1184
1185			this.setHeaderHeight();
1186
1187			this.eventHandlers();
1188
1189		}
1190
1191		eventHandlers(){
1192
1193			super.eventHandlers();
1194
1195			$(document.body).on( 'xoo_wsc_cart_toggled', this.drawOutOnCartOpen.bind(this) );
1196			$(document.body).on( 'click', '.xoo-wsc-toggle-drawer', this.toggleDrawer.bind(this) );
1197			$(document.body).on( 'click', '.xoo-wscdh-close', this.close.bind(this) );
1198			//$(document.body).on( 'wc_fragments_loaded', this.onCartUpdate.bind(this) );
1199		}
1200
1201		onCartUpdate(){
1202			super.onCartUpdate();
1203			this.setHeaderHeight();
1204			setTimeout(function(){
1205				drawer.toggleOnContentBasis();
1206			}, 0);
1207			
1208		}
1209
1210
1211		toggleOnContentBasis(){
1212
1213			var hasContent = !this.isDrawerEmpty();
1214
1215			if( this.isOpen() ){
1216				if( !hasContent ){
1217					this.toggle('hide');
1218					this.$modal.find('.xoo-wsc-dtg-icon').addClass('xoo-wsc-disabled');
1219					this.emptyClosed = true;
1220				}
1221			}
1222			else{
1223				if( hasContent && cart.isOpen() && this.emptyClosed ){
1224					this.toggle('show');
1225					this.$modal.find('.xoo-wsc-dtg-icon').removeClass('xoo-wsc-disabled');
1226					this.emptyClosed = false;
1227				}
1228			}
1229		}
1230
1231		setHeaderHeight(){
1232			var $cartHeader = $('.xoo-wsch-top');
1233			if( !$cartHeader.length ) return;
1234
1235			var cartHeaderHeight = $cartHeader.height();
1236
1237			this.$modal.closest('.xoo-wsc-markup').find('.xoo-wsc-drawer-header, .xoo-wsc-sl-heading').each(function( index, el ){
1238
1239				var $el = $(el);
1240
1241				if( $el.height() < $cartHeader.height() ){
1242					$el.height( cartHeaderHeight );
1243				}
1244			})
1245	
1246			
1247		}
1248
1249		isDrawerEmpty(){
1250			return !this.$modal.find('.xoo-wsc-dr-content').length;
1251		}
1252
1253
1254		toggleDrawer(){
1255			this.toggle();
1256		}
1257
1258
1259		drawOutOnCartOpen(e,type){
1260			
1261			if( !cart.isOpen() || this.isDrawerEmpty() ) return;
1262
1263			setTimeout( function(){
1264				drawer.toggle('show');
1265				initMasonryLayout('suggested');
1266			}, xoo_wsc_params.drawerWait );
1267
1268		}
1269
1270
1271		close(e){
1272			this.toggle('hide');
1273		}
1274
1275		getDataType(){
1276			return this.$modal.find('.xoo-wsc-dr-content').data('drawer');
1277		}
1278
1279
1280	}
1281
1282	
1283
1284	class Slider extends Container{
1285
1286		constructor( $modal ){
1287
1288			super( $modal, 'slider' );
1289
1290			this.eventHandlers();
1291
1292			this.shipping = xoo_wsc_params.shippingEnabled ? Shipping.init( this ) : null;
1293
1294		}
1295
1296		eventHandlers(){
1297
1298			super.eventHandlers();
1299
1300
1301			$( document.body ).on( 'click', '.xoo-wsc-toggle-slider', this.triggerSlider.bind(this) );
1302			$( document.body ).on( 'xoo_wsc_cart_toggled', this.closeSliderOnCartClose.bind(this) );
1303
1304			if( xoo_wsc_params.sliderAutoClose ){
1305				$( document.body ).on( 'xoo_wsc_coupon_applied xoo_wsc_shipping_calculated updated_shipping_method xoo_wsc_coupon_removed xoo_wsc_moved_from_save_list added_to_cart', this.closeSlider.bind(this) );
1306			}
1307
1308			$(document.body).on( 'submit', 'form.xoo-wsc-sl-apply-coupon', this.submitCouponForm.bind(this) );
1309			$(document.body).on( 'click', '.xoo-wsc-coupon-apply-btn', this.applyCouponFromBtn.bind(this) );
1310			$(document.body).on( 'click', '.xoo-wsc-remove-coupon', this.removeCoupon.bind(this) );
1311			$(document.body).on( 'click', '.xoo-wsc-savl-del', this.deleteSavedForLaterItem.bind(this) );
1312			$(document.body).on( 'click', '.xoo-wsc-savl-atc', this.moveSavedForLaterItemToCart.bind(this) );
1313
1314			$( document.body ).on( 'click', '.xoo-wsc-toggle-slider[data-sli
1314der="quickview"]', this.loadQuickview.bind(this) );
1315
1316		}
1317
1318
1319		loadQuickview(e){
1320
1321			e.preventDefault();
1322
1323			this.toggle('show');
1324
1325			var $toggler 		= $(e.currentTarget),
1326				formData 		= {};
1327
1328			if( $toggler.data('cart_key') ){
1329				formData['cart_key'] = $toggler.data('cart_key');
1330			}
1331			else if( $toggler.data('product_id') ){
1332				formData['product_id'] = $toggler.data('product_id');
1333			}
1334			else{
1335				return;
1336			}
1337
1338			var $sliderContent = $('.xoo-wsc-sl-quickview .xoo-wsc-sl-body');
1339
1340			$sliderContent.html('');
1341
1342			this.block();
1343			
1344			$.ajax({
1345				url: get_wcurl( 'xoo_wsc_load_quickview' ),
1346				type: 'POST',
1347				context: this,
1348				data: this.setAjaxData(formData),
1349				success: function(response){
1350
1351					$sliderContent.html(response);
1352
1353					QuickView.load();
1354
1355					$(document.body).trigger( 'xoo_wsc_quickview_loaded', [response, formData] );
1356
1357					this.unblock();
1358
1359				}
1360
1361			})
1362		}
1363
1364
1365		moveSavedForLaterItemToCart(e){
1366
1367			var $item 			= $(e.currentTarget).closest('.xoo-wsc-savl-product'),
1368				cartKey 		= $item.data('ckey'),
1369				formData 		= {
1370				cart_key: cartKey,
1371			}
1372
1373			this.block();
1374			
1375			$.ajax({
1376				url: get_wcurl( 'xoo_wsc_move_save_for_later_item' ),
1377				type: 'POST',
1378				context: this,
1379				data: this.setAjaxData(formData),
1380				success: function(response){
1381
1382					this.updateFragments( response );
1383
1384					$(document.body).trigger( 'xoo_wsc_moved_from_save_list', [response, cartKey] );
1385
1386					this.unblock();
1387
1388				}
1389
1390			})
1391		}
1392
1393		deleteSavedForLaterItem(e){
1394
1395			var $item 			= $(e.currentTarget).closest('.xoo-wsc-savl-product'),
1396				cartKey 		= $item.data('ckey'),
1397				formData 		= {
1398				cart_key: cartKey,
1399			}
1400
1401			this.block();
1402			
1403			$.ajax({
1404				url: get_wcurl( 'xoo_wsc_delete_save_for_later_item' ),
1405				type: 'POST',
1406				context: this,
1407				data: this.setAjaxData(formData, 'slider' ),
1408				success: function(response){
1409
1410					this.updateFragments( response );
1411
1412					$(document.body).trigger( 'xoo_wsc_delete_from_save_list', [response, cartKey] );
1413
1414					this.unblock();
1415
1416				}
1417
1418			})
1419		}
1420
1421
1422		removeCoupon(e){
1423
1424			e.preventDefault();
1425
1426			var $removeEl 	= $(e.currentTarget),
1427				coupon 		= $removeEl.data('code'),
1428				formData 	= {
1429					coupon: coupon
1430				};
1431
1432			this.block();	
1433
1434			$.ajax( {
1435				url: get_wcurl( 'xoo_wsc_remove_coupon' ),
1436				type: 'POST',
1437				context: this,
1438				data: this.setAjaxData( formData, cart.$modal.find( $removeEl ).length ? 'cart' : 'slider' ),
1439				success: function( response ) {
1440					this.updateFragments(response);
1441				},
1442				complete: function() {
1443					this.unblock();
1444					this.updateCartCheckoutPage();
1445					$( document.body ).trigger( 'xoo_wsc_coupon_removed' );
1446				}
1447			} );
1448		}
1449
1450		onCartUpdate(){
1451			super.onCartUpdate();
1452			this.toggleContent();
1453		}
1454
1455		closeSlider(){
1456			this.toggle('hide');
1457		}
1458
1459
1460		applyCouponFromBtn(e){
1461			this.applyCoupon( $(e.currentTarget).val() );
1462		}
1463
1464		submitCouponForm(e){
1465
1466			e.preventDefault();
1467
1468			var $form = $(e.currentTarget);
1469
1470			this.applyCoupon( $form.find('input[name="xoo-wsc-slcf-input"]').val() );
1471
1472		}
1473
1474
1475		closeSliderOnCartClose(e){
1476
1477			var $this = $(e.currentTarget); 
1478
1479			if( !cart.$modal.hasClass('xoo-wsc-cart-active') ){
1480				this.toggle('hide');
1481			}
1482
1483		}
1484
1485
1486		triggerSlider(e){
1487
1488			var $toggler 	= $(e.currentTarget),
1489 				slider 		= $toggler.data('slider');
1490
1491			if( slider === 'shipping' && isCheckoutPage ){
1492				Notice.add( xoo_wsc_params.strings.calculateCheckout, 'error' );
1493				Notice.showNotification();
1494				return;
1495			}
1496
1497
1498			this.$modal.attr( 'data-slider', slider );
1499			
1500			this.toggle();
1501
1502			this.toggleContent();
1503		}
1504
1505
1506		toggleContent(){
1507
1508			var activeSlider = '';
1509
1510			$('.xoo-wsc-sl-content').hide();
1511			
1512			var activeSlider 	= this.$modal.attr('data-slider'),
1513				$toggleEl 		= $('.xoo-wsc-sl-content[data-slider="'+activeSlider+'"]');
1514	
1515			if( $toggleEl.length ) $toggleEl.show();
1516
1517			if( activeSlider === 'savelater' && this.isOpen() ){
1518				initMasonryLayout('saveLater');
1519			}
1520
1521			$( document.body ).trigger( 'xoo_wsc_slider_data_toggled', [activeSlider] );
1522		}
1523
1524
1525		applyCoupon( coupon ){
1526
1527			if( !coupon ){
1528				Notice.add( xoo_wsc_params.strings.couponEmpty, 'error' );
1529				Notice.showNotification();
1530				return;
1531			}
1532
1533			this.block();
1534
1535			var formData = {
1536				'coupon': coupon,
1537			}
1538
1539			$.ajax( {
1540				url: get_wcurl('xoo_wsc_apply_coupon'),
1541				type: 'POST',
1542				context: this,
1543				data: this.setAjaxData( formData ),
1544				success: function( response ) {
1545					this.updateFragments(response);
1546				},
1547				complete: function() {
1548					this.unblock();
1549					this.updateCartCheckoutPage();
1550					$( document.body ).trigger( 'xoo_wsc_coupon_applied' );
1551				}
1552			} );
1553
1554		}
1555
1556	}
1557
1558	
1559
1560	var Shipping = {
1561
1562		init: function( slider ){
1563			slider.$modal.on( 'change', 'input.xoo-wsc-shipping-method', this.shippingMethodChange );
1564			slider.$modal.on( 'submit', 'form.woocommerce-shipping-calculator', this.shippingCalculatorSubmit );
1565			slider.$modal.on( 'click', '.shipping-calculator-button', this.toggleCalculator );
1566			$(document.body).on( 'wc_fragments_loaded xoo_wsc_slider_data_toggled', this.initSelect2 );
1567		},
1568
1569		toggleCalculator: function(e){
1570
1571			e.preventDefault();
1572			e.stopImmediatePropagation();
1573
1574			$(this).siblings('.shipping-calculator-form').slideToggle();
1575			$( document.body ).trigger( 'country_to_state_changed' );
1576		},
1577
1578		shippingCalculatorSubmit: function(e){
1579
1580			e.preventDefault();
1581			e.stopImmediatePropagation();
1582
1583			var $form = $(this);
1584
1585			slider.block();
1586
1587			// Provide the submit button value because wc-form-handler expects it.
1588			$( '<input />' )
1589				.attr( 'type', 'hidden' )
1590				.attr( 'name', 'calc_shipping' )
1591				.attr( 'value', 'x' )
1592				.appendTo( $form );
1593
1594			var formData = $form.serialize();
1595
1596			// Make call to actual form post URL.
1597			$.ajax( {
1598				url: get_wcurl( 'xoo_wsc_calculate_shipping' ),
1599				type: 'POST',
1600				context: this,
1601				data: slider.setAjaxData(formData),
1602				success: function( response ) {
1603					slider.updateFragments(response);
1604				},
1605				complete: function() {
1606					slider.unblock();
1607					slider.updateCartCheckoutPage();
1608					$( document.body ).trigger( 'xoo_wsc_shipping_calculated' );
1609				}
1610			} );
1611
1612		},
1613
1614		shippingMethodChange: function(e){
1615
1616			e.preventDefault();
1617			e.stopImmediatePropagation();
1618
1619			var shipping_methods = {};
1620
1621			slider.block();
1622
1623			$( 'select.shipping_method, :input[name^=xoo-wsc-shipping_method][type=radio]:checked, :input[name^=shipping_method][type=hidden]' ).each( function() {
1624				shipping_methods[ $( this ).data( 'index' ) ] = $( this ).val();
1625			} );
1626
1627			var formData = {
1628				shipping_method: shipping_methods,
1629			}
1630
1631			$.ajax( {
1632				type:     'POST',
1633				url:      get_wcurl( 'xoo_wsc_update_shipping_method' ),
1634				data:     slider.setAjaxData( formData ),
1635				success:  function( response ) {
1636					slider.updateFragments(response);
1637				},
1638				complete: function() {
1639					slider.unblock();
1640					slider.updateCartCheckoutPage();
1641					$( document.body ).trigger( 'updated_shipping_method' );
1642				}
1643			} );
1644
1645		},
1646
1647		initSelect2: function(e){
1648			$( document.body ).trigger( 'country_to_state_changed' );
1649		},
1650	}
1651
1652
1653	var cart 	= new Cart( $('.xoo-wsc-modal') ),
1654		slider 	= new Slider( $('.xoo-wsc-slider-modal') );
1655		drawer 	= new Drawer( $('.xoo-wsc-drawer-modal') );
1656
1657
1658	var AnimateCard = {
1659
1660		type: xoo_wsc_params.cardAnimate.type,
1661		duration: xoo_wsc_params.cardAnimate.duration,
1662
1663		init: function(){
1664
1665			var onEvent = xoo_wsc_params.cardAnimate.event === 'back_hover' ? 'mouseenter' : 'click';
1666		
1667			$('body').on( onEvent, '.xoo-wsc-has-back', this.animate );
1668			$('body').on( 'mouseleave', '.xoo-wsc-has-back', this.reverseAnimate );
1669
1670		},
1671		animate: function(e){
1672
1673			if( e.target.classList.contains('xoo-wsc-smr-del') ) return;
1674
1675			var $img = $(this).find('.xoo-wsc-img-col');
1676
1677			if( !$img.hasClass('xoo-wsc-caniming') ){
1678				e.preventDefault();
1679			}
1680			else{
1681				return;
1682			}
1683
1684			$img.attr('data-exclasses', $img.attr('class') );
1685
1686			$img.removeClass()
1687			$img.addClass($img.attr('data-exclasses'));
1688
1689			$img.addClass( 'xoo-wsc-caniming' + ' ' + AnimateCard.type );
1690
1691		},
1692		reverseAnimate: function(){
1693
1694			var $img = $(this).find('.xoo-wsc-img-col');
1695
1696			if( !$img.hasClass( 'xoo-wsc-caniming' ) ) return;
1697
1698			$img.addClass(AnimateCard.type+'Return');
1699
1700			AnimateCard.clear = setTimeout(function(){
1701				$img.removeClass().addClass( $img.attr('data-exclasses') );
1702			}, AnimateCard.duration * 1000);
1703
1704		}
1705	}
1706
1707	if( xoo_wsc_params.cardAnimate.enable === "yes" ){
1708		AnimateCard.init();
1709	}
1710
1711
1712
1713	var Celebrate = {
1714
1715		canvasIndex: 0,
1716
1717		myconfetti: '',
1718
1719		Celebrate: async function( $bar, celebrationName ){
1720
1721			if (typeof Celebrate[celebrationName] !== 'function') return;
1722
1723			const index = Celebrate.canvasIndex++;
1724
1725			const myconfetti = await Celebrate.CreateCanvas(index);
1726
1727			const barPos = Celebrate.BarPosition( $bar );
1728
1729			Celebrate[celebrationName](myconfetti, barPos);
1730
1731		},
1732
1733		CreateCanvas: async function(index){
1734
1735			const canvasID = 'xoo_canvas_' + index;
1736
1737		    // Append a fresh canvas for this celebration
1738		    $('.xoo-wsc-container').append('<canvas id="'+canvasID+'"></canvas>').show();
1739
1740		    const canvas = document.getElementById(canvasID);
1741
1742		    // Create a separate confetti instance for this canvas
1743		    return await confetti.create(canvas, { resize: true });
1744			
1745		},
1746
1747		BarPosition: function( $bar ){
1748			
1749			var windowHeight 	= $(window).height(),
1750				$barPole 		= $bar.find('.xoo-wsc-bar');
1751
1752			var barPosition 	= $barPole.offset().top - $(window).scrollTop();
1753
1754			Celebrate.barPosition = barPosition/windowHeight;
1755			
1756			return Celebrate.barPosition;
1757			
1758		},
1759
1760		Fireworks: function( myconfetti, barPos ){
1761		    const duration = 3 * 1000,
1762		          animationEnd = Date.now() + duration,
1763		          defaults = { startVelocity: 30, spread: 100, ticks: 60, zIndex: 0 };
1764
1765		    function randomInRange(min, max) {
1766		        return Math.random() * (max - min) + min;
1767		    }
1768
1769		    const interval = setInterval(function(){
1770		        const timeLeft = animationEnd - Date.now();
1771		        if (timeLeft <= 0) return clearInterval(interval);
1772
1773		        const particleCount = 50 * (timeLeft / duration);
1774
1775		        myconfetti(Object.assign({}, defaults, {
1776		            particleCount,
1777		            origin: { x: randomInRange(0.1, 0.3), y: barPos }
1778		        }));
1779
1780		        myconfetti(Object.assign({}, defaults, {
1781		            particleCount,
1782		            origin: { x: randomInRange(0.7, 0.9), y: barPos }
1783		        }));
1784
1785		    }, 250);
1786		},
1787
1788		Stars: function( myconfetti, barPos ){
1789
1790			const defaults = {
1791				origin: { x: 0.5, y: barPos },
1792				spread: 360,
1793				ticks: 50,
1794				gravity: 0,
1795				decay: 0.94,
1796				startVelocity: 30,
1797				shapes: ["star"],
1798				colors: ["FFE400", "FFBD00", "E89400", "FFCA6C", "FDFFB8"],
1799			};
1800
1801			function shoot() {
1802				myconfetti({
1803					...defaults,
1804					particleCount: 40,
1805					scalar: 1,
1806					shapes: ["star"],
1807				});
1808
1809				myconfetti({
1810					...defaults,
1811					particleCount: 10,
1812					scalar: 0.75,
1813					shapes: ["circle"],
1814				});
1815			}
1816
1817			setTimeout(shoot, 0);
1818			setTimeout(shoot, 100);
1819			setTimeout(shoot, 200);
1820		},
1821
1822		SchoolPride: function( myconfetti, barPos ){
1823
1824			const end = Date.now() + 1.5 * 1000;
1825
1826			// go Buckeyes!
1827			const colors = ["#bb0000", "#ffffff"];
1828
1829			(function frame() {
1830				myconfetti({
1831					particleCount: 2,
1832					angle: 60,
1833					spread: 55,
1834					origin: { x: 0, y: barPos },
1835					colors: colors,
1836				});
1837
1838				myconfetti({
1839					particleCount: 2,
1840					angle: 120,
1841					spread: 55,
1842					origin: { x: 1, y: barPos },
1843					colors: colors,
1844				});
1845
1846				if (Date.now() < end) {
1847					requestAnimationFrame(frame);
1848				}
1849			})();
1850		},
1851
1852		RealisticLook: function( myconfetti, barPos ){
1853
1854			const count = 1000,
1855
1856			defaults = {
1857				origin: { y: barPos },
1858			};
1859
1860			function fire(particleRatio, opts) {
1861				myconfetti(
1862					Object.assign({}, defaults, opts, {
1863						particleCount: Math.floor(count * particleRatio),
1864					})
1865				);
1866			}
1867
1868			fire(0.25, {
1869				spread: 26,
1870				startVelocity: 55,
1871			});
1872
1873			fire(0.2, {
1874				spread: 60,
1875			});
1876
1877			fire(0.35, {
1878				spread: 100,
1879				decay: 0.91,
1880				scalar: 0.8,
1881			});
1882
1883			fire(0.1, {
1884				spread: 120,
1885				startVelocity: 25,
1886				decay: 0.92,
1887				scalar: 1.2,
1888			});
1889
1890			fire(0.1, {
1891				spread: 120,
1892				startVelocity: 45,
1893			});
1894		},
1895
1896		BasicCannon: function( myconfetti, barPos ){
1897			myconfetti({
1898			  particleCount: 400,
1899			  spread: 70,
1900			  origin: { y: barPos },
1901			});
1902		}
1903
1904	}
1905
1906
1907
1908	var scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
1909
1910	$('<style>')
1911	  .prop('type', 'text/css')
1912	  .html('body.xoo-wsc-cart-active { padding-right: ' + scrollBarWidth + 'px; }')
1913	  .appendTo('head');
1914	})
1915

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.