PageSourceSearch

https://niituniversity.in/wp-content/themes/estudiar/vamtam/assets/js/all.js?ver=1727779689

js niituniversity.in collected 2026-10-02 05:57:51 UTC 56,689 bytes, 1,709 lines download raw bytes

1/**
2 * Often used vanilla js functions, so that we don't need
3 * to use all of underscore/jQuery
4 */
5(function( undefined ) {
6	"use strict";
7
8	var v = ( window.VAMTAM = window.VAMTAM || {} ); // Namespace
9
10	// Returns a function, that, as long as it continues to be invoked, will not
11	// be triggered. The function will be called after it stops being called for
12	// N milliseconds. If `immediate` is passed, trigger the function on the
13	// leading edge, instead of the trailing.
14	v.debounce = function( func, wait = 300, immediate = false ) {
15		var timeout;
16		return function() {
17			var context = this, args = arguments;
18			var later = function() {
19				timeout = null;
20				if ( ! immediate ) func.apply( context, args );
21			};
22			var callNow = immediate && ! timeout;
23			clearTimeout( timeout );
24			timeout = setTimeout( later, wait );
25			if ( callNow ) func.apply( context, args );
26		};
27	};
28
29	// vanilla jQuery.fn.offset() replacement
30	// @see https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/
31
32	v.offset = function( el ) {
33		var rect = el.getBoundingClientRect(),
34		scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
35		scrollTop = window.pageYOffset || document.documentElement.scrollTop;
36		return { top: rect.top + scrollTop, left: rect.left + scrollLeft };
37	};
38
39	// Faster scroll-based animations
40
41	v.scroll_handlers = [];
42	v.latestKnownScrollY = 0;
43
44	var ticking = false;
45
46	v.addScrollHandler = function( handler ) {
47		requestAnimationFrame( function() {
48			handler.init();
49			v.scroll_handlers.push( handler );
50
51			handler.measure( v.latestKnownScrollY );
52			handler.mutate( v.latestKnownScrollY );
53		} );
54	};
55
56	v.onScroll = function() {
57		v.latestKnownScrollY = window.pageYOffset;
58
59		if ( ! ticking ) {
60			ticking = true;
61
62			requestAnimationFrame( function() {
63				var i;
64
65				for ( i = 0; i < v.scroll_handlers.length; i++ ) {
66					v.scroll_handlers[i].measure( v.latestKnownScrollY );
67				}
68
69				for ( i = 0; i < v.scroll_handlers.length; i++ ) {
70					v.scroll_handlers[i].mutate( v.latestKnownScrollY );
71				}
72
73				ticking = false;
74			} );
75		}
76	};
77
78	window.addEventListener( 'scroll', v.onScroll, { passive: true } );
79
80	// Load an async script
81	v.load_script = function( src, callback ) {
82		var s = document.createElement('script');
83		s.type = 'text/javascript';
84		s.async = true;
85		s.src = src;
86
87		if ( callback ) {
88			s.onload = callback;
89		}
90
91		document.getElementsByTagName('script')[0].before( s );
92	};
93
94	v.load_style = function( href, media, callback, after ) {
95		var l = document.createElement('link');
96		l.rel = 'stylesheet';
97		l.type = 'text/css';
98		l.media = media;
99		l.href = href;
100
101		if ( callback ) {
102			l.onload = callback;
103		}
104
105		if ( after ) {
106			after.after( l );
107		} else {
108			document.getElementsByTagName('link')[0].before( l );
109		}
110	};
111
112	// Checks if current window size is inside the below-max breakpoint range.
113	v.isBelowMaxDeviceWidth = function () {
114		return ! window.matchMedia( '(min-width: ' + VAMTAM_FRONT.max_breakpoint + 'px)' ).matches;
115	};
116
117	// Checks if current window size is inside the max breakpoint range.
118	v.isMaxDeviceWidth = function () {
119		return window.matchMedia( '(min-width: ' + VAMTAM_FRONT.max_breakpoint + 'px)' ).matches;
120	};
121
122	v.isMobileBrowser = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/.test( navigator.userAgent ) || ( /Macintosh/.test( navigator.userAgent ) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2 );
123
124	v.getScrollbarWidth = () => window.innerWidth - document.documentElement.clientWidth;
125})();
126
127(function($, v, undefined) {
128	"use strict";
129
130	var mainHeader      = $('header.main-header');
131	var header_contents = mainHeader.find( '.header-contents' );
132	var menu_toggle     = document.getElementById( 'vamtam-fallback-main-menu-toggle' );
133	var original_toggle = document.querySelector( '#main-menu > .mega-menu-wrap > .mega-menu-toggle' );
134
135	// scrolling below
136
137	var smoothScrollTimer, smoothScrollCallback;
138
139	var smoothScrollListener = function() {
140		clearTimeout( smoothScrollTimer );
141
142		smoothScrollTimer = setTimeout( scrollToElComplete, 200 );
143	};
144
145	var scrollToElComplete = function() {
146		window.removeEventListener( 'scroll', smoothScrollListener, { passive: true } );
147		v.blockStickyHeaderAnimation = false;
148
149		if ( smoothScrollCallback ) {
150			smoothScrollCallback();
151		}
152	};
153
154	var scrollToEl = function( el, duration, callback ) {
155		requestAnimationFrame( function() {
156			var el_offset = el.offset().top;
157
158			v.blockStickyHeaderAnimation = true;
159
160			// measure header height
161			var header_height = 0;
162			header_height = header_contents.height() || 0;
163
164
165			var scroll_position = el_offset - v.adminBarHeight - header_height;
166
167			smoothScrollCallback = callback;
168
169			window.addEventListener( 'scroll', smoothScrollListener, { passive: true } );
170
171			window.scroll( { left: 0, top: scroll_position, behavior: 'smooth' } );
172
173			if ( el.attr( 'id' ) ) {
174				if ( history.pushState ) {
175					history.pushState( null, null, '#' + el.attr( 'id' ) );
176				} else {
177					window.location.hash = el.attr( 'id' );
178				}
179			}
180
181			menu_toggle && menu_toggle.classList.remove( 'mega-menu-open' );
182			original_toggle && original_toggle.classList.remove( 'mega-menu-open' );
183		} );
184	};
185
186	$( document.body ).on('click', '.vamtam-animated-page-scroll[href], .vamtam-animated-page-scroll [href], .vamtam-animated-page-scroll [data-href]', function(e) {
187		var href = $( this ).prop( 'href' ) || $( this ).data( 'href' );
188		var el   = $( '#' + ( href ).split( "#" )[1] );
189
190		var l  = document.createElement('a');
191		l.href = href;
192
193		if(el.length && l.pathname === window.location.pathname) {
194			menu_toggle && menu_toggle.classList.remove( 'mega-menu-open' );
195			original_toggle && original_toggle.classList.remove( 'mega-menu-open' );
196
197			scrollToEl( el );
198			e.preventDefault();
199		}
200	});
201
202	if ( window.location.hash !== "" &&
203		(
204			$( '.vamtam-animated-page-scroll[href*="' + window.location.hash + '"]' ).length ||
205			$( '.vamtam-animated-page-scroll [href*="' + window.location.hash + '"]').length ||
206			$( '.vamtam-animated-page-scroll [data-href*="'+window.location.hash+'"]' ).length
207		)
208	) {
209		var el = $( window.location.hash );
210
211		if ( el.length > 0 ) {
212			$( window ).add( 'html, body, #page' ).scrollTop( 0 );
213		}
214
215		setTimeout( function() {
216			scrollToEl( el );
217		}, 400 );
218	}
219})( jQuery, window.VAMTAM );
220
221/* jshint multistr:true */
222(function( $, undefined ) {
223	"use strict";
224
225	window.VAMTAM = window.VAMTAM || {}; // Namespace
226
227	$(function () {
228		window.VAMTAM.adminBarHeight = document.body.classList.contains( 'admin-bar' ) ? 32 : 0;
229
230		if ( /iPad|iPhone|iPod/.test( navigator.userAgent ) && ! window.MSStream) {
231			requestAnimationFrame( function() {
232				document.documentElement.classList.add( 'ios-safari' );
233			} );
234		}
235
236		if ( navigator.userAgent.includes( 'Safari' ) && ! navigator.userAgent.includes( 'Chrome' ) ) {
237			requestAnimationFrame( function() {
238				document.documentElement.classList.add( 'safari' );
239			} );
240		}
241
242		if ( navigator.userAgent.includes( 'Safari' ) && ! navigator.userAgent.includes( 'Chrome' ) ) {
243			requestAnimationFrame( function() {
244				document.documentElement.classList.add( 'safari' );
245			} );
246		}
247
248		// prevent hover when scrolling
249		(function() {
250			var wrapper = document.body,
251				timer;
252
253			window.addEventListener( 'scroll', function() {
254				clearTimeout(timer);
255
256				requestAnimationFrame( function() {
257					wrapper.classList.add( 'disable-hover' );
258
259					timer = setTimeout( function() {
260						wrapper.classList.remove( 'disable-hover' );
261					}, 300 );
262				} );
263			}, { passive:true } );
264		})();
265
266		// print trigger
267
268		document.addEventListener( 'click', function( e ) {
269			if ( e.target.closest( '.vamtam-trigger-print' ) ) {
270				window.print();
271				e.preventDefault();
272			}
273		} );
274
275		// Code which depends on the window width
276		// =====================================================================
277
278		window.VAMTAM.resizeElements = function() {
279			// video size
280			$('#page .media-inner,\
281				.wp-block-embed-vimeo:not(.wp-has-aspect-ratio),\
282				:not(.wp-block-embed__wrapper) > .vamtam-video-frame').find('iframe, object, embed, video').each(function() {
283
284				setTimeout( function() {
285					requestAnimationFrame( function() {
286						var v_width = this.offsetWidth;
287
288						this.style.width = '100%';
289
290						if ( this.width === '0' && this.height === '0' ) {
291							this.style.height = ( v_width * 9/16 ) + 'px';
292						} else {
293							this.style.height = ( this.height * v_width / this.width ) + 'px';
294						}
295
296						$( this ).trigger('vamtam-video-resized');
297					}.bind( this ) );
298				}.bind( this ), 50 );
299			});
300
301			setTimeout( function() {
302				requestAnimationFrame( function() {
303					$('.mejs-time-rail').css('width', '-=1px');
304				} );
305			}, 100 );
306		};
307
308		window.addEventListener( 'resize', window.VAMTAM.debounce( window.VAMTAM.resizeElements, 100 ), false );
309		window.VAMTAM.resizeElements();
310	} );
311
312	// Handles various overlay types.
313	/*
314		How it works:
315			-keep track of all overlays (vamtam-overlay-trigger class).
316			-keep track of all overlays state (active or not).
317			-bind the relevant click handlers (custom for each overlay type).
318			-attach a doc click handler which figures out which overlays to close or not.
319			-if we switch breakpoint (below-max / max) we close all overlays to avoid conflicts.
320
321		*Every overlay type will be a bit different so it will prob need
322		some custom coding (defining the overlay's targets, close triggers).
323	*/
324	var vamtamOverlaysHandler = function () {
325		var elsThatCauseOverlay    = document.querySelectorAll( '.vamtam-overlay-trigger' );
326		var elsThatCauseOverlayArr = [];
327		var prevIsBelowMax         = window.VAMTAM.isBelowMaxDeviceWidth();
328
329		var triggerCloseHandlers = function () {
330			elsThatCauseOverlayArr.forEach( function( el ) {
331				if ( el.isActive ) {
332					el.closeTrigger.click();
333				}
334			} );
335		};
336
337		var overlaysResizeHandler = function () {
338			var isBelowMax = window.VAMTAM.isBelowMaxDeviceWidth();
339			if ( prevIsBelowMax !== isBelowMax) {
340				// We changed breakpoint (max/below-max).
341				// Close all overlays.
342				triggerCloseHandlers();
343				prevIsBelowMax = isBelowMax;
344			}
345		};
346
347		var overlayCloseHandler = function ( target ) {
348			// Is this an elementor menu overlay?
349			if ( $( target ).hasClass( 'elementor-menu-toggle' ) ) {
350				// Button is a toggle (on/off).
351				target.removeEventListener( 'click', onOverlayCloseClick );
352				target.addEventListener( 'click', onOverlayCloseClick );
353				return;
354			}
355			// Add other type of overlays here.
356		};
357
358		var onOverlayCloseClick = function ( e ) {
359			// Is this an elementor menu overlay?
360			var target = e.currentTarget;
361			if ( $( target ).hasClass( 'elementor-menu-toggle' ) ) {
362				var elRow = $( target ).closest( '.elementor-row' );
363				// Elementor >= v3.0.
364				if ( ! elRow.length ) {
365					// v3.0 removed the .elementor-row element.
366					elRow = $( target ).closest( '.elementor-container' );
367				}
368
369				if ( elRow.hasClass( 'vamtam-overlay-trigger--overlay' ) ) {
370					// We need to remove the overlay
371					elRow.removeClass( 'vamtam-overlay-trigger--overlay' );
372					target.removeEventListener( 'click', onOverlayCloseClick ); // cause it's a toggle.
373					elsThatCauseOverlayArr.forEach( function( e ) {
374						if ( e.overlayTarget === target || e.closeTrigger === target ) {
375							e.isActive = false;
376						}
377					});
378				}
379			}
380			// Add other type of overlays here.
381
382			var activeOverlays = $( '.vamtam-overlay-trigger--overlay .vamtam-overlay-element:visible' );
383			if ( activeOverlays.length < 2 ) { // If there are other active overlays, don't activate scrollers/stt.
384				// Enable page scroll.
385				$( 'html, body' ).removeClass( 'vamtam-disable-scroll' );
386				// Show stt.
387				$( '#scroll-to-top' ).removeClass( 'hidden' );
388			}
389		};
390
391		var onOverlayTriggerClick = function ( e ) {
392			var target = e.currentTarget;
393			// Is this an elementor menu overlay?
394			if ( $( target ).hasClass( 'elementor-menu-toggle' ) ) {
395				var elRow = $( target ).closest( '.elementor-row' );
396				// Elementor >= v3.0.
397				if ( ! elRow.length ) {
398					// v3.0 removed the .elementor-row element.
399					elRow = $( target ).closest( '.elementor-container' );
400				}
401
402				// This is for moving the overlay underneath the main-menu.
403				if ( ! elRow.hasClass( 'vamtam-menu-nav-overlay-inside' ) ) {
404					elRow.addClass( 'vamtam-menu-nav-overlay-inside' );
405					$( elRow ).find( '.vamtam-overlay-element' ).css( 'top', ( $( elRow )[ 0 ].getBoundingClientRect().top + $( elRow ).height() ) + 'px' );
406				}
407
408				if ( ! elRow.hasClass( 'vamtam-overlay-trigger--overlay' ) ) {
409					// We need to add the overlay class
410					elRow.addClass( 'vamtam-overlay-trigger--overlay' );
411					elsThatCauseOverlayArr.forEach( function( e ) {
412						if ( e.overlayTarget === target || e.closeTrigger === target ) {
413							e.isActive = true;
414						}
415					});
416				} else {
417					// This is a close instruction, let onOverlayCloseClick() handle it.
418					return;
419				}
420			}
421			// Add other type of overlays here.
422
423			// Disable page scroll.
424			$( 'html, body' ).addClass( 'vamtam-disable-scroll' );
425			// Hide stt
426			$( '#scroll-to-top' ).addClass( 'hidden' );
427
428			// Register the overlay close handler
429			overlayCloseHandler( target );
430		};
431
432		elsThatCauseOverlay.forEach( function ( el ) {
433			// Is this an elementor menu overlay?
434			if ( $( el ).hasClass( 'elementor-widget-nav-menu' ) ) {
435				// Get menu toggle.
436				var menuToggle = $( el ).find( '.elementor-menu-toggle' )[ 0 ];
437
438				// The click listener should be on menu toggle for nav menus.
439				menuToggle.removeEventListener( 'click', onOverlayTriggerClick );
440				menuToggle.addEventListener( 'click', onOverlayTriggerClick );
441
442				elsThatCauseOverlayArr.push( {
443					overlayTarget: el, // The el that holds the vamtam-overlay-trigger class.
444					closeTrigger: menuToggle, // The el that closes the overlay.
445					isActive: false // If the overlay is active or not.
446				} );
447
448				// Add the overlay el.
449				var elRow = $( el ).closest( '.elementor-row' );
450				// Elementor >= v3.0.
451				if ( ! elRow.length ) {
452					// v3.0 removed the .elementor-row element.
453					elRow = $( el ).closest( '.elementor-container' );
454				}
455				$( '<span class="vamtam-overlay-element"></span>' ).appendTo( elRow );
456
457				return;
458			}
459			// Add other type of overlays here.
460		} );
461
462		if ( elsThatCauseOverlay.length ) {
463			var docClickHandler = function ( e ) {
464				elsThatCauseOverlayArr.forEach( function( el ) {
465					if ( ! el.isActive ) {
466						return;
467					}
468					// If a click happened,
469					// and there is an active overlay,
470					// and the click target isn't the overlay target or an element inside it,
471					// then call the overlay close handler.
472					if ( e.target !== el.overlayTarget && ! el.overlayTarget.contains( e.target ) ) {
473						el.closeTrigger.click();
474					}
475				} );
476			};
477
478			document.addEventListener( 'click', docClickHandler, true ); // we need capture phase here.
479			window.addEventListener( 'resize', window.VAMTAM.debounce( overlaysResizeHandler, 200 ), false );
480		}
481	};
482
483	const addScrollbarWidthCSSProp = () => {
484		jQuery( 'html' ).css( '--vamtam-scrollbar-width', window.VAMTAM.getScrollbarWidth() + 'px' );
485	};
486
487	// Low priority scripts are loaded later
488	document.addEventListener('DOMContentLoaded', function () {
489		window.VAMTAM.load_script( VAMTAM_FRONT.jspath + 'low-priority.js' );
490
491		vamtamOverlaysHandler();
492
493		addScrollbarWidthCSSProp();
494	}, { passive: true } );
495
496})(jQuery);
497
498( function( $, v, undefined ) {
499	'use strict';
500
501	window.Cookies = window.Cookies || {
502		get: function( name ) {
503			var value = '; ' + document.cookie;
504			var parts = value.split( '; ' + name + '=' );
505
506			if ( parts.length === 2 ) {
507				return parts.pop().split( ';' ).shift();
508			}
509		}
510	};
511
512	var bijouxCustomNumericInputs = function () {
513		var numInputs = document.querySelectorAll( 'input[type="number"]:not([max="1"])' );
514		numInputs.forEach( function( input ) {
515			var $parent = $( input ).parent();
516
517			$parent.append( '<div class="vamtam-count-wrap"></div>' );
518			$parent.append( '<span class="vamtam-increment"  onclick="this.parentNode.querySelector(\'input[type=number]\').stepUp();this.parentNode.querySelector(\'input[type=number]\').dispatchEvent(new Event(\'change\', {bubbles: true}))">+</span>' );
519			$parent.append( '<span class="vamtam-decrement"  onclick="this.parentNode.querySelector(\'input[type=number]\').stepDown();this.parentNode.querySelector(\'input[type=number]\').dispatchEvent(new Event(\'change\', {bubbles: true}))">-</span>' );
520
521			var $wrap = $parent.find( '.vamtam-count-wrap' ),
522				$inc  = $parent.find( '.vamtam-increment' ),
523				$dec  = $parent.find( '.vamtam-decrement' );
524
525			$( $dec ).appendTo( $wrap );
526			$( input ).appendTo( $wrap );
527			$( $inc ).appendTo( $wrap );
528		} );
529	};
530
531	$( function() {
532		var dropdown        = $( '.fixed-header-box .cart-dropdown' ),
533			link            = $( '.vamtam-cart-dropdown-link' ),
534			count           = $( '.products', link ),
535			$elementorCart  = $( '.elementor-widget-woocommerce-menu-cart' ),
536			isElementorCart = $elementorCart.length,
537			$itemsCount     = isElementorCart && $( $elementorCart ).find( '.vamtam-elementor-menu-cart__header .item-count' ),
538			isCartPage      = 'wc_add_to_cart_params' in window && window.wc_add_to_cart_params.is_cart;
539
540		$( document.body ).on( 'applied_coupon_in_checkout', function() {
541			let error = document.querySelector( '.woocommerce-error' );
542			error && error.scrollIntoView( { block: 'center', 'behavior': 'smooth' } );
543		} );
544
545		function fixElementorWcCartConflicts() {
546			if ( isCartPage ) {
547				// Cart page
548				var targets = document.querySelectorAll( '.woocommerce-cart-form__contents' );
549				targets.forEach( function( target ) {
550					var shouldRemoveClass = ! $( target ).hasClass( 'shop_table' ) && ! $( target ).parent().hasClass( 'vamtam-cart-main' );
551					if ( shouldRemoveClass ) {
552						// This class is used by WC. https://github.com/woocommerce/woocommerce/blob/master/assets/js/frontend/cart.js#L92
553						// Elementor uses on their menu cart which causes problems.
554						// So, if we are on the cart page and the class is not added by WC or us, remove it.
555						$( target ).removeClass( 'woocommerce-cart-form__contents' );
556					}
557				});
558			}
559		}
560
561		window.VAMTAM.bijouxCustomNumericInputs = bijouxCustomNumericInputs;
562
563		var isFrontend = ! ( 'elementorFrontend' in window ) || ! window.elementorFrontend.isEditMode();
564
565		if ( isFrontend ) {
566			$( document ).ready( function () {
567				if ( document.body.classList.contains( 'elementor-active' ) ) {
568					bijouxCustomNumericInputs();
569				}
570			} );
571		} else {
572			$(window).on('elementor/frontend/init', function(){
573				window.elementor.on('document:loaded', function(){
574					// The timeout is for ensuring that when the function is run, the frontend DOM has
575					// been created (when on editor). Can't seem to find a proper event for this from Elementor.
576					setTimeout( function() {
577						bijouxCustomNumericInputs();
578					}, 1000 );
579				} );
580			} );
581		}
582
583		function triggerSideCart() {
584			const toggleCartOpenBtns = $( '#elementor-menu-cart__toggle_button:visible' );
585			$.each( toggleCartOpenBtns, function ( i, el ) {
586				el.click();
587			} );
588		}
589
590		var openCartHandle = function ( e ) {
591			const toggleCartOpenBtns = $( '.elementor-widget-woocommerce-menu-cart .elementor-menu-cart__toggle_button' );
592			let toggleClicked = false;
593
594			$.each( toggleCartOpenBtns, function ( i, el ) {
595				if ( $( el ).is( e.target ) || $( el ).has( e.target ).length ) {
596					toggleClicked = true;
597					return false; // break.
598				}
599			} );
600
601			if ( ! toggleClicked ) {
602				/*
603					We only care about clicks on the toggle button.
604
605					We do manual target detection because we cant use the on() method to attach
606					the event cause we need capture phase.
607				*/
608				return;
609			}
610
611			e.preventDefault();
612			if ( isCartPage ) {
613				// Don't do anything on cart page.
614				e.stopImmediatePropagation();
615				return false;
616			} else {
617				if ( window.VAMTAM.isMobileBrowser ) {
618					// Redirect to cart page.
619					e.stopImmediatePropagation();
620					window.location = window.wc_add_to_cart_params.cart_url;
621					return false;
622				}
623
624				// Disable page scroll.
625				$( 'body' ).addClass( 'vamtam-disable-scroll' );
626				// Hide stt
627				$( '#scroll-to-top' ).addClass( 'hidden' );
628				// Furthest section from target inside header.
629				var sectionWrapSection = $( e.target ).closest( '.elementor-section-wrap' ).find( 'section.elementor-element' ).first();
630				// This is so the element tree gets it's own layer. We need this for top to work correctly.
631				sectionWrapSection.css( 'will-change', 'transform' );
632				// Raise z-index cause sometimes card gets hidden by other elements.
633				sectionWrapSection.css( 'z-index', '1000' );
634			}
635		};
636
637		var closeCartHandle = function ( e, cartIsEmpty ) {
638			var targetIsWrapperOrCloseBtn = $( e.target ).is( '.elementor-menu-cart__container, .vamtam-close-cart, .e-close-cart-custom-icon' );
639			var lastItemRemoved           = e === 'no-target' && cartIsEmpty;
640			if ( targetIsWrapperOrCloseBtn || lastItemRemoved ) {
641				// Enable page scroll.
642				$( 'body' ).removeClass( 'vamtam-disable-scroll' );
643				// Show stt.
644				$( '#scroll-to-top' ).removeClass( 'hidden' );
645				// Unset z-index
646				$( e.target ).closest( 'section.elementor-element' ).css( 'z-index', '' );
647			}
648		};
649
650		// Registers the handlers that toggle the scroll to top.
651		function bindOpenCloseMenuCartHandlers() {
652			// Menu cart open btn (Elementor)
653			const toggleCartOpenBtns =  document.querySelectorAll( '.elementor-widget-woocommerce-menu-cart .elementor-menu-cart__toggle_wrapper' );
654			toggleCartOpenBtns.forEach( function( el ) {
655				el.removeEventListener( 'click', openCartHandle );
656				el.addEventListener( 'click', openCartHandle, true );
657			});
658
659			// Menu cart wrap/close btn (Elementor)
660			const toggleCartCloseBtns =  document.querySelectorAll( '.elementor-widget-woocommerce-menu-cart .elementor-menu-cart__container .elementor-menu-cart__close-button, .elementor-widget-woocommerce-menu-cart .elementor-menu-cart__container' );
661			toggleCartCloseBtns.forEach( function( el ) {
662				el.removeEventListener( 'click', closeCartHandle );
663				el.addEventListener( 'click', closeCartHandle );
664			} );
665		}
666		bindOpenCloseMenuCartHandlers();
667
668		function moveScrollToTop( reset ) {
669			const $stt = $('#scroll-to-top.vamtam-scroll-to-top');
670			const $wcMsg = $('.woocommerce-notices-wrapper .woocommerce-message');
671			if ( $stt.length ) {
672				if ( reset ) {
673					$stt.css( 'bottom', '10px' );
674				} else {
675					if ( $wcMsg.length ) {
676						$stt.css('bottom', $wcMsg.outerHeight() + 10 + 'px');
677					} else {
678						$stt.css( 'bottom', '95px' );
679					}
680
681				}
682			}
683		}
684
685		// "vamtam_elementor_menu_cart_fragments" == "added_to_cart" + "removed_from_cart" + "wc_fragments_refreshed" + "wc_fragments_loaded"
686		// We also add "wc_fragments_loaded" on "vamtam_elementor_menu_cart_fragments" for caching reasons.
687		const menuCartEvents = isElementorCart ? 'vamtam_elementor_menu_cart_fragments wc_fragments_loaded' : 'added_to_cart removed_from_cart wc_fragments_refreshed wc_fragments_loaded';
688		$( document.body ).on( menuCartEvents, function() {
689			var count_val = parseInt( Cookies.get( 'woocommerce_items_in_cart' ) || 0, 10 );
690			if ( count_val > 0 ) {
691				if ( isElementorCart ) {
692					$elementorCart.removeClass( 'hidden' );
693					var itemsInCart = $elementorCart[ 0 ].querySelectorAll( '.cart_item .quantity select, .cart_item .quantity .vamtam-quantity-input' ),
694						getFromTextContent = false,
695						bubbleIconEls = $elementorCart.find( '#elementor-menu-cart__toggle_button .elementor-button-icon-qty' );
696
697					if ( ! itemsInCart.length ) {
698						itemsInCart = $elementorCart[ 0 ].querySelectorAll( '.cart_item .product-quantity' );
699						getFromTextContent = true;
700					}
701
702					var total = 0;
703					itemsInCart.forEach( function( item ) {
704						const val = getFromTextContent ? item.textContent : item.value;
705						total += parseInt( val, 10 );
706					} );
707
708					$itemsCount.text( '(' + total + ')' );
709
710					$.each( bubbleIconEls, function( index, el ) {
711						const bubbleIconVal = parseInt( $( el ).attr( 'data-counter' ), 10 );
712						// Mismatch between products total and cart bubble icon - Can happen due to caching.
713						if ( total !== bubbleIconVal ) {
714							$( el ).attr( 'data-counter', total );
715						}
716					} );
717				} else {
718					var count_real = 0;
719
720					var widgetShoppingCart = document.querySelector( '.widget_shopping_cart' ),
721						spans              = widgetShoppingCart ? widgetShoppingCart.querySelectorAll( 'li .quantity' ) : [];
722
723					if ( widgetShoppingCart ) {
724						for ( var i = 0; i < spans.length; i++ ) {
725							count_real += parseInt( spans[i].innerHTML.split( '<span' )[0].replace( /[^\d]/g, '' ), 10 );
726						}
727
728						// sanitize count_real - if it's not a number, then don't show the counter at all
729						count_real = count_real >= 0 ? count_real : '';
730
731						count.text( count_real );
732						count.removeClass( 'cart-empty' );
733						dropdown.removeClass( 'hidden' );
734					}
735				}
736			} else {
737				if ( isElementorCart ) {
738					var hideEmpty = $elementorCart.hasClass( 'elementor-menu-cart--empty-indicator-hide' );
739					$elementorCart.toggleClass( 'hidden', hideEmpty );
740					$itemsCount.text( '(0)' );
741					closeCartHandle( 'no-target', true );
742				} else {
743					var show_if_empty = dropdown.hasClass( 'show-if-empty' );
744
745					count.addClass( 'cart-empty' );
746					count.text( '0' );
747
748					dropdown.toggleClass( 'hidden', ! show_if_empty );
749				}
750			}
751
752			document.body.classList.toggle( 'vamtam-wc-cart-empty', count_val === 0 );
753
754			// Move the scroll to top so it's not on top of checkout message (single product).
755			var isSingleProduct = $('body').hasClass('single-product');
756			var checkoutMessageExists = isSingleProduct ? $('.woocommerce-notices-wrapper .woocommerce-message').length : false;
757			if ( checkoutMessageExists ) {
758				moveScrollToTop();
759			}
760
761			bijouxCustomNumericInputs();
762			bindOpenCloseMenuCartHandlers();
763			fixElementorWcCartConflicts();
764		} );
765
766		function injectWCNotice( notice ) {
767			if ( notice ) {
768				// Append notice.
769				$( '.woocommerce-notices-wrapper').empty().append( notice );
770				// Remove notice btn handler.
771				var $closeNoticeBtn = $( '.woocommerce-notices-wrapper' ).find( '.vamtam-close-notice-btn' );
772
773				if ( ! $closeNoticeBtn.length ) {
774					return;
775				}
776
777				$closeNoticeBtn[ 0 ].addEventListener( 'click', function () {
778					var $msg = $( this ).closest( '.woocommerce-message' );
779					$msg.fadeOut( 'fast' );
780					moveScrollToTop( true );
781					setTimeout( function() {
782						$msg.remove();
783					}, 2000 );
784				} );
785				// Remove notice after 10s.
786				setTimeout( function() {
787					var $msg = $closeNoticeBtn.closest( '.woocommerce-message' );
788					$msg.fadeOut( 'fast' );
789					setTimeout( function() {
790						$msg.remove();
791						moveScrollToTop( true );
792					}, 2000 );
793				}, 1000 * 10 );
794			}
795		}
796
797		function moveCheckoutErrorNotices() {
798			const isCheckout     = $( document.body ).hasClass( 'woocommerce-checkout' ),
799				  $checkout_form = isCheckout && $( 'form.checkout' ),
800				  $dest          = isCheckout && $( '.woocommerce > .woocommerce-notices-wrapper' ).first();
801
802			if ( ! isCheckout || ! $checkout_form.length || ! $dest.length ) {
803				return;
804			}
805
806			const onCheckoutError = function () {
807				const noticeGroup = $checkout_form.find( '.woocommerce-NoticeGroup.woocommerce-NoticeGroup-checkout' );
808				$dest.append( noticeGroup );
809			};
810
811			$( document.body ).on( 'checkout_error', onCheckoutError );
812		}
813
814		// Products with stock management that have a single last unit available.
815		function lastStockQtyFix() {
816			if ( $( 'body' ).hasClass( 'single-product' ) && ! $( '.sold-individually' ).length ) {
817				const $stock = $( '.stock.in-stock' );
818				const qty = $( 'input[name="quantity"][max="1"][min="1"]' );
819				if ( $stock.length &&  qty.length) {
820					$stock.addClass( 'last-one' );
821				}
822			}
823		}
824		lastStockQtyFix();
825
826		// Apply coupon (standard cart).
827		$( document ).on( 'click', '.woocommerce-cart button[name="apply_coupon"]:not(".e-apply-coupon"):visible', function( e ) {
828			e.preventDefault();
829			// This is a proxy btn, trigger the sumbit which is inside the wc-cart-form.
830			const $applyCouponSubmit = $( 'input[type="submit"][name="apply_coupon"]' );
831			$applyCouponSubmit.trigger( 'click' );
832		});
833
834		if ( window.VAMTAM_FRONT.enable_ajax_add_to_cart === 'yes' ) {
835			// Add to cart ajax
836			$( document ).on( 'click', '.single_add_to_cart_button, .products.vamtam-wc.table-layout .add_to_cart_button:not(.product_type_variable)', function( e ) {
837				// Collect product data.
838				var $thisbutton   = $( this ),
839					$form         = $thisbutton.closest( 'form.cart' ),
840					id            = $thisbutton.val(),
841					product_qty   = $form.find( 'input[name=quantity]' ).val() || 1,
842					product_id    = $form.find( 'input[name=product_id]' ).val() || id,
843					variation_id  = $form.find( 'input[name=variation_id]' ).val() || 0,
844					isVariable    = variation_id,
845					isBookable    = $form.find( 'input[name=add-to-cart].wc-booking-product-id' ).val(),
846					isGrouped     = $form.hasClass( 'grouped_form' ),
847					isExternal    = $form.parent( '.elementor-product-external').length && $form.attr('method') === 'get',
848					isTableLayout = $thisbutton.closest( '.products.vamtam-wc.table-layout' ).length,
849					products      = {};
850
851				// TODO: Until we find a proper ajax solution for variable products.
852				if ( isVariable ) {
853					const disableThemeHandler = $thisbutton.parents( '.elementor-widget-woocommerce-product-add-to-cart.vamtam-has-disable-theme-ajax-vars' ).length;
854					if ( disableThemeHandler ) {
855						return;
856					}
857				}
858
859				// Don't submit the form.
860				e.preventDefault();
861
862				// External product.
863				if ( isExternal ) {
864					// Open the external link in a new tab instead.
865					window.open( $form.attr( 'action' ),'_blank' );
866					return;
867				}
868
869				if ( ! window.wc_add_to_cart_params ) {
870					return; // No ajax_url
871				}
872
873				// Grouped products
874				if ( isGrouped ) {
875					product_id = parseInt( $form.find( 'input[name=add-to-cart]' ).val() );
876					var $products  = $form.find( '[id^="product-"]' );
877
878					$.each( $products, function( index, product ) {
879						var addToCartBtn = $( product ).find( '.add_to_cart_button' );
880						var p_id = $( product ).attr( 'id' ).substr( 8 ), // the "product-" part.
881							p_qty;
882
883						if ( addToCartBtn.length ) {
884							p_qty = parseInt( addToCartBtn.attr( 'data-quantity' ) ) || 0;
885						} else {
886							p_qty = parseInt( $( product ).find( 'input.qty' ).val() ) || 0;
887						}
888
889						products[ p_id ] = p_qty;
890					} );
891				}
892
893				// Table Layout.
894				if ( isTableLayout ) {
895					const $row = $thisbutton.closest( 'tr.vamtam-product' );
896					if ( $row.length ) {
897						product_qty = $row.find( 'input[name=quantity]' ).val() || 1;
898						product_id  = $thisbutton.attr( 'data-product_id' ) || id;
899					}
900				}
901
902				// Format post data.
903				var data = {};
904				if ( isBookable ) {
905					// Channel bookables through our woocommerce_ajax_add_to_cart so there's
906					// a single endpoint for all "add to cart" actions.
907					const fData = new FormData( $form[ 0 ] );
908					fData.forEach( function( value, key ){
909						// We need to generate those fields to pass woocommerce_add_to_cart_validation
910						// since we are not posting the form directly to wc_bookings.
911						if ( key === 'add-to-cart' ) {
912							data.product_id = value;
913						} else {
914							data[ key.replace( 'wc_bookings_field', '' ) ] = value;
915						}
916
917						// if key contains "[]" it should be treated as an array.
918						if ( key.includes( '[]') ) {
919							data[ key ] = fData.getAll( key );
920						} else {
921							data[ key ] = value;
922						}
923					});
924					data.is_wc_booking = true;
925				} else if ( isGrouped ) {
926					// Grouped product
927					data = {
928						product_id: product_id,
929						products: products,
930						is_grouped: true,
931					};
932				} else if ( isVariable ) {
933					// Variable product
934					data = {
935						product_id: product_id,
936						is_variable: true,
937					};
938					// Send all fields.
939					const fData = new FormData( $form[ 0 ] );
940					fData.forEach( function( value, key ) {
941						if ( key === 'add-to-cart' ) {
942							// the "add-to-cart: id" pair triggers WC's WC_Form_Handler::add_to_cart_action()
943							// and the product ends up being added twice to the cart.
944							data.product_id = value;
945						} else {
946							// if key contains "[]" it should be treated as an array.
947							if ( key.includes( '[]') ) {
948								data[ key ] = fData.getAll( key );
949							} else {
950								data[ key ] = value;
951							}
952						}
953					} );
954				} else {
955					// Simple product
956					data = {
957						product_id: product_id,
958					};
959
960					// Send all fields.
961					const fData = new FormData( $form[ 0 ] );
962					fData.forEach( function( value, key ) {
963						if ( key === 'add-to-cart' ) {
964							// the "add-to-cart: id" pair triggers WC's WC_Form_Handler::add_to_cart_action()
965							// and the product ends up being added twice to the cart.
966							if ( ! data.product_id ) {
967								data.product_id = value;
968							}
969						} else {
970							// if key contains "[]" it should be treated as an array.
971							if ( key.includes( '[]') ) {
972								data[ key ] = fData.getAll( key );
973							} else {
974								data[ key ] = value;
975							}
976						}
977					} );
978				}
979
980				// Common fields.
981				data.product_sku  = '';
982				data.quantity     = product_qty;
983				data.variation_id = variation_id;
984				data.action       = 'woocommerce_ajax_add_to_cart';
985
986				// Triger adding_to_cart event (theme/plugins might wanna use it).
987				$( document.body ).trigger( 'adding_to_cart', [$thisbutton, data] );
988
989				// Perform Ajax.
990				$.ajax({
991					type: 'post',
992					url: window.wc_add_to_cart_params.ajax_url,
993					data: data,
994					beforeSend: function () {
995						$thisbutton.removeClass( 'added' ).addClass( 'loading' );
996					},
997					complete: function ( response ) {
998						if ( response.error ) {
999							$thisbutton.removeClass( 'loading' );
1000						} else {
1001							$thisbutton.addClass( 'added' ).removeClass( 'loading' );
1002						}
1003					},
1004					success: function ( response ) {
1005						if ( response.error ) {
1006							// Inject wc notice if there's one.
1007							injectWCNotice( response.notice );
1008							$( document.body ).trigger( 'wc_fragments_refreshed' );
1009						} else {
1010							// Successful addition
1011							if ( response.redirect_to_cart ) {
1012								// User has enabled redirect to cart on successful addition.
1013								// Redirect to cart page, don't do anything else.
1014								window.location = window.wc_add_to_cart_params.cart_url;
1015								return;
1016							}
1017
1018							if ( isElementorCart ) {
1019								if ( isTableLayout ) {
1020									const shouldTriggerSideCart = ! window.VAMTAM.isMobileBrowser && $thisbutton.parents( '.vamtam-has-adc-triggers-menu-cart[data-widget_type="woocommerce-products.products_table_layout"]' ).length;
1021									if ( shouldTriggerSideCart ) {
1022										setTimeout(() => {
1023											triggerSideCart();
1024										}, 500);
1025									}
1026								} else {
1027									const shouldTriggerSideCart = ! window.VAMTAM.isMobileBrowser;
1028									if ( shouldTriggerSideCart ) {
1029										setTimeout(() => {
1030											triggerSideCart();
1031										}, 500);
1032									}
1033								}
1034							} else {
1035								// Inject wc notice if there's one.
1036								injectWCNotice( response.fragments.notice );
1037							}
1038							$( document.body ).trigger( 'added_to_cart', [response.fragments, response.cart_hash, $thisbutton] );
1039						}
1040					},
1041				});
1042
1043				return false;
1044			});
1045		}
1046
1047		if ( window.wc_add_to_cart_params ) {
1048			// Ajax delete product in the menu cart.
1049			$( document ).on( 'click', '.mini_cart_item a.remove, .woocommerce-mini-cart .woocommerce-cart-form__cart-item .product-remove > a:not([class])', function ( e ) {
1050				// Don't refresh.
1051				e.preventDefault();
1052
1053				// Collect product data.
1054				var $thisbutton       = $( this ),
1055					product_id        = $( this ).attr( 'data-product_id' ),
1056					cart_item_key     = $( this ).attr( 'data-cart_item_key' ),
1057					product_container = $( this ).parents('.mini_cart_item, .woocommerce-cart-form__cart-item' );
1058
1059				// Perform Ajax.
1060				$.ajax({
1061					type: 'post',
1062					dataType: 'json',
1063					url: window.wc_add_to_cart_params.ajax_url,
1064					data: {
1065						action: 'product_remove',
1066						product_id: product_id,
1067						cart_item_key: cart_item_key
1068					},
1069					beforeSend: function () {
1070						product_container.css( 'pointer-events', 'none' ).css( 'opacity', '0.5' );
1071						$( 'body' ).css( 'cursor', 'wait' );
1072					},
1073					complete: function () {
1074						$( 'body' ).css( 'cursor', 'default' );
1075					},
1076					success: function( response ) {
1077						if ( ! response || ! response.fragments ) {
1078							window.location = $thisbutton.attr( 'href' );
1079							return;
1080						}
1081						$( document.body ).trigger( 'removed_from_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
1082					},
1083					error: function() {
1084						window.location = $thisbutton.attr( 'href' );
1085						return;
1086					},
1087				});
1088			});
1089		}
1090
1091		// Ajax update product quantity from cart (menu/standard).
1092		const cartQtySelector = '.woocommerce-cart-form__cart-item .vamtam-quantity';
1093		$( document ).on( 'change', `${cartQtySelector} select, ${cartQtySelector} input`, v.debounce( function ( e ) {
1094			e.preventDefault();
1095
1096			// Collect data.
1097			var isStandardCard    = $( '.woocommerce-cart' ).length,
1098				product_quantity  = $( this ).val(),
1099				product_id        = $( this ).attr( 'data-product_id' ),
1100				cart_item_key     = $( this ).attr( 'data-cart_item_key' ),
1101				product_container = $( this ).parents('.mini_cart_item, .woocommerce-cart-form__cart-item' );
1102
1103			if ( isStandardCard ) {
1104				var $updateCardBtn = $( 'input[type="submit"][name="update_cart"]' );
1105				$updateCardBtn.prop( 'disabled', false );
1106				$updateCardBtn.trigger( 'click' );
1107				return;
1108			}
1109
1110			if ( ! window.wc_add_to_cart_params ) {
1111				return; // No ajax_url
1112			}
1113
1114			// Perform Ajax.
1115			$.ajax({
1116				type: 'post',
1117				dataType: 'json',
1118				url: window.wc_add_to_cart_params.ajax_url,
1119				data: {
1120					action : 'update_item_from_cart',
1121					'product_id' : product_id,
1122					'cart_item_key' : cart_item_key,
1123					'product_quantity' : product_quantity,
1124				},
1125				beforeSend: function () {
1126					product_container.css( 'pointer-events', 'none' ).css( 'opacity', '0.5' );
1127					$( 'body' ).css( 'cursor', 'wait' );
1128				},
1129				complete: function () {
1130					product_container.css( 'pointer-events', 'auto' ).css( 'opacity', '1' );
1131					$( 'body' ).css( 'cursor', 'default' );
1132				},
1133				success: function( response ) {
1134					if ( ! response || ! response.fragments ) {
1135						return;
1136					}
1137					$( document.body ).trigger( 'wc_fragment_refresh' );
1138				},
1139				error: function() {
1140					return;
1141				}
1142			});
1143		} ) );
1144
1145		window.addEventListener('load',function(){
1146			moveCheckoutErrorNotices();
1147			if ( isElementorCart ) {
1148				bindOpenCloseMenuCartHandlers();
1149				fixElementorWcCartConflicts();
1150			}
1151		} );
1152
1153		function onElementorMenuCartFragmentsUpdated() {
1154			/*
1155				They have replaced WC's cart-fragments ajax handling but have not provided any way of reacting to their changes.
1156				We do this ourselves here.
1157			*/
1158			$( document ).ajaxComplete( ( event, xhr, settings ) => {
1159				const response = xhr.responseJSON,
1160					responseOk = response && response.fragments,
1161					actionOK   = ( settings.data &&  settings.data.indexOf( 'action=elementor_menu_cart_fragments' ) !== -1 );
1162
1163				if ( responseOk && actionOK ) {
1164					$( document.body ).trigger( 'vamtam_elementor_menu_cart_fragments' );
1165				}
1166			} );
1167		}
1168
1169		if ( isElementorCart ) {
1170			onElementorMenuCartFragmentsUpdated();
1171		}
1172	} );
1173} )( jQuery, window.VAMTAM );
1174
1175( function( $, undefined ) {
1176	"use strict";
1177
1178	window.VAMTAM = window.VAMTAM || {}; // Namespace
1179	window.VAMTAM.CUSTOM_ANIMATIONS = {};
1180
1181	$( function() {
1182		window.VAMTAM.CUSTOM_ANIMATIONS = {
1183			init: function () {
1184				this.VamtamCustomAnimations.init();
1185			},
1186			onDomReady: function () {
1187				this.VamtamCustomAnimations.scrollBasedAnims();
1188			},
1189			// Handles custom animations.
1190			VamtamCustomAnimations: {
1191				init: function() {
1192					this.registerAnimations();
1193					this.utils.watchScrollDirection();
1194					// this.observedAnims(); // Disabled in favor of elementorFrontend.waypoint().
1195				},
1196				registerAnimations: function () {
1197					var self = this;
1198
1199					// Register animations here.
1200					var animations = [
1201						'stickyHeader', // Same name as function.
1202						// Caridad-only.
1203						'cursorAnimation', // Same name as function.
1204					];
1205
1206					animations.forEach( function( animation ) {
1207						self[ animation ].apply( self );
1208					} );
1209				},
1210				// A sticky header animation.
1211				stickyHeader: function () {
1212					var $target                = $( '.vamtam-sticky-header' ),
1213						topScrollOffsetTrigger = 300,
1214						_self                  = this;
1215
1216					if ( ! $target.length ) {
1217						return;
1218					}
1219
1220					if ( $target.length > 1 ) {
1221						// There should only be one sticky header.
1222						$target = $target[ 0 ];
1223					}
1224
1225					( function () { // IIFE for closure so $target is available in rAF.
1226						var prevAnimState,
1227							isTransparentHeader = $( $target ).hasClass( 'vamtam-sticky-header--trans
1227parent-header' ),
1228							isFrontend          = ! window.elementorFrontend.isEditMode();
1229
1230						// state: fixed, scrolled up (not visible).
1231						var fixedHiddenState = function () {
1232							$( $target ).removeClass( 'vamtam-sticky-header--fixed-shown' );
1233							if ( ! $( $target ).hasClass( 'vamtam-sticky-header--fixed-hidden' ) ) {
1234								$( $target ).addClass( 'vamtam-sticky-header--fixed-hidden' );
1235							}
1236							prevAnimState = 'fixedHiddenState';
1237						};
1238
1239						// state: fixed, scrolled down (visible).
1240						var fixedShownState = function () {
1241							$( $target ).removeClass( 'vamtam-sticky-header--fixed-hidden' );
1242							if ( ! $( $target ).hasClass( 'vamtam-sticky-header--fixed-shown' ) ) {
1243								$( $target ).addClass( 'vamtam-sticky-header--fixed-shown' );
1244							}
1245							prevAnimState = 'fixedShownState';
1246						};
1247
1248						// state: no animation.
1249						var noAnimState = function () {
1250							$( $target ).removeClass( 'vamtam-sticky-header--fixed-shown' );
1251							$( $target ).removeClass( 'vamtam-sticky-header--fixed-hidden' );
1252							prevAnimState = 'noAnimState';
1253						};
1254
1255						const headerShouldAnimate = () => {
1256							// If a link inside the header is being hovered, we don't want to trigger the sticky header.
1257							if ( $( $target ).find( 'a:hover' ).length ) {
1258								return false;
1259							}
1260							// If a mega-menu belonging to the header is open, we don't want to trigger the sticky header.
1261							if ( $( '.vamtam-header-mega-menu:visible' ).length ) {
1262								return false;
1263							}
1264
1265							return true;
1266						};
1267
1268						// Initial phase
1269
1270						if ( isFrontend ) {
1271							$( $target ).after( '<div class="vamtam-prevent-scroll-jumps"></div>' );
1272						}
1273
1274						function preventScrollJumps() {
1275							if ( ! isFrontend ) {
1276								return;
1277							}
1278							// Apply a negative margin to prevent content jumps.
1279							var stickyHeight = $( $target ).innerHeight();
1280							$( $target ).css( 'margin-bottom', '-' + stickyHeight + 'px' );
1281							$( $target ).next( '.vamtam-prevent-scroll-jumps' ).css( 'padding-top', stickyHeight + 'px' );
1282						}
1283
1284						/*
1285							Fixes an issue where on webkit the parent container of an icon with no specialized height (parent)
1286							has a bit more space allocated to it creating bigger than necesseary height requirements for the whole block
1287							tha leads to problems like in https://github.com/veniko/estudiar/issues/37
1288						*/
1289						function reduceRedundantParentHeightOfIconForWebkit() {
1290							if ( ! $( 'body' ).hasClass( 'e--ua-webkit' ) ) {
1291								return;
1292							}
1293
1294							// Get all icons in header.
1295							const $icons = $( '.vamtam-sticky-header' ).find( '.elementor-icon-wrapper > .elementor-icon' );
1296							$.each( $icons, function ( i, icon ) {
1297								const $icon = $( icon ),
1298									iconHeight = $icon.height(), // Pixels.
1299									$iconParent = $icon.parent(), // .elementor-icon-wrapper
1300									iconParentHeight = $icon.parent().height(), // Pixels.
1301									heightDiffWithParent = Math.abs( iconHeight - iconParentHeight );
1302
1303								if ( heightDiffWithParent > 5 ) {
1304									$iconParent.css( 'height', ( iconParentHeight - 1 ) + 'px' ); // remove 1px from parent.
1305								}
1306							} );
1307						}
1308
1309						if ( window.VAMTAM.isMaxDeviceWidth() ) {
1310							preventScrollJumps();
1311
1312							setTimeout(() => {
1313								reduceRedundantParentHeightOfIconForWebkit();
1314								preventScrollJumps();
1315							}, 50);
1316						}
1317
1318						// If passed the trigger point it should always be at fixed hidden state.
1319						const initialScrollPosCheck = ( pageLoad = false ) => {
1320							if ( window.pageYOffset >= topScrollOffsetTrigger ) {
1321								fixedHiddenState();
1322							} else if ( ! pageLoad ) {
1323								// Sometimes the browser's onload scroll comes after the initialScrollPosCheck() so we check on page load jic. Happens mostly when initial scroll pos is after middle of page.
1324								window.addEventListener( 'load', function() {
1325									if ( ! prevAnimState ) {
1326										setTimeout( () => {
1327											initialScrollPosCheck( true );
1328										}, 10 );
1329									}
1330								} );
1331							}
1332						};
1333						initialScrollPosCheck();
1334
1335						var scrollTimer = null, lastScrollYPause = window.scrollY, lastDirection; // Used to check if the user has scrolled up far enough to trigger the sticky header.
1336						window.addEventListener( 'scroll', function( e ) {
1337							if ( scrollTimer !== null ) {
1338								clearTimeout( scrollTimer );
1339							}
1340
1341							// If the user hasn't scrolled for 500ms we use that as the new Y point.
1342							scrollTimer = setTimeout( function() {
1343								lastScrollYPause = window.scrollY;
1344						  	}, 500 );
1345
1346							var anim = window.VAMTAM.debounce( function() {
1347								if ( e.target.nodeName === '#document' ) {
1348
1349									if ( ! headerShouldAnimate() ) {
1350
1351										// Don't animate, but go to fixedShown state for the transparent header.
1352										if ( isTransparentHeader ) {
1353											if ( prevAnimState !== 'fixedShownState' ) {
1354												fixedShownState();
1355											}
1356										}
1357
1358										return;
1359									}
1360
1361									var direction =  _self.utils.getScrollDirection();
1362
1363									if ( lastDirection !== direction ) {
1364										lastScrollYPause = window.scrollY;
1365									}
1366									lastDirection = direction;
1367
1368									const scrollDifference = Math.abs( window.scrollY - lastScrollYPause ); // Pixels.
1369									if ( scrollDifference < 80 && window.scrollY > 80 ) {
1370										return;
1371									}
1372
1373									if ( direction === 'up' ) {
1374										if ( window.pageYOffset >= topScrollOffsetTrigger ) {
1375											if ( prevAnimState !== 'fixedShownState' ) {
1376												fixedShownState();
1377											}
1378										} else {
1379											if ( prevAnimState !== 'noAnimState' ) {
1380												noAnimState();
1381											}
1382										}
1383										return;
1384									}
1385
1386									if ( direction === 'down' ) {
1387										if ( window.pageYOffset >= topScrollOffsetTrigger || isTransparentHeader ) { // Transparent header gets hidden right away.
1388											// Safe-guard for times when the opening of the cart can cause a scroll down and hide the menu (also sliding the cart upwards).
1389											var menuCardNotVisible = ! $( $target ).find( '.elementor-menu-cart--shown' ).length;
1390											if ( prevAnimState !== 'fixedHiddenState' && menuCardNotVisible ) {
1391												fixedHiddenState();
1392											}
1393										}
1394									}
1395								}
1396							}, 200 );
1397
1398							if ( window.VAMTAM.isMaxDeviceWidth() ) {
1399								preventScrollJumps();
1400								requestAnimationFrame( anim );
1401							} else if ( prevAnimState !== 'noAnimState' ) {
1402								noAnimState();
1403							}
1404						}, { passive: true } );
1405					} )();
1406				},
1407				// Attaches observers to required anims and fires (adds vamtam-animate class & triggers vamtam:animate event)
1408				// them only when they are visible.
1409				observedAnims: function() {
1410					var observeClass    = 'vamtam-observe',
1411						animClass       = 'vamtam-animate',
1412						loopedAnimClass = 'vamtam-looped', // Whenever the el toggles to visible the anim will fire.
1413						animEls         = document.querySelectorAll( '.' + observeClass );
1414
1415					if ( ! animEls.length ) {
1416						return;
1417					}
1418
1419					var observer;
1420
1421					var cb = function( iOEntries, observer ) {
1422						iOEntries.forEach( function( entry ) {
1423							var isVisible = false,
1424								el        = entry.target,
1425								$el       = el && $( el );
1426
1427							if ( entry.isIntersecting ) {
1428								isVisible = true;
1429							}
1430
1431							if ( isVisible ) {
1432								if ( ! $el.hasClass( animClass ) ) {
1433									$el.addClass( animClass );
1434									$el.trigger('vamtam:animate');
1435								}
1436
1437								if ( ! $el.hasClass( loopedAnimClass ) ) {
1438									// If not looped, stop observing (anim fires only once).
1439									observer && observer.unobserve && observer.unobserve( el );
1440								}
1441							} else {
1442								if ( $el.hasClass( animClass ) ) {
1443									$el.removeClass( animClass );
1444								}
1445							}
1446						} );
1447					};
1448
1449					animEls.forEach( function( el ) {
1450						var $el = $( el );
1451						$el.removeClass( animClass );
1452
1453						if ( ! observer ) {
1454							observer = new IntersectionObserver( cb );
1455						}
1456
1457						observer.observe( el );
1458					} );
1459				},
1460				// Scroll-based anims.
1461				scrollBasedAnims: function() {
1462					var scrollAnims = [
1463						'[data-settings*="growFromLeftScroll"]',
1464						'[data-settings*="growFromRightScroll"]',
1465					];
1466
1467					var animEls = document.querySelectorAll( scrollAnims.join( ', ' ) );
1468
1469					if ( ! animEls.length ) {
1470						return;
1471					}
1472
1473					var observer, entries = {}, _this = this;
1474
1475					var cb = function( iOEntries ) {
1476						iOEntries.forEach( function( entry ) {
1477							var currentScrollY       = entry.boundingClientRect.y,
1478								isInViewport         = entry.isIntersecting,
1479								observedEl           = entry.target,
1480								scrollPercentage     = Math.abs( parseFloat( ( entry.intersectionRatio * 100 ).toFixed( 2 ) ) ),
1481								prevScrollPercentage = entries[ observedEl.dataset.vamtam_anim_id ].lastScrollPercentage,
1482								lastScrollY          = entries[ observedEl.dataset.vamtam_anim_id ].lastScrollY,
1483								animateEl            = entries[ observedEl.dataset.vamtam_anim_id ].animateEl;
1484
1485							var animate = function () {
1486								window.requestAnimationFrame( function() {
1487									animateEl.style.setProperty( '--vamtam-scroll-ratio', scrollPercentage + '%' );
1488								} );
1489							};
1490
1491							if ( isInViewport && lastScrollY !== currentScrollY ) {
1492								if( _this.utils.getScrollDirection() === 'down') {
1493									if ( prevScrollPercentage < scrollPercentage ) {
1494										animate();
1495									}
1496								} else {
1497									animate();
1498								}
1499							}
1500
1501							entries[ observedEl.dataset.vamtam_anim_id ].lastScrollY          = currentScrollY;
1502							entries[ observedEl.dataset.vamtam_anim_id ].lastScrollPercentage = scrollPercentage;
1503						} );
1504					};
1505
1506					var buildThresholdList = function() {
1507						var thresholds = [],
1508							numSteps   = 50,
1509							i;
1510
1511						for ( i = 1.0; i <= numSteps; i++ ) {
1512							var ratio = i / numSteps;
1513							thresholds.push( ratio );
1514						}
1515
1516						thresholds.push( 0 );
1517						return thresholds;
1518					};
1519
1520					const thresholds = buildThresholdList();
1521
1522					animEls.forEach( function( el ) {
1523						if ( ! observer ) {
1524							var options = {
1525								root: null,
1526								rootMargin: "20% 0% 20% 0%",
1527								threshold: thresholds,
1528							};
1529							observer = new IntersectionObserver( cb, options );
1530						}
1531
1532						// Init.
1533						el.style.setProperty( '--vamtam-scroll-ratio', '1%' );
1534
1535						var observeEl;
1536						if ( el.classList.contains( 'elementor-widget' ) || el.classList.contains( 'elementor-column' ) ) {
1537							// For widgets we observe .elementor-widget-wrap
1538							// For columns we observe .elementor-row
1539							observeEl = el.parentElement;
1540							observeEl.setAttribute('data-vamtam_anim_id', el.dataset.id );
1541						} else {
1542							// Sections.
1543							// Add scroll anim wrapper.
1544							$( el ).before( '<div class="vamtam-scroll-anim-wrap" data-vamtam_anim_id="' + el.dataset.id + '"></div>' );
1545							var $wrap = $( el ).prev( '.vamtam-scroll-anim-wrap' );
1546							$( $wrap ).append( el );
1547							observeEl = $wrap[ 0 ];
1548						}
1549
1550						entries[el.dataset.id] = {
1551							lastScrollY: '',
1552							lastScrollPercentage: '',
1553							observeEl: observeEl,
1554							animateEl: el,
1555						};
1556
1557						observer.observe( observeEl );
1558					} );
1559				},
1560				// Caridad-only.
1561				cursorAnimation: function() {
1562					const isEditor = window.elementorFrontend.isEditMode();
1563
1564					if ( isEditor ||
1565						this.utils.isTouchDevice() ||
1566						$( 'body' ).filter( '.no-theme-cursor, .no-estudiar-cursor' ).length ||
1567						! ( 'elementorFrontendConfig' in window ) ||
1568						! window.elementorFrontendConfig.kit.vamtam_theme_has_theme_cursor )
1569					{
1570						return;
1571					}
1572
1573					$( 'body' )
1574						.append( '<span id="mouseDot" class="mouse-dot"></span>' )
1575						.addClass( 'has-mouse-dot' );
1576
1577					var $mouseDot = $( '#mouseDot' ),
1578						mouseX = 0, mouseY = 0,
1579						xp = 0, yp = 0,
1580						timer;
1581
1582					$( document ).on( 'mousemove mouseenter', function( e ) {
1583						clearTimeout(timer);
1584
1585						if ( window.VAMTAM.isBelowMaxDeviceWidth() ) {
1586							return;
1587						}
1588
1589						if ( ! $mouseDot.hasClass( 'moving' ) ) {
1590							$mouseDot.addClass( 'moving' );
1591						}
1592
1593						mouseX = e.clientX;
1594						mouseY = e.clientY;
1595
1596						timer = setTimeout(function() {
1597							$mouseDot.removeClass( 'moving' );
1598						}, 500 );
1599					} );
1600
1601					// Position circle.
1602					window.requestAnimationFrame( function () {
1603						setInterval( function() {
1604							xp += ( ( mouseX - xp ) / 6 );
1605							yp += ( ( mouseY - yp ) / 6 );
1606							$mouseDot.css( {
1607								transform: 'translate(' + xp + 'px, ' + yp + 'px)',
1608							} );
1609						}, 20 );
1610					} );
1611
1612					// Handler for links.
1613					var onMouseOver = function( e ) {
1614						let hoveringOverLink, hoveringOverIframe;
1615
1616						if ( e.target.href ) {
1617							hoveringOverLink = true;
1618						} else if ( e.target.tagName === 'IFRAME' ) {
1619							hoveringOverIframe = true;
1620						} else {
1621							// Check if it's wrapped by a link (common-case).
1622							if ( $( e.target ).parent( 'a[href]' ).length ) {
1623								hoveringOverLink = true;
1624							}
1625
1626							// < -- Custom Cases -- >
1627							// Button.
1628							if ( $( e.target ).closest( 'a.elementor-button-link[href]' ).length ) {
1629								hoveringOverLink = true;
1630							}
1631						}
1632
1633						if ( hoveringOverLink ) {
1634							window.requestAnimationFrame( function() {
1635								$mouseDot.addClass( 'over-link' );
1636							} );
1637						} else {
1638							window.requestAnimationFrame( function() {
1639								$mouseDot.removeClass( 'over-link' );
1640							} );
1641						}
1642
1643						if ( hoveringOverIframe ) {
1644							window.requestAnimationFrame( function() {
1645								$mouseDot.addClass( 'over-iframe' );
1646							} );
1647						} else {
1648							window.requestAnimationFrame( function() {
1649								$mouseDot.removeClass( 'over-iframe' );
1650							} );
1651						}
1652
1653					};
1654					$( document ).on( 'mouseover', window.VAMTAM.debounce( onMouseOver, 100 ) );
1655				},
1656				// Common funcs used in custom animations.
1657				utils: {
1658					getAdminBarHeight: function () {
1659						return window.VAMTAM.adminBarHeight;
1660					},
1661					watchScrollDirection: function () {
1662						var watcher = function () {
1663							this.lastScrollTop = 0;
1664							this.utils = this;
1665							return {
1666								init: function () {
1667								},
1668								measure: function ( cpos ) {
1669									this.direction = cpos > this.lastScrollTop ? 'down' : 'up';
1670								}.bind( this ),
1671								mutate: function ( cpos ) {
1672									this.utils.getScrollDirection = function () {
1673										return this.direction;
1674									};
1675									this.lastScrollTop = cpos <= 0 ? 0 : cpos; // For Mobile or negative scrolling
1676								}.bind( this ),
1677							};
1678						}.bind( this );
1679
1680						window.VAMTAM.addScrollHandler( watcher() );
1681					},
1682					isTouchDevice: function() {
1683						const prefixes = ' -webkit- -moz- -o- -ms- '.split( ' ' );
1684
1685						const mq = function( query ) {
1686							return window.matchMedia( query ).matches;
1687						};
1688
1689						if ( ( 'ontouchstart' in window ) || window.DocumentTouch && document instanceof DocumentTouch ) { // jshint ignore:line
1690							return true;
1691						}
1692
1693						// include the 'heartz' as a way to have a non matching MQ to help terminate the join
1694						// https://git.io/vznFH
1695						var query = [ '(', prefixes.join( 'touch-enabled),(' ), 'heartz', ')' ].join( '' );
1696
1697						return mq( query );
1698					},
1699				}
1700			},
1701		};
1702
1703		window.VAMTAM.CUSTOM_ANIMATIONS.init();
1704
1705		$( window ).ready( function () {
1706			window.VAMTAM.CUSTOM_ANIMATIONS.onDomReady();
1707		} );
1708	});
1709})( jQuery );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.