PluginProbe
Easy Elements for Elementor – Addons & Website Templates / 1.4.9
Easy Elements for Elementor – Addons & Website Templates v1.4.9
1.5.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.6 1.4.7 1.4.8 1.4.5 1.4.4 1.4.3 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 All 47 releases
easy-elements / assets / js / custom.js

custom.js in Easy Elements for Elementor – Addons & Website Templates 1.4.9, at assets/js/custom.js

1,510 lines 53.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($) {
2 "use strict";
3 function initBackPostSlider($scope) {
4 var $slider = $scope.find('.eel-all-slider');
5 if (!$slider.length) {
6 return;
7 }
8 var loop = $slider.data('loop') === true || $slider.data('loop') === 'true';
9 var autoplay = $slider.data('autoplay') === true || $slider.data('autoplay') === 'true';
10 var autoplayDelay = parseInt($slider.data('autoplay-delay'), 10) || 3000;
11 var slidesPerView = parseInt($slider.data('slides-per-view'), 10) || 3;
12 var spvSkin1 = parseInt($slider.data('slides-per-view-skin1'), 10);
13 var spvSkin4 = parseInt($slider.data('slides-per-view-skin4'), 10);
14 var spvSkin11 = parseInt($slider.data('slides-per-view-skin11'), 10);
15 var spvSpecificDefault = parseInt($slider.data('slides-per-view-default'), 10);
16 var finalSlidesPerView;
17 if (spvSkin1) {
18 finalSlidesPerView = spvSkin1;
19 } else if (spvSkin4) {
20 finalSlidesPerView = spvSkin4;
21 } else if (spvSkin11) {
22 finalSlidesPerView = spvSkin11;
23 } else if (spvSpecificDefault) {
24 finalSlidesPerView = spvSpecificDefault;
25 } else {
26 finalSlidesPerView = slidesPerView;
27 }
28 var speed = parseInt($slider.data('speed'), 10) || 600;
29 var centeredSlides = $slider.data('centered-slides') === true || $slider.data('centered-slides') === 'true';
30 var freeMode = $slider.data('free-mode') === true || $slider.data('free-mode') === 'true';
31 var spaceBetween = parseInt($slider.data('space-between'), 10) || 0;
32 var slidesPerViewTablet = parseInt($slider.data('slides-per-view-tablet'), 10) || 2;
33 var slidesPerViewMobile = parseInt($slider.data('slides-per-view-mobile'), 10) || 1;
34 var paginationType = $slider.data('pagination') !== 'none' ? $slider.data('pagination') : false;
35 var navigation = $slider.data('navigation') === true || $slider.data('navigation') === 'true';
36 var effect = $slider.data('effect') || 'slide';
37 var cubeShadow = $slider.data('cube-shadow') === true || $slider.data('cube-shadow') === 'true';
38 var coverflowRotate = parseInt($slider.data('coverflow-rotate'), 10) || 50;
39 var coverflowStretch = parseInt($slider.data('coverflow-stretch'), 10) || 0;
40
41 // Find navigation elements within the scope
42 var $nextButton = $scope.find('.swiper-next');
43 var $prevButton = $scope.find('.swiper-prev');
44 var $pagination = $scope.find('.swiper-pagination');
45
46 // Prevent multiple instances and duplicated handlers if Elementor re-runs init
47 if ($slider[0] && $slider[0].swiper) {
48 try { $slider[0].swiper.destroy(true, true); } catch (e) {}
49 }
50 if ($nextButton.length) { $nextButton.off('click.easyStopAuto click.easyFadeNav'); }
51 if ($prevButton.length) { $prevButton.off('click.easyStopAuto click.easyFadeNav'); }
52
53 var hasProgressBar = $pagination.hasClass('swiper-pagination-progressbar');
54 var kbDirection = $slider.data('kenburns-direction') || 'in';
55
56 var effectOptions = {};
57
58 if (effect === 'cube') {
59 effectOptions = {
60 cubeEffect: {
61 shadow: cubeShadow,
62 slideShadows: cubeShadow,
63 shadowOffset: 20,
64 shadowScale: 0.94,
65 }
66 };
67 } else if (effect === 'coverflow') {
68 effectOptions = {
69 coverflowEffect: {
70 rotate: coverflowRotate,
71 stretch: coverflowStretch,
72 depth: 100,
73 modifier: 1,
74 slideShadows: true,
75 }
76 };
77 } else if (effect === 'flip') {
78 effectOptions = {
79 flipEffect: {
80 slideShadows: true,
81 limitRotation: true,
82 }
83 };
84 } else if (effect === 'cards') {
85 effectOptions = {
86 cardsEffect: {
87 slideShadows: true,
88 rotate: true,
89 perSlideOffset: 8,
90 }
91 };
92 } else if (effect === 'creative') {
93 var creativeStyle = $slider.data('creative-style') || 'default';
94 if (creativeStyle === 'zoom') {
95 effectOptions = {
96 creativeEffect: {
97 limitProgress: true,
98 prev: { scale: 1.1, opacity: 0, translate: [0, 0, 0] },
99 next: { scale: 1.6, opacity: 0, translate: [0, 0, 0] },
100 },
101 };
102 } else {
103 effectOptions = {
104 creativeEffect: {
105 limitProgress: true,
106 prev: { shadow: true, translate: [0, 0, -400] },
107 next: { translate: ['100%', 0, 0] },
108 },
109 };
110 }
111 } else if (effect === 'fade') {
112 effectOptions = {
113 fadeEffect: { crossFade: true }
114 };
115 } else if (effect === 'kenburns') {
116 effectOptions = {
117 effect: 'fade',
118 fadeEffect: { crossFade: true },
119 on: {
120 init: function () {
121 var swiper = this;
122 setTimeout(function() {
123 var $activeSlide = $(swiper.el).find('.swiper-slide-active');
124 $activeSlide.find('.hero-content-wrapper').addClass('eel-text-animated');
125 $activeSlide.find('.hero-slide-background img').addClass('eel-kb-active-' + kbDirection);
126 }, 200);
127 },
128 slideChange: function () {
129 var $allSlides = $(this.el).find('.swiper-slide');
130 $allSlides.find('.hero-content-wrapper').removeClass('eel-text-animated');
131 $allSlides.find('.hero-slide-background img').removeClass('eel-kb-active-in eel-kb-active-out');
132 },
133 transitionEnd: function () {
134 var swiper = this;
135 var $activeSlide = $(swiper.el).find('.swiper-slide-active');
136 $activeSlide.find('.hero-content-wrapper').addClass('eel-text-animated');
137 $activeSlide.find('.hero-slide-background img').addClass('eel-kb-active-' + kbDirection);
138 }
139 }
140 };
141 }
142
143 // Loop handling tuned to avoid double-advance on loop edges
144 var totalSlides = $slider.find('.swiper-slide').length;
145 var isFade = effect === 'fade';
146 // Skin 11 shows one testimonial per view, so use its effective slides-per-view for the loop math.
147 var isSkin11ForLoop = $slider.find('.ee--tstml-inner-wrap.skin11').length > 0;
148 var visibleSlides = isFade ? 1 : (isSkin11ForLoop ? finalSlidesPerView : slidesPerView);
149 var canLoop = totalSlides > visibleSlides;
150 var loopConfig = {};
151 if (loop && (canLoop || isFade)) {
152 loopConfig = {
153 loop: true,
154 loopAdditionalSlides: isFade ? totalSlides : 20,
155 loopedSlides: isFade ? totalSlides : Math.max(Math.ceil(visibleSlides), Math.min(totalSlides, 10))
156 };
157 } else {
158 loopConfig = { loop: false, rewind: !!loop };
159 }
160
161 // Skin 11 (testimonials): build a looping, clickable avatar thumbnail carousel synced to the main slider.
162 var eelTstmlSkin11 = $slider.find('.ee--tstml-inner-wrap.skin11').length > 0;
163 var eelThumbsSwiper = null;
164 if (eelTstmlSkin11) {
165 // Remove any thumbnail strip left over from a previous Elementor (re)init,
166 // so the click/sync wiring always references the live main swiper.
167 var $eelOldThumbs = $scope.find('.eel-tstml-thumbs');
168 if ($eelOldThumbs.length) {
169 if ($eelOldThumbs[0].swiper) { try { $eelOldThumbs[0].swiper.destroy(true, true); } catch (e) {} }
170 $eelOldThumbs.remove();
171 }
172 $scope.find('.eel-tstml-thumb-meta').remove();
173 var eelTstmlAvatars = [], eelTstmlNames = [], eelTstmlDesigs = [];
174 $slider.find('.swiper-slide').not('.swiper-slide-duplicate').each(function () {
175 var src = $(this).find('.eel-picture img').attr('src');
176 if (src) {
177 eelTstmlAvatars.push(src);
178 eelTstmlNames.push(($(this).find('.eel-name').first().text() || '').trim());
179 eelTstmlDesigs.push(($(this).find('.eel-designation').first().text() || '').trim());
180 }
181 });
182 if (eelTstmlAvatars.length) {
183 var eelThumbsHtml = '<div class="eel-tstml-thumbs swiper"><div class="swiper-wrapper">';
184 eelTstmlAvatars.forEach(function (src, i) {
185 eelThumbsHtml += '<div class="swiper-slide" data-eel-thumb-index="' + i + '"><span class="eel-thumb-img"><img src="' + src + '" alt="" /></span></div>';
186 });
187 eelThumbsHtml += '</div></div>';
188 var $eelThumbs = $(eelThumbsHtml);
189 $slider.after($eelThumbs);
190 var $eelThumbMeta = $('<div class="eel-tstml-thumb-meta"><div class="eel-thumb-name"></div><div class="eel-thumb-designation"></div></div>');
191 $eelThumbs.after($eelThumbMeta);
192 try {
193 eelThumbsSwiper = new Swiper($eelThumbs[0], {
194 loop: eelTstmlAvatars.length > 3,
195 centeredSlides: true,
196 slidesPerView: Math.min(3, eelTstmlAvatars.length),
197 spaceBetween: 14,
198 allowTouchMove: false,
199 simulateTouch: false,
200 touchStartPreventDefault: false,
201 watchSlidesProgress: true,
202 breakpoints: {
203 0: { slidesPerView: Math.min(3, eelTstmlAvatars.length) },
204 768: { slidesPerView: Math.min(3, eelTstmlAvatars.length) }
205 }
206 });
207 } catch (e) { eelThumbsSwiper = null; }
208 }
209 }
210
211 var swiper = new Swiper($slider[0], {
212 ...loopConfig,
213 speed: speed,
214 effect: effect,
215 normalizeSlideIndex: true,
216 preventInteractionOnTransition: true,
217 simulateTouch: true,
218 touchRatio: 1,
219 grabCursor: true,
220 mousewheel: hasProgressBar ? {
221 enabled: true,
222 sensitivity: 1,
223 thresholdDelta: 50,
224 thresholdTime: 200,
225 releaseOnEdges: true,
226 invert: false,
227 forceToAxis: false,
228 eventsTarget: 'container'
229 } : false,
230 autoplay: autoplay ? {
231 delay: autoplayDelay,
232 disableOnInteraction: isFade ? true : false,
233 } : false,
234 slidesPerView: visibleSlides,
235 spaceBetween: isFade ? 0 : spaceBetween,
236 centeredSlides: isFade ? false : centeredSlides,
237 freeMode: freeMode,
238 pagination: paginationType && $pagination.length ? {
239 el: $pagination[0],
240 clickable: true,
241 type: paginationType,
242 renderBullet: function (index, className) {
243 let num = (index + 1).toString().padStart(2, '0');
244 return `<span class="${className}">${num}</span>`;
245 }
246 } : false,
247
248 // Progress bar for mouse scroll - only when swiper-pagination-progressbar class is present
249 progressbar: hasProgressBar ? {
250 el: '.swiper-progressbar',
251 type: 'progressbar',
252 } : false,
253
254 navigation: (!isFade) && navigation && ($nextButton.length || $prevButton.length) ? {
255 nextEl: $nextButton.length ? $nextButton[0] : null,
256 prevEl: $prevButton.length ? $prevButton[0] : null,
257 } : false,
258 breakpoints: {
259 0: {
260 slidesPerView: isFade ? 1 : slidesPerViewMobile,
261 },
262 768: {
263 slidesPerView: isFade ? 1 : slidesPerViewTablet,
264 },
265 1024: {
266 slidesPerView: isFade ? 1 : finalSlidesPerView,
267 },
268 },
269 ...effectOptions,
270 });
271
272 // Skin 11: wire avatar thumbnails to control the main slider and keep active state in sync.
273 if (eelTstmlSkin11 && eelThumbsSwiper) {
274 var $eelThumbsRoot = $(eelThumbsSwiper.el);
275 var eelGoToSlide = function (idx) {
276 if (isNaN(idx)) { return; }
277 var main = $slider[0] && $slider[0].swiper;
278 if (!main || !main.params) { return; }
279 if (loop && (canLoop || isFade)) { main.slideToLoop(idx); }
280 else { main.slideTo(idx); }
281 };
282 $eelThumbsRoot.on('click.eelThumb', '.swiper-slide', function () {
283 eelGoToSlide(parseInt($(this).attr('data-eel-thumb-index'), 10));
284 });
285 var eelSyncThumbs = function () {
286 var active = swiper.realIndex || 0;
287 if ( $eelThumbMeta ) {
288 $eelThumbMeta.find('.eel-thumb-name').text(eelTstmlNames[active] || '');
289 $eelThumbMeta.find('.eel-thumb-designation').text(eelTstmlDesigs[active] || '');
290 }
291 $eelThumbsRoot.find('.swiper-slide').removeClass('swiper-slide-thumb-active')
292 .filter('[data-eel-thumb-index="' + active + '"]').addClass('swiper-slide-thumb-active');
293 if (eelThumbsSwiper.params && eelThumbsSwiper.params.loop) {
294 try { eelThumbsSwiper.slideToLoop(active); } catch (e) {}
295 } else {
296 try { eelThumbsSwiper.slideTo(active); } catch (e) {}
297 }
298 };
299 swiper.on('slideChange', eelSyncThumbs);
300 eelSyncThumbs();
301 }
302
303 // Fade: attach custom navigation so Next/Prev work
304 if (isFade && ($nextButton.length || $prevButton.length)) {
305 var isTransitioning = false;
306 swiper.on('transitionStart', function () { isTransitioning = true; });
307 swiper.on('transitionEnd', function () { isTransitioning = false; });
308 if ($nextButton.length) {
309 $nextButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
310 e.preventDefault();
311 e.stopPropagation();
312 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
313 if (isTransitioning || (swiper && swiper.animating)) return;
314 swiper.slideNext();
315 });
316 }
317 if ($prevButton.length) {
318 $prevButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
319 e.preventDefault();
320 e.stopPropagation();
321 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
322 if (isTransitioning || (swiper && swiper.animating)) return;
323 swiper.slidePrev();
324 });
325 }
326 }
327
328 // Non-fade: if loop+autoplay, stop autoplay on manual nav to avoid double-advance
329 if (!isFade && loop && autoplay) {
330 if ($nextButton.length) {
331 $nextButton.on('click.easyStopAuto', function () {
332 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
333 swiper.autoplay.stop();
334 }
335 });
336 }
337 if ($prevButton.length) {
338 $prevButton.on('click.easyStopAuto', function () {
339 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
340 swiper.autoplay.stop();
341 }
342 });
343 }
344 }
345 }
346
347
348 if (!window.EEL_AddWidgetTypeBodyClass) {
349 window.EEL_AddWidgetTypeBodyClass = true;
350
351 function addWidgetTypeToBody($scope) {
352 if (!$scope || !$scope.length) return;
353
354 var widgetType = $scope.data('widget_type');
355 if (!widgetType) return;
356
357 var safeWidgetType = widgetType
358 .toString()
359 .replace(/[^a-z0-9_-]/gi, '-')
360 .toLowerCase();
361
362 var className = 'easy-eel-has-widget-' + safeWidgetType;
363
364 if (!document.body.classList.contains(className)) {
365 document.body.classList.add(className);
366 }
367 }
368
369 /* -------------------------------------------------
370 * Elementor Hooks
371 * ------------------------------------------------- */
372 $(window).on('elementor/frontend/init', function () {
373
374 // Slider init
375 elementorFrontend.hooks.addAction(
376 'frontend/element_ready/global',
377 initBackPostSlider
378 );
379
380 // Widget type → body class
381 elementorFrontend.hooks.addAction(
382 'frontend/element_ready/global',
383 function ($scope) {
384 addWidgetTypeToBody($scope);
385 }
386 );
387
388 });
389 }
390
391
392 $(window).on('elementor/frontend/init', function () {
393
394 function checkStickySection() {
395 const stickySection = document.querySelector('.eel-sticky-section');
396 if (stickySection) {
397 document.body.classList.add('sticky-enabled-overlap');
398 } else {
399 document.body.classList.remove('sticky-enabled-overlap');
400 }
401 }
402
403 checkStickySection();
404
405 const observer = new MutationObserver(checkStickySection);
406 observer.observe(document.body, { childList: true, subtree: true });
407 });
408
409
410
411 $(window).on('elementor/frontend/init', function () {
412 function initReveal_ad($scope) {
413 const revealElements = $scope.find(".eel-img-advance-wrap");
414 const revealAnimate = (el) => {
415 const target = el.querySelector(".eel-advance-img-main");
416 if(target && !target.classList.contains("el-reveal-animate")) {
417 target.classList.add("el-reveal-animate");
418 }
419 };
420 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
421 if(isEditor){
422 revealElements.each(function(){
423 revealAnimate(this);
424 });
425 } else {
426 const observer = new IntersectionObserver((entries, obs) => {
427 entries.forEach(entry => {
428 if(entry.isIntersecting){
429 revealAnimate(entry.target);
430 obs.unobserve(entry.target);
431 }
432 });
433 }, { threshold: 0.3 });
434
435 revealElements.each(function(){
436 observer.observe(this);
437 });
438
439 // Lenis safe
440 if (window.Lenis && typeof window.Lenis.raf === 'function') {
441 window.Lenis.raf(() => {});
442 }
443 }
444 }
445
446 elementorFrontend.hooks.addAction(
447 'frontend/element_ready/eel-advance-image.default',
448 initReveal_ad
449 );
450
451 function initReveal($scope) {
452 const revealElements = $scope.find(".eel-img-reveal-wrap");
453
454 const revealAnimate = (el) => {
455 const target = el.querySelector(".eel-reveal-img-main");
456 if(target && !target.classList.contains("el-reveal-animate")) {
457 target.classList.add("el-reveal-animate");
458 }
459 };
460
461 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
462
463 if(isEditor){
464 revealElements.each(function(){
465 revealAnimate(this);
466 });
467 } else {
468 const observer = new IntersectionObserver((entries, obs) => {
469 entries.forEach(entry => {
470 if(entry.isIntersecting){
471 revealAnimate(entry.target);
472 obs.unobserve(entry.target);
473 }
474 });
475 }, { threshold: 0.3 });
476
477 revealElements.each(function(){
478 observer.observe(this);
479 });
480
481 // Lenis safe
482 if (window.Lenis && typeof window.Lenis.raf === 'function') {
483 window.Lenis.raf(() => {});
484 }
485 }
486 }
487
488 elementorFrontend.hooks.addAction(
489 'frontend/element_ready/eel-image-reveal.default',
490 initReveal
491 );
492
493 });
494
495
496 $(window).on("elementor/frontend/init", function () {
497 var EasyJarallax = function ($scope, $) {
498 if (typeof jarallax === 'undefined') return;
499
500 var $wrappers = $scope.hasClass('eele-has-jarallax') ? $scope : $scope.find('.eele-has-jarallax, .eele-inner-jarallax');
501 if (!$wrappers.length) return;
502
503 $wrappers.each(function () {
504 var $wrapper = $(this);
505 var bg = $wrapper.data('jarallax-bg');
506 var speed = $wrapper.data('jarallax-speed') || 0.5;
507 if (!bg) return;
508
509 // Destroy previous instance if re-rendering in editor
510 var $oldJarallax = $wrapper.find('.jarallax');
511 if ($oldJarallax.length) {
512 $oldJarallax.each(function () {
513 jarallax(this, 'destroy');
514 });
515 $oldJarallax.remove();
516 }
517
518 var $div = $('<div>', { 'class': 'jarallax eele-jarallax-bg', 'data-speed': speed });
519 var $img = $('<img>', { 'class': 'jarallax-img', src: bg, alt: '', decoding: 'async' });
520 $div.append($img);
521 $wrapper.append($div);
522
523 jarallax($div[0], {
524 speed: speed,
525 imgPosition: '50% 50%',
526 imgRepeat: 'no-repeat',
527 imgSize: 'cover',
528 zIndex: -100
529 });
530 });
531 };
532
533 // Image widget parallax
534 var EasyJarallaxImage = function ($scope, $) {
535 if (typeof jarallax === 'undefined') return;
536 if (!$scope.hasClass('eele-has-jarallax-img-yes')) return;
537
538 var $img = $scope.find('.elementor-widget-container img').first();
539 if (!$img.length || !$img.attr('src')) return;
540
541 var $container = $scope.find('.elementor-widget-container');
542
543 // If already wrapped from a previous run (editor re-render), unwrap to start clean
544 if ($img.parent('.eele-img-jarallax-wrap').length) {
545 try { jarallax($img.parent()[0], 'destroy'); } catch (e) {}
546 $img.unwrap();
547 $img.removeClass('jarallax-img');
548 }
549
550 // Clean up any leftover empty jarallax bg divs from older buggy code
551 $container.find('> .eele-jarallax-bg, > a > .eele-jarallax-bg').each(function () {
552 try { jarallax(this, 'destroy'); } catch (e) {}
553 }).remove();
554
555 // Wrap the original image so it becomes the parallax source itself.
556 // Do NOT add `eele-jarallax-bg` — that class has global CSS
557 // (position:absolute; z-index:-1) for container background parallax,
558 // which would hide the image entirely.
559 $img.addClass('jarallax-img');
560 $img.wrap('<div class="jarallax jarallax-container eele-img-jarallax-wrap"></div>');
561 var $div = $img.parent();
562
563 function initParallax() {
564 // Give the wrapper a size so it doesn't collapse once jarallax positions
565 // the img absolutely. User-set width/height (via panel) uses !important
566 // and will still override these fallbacks.
567 var nW = $img[0].naturalWidth;
568 var nH = $img[0].naturalHeight;
569 if (nW && nH) {
570 if (!$div[0].style.width) $div.css('width', '100%');
571 if (!$div[0].style.height) $div.css('aspect-ratio', nW + ' / ' + nH);
572 } else if (!$div[0].style.height) {
573 var fallbackH = $div[0].getBoundingClientRect().height;
574 if (fallbackH > 0) $div.css('height', fallbackH + 'px');
575 }
576
577 jarallax($div[0], {
578 speed: 0.5,
579 imgPosition: '50% 50%',
580 imgRepeat: 'no-repeat',
581 imgSize: 'cover',
582 zIndex: 0
583 });
584 }
585
586 if ($img[0].complete && $img[0].naturalWidth > 0) {
587 initParallax();
588 } else {
589 $img.one('load', initParallax);
590 }
591 };
592
593 elementorFrontend.hooks.addAction("frontend/element_ready/global", EasyJarallax);
594 elementorFrontend.hooks.addAction("frontend/element_ready/image.default", EasyJarallaxImage);
595 elementorFrontend.hooks.addAction("frontend/element_ready/eel-advance-image.default", EasyJarallaxImage);
596
597 // --- Lenis integration for Jarallax ---
598 function syncJarallaxWithLenis() {
599 if (window.lenis && typeof jarallax !== 'undefined') {
600 window.lenis.on('scroll', function () {
601 jarallax(document.querySelectorAll('.jarallax'), 'onScroll');
602 });
603 } else {
604 setTimeout(syncJarallaxWithLenis, 200);
605 }
606 }
607 syncJarallaxWithLenis();
608 });
609
610
611 jQuery(window).on('elementor/frontend/init', function() {
612
613 elementorFrontend.hooks.addAction('frontend/element_ready/eel-video-popup.default', function($scope, $) {
614
615 const wrapper = $scope.find('.eel-video-popup-wrapper');
616 const overlay = wrapper.find('.eel-video-overlay');
617 // Find video element (try with class first, then without)
618 let videoEl = wrapper.find('video.eel-normal-video');
619 if (!videoEl.length) {
620 videoEl = wrapper.find('video');
621 }
622 // Find iframe element (try with class first, then without)
623 let iframeEl = wrapper.find('iframe.eel-normal-video');
624 if (!iframeEl.length) {
625 iframeEl = wrapper.find('iframe');
626 }
627
628 // Helper function to get YouTube embed URL
629 function getYouTubeEmbedUrl(url) {
630 const regExp = /(?:v=|\/)([0-9A-Za-z_-]{11}).*/;
631 const match = url.match(regExp);
632 if (match && match[1]) {
633 return 'https://www.youtube.com/embed/' + match[1] + '?autoplay=1';
634 }
635 return null;
636 }
637
638 // Helper function to get Vimeo embed URL
639 function getVimeoEmbedUrl(url) {
640 const match = url.match(/(\d+)/);
641 if (match && match[1]) {
642 return 'https://player.vimeo.com/video/' + match[1] + '?autoplay=1';
643 }
644 return null;
645 }
646
647 // Helper function to open lightbox
648 function openLightbox(videoType, videoUrl, popupId, animation) {
649 const lightboxOverlay = $('#' + popupId);
650 const iframeWrapper = lightboxOverlay.find('.eel-video-popup-iframe-wrapper');
651 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
652
653 if (!lightboxOverlay.length) return;
654
655 // Prevent duplicate opening if already active
656 if (lightboxOverlay.hasClass('active')) {
657 return;
658 }
659
660 let embedHtml = '';
661
662 if (videoType === 'youtube') {
663 const embedUrl = getYouTubeEmbedUrl(videoUrl);
664 if (embedUrl) {
665 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
666 }
667 } else if (videoType === 'vimeo') {
668 const embedUrl = getVimeoEmbedUrl(videoUrl);
669 if (embedUrl) {
670 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
671 }
672 } else if (videoType === 'self_hosted') {
673 embedHtml = '<video src="' + videoUrl + '" controls autoplay></video>';
674 }
675
676 if (embedHtml) {
677 iframeWrapper.html(embedHtml);
678
679 // Apply animation if set
680 if (animation && animation.trim() !== '') {
681 // Remove any existing animation classes
682 const currentClasses = lightboxContent.attr('class') || '';
683 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
684 if (animationClasses) {
685 lightboxContent.removeClass(animationClasses.join(' '));
686 }
687 // Add new animation classes
688 lightboxContent.addClass('animated ' + animation.trim());
689 } else {
690 // Remove animation classes if no animation
691 const currentClasses = lightboxContent.attr('class') || '';
692 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
693 if (animationClasses) {
694 lightboxContent.removeClass(animationClasses.join(' '));
695 }
696 }
697
698 lightboxOverlay.addClass('active');
699 $('body').css('overflow', 'hidden');
700 }
701 }
702
703 // Close lightbox handler
704 $(document).on('click', '.eel-video-popup-close', function(e) {
705 e.preventDefault();
706 const lightboxOverlay = $(this).closest('.eel-video-popup-overlay');
707 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
708 lightboxOverlay.removeClass('active');
709 lightboxContent.removeClass('animated');
710 lightboxOverlay.find('.eel-video-popup-iframe-wrapper').html('');
711 $('body').css('overflow', '');
712 });
713
714 // Close lightbox on overlay click
715 $(document).on('click', '.eel-video-popup-overlay', function(e) {
716 if ($(e.target).hasClass('eel-video-popup-overlay')) {
717 const lightboxContent = $(this).find('.eel-video-popup-content');
718 $(this).removeClass('active');
719 lightboxContent.removeClass('animated');
720 $(this).find('.eel-video-popup-iframe-wrapper').html('');
721 $('body').css('overflow', '');
722 }
723 });
724
725 // Close lightbox on ESC key
726 $(document).on('keydown', function(e) {
727 if (e.keyCode === 27) { // ESC key
728 $('.eel-video-popup-overlay.active').each(function() {
729 const lightboxContent = $(this).find('.eel-video-popup-content');
730 $(this).removeClass('active');
731 lightboxContent.removeClass('animated');
732 $(this).find('.eel-video-popup-iframe-wrapper').html('');
733 $('body').css('overflow', '');
734 });
735 }
736 });
737
738 if (overlay.length) {
739 // Remove existing handler to prevent duplicate
740 overlay.off('click.eelVideoOverlay');
741 overlay.on('click.eelVideoOverlay', function(e) {
742 e.preventDefault();
743 e.stopPropagation();
744
745 const $overlay = $(this);
746 const useLightbox = $overlay.data('lightbox') === 'yes';
747 const videoType = $overlay.data('video-type');
748 const videoUrl = $overlay.data('video-url');
749 const popupId = $overlay.data('popup-id');
750 const animation = $overlay.data('animation') || '';
751
752 // If lightbox is enabled, open lightbox
753 if (useLightbox && videoType && videoUrl && popupId) {
754 // Check if lightbox is already open to prevent duplicate
755 const lightboxOverlay = $('#' + popupId);
756 if (lightboxOverlay.hasClass('active')) {
757 return;
758 }
759 openLightbox(videoType, videoUrl, popupId, animation);
760 return;
761 }
762
763 // Otherwise, play inline (original behavior)
764 // Self-hosted video play
765 if (videoEl.length) {
766 const video = videoEl.get(0);
767
768 // Function to play video
769 const playVideo = function() {
770 const playPromise = video.play();
771 if (playPromise !== undefined) {
772 playPromise.catch(function(error) {
773 console.log('Video play failed:', error);
774 // If play fails due to autoplay policy, try with muted
775 if (error.name === 'NotAllowedError' && !video.muted) {
776 video.muted = true;
777 video.play().then(function() {
778 // Unmute after play starts (if user wants sound)
779 setTimeout(function() {
780 video.muted = false;
781 }, 100);
782 }).catch(function(err) {
783 console.log('Video play with mute also failed:', err);
784 });
785 }
786 });
787 }
788 };
789
790 // Always try to load and play
791 if (video.readyState >= 2) {
792 // Video is already loaded, play immediately
793 playVideo();
794 } else {
795 // Video not loaded, load it first then play
796 video.load();
797 // Wait for video to be ready to play
798 const tryPlay = function() {
799 if (video.readyState >= 2) {
800 playVideo();
801 } else {
802 video.addEventListener('canplay', playVideo, { once: true });
803 video.addEventListener('loadeddata', playVideo, { once: true });
804 }
805 };
806 tryPlay();
807 }
808 }
809
810 // YouTube / Vimeo iframe autoplay
811 if (iframeEl.length) {
812 let src = iframeEl.attr('src');
813 if (src) {
814 // Check if it's YouTube or Vimeo
815 const isYouTube = src.indexOf('youtube.com') !== -1 || src.indexOf('youtu.be') !== -1;
816 const isVimeo = src.indexOf('vimeo.com') !== -1;
817
818 if (isYouTube || isVimeo) {
819 try {
820 // Use URL object for proper parsing
821 const url = new URL(src);
822
823 if (isYouTube) {
824 // YouTube: add autoplay, preserve original mute setting
825 url.searchParams.set('autoplay', '1');
826 // Only set mute=1 if it was already in the URL (preserve original setting)
827 // If mute was not in original URL, don't add it
828 if (!url.searchParams.has('mute')) {
829 // Don't add mute if it wasn't there originally
830 } else {
831 // Keep the original mute value
832 }
833 // Reload iframe with new src
834 iframeEl.attr('src', url.toString());
835 } else if (isVimeo) {
836 // Vimeo: add autoplay (Vimeo doesn't need mute for autoplay)
837 url.searchParams.set('autoplay', '1');
838 // Reload iframe with new src
839 iframeEl.attr('src', url.toString());
840 }
841 } catch (e) {
842 // Fallback for browsers that don't support URL constructor
843 // Remove existing autoplay parameter if present
844 src = src.replace(/[?&]autoplay=[^&]*/g, '');
845
846 if (isYouTube) {
847 // Check if mute parameter exists in original URL
848 const hasMute = /[?&]mute=/.test(src);
849 // Add autoplay=1
850 const separator = src.indexOf('?') === -1 ? '?' : '&';
851 src += separator + 'autoplay=1';
852 // Only add mute if it was already there (preserve original setting)
853 // Don't add mute if it wasn't in original URL
854 } else if (isVimeo) {
855 // Vimeo: just add autoplay=1
856 const separator = src.indexOf('?') === -1 ? '?' : '&';
857 src += separator + 'autoplay=1';
858 }
859
860 // Update src without clearing first
861 iframeEl.attr('src', src);
862 }
863 }
864 }
865 }
866
867 // Remove overlay after a small delay to ensure video starts
868 setTimeout(function() {
869 overlay.fadeOut(300, function() {
870 $(this).remove();
871 });
872 }, 200);
873 });
874 }
875
876 // Handle popup button clicks (for display_type = 'popup')
877 const popupBtn = wrapper.find('.entro-all-video-popup');
878 if (popupBtn.length) {
879 // If the global popup (from pro plugin) exists, let eel-popup.js handle it
880 // to avoid transform/motion effect containment issues with position:fixed
881 const globalPopup = document.querySelector('.entro-all-video-popup-wrap');
882 if (globalPopup) {
883 // Global popup exists — do not bind per-widget handler.
884 // The pro plugin's eel-popup.js will handle it since it's already in body.
885 } else {
886 // No global popup — use per-widget overlay, moved to body
887 const popupOverlay = wrapper.find('.eel-video-popup-overlay');
888 if (popupOverlay.length && !popupOverlay.data('moved-to-body')) {
889 popupOverlay.data('moved-to-body', true);
890 popupOverlay.appendTo('body');
891 }
892
893 // Remove existing handler to prevent duplicate
894 popupBtn.off('click.eelVideoPopup');
895 popupBtn.on('click.eelVideoPopup', function(e) {
896 e.preventDefault();
897 e.stopPropagation();
898 const $btn = $(this);
899 const videoType = $btn.data('video-type');
900 const videoUrl = $btn.data('video-src');
901 const popupId = $btn.data('popup-id');
902 const lightboxOverlay = $('#' + popupId);
903 const animation = lightboxOverlay.data('animation') || '';
904
905 if (videoType && videoUrl && popupId) {
906 // Check if lightbox is already open to prevent duplicate
907 if (lightboxOverlay.hasClass('active')) {
908 return;
909 }
910 openLightbox(videoType, videoUrl, popupId, animation);
911 }
912 });
913 }
914 }
915 });
916
917 });
918
919 // Single Page Navigation
920 document.addEventListener('DOMContentLoaded', function () {
921 const navWrappers = document.querySelectorAll('.eel-single-nav-list');
922 if (!navWrappers.length) return;
923
924 navWrappers.forEach(function (wrapper) {
925
926 const navLinks = wrapper.querySelectorAll('.eel-nav-item a');
927 const navItems = wrapper.querySelectorAll('.eel-nav-item');
928
929 if (!navLinks.length) return;
930
931 wrapper.addEventListener('click', function (e) {
932
933 const link = e.target.closest('.eel-nav-item a');
934 if (!link || !wrapper.contains(link)) return;
935
936 const href = link.getAttribute('href');
937
938 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
939 return;
940 }
941
942 const target = document.querySelector(href);
943 if (!target) return;
944
945 e.preventDefault();
946
947 target.scrollIntoView({
948 behavior: 'smooth',
949 block: 'start'
950 });
951 });
952
953 /* ========= SCROLL → ACTIVE CHANGE ========= */
954 const sectionsMap = new Map();
955
956 navLinks.forEach(link => {
957 const href = link.getAttribute('href');
958
959 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
960 return;
961 }
962
963 const section = document.querySelector(href);
964 if (section) {
965 sectionsMap.set(section, href);
966 }
967 });
968
969 function setActive(href) {
970 navItems.forEach(item => item.classList.remove('active'));
971
972 navLinks.forEach(link => {
973 if (link.getAttribute('href') === href) {
974 link.closest('.eel-nav-item')?.classList.add('active');
975 }
976 });
977 }
978
979 const observer = new IntersectionObserver(
980 (entries) => {
981 entries.forEach(entry => {
982 if (entry.isIntersecting) {
983 const id = sectionsMap.get(entry.target);
984 if (id) setActive(id);
985 }
986 });
987 },
988 {
989 root: null,
990 rootMargin: '-40% 0px -40% 0px',
991 threshold: 0.1
992 }
993 );
994
995 sectionsMap.forEach((id, section) => {
996 observer.observe(section);
997 });
998
999 });
1000
1001 });
1002
1003 // Sticky Navigation single page
1004
1005 function applyStickyToContainer($container) {
1006 if ($container.find('.elementor-widget-eel-single-nav').length === 0) {
1007 return;
1008 }
1009
1010 $container.addClass('eel-single-nav-sticky-enabled');
1011 }
1012
1013 /* ===== Frontend ===== */
1014 $(window).on('elementor/frontend/init', function () {
1015 elementorFrontend.hooks.addAction(
1016 'frontend/element_ready/container',
1017 function ($scope) {
1018 applyStickyToContainer($scope);
1019 }
1020 );
1021 });
1022
1023 /* ===== Editor ===== */
1024 if (window.elementor && elementor.isEditMode()) {
1025 elementor.hooks.addAction('editor:init', function () {
1026 elementorFrontend.hooks.addAction(
1027 'frontend/element_ready/container',
1028 function ($scope) {
1029 applyStickyToContainer($scope);
1030 }
1031 );
1032 });
1033 }
1034
1035 // Mobile Menu Sidebar
1036 if ($('.sidebar-on-mobile-single-nav').length) {
1037 // Sidebar toggle
1038 $('.eel-nav-menu-icon').on('click', function(e){
1039 e.stopPropagation();
1040 $('.sidebar-on-mobile-single-nav').toggleClass('easyel-open');
1041 $('body').toggleClass('sidebar-on-mobile-single-nav-active');
1042 });
1043 // Click outside to close sidebar
1044 $(document).on('click', function(){
1045 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
1046 $('body').removeClass('sidebar-on-mobile-single-nav-active');
1047 $('.sidebar-on-mobile-single-nav ul.sub-menu').slideUp(300);
1048 $('.sidebar-on-mobile-single-nav .sub-arrow').removeClass('active').attr('aria-expanded', false);
1049 });
1050
1051 $('.sidebar-on-mobile-single-nav, .eel-nav-menu').on('click', 'li:not(.menu-item-has-children) a', function(e){
1052 $('.sidebar-on-mobile-single-nav li a, .eel-nav-menu li a').removeClass('eel-active');
1053 $(this).addClass('eel-active');
1054 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
1055 $('body').removeClass('sidebar-on-mobile-single-nav-active');
1056 $('body').removeClass('sidebar-on-mobile-active');
1057 });
1058
1059 // Prevent closing when clicking inside sidebar
1060 $('.sidebar-on-mobile-single-nav').on('click', function(e){
1061 e.stopPropagation();
1062 });
1063 }
1064
1065 jQuery(document).ready(function($){
1066 var $allSidebars = $('.sidebar-on-mobile-mega-nav');
1067 var $body = $('body');
1068
1069 if(!$allSidebars.length) return;
1070
1071 /* ========== Inject submenu icon ========== */
1072 $allSidebars.find('li.menu-item-has-children').each(function(){
1073 if(!$(this).children('.submenu-parent-icon').length){
1074 var svgIcon = '<span class="submenu-parent-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg></span>';
1075 $(this).prepend(svgIcon);
1076 }
1077 });
1078
1079 // Open sidebar — match hamburger to its own sidebar via data attributes
1080 $(document).on('click', '.eel-mega-menu-icon-mobile', function(e){
1081 e.preventDefault();
1082 e.stopPropagation();
1083 var targetId = $(this).attr('data-mega-target');
1084 var $sidebar;
1085 if (targetId) {
1086 $sidebar = $('.sidebar-on-mobile-mega-nav[data-mega-id="' + targetId + '"]');
1087 }
1088 // Fallback for old markup without data attributes
1089 if (!$sidebar || !$sidebar.length) {
1090 $sidebar = $allSidebars.first();
1091 }
1092 $allSidebars.not($sidebar).removeClass('easyel-open');
1093 $sidebar.addClass('easyel-open');
1094 $body.addClass('sidebar-on-mobile-mega-nav-active');
1095 });
1096
1097 // Close sidebar (icon)
1098 $(document).on('click', '.eel-mega-menu-icon-close', function(e){
1099 e.preventDefault();
1100 e.stopPropagation();
1101 $(this).closest('.sidebar-on-mobile-mega-nav').removeClass('easyel-open');
1102 $body.removeClass('sidebar-on-mobile-mega-nav-active');
1103 });
1104
1105 // Click outside sidebar (overlay)
1106 $(document).on('click', function(){
1107 $allSidebars.removeClass('easyel-open');
1108 $body.removeClass('sidebar-on-mobile-mega-nav-active');
1109 });
1110
1111 // Prevent sidebar clicks from closing
1112 $(document).on('click', '.sidebar-on-mobile-mega-nav', function(e){
1113 if (!$(e.target).closest('.eel-mega-menu-icon-close').length) {
1114 e.stopPropagation();
1115 }
1116 });
1117
1118 /* ========== Submenu toggle ========== */
1119 $(document).on('click', '.sidebar-on-mobile-mega-nav .submenu-parent-icon', function(e){
1120 e.preventDefault();
1121 e.stopPropagation();
1122
1123 var $li = $(this).closest('li.menu-item-has-children');
1124 var $submenu = $li.children('ul.sub-menu');
1125
1126 // close other submenus
1127 $li.siblings('li.menu-item-has-children')
1128 .removeClass('eel-sub-open')
1129 .children('ul.sub-menu').slideUp(300);
1130
1131 $li.siblings('li.menu-item-has-children')
1132 .children('.submenu-parent-icon').removeClass('active');
1133
1134 // toggle current
1135 $submenu.slideToggle(300);
1136 $li.toggleClass('eel-sub-open');
1137 $(this).toggleClass('active');
1138 });
1139 });
1140
1141 jQuery(window).on('elementor/frontend/init', function() {
1142 elementorFrontend.hooks.addAction('frontend/element_ready/eel-vertical-navigation.default', function($scope) {
1143
1144 var $sidebar = $scope.find('.sidebar-on-mobile-vertical-nav');
1145 var $body = jQuery('body');
1146
1147 if($sidebar.length) {
1148 $sidebar.find('li.menu-item-has-children').each(function(){
1149 if(!jQuery(this).children('.submenu-parent-icon').length){
1150 var svgIcon = '<span class="submenu-parent-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg></span>';
1151 jQuery(this).prepend(svgIcon);
1152 }
1153 });
1154
1155 $scope.on('click', '.eel-vertical-menu-icon-mobile', function(e){
1156 e.preventDefault();
1157 e.stopPropagation();
1158 $sidebar.addClass('easyel-open');
1159 $body.addClass('sidebar-on-mobile-vertical-nav-active');
1160 });
1161
1162 $scope.on('click', '.eel-vertical-menu-icon-close', function(e){
1163 e.preventDefault();
1164 e.stopPropagation();
1165 closeSidebar();
1166 });
1167
1168 jQuery(document).on('click', function(e){
1169 if (!jQuery(e.target).closest('.sidebar-on-mobile-vertical-nav, .eel-vertical-menu-icon-mobile').length) {
1170 closeSidebar();
1171 }
1172 });
1173
1174 function closeSidebar() {
1175 $sidebar.removeClass('easyel-open');
1176 $body.removeClass('sidebar-on-mobile-vertical-nav-active');
1177 }
1178
1179 /* ========== Submenu Toggle (Accordion) ========== */
1180 $sidebar.find('.submenu-parent-icon').off('click').on('click', function(e){
1181 e.preventDefault();
1182 e.stopPropagation();
1183
1184 var $this = jQuery(this);
1185 var $li = $this.closest('li.menu-item-has-children');
1186 var $submenu = $li.children('ul.sub-menu');
1187 $li.siblings('li.menu-item-has-children').each(function(){
1188 var $sibling = jQuery(this);
1189 $sibling.removeClass('eel-sub-open is-open-vertical');
1190 $sibling.children('ul.sub-menu').slideUp(300);
1191 $sibling.children('.submenu-parent-icon').removeClass('active');
1192 $sibling.find('> a').removeClass('eel-vertical-open');
1193 });
1194 if ($li.hasClass('eel-sub-open')) {
1195 $submenu.slideUp(300);
1196 $li.removeClass('eel-sub-open is-open-vertical');
1197 $this.removeClass('active');
1198 $li.find('> a').removeClass('eel-vertical-open');
1199 } else {
1200 $submenu.slideDown(300);
1201 $li.addClass('eel-sub-open is-open-vertical');
1202 $this.addClass('active');
1203 $li.find('> a').addClass('eel-vertical-open');
1204 }
1205 });
1206 }
1207 });
1208 });
1209
1210 })(jQuery);
1211
1212 (function ($) {
1213 function eelMegaNavigationInit() {
1214 $('.elementor-widget-eel-mega-navigation')
1215 .parent()
1216 .addClass('parant-eel-mega-static');
1217 }
1218 // Frontend
1219 $(window).on('load', function () {
1220 eelMegaNavigationInit();
1221 });
1222
1223 // Elementor Editor
1224 $(window).on('elementor/frontend/init', function () {
1225 if (elementorFrontend.isEditMode()) {
1226 eelMegaNavigationInit();
1227 }
1228 elementorFrontend.hooks.addAction(
1229 'frontend/element_ready/eel-mega-navigation.default',
1230 eelMegaNavigationInit
1231 );
1232 });
1233
1234 })(jQuery);
1235
1236
1237
1238 (function($){
1239
1240 let eelObserverAttached = false;
1241
1242 function updateMegaMenuActive() {
1243 const $mega = $('.easyel--elementor-template-mega-menu');
1244 if (!$mega.length) return;
1245
1246 const $parent = $mega.parent();
1247
1248 if ($mega.hasClass('easyel-mega--current')) {
1249 $parent.addClass('easyel-mega--current-active menu-item-has-children');
1250 } else {
1251 $parent.removeClass('easyel-mega--current-active menu-item-has-children');
1252 }
1253 }
1254
1255 function updateElementorPositions() {
1256 if ($('.easyel-mega--current-active').length) {
1257 $('header .elementor-element').css('position', 'static');
1258 $('.easyel-mega--current-active .elementor-element').css('position', '');
1259 } else {
1260 $('header .elementor-element').css('position', '');
1261 }
1262 }
1263
1264 function attachObserverOnce() {
1265 if (eelObserverAttached) return;
1266 eelObserverAttached = true;
1267
1268 const observer = new MutationObserver(() => {
1269 updateMegaMenuActive();
1270 updateElementorPositions();
1271 });
1272
1273 observer.observe(document.body, {
1274 attributes: true,
1275 subtree: true,
1276 attributeFilter: ['class']
1277 });
1278 }
1279
1280 function initMegaMenuJS(scope) {
1281 if (!scope.find('.elementor-widget-eel-navigation-menu').length) return;
1282
1283 updateMegaMenuActive();
1284 updateElementorPositions();
1285 attachObserverOnce();
1286 }
1287
1288 // Frontend
1289 $(window).on('load', function(){
1290 initMegaMenuJS($(document.body));
1291 });
1292
1293 // Elementor Editor
1294 $(window).on('elementor/frontend/init', function () {
1295 elementorFrontend.hooks.addAction(
1296 'frontend/element_ready/eel-navigation-menu.default',
1297 function($scope){
1298 initMegaMenuJS($scope);
1299 }
1300 );
1301 });
1302
1303
1304 // Image Comparison
1305 var eelImageBeforeAfter = function ($scope, $) {
1306 var $container = $scope.find(".eel_comparison-container");
1307 if (!$container.length) {
1308 return;
1309 }
1310 $container.each(function () {
1311 var $this = $(this);
1312 var offset = $this.data("offset") || 0.5;
1313 var orientation = $this.data("orientation") || "horizontal";
1314 var before_text = $this.data("before_label") || "Before";
1315 var after_text = $this.data("after_label") || "After";
1316 var initeel_comparison = function() {
1317 if ($.isFunction($.fn.eel_comparison)) {
1318 $this.eel_comparison({
1319 default_offset_pct: offset,
1320 orientation: orientation,
1321 before_label: before_text,
1322 after_label: after_text,
1323 no_overlay: false,
1324 move_slider_on_hover: false,
1325 click_to_move: true
1326 });
1327 }
1328 };
1329 if (document.readyState === 'complete') {
1330 initeel_comparison();
1331 } else {
1332 $(window).on('load', initeel_comparison);
1333 }
1334 });
1335 };
1336 $(window).on('elementor/frontend/init', function () {
1337 elementorFrontend.hooks.addAction('frontend/element_ready/eel-image-before-after.default', eelImageBeforeAfter);
1338 });
1339
1340
1341 jQuery(window).on('elementor/frontend/init', function() {
1342 elementorFrontend.hooks.addAction('frontend/element_ready/eel-vertical-navigation.default', function($scope) {
1343 const menuContainer = $scope.find('.eel-vertical-verticalmenu.eel_click');
1344 if (menuContainer.length) {
1345 const icons = $scope.find('.eel-vertical-menu-area .submenu-parent-icon');
1346
1347 icons.on('click', function(e) {
1348 e.preventDefault();
1349 e.stopPropagation();
1350
1351 const $this = jQuery(this);
1352 const parentLi = $this.closest('li');
1353 const subMenu = parentLi.find('> .sub-menu.eel_click');
1354 const parentLink = $this.closest('a');
1355
1356 if (subMenu.length === 0) return;
1357
1358 if (parentLi.hasClass('is-open-vertical')) {
1359 subMenu.css('max-height', subMenu[0].scrollHeight + 'px');
1360 setTimeout(() => {
1361 subMenu.css({
1362 'max-height': '0',
1363 'opacity': '0'
1364 });
1365 }, 10);
1366
1367 parentLi.removeClass('is-open-vertical');
1368 parentLink.removeClass('eel-vertical-open');
1369 } else {
1370 const siblings = parentLi.siblings('.is-open-vertical');
1371 siblings.each(function() {
1372 const siblingSub = jQuery(this).find('> .sub-menu.eel_click');
1373 siblingSub.css({
1374 'max-height': '0',
1375 'opacity': '0'
1376 });
1377 jQuery(this).removeClass('is-open-vertical');
1378 jQuery(this).find('> a').removeClass('eel-vertical-open');
1379 });
1380
1381 parentLi.addClass('is-open-vertical');
1382 parentLink.addClass('eel-vertical-open');
1383 subMenu.css({
1384 'opacity': '1',
1385 'max-height': subMenu[0].scrollHeight + 'px'
1386 });
1387
1388 subMenu.one('transitionend', function() {
1389 if (parentLi.hasClass('is-open-vertical')) {
1390 subMenu.css('max-height', 'none');
1391 }
1392 });
1393 }
1394 });
1395 }
1396 });
1397 });
1398
1399 })(jQuery);
1400
1401
1402
1403
1404 // Sticky Header (navigation-menu widget).
1405 // Only runs when the widget enabled "Sticky Header" — in that case the PHP
1406 // localizes `eelStickyHeaderSettings` to this handle. When the option is off
1407 // the variable is absent, so this block no-ops even though custom.js loads on
1408 // every page.
1409 (function($) {
1410 function initStickyHeaderScript($scope) {
1411 // Gate: bail unless the nav widget turned sticky on.
1412 if (typeof eelStickyHeaderSettings === 'undefined' || !eelStickyHeaderSettings.enableSticky) {
1413 return;
1414 }
1415
1416 // Skip on mobile — the margin-top mutation on scroll causes layout
1417 // shift that delays Elementor's IntersectionObserver, making motion
1418 // fx widgets load late.
1419 if (window.innerWidth < 768) return;
1420
1421 var header = $('header.easy-site-header');
1422 var page = $('#page');
1423 var topbar = $('.topbar-sticky-hide-yes');
1424 var isFixedHeader = $('body').is('.easyel-fixed-header, .rivora-sidebar-menu');
1425
1426 if (!header.length || !page.length) {
1427 return;
1428 }
1429
1430 header.addClass("eel-sticky-header-on");
1431
1432 function updatePaddingAndMargin(scrollDirection, scroll) {
1433 var headerHeight = header.outerHeight();
1434 var topbarHeight = topbar.length ? topbar.outerHeight() : 0;
1435 var isTopSticky = header.hasClass('eel-fixed-top-sticky');
1436
1437 // page padding-top
1438 if (typeof eelStickyHeaderSettings !== 'undefined' && eelStickyHeaderSettings.enablePadding) {
1439 if (!isFixedHeader) {
1440 page.css('padding-top', headerHeight + 'px');
1441 } else {
1442 page.css('padding-top', '');
1443 }
1444 }
1445
1446 // fixed-top-sticky
1447 if (isTopSticky) {
1448 if (scroll > 100) {
1449 header.addClass('eel--fixed-top-sticky');
1450 header.css('margin-top', `-${topbarHeight}px`);
1451 } else {
1452 header.removeClass('eel--fixed-top-sticky');
1453 header.css('margin-top', '0px');
1454 }
1455 return;
1456 }
1457
1458 // sticky behavior
1459 if (header.hasClass('eel-up-scroll')) {
1460 header.css('margin-top', `-${topbarHeight}px`);
1461 } else {
1462 header.css('margin-top', '0px');
1463 }
1464 }
1465
1466 let lastScroll = 0;
1467 const stickyScrollThreshold = 50;
1468
1469 function sticky_header() {
1470 let scroll = $(window).scrollTop();
1471 let isTopSticky = header.hasClass('eel-fixed-top-sticky');
1472 let scrollDirection = scroll > lastScroll ? 'down' : 'up';
1473
1474 if (isTopSticky) {
1475 header.addClass('eel-sticky-header');
1476 updatePaddingAndMargin(scrollDirection, scroll);
1477 lastScroll = scroll;
1478 return;
1479 }
1480
1481 if (scroll > stickyScrollThreshold) {
1482 header.addClass('eel-sticky-header');
1483 if (scroll > lastScroll) {
1484 header.removeClass('eel-up-scroll').addClass('eel-down-scroll');
1485 } else {
1486 header.removeClass('eel-down-scroll').addClass('eel-up-scroll');
1487 }
1488 } else {
1489 header.removeClass('eel-sticky-header eel-up-scroll eel-down-scroll');
1490 }
1491
1492 updatePaddingAndMargin(scrollDirection, scroll);
1493 lastScroll = scroll;
1494 }
1495
1496 $(document).ready(function() {
1497 updatePaddingAndMargin('up', 0);
1498 sticky_header();
1499 });
1500
1501 $(window).on('scroll resize', function() {
1502 sticky_header();
1503 });
1504 }
1505
1506 $(window).on('elementor/frontend/init', function() {
1507 elementorFrontend.hooks.addAction('frontend/element_ready/global', initStickyHeaderScript);
1508 });
1509 })(jQuery);
1510