PageSourceSearch

https://alcohuaz.cl/wp-content/plugins/woocommerce-side-cart-premium/assets/js/xoo-wsc-main.js?ver=4.8.1

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

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.