PluginProbe
Easy Elements for Elementor – Addons & Website Templates / 1.3.9
Easy Elements for Elementor – Addons & Website Templates v1.3.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.3.9, at assets/js/custom.js

1,230 lines 42.0 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 spvSpecificDefault = parseInt($slider.data('slides-per-view-default'), 10);
15 var finalSlidesPerView;
16 if (spvSkin1) {
17 finalSlidesPerView = spvSkin1;
18 } else if (spvSkin4) {
19 finalSlidesPerView = spvSkin4;
20 } else if (spvSpecificDefault) {
21 finalSlidesPerView = spvSpecificDefault;
22 } else {
23 finalSlidesPerView = slidesPerView;
24 }
25 var speed = parseInt($slider.data('speed'), 10) || 600;
26 var centeredSlides = $slider.data('centered-slides') === true || $slider.data('centered-slides') === 'true';
27 var freeMode = $slider.data('free-mode') === true || $slider.data('free-mode') === 'true';
28 var spaceBetween = parseInt($slider.data('space-between'), 10) || 0;
29 var slidesPerViewTablet = parseInt($slider.data('slides-per-view-tablet'), 10) || 2;
30 var slidesPerViewMobile = parseInt($slider.data('slides-per-view-mobile'), 10) || 1;
31 var paginationType = $slider.data('pagination') !== 'none' ? $slider.data('pagination') : false;
32 var navigation = $slider.data('navigation') === true || $slider.data('navigation') === 'true';
33 var effect = $slider.data('effect') || 'slide';
34 var cubeShadow = $slider.data('cube-shadow') === true || $slider.data('cube-shadow') === 'true';
35 var coverflowRotate = parseInt($slider.data('coverflow-rotate'), 10) || 50;
36 var coverflowStretch = parseInt($slider.data('coverflow-stretch'), 10) || 0;
37
38 // Find navigation elements within the scope
39 var $nextButton = $scope.find('.swiper-next');
40 var $prevButton = $scope.find('.swiper-prev');
41 var $pagination = $scope.find('.swiper-pagination');
42
43 // Prevent multiple instances and duplicated handlers if Elementor re-runs init
44 if ($slider[0] && $slider[0].swiper) {
45 try { $slider[0].swiper.destroy(true, true); } catch (e) {}
46 }
47 if ($nextButton.length) { $nextButton.off('click.easyStopAuto click.easyFadeNav'); }
48 if ($prevButton.length) { $prevButton.off('click.easyStopAuto click.easyFadeNav'); }
49
50 var hasProgressBar = $pagination.hasClass('swiper-pagination-progressbar');
51 var kbDirection = $slider.data('kenburns-direction') || 'in';
52
53 var effectOptions = {};
54
55 if (effect === 'cube') {
56 effectOptions = {
57 cubeEffect: {
58 shadow: cubeShadow,
59 slideShadows: cubeShadow,
60 shadowOffset: 20,
61 shadowScale: 0.94,
62 }
63 };
64 } else if (effect === 'coverflow') {
65 effectOptions = {
66 coverflowEffect: {
67 rotate: coverflowRotate,
68 stretch: coverflowStretch,
69 depth: 100,
70 modifier: 1,
71 slideShadows: true,
72 }
73 };
74 } else if (effect === 'flip') {
75 effectOptions = {
76 flipEffect: {
77 slideShadows: true,
78 limitRotation: true,
79 }
80 };
81 } else if (effect === 'cards') {
82 effectOptions = {
83 cardsEffect: {
84 slideShadows: true,
85 rotate: true,
86 perSlideOffset: 8,
87 }
88 };
89 } else if (effect === 'creative') {
90 var creativeStyle = $slider.data('creative-style') || 'default';
91 if (creativeStyle === 'zoom') {
92 effectOptions = {
93 creativeEffect: {
94 limitProgress: true,
95 prev: { scale: 1.1, opacity: 0, translate: [0, 0, 0] },
96 next: { scale: 1.6, opacity: 0, translate: [0, 0, 0] },
97 },
98 };
99 } else {
100 effectOptions = {
101 creativeEffect: {
102 limitProgress: true,
103 prev: { shadow: true, translate: [0, 0, -400] },
104 next: { translate: ['100%', 0, 0] },
105 },
106 };
107 }
108 } else if (effect === 'fade') {
109 effectOptions = {
110 fadeEffect: { crossFade: true }
111 };
112 } else if (effect === 'kenburns') {
113 effectOptions = {
114 effect: 'fade',
115 fadeEffect: { crossFade: true },
116 on: {
117 init: function () {
118 var swiper = this;
119 setTimeout(function() {
120 var $activeSlide = $(swiper.el).find('.swiper-slide-active');
121 $activeSlide.find('.hero-content-wrapper').addClass('eel-text-animated');
122 $activeSlide.find('.hero-slide-background img').addClass('eel-kb-active-' + kbDirection);
123 }, 200);
124 },
125 slideChange: function () {
126 var $allSlides = $(this.el).find('.swiper-slide');
127 $allSlides.find('.hero-content-wrapper').removeClass('eel-text-animated');
128 $allSlides.find('.hero-slide-background img').removeClass('eel-kb-active-in eel-kb-active-out');
129 },
130 transitionEnd: function () {
131 var swiper = this;
132 var $activeSlide = $(swiper.el).find('.swiper-slide-active');
133 $activeSlide.find('.hero-content-wrapper').addClass('eel-text-animated');
134 $activeSlide.find('.hero-slide-background img').addClass('eel-kb-active-' + kbDirection);
135 }
136 }
137 };
138 }
139
140 // Loop handling tuned to avoid double-advance on loop edges
141 var totalSlides = $slider.find('.swiper-slide').length;
142 var isFade = effect === 'fade';
143 var visibleSlides = isFade ? 1 : slidesPerView;
144 var canLoop = totalSlides > visibleSlides;
145 var loopConfig = {};
146 if (loop && (canLoop || isFade)) {
147 loopConfig = {
148 loop: true,
149 loopAdditionalSlides: isFade ? totalSlides : 20,
150 loopedSlides: isFade ? totalSlides : Math.max(Math.ceil(visibleSlides), Math.min(totalSlides, 10))
151 };
152 } else {
153 loopConfig = { loop: false, rewind: !!loop };
154 }
155
156 var swiper = new Swiper($slider[0], {
157 ...loopConfig,
158 speed: speed,
159 effect: effect,
160 normalizeSlideIndex: true,
161 preventInteractionOnTransition: true,
162 simulateTouch: true,
163 touchRatio: 1,
164 grabCursor: true,
165 mousewheel: hasProgressBar ? {
166 enabled: true,
167 sensitivity: 1,
168 thresholdDelta: 50,
169 thresholdTime: 200,
170 releaseOnEdges: true,
171 invert: false,
172 forceToAxis: false,
173 eventsTarget: 'container'
174 } : false,
175 autoplay: autoplay ? {
176 delay: autoplayDelay,
177 disableOnInteraction: isFade ? true : false,
178 } : false,
179 slidesPerView: visibleSlides,
180 spaceBetween: isFade ? 0 : spaceBetween,
181 centeredSlides: isFade ? false : centeredSlides,
182 freeMode: freeMode,
183 pagination: paginationType && $pagination.length ? {
184 el: $pagination[0],
185 clickable: true,
186 type: paginationType,
187 renderBullet: function (index, className) {
188 let num = (index + 1).toString().padStart(2, '0');
189 return `<span class="${className}">${num}</span>`;
190 }
191 } : false,
192
193 // Progress bar for mouse scroll - only when swiper-pagination-progressbar class is present
194 progressbar: hasProgressBar ? {
195 el: '.swiper-progressbar',
196 type: 'progressbar',
197 } : false,
198
199 navigation: (!isFade) && navigation && ($nextButton.length || $prevButton.length) ? {
200 nextEl: $nextButton.length ? $nextButton[0] : null,
201 prevEl: $prevButton.length ? $prevButton[0] : null,
202 } : false,
203 breakpoints: {
204 0: {
205 slidesPerView: isFade ? 1 : slidesPerViewMobile,
206 },
207 768: {
208 slidesPerView: isFade ? 1 : slidesPerViewTablet,
209 },
210 1024: {
211 slidesPerView: isFade ? 1 : finalSlidesPerView,
212 },
213 },
214 ...effectOptions,
215 });
216
217 // Fade: attach custom navigation so Next/Prev work
218 if (isFade && ($nextButton.length || $prevButton.length)) {
219 var isTransitioning = false;
220 swiper.on('transitionStart', function () { isTransitioning = true; });
221 swiper.on('transitionEnd', function () { isTransitioning = false; });
222 if ($nextButton.length) {
223 $nextButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
224 e.preventDefault();
225 e.stopPropagation();
226 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
227 if (isTransitioning || (swiper && swiper.animating)) return;
228 swiper.slideNext();
229 });
230 }
231 if ($prevButton.length) {
232 $prevButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
233 e.preventDefault();
234 e.stopPropagation();
235 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
236 if (isTransitioning || (swiper && swiper.animating)) return;
237 swiper.slidePrev();
238 });
239 }
240 }
241
242 // Non-fade: if loop+autoplay, stop autoplay on manual nav to avoid double-advance
243 if (!isFade && loop && autoplay) {
244 if ($nextButton.length) {
245 $nextButton.on('click.easyStopAuto', function () {
246 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
247 swiper.autoplay.stop();
248 }
249 });
250 }
251 if ($prevButton.length) {
252 $prevButton.on('click.easyStopAuto', function () {
253 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
254 swiper.autoplay.stop();
255 }
256 });
257 }
258 }
259 }
260
261
262 if (!window.EEL_AddWidgetTypeBodyClass) {
263 window.EEL_AddWidgetTypeBodyClass = true;
264
265 function addWidgetTypeToBody($scope) {
266 if (!$scope || !$scope.length) return;
267
268 var widgetType = $scope.data('widget_type');
269 if (!widgetType) return;
270
271 var safeWidgetType = widgetType
272 .toString()
273 .replace(/[^a-z0-9_-]/gi, '-')
274 .toLowerCase();
275
276 var className = 'easy-eel-has-widget-' + safeWidgetType;
277
278 if (!document.body.classList.contains(className)) {
279 document.body.classList.add(className);
280 }
281 }
282
283 /* -------------------------------------------------
284 * Elementor Hooks
285 * ------------------------------------------------- */
286 $(window).on('elementor/frontend/init', function () {
287
288 // Slider init
289 elementorFrontend.hooks.addAction(
290 'frontend/element_ready/global',
291 initBackPostSlider
292 );
293
294 // Widget type → body class
295 elementorFrontend.hooks.addAction(
296 'frontend/element_ready/global',
297 function ($scope) {
298 addWidgetTypeToBody($scope);
299 }
300 );
301
302 });
303 }
304
305
306 $(window).on('elementor/frontend/init', function () {
307
308 function checkStickySection() {
309 const stickySection = document.querySelector('.eel-sticky-section');
310 if (stickySection) {
311 document.body.classList.add('sticky-enabled-overlap');
312 } else {
313 document.body.classList.remove('sticky-enabled-overlap');
314 }
315 }
316
317 checkStickySection();
318
319 const observer = new MutationObserver(checkStickySection);
320 observer.observe(document.body, { childList: true, subtree: true });
321 });
322
323
324
325 $(window).on('elementor/frontend/init', function () {
326 function initReveal_ad($scope) {
327 const revealElements = $scope.find(".eel-img-advance-wrap");
328 const revealAnimate = (el) => {
329 const target = el.querySelector(".eel-advance-img-main");
330 if(target && !target.classList.contains("el-reveal-animate")) {
331 target.classList.add("el-reveal-animate");
332 }
333 };
334 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
335 if(isEditor){
336 revealElements.each(function(){
337 revealAnimate(this);
338 });
339 } else {
340 const observer = new IntersectionObserver((entries, obs) => {
341 entries.forEach(entry => {
342 if(entry.isIntersecting){
343 revealAnimate(entry.target);
344 obs.unobserve(entry.target);
345 }
346 });
347 }, { threshold: 0.3 });
348
349 revealElements.each(function(){
350 observer.observe(this);
351 });
352
353 // Lenis safe
354 if (window.Lenis && typeof window.Lenis.raf === 'function') {
355 window.Lenis.raf(() => {});
356 }
357 }
358 }
359
360 elementorFrontend.hooks.addAction(
361 'frontend/element_ready/eel-advance-image.default',
362 initReveal_ad
363 );
364
365 function initReveal($scope) {
366 const revealElements = $scope.find(".eel-img-reveal-wrap");
367
368 const revealAnimate = (el) => {
369 const target = el.querySelector(".eel-reveal-img-main");
370 if(target && !target.classList.contains("el-reveal-animate")) {
371 target.classList.add("el-reveal-animate");
372 }
373 };
374
375 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
376
377 if(isEditor){
378 revealElements.each(function(){
379 revealAnimate(this);
380 });
381 } else {
382 const observer = new IntersectionObserver((entries, obs) => {
383 entries.forEach(entry => {
384 if(entry.isIntersecting){
385 revealAnimate(entry.target);
386 obs.unobserve(entry.target);
387 }
388 });
389 }, { threshold: 0.3 });
390
391 revealElements.each(function(){
392 observer.observe(this);
393 });
394
395 // Lenis safe
396 if (window.Lenis && typeof window.Lenis.raf === 'function') {
397 window.Lenis.raf(() => {});
398 }
399 }
400 }
401
402 elementorFrontend.hooks.addAction(
403 'frontend/element_ready/eel-image-reveal.default',
404 initReveal
405 );
406
407 });
408
409
410 $(window).on("elementor/frontend/init", function () {
411 var EasyJarallax = function ($scope, $) {
412 var $wrappers = $scope.hasClass('eele-has-jarallax') ? $scope : $scope.find('.eele-has-jarallax, .eele-inner-jarallax');
413 if (!$wrappers.length) return;
414
415 $wrappers.each(function () {
416 var $wrapper = $(this);
417 var bg = $wrapper.data('jarallax-bg');
418 var speed = $wrapper.data('jarallax-speed') || 0.5;
419 if (!bg) return;
420
421 var $jarallaxDiv = $wrapper.find('.jarallax');
422 if ($jarallaxDiv.length === 0) {
423 var jarallaxMarkup = '<div class="jarallax eele-jarallax-bg" data-speed="' + speed + '">\
424 <img class="jarallax-img" src="' + bg + '" alt="" decoding="async">\
425 </div>';
426 $wrapper.append(jarallaxMarkup);
427 $jarallaxDiv = $wrapper.find('.jarallax');
428 }
429
430 // Initialize Jarallax
431 $jarallaxDiv.each(function () {
432 jarallax(this, {
433 speed: $(this).data('speed'),
434 imgPosition: '50% 50%',
435 imgRepeat: 'no-repeat',
436 imgSize: 'cover',
437 disableVideo: /iPad|iPhone|iPod/.test(navigator.userAgent),
438 zIndex: -100
439 });
440 });
441 });
442 };
443
444 elementorFrontend.hooks.addAction("frontend/element_ready/global", EasyJarallax);
445
446 // --- Lenis integration for Jarallax ---
447 if (typeof window.lenis !== 'undefined') {
448 const lenisRAF = (time) => {
449 window.lenis.raf(time);
450
451 if (typeof jarallax !== 'undefined') {
452 jarallax(document.querySelectorAll('.jarallax'), 'onScroll');
453 }
454 requestAnimationFrame(lenisRAF);
455 };
456 requestAnimationFrame(lenisRAF);
457 }
458 });
459
460
461 jQuery(window).on('elementor/frontend/init', function() {
462
463 elementorFrontend.hooks.addAction('frontend/element_ready/eel-video-popup.default', function($scope, $) {
464
465 const wrapper = $scope.find('.eel-video-popup-wrapper');
466 const overlay = wrapper.find('.eel-video-overlay');
467 // Find video element (try with class first, then without)
468 let videoEl = wrapper.find('video.eel-normal-video');
469 if (!videoEl.length) {
470 videoEl = wrapper.find('video');
471 }
472 // Find iframe element (try with class first, then without)
473 let iframeEl = wrapper.find('iframe.eel-normal-video');
474 if (!iframeEl.length) {
475 iframeEl = wrapper.find('iframe');
476 }
477
478 // Helper function to get YouTube embed URL
479 function getYouTubeEmbedUrl(url) {
480 const regExp = /(?:v=|\/)([0-9A-Za-z_-]{11}).*/;
481 const match = url.match(regExp);
482 if (match && match[1]) {
483 return 'https://www.youtube.com/embed/' + match[1] + '?autoplay=1';
484 }
485 return null;
486 }
487
488 // Helper function to get Vimeo embed URL
489 function getVimeoEmbedUrl(url) {
490 const match = url.match(/(\d+)/);
491 if (match && match[1]) {
492 return 'https://player.vimeo.com/video/' + match[1] + '?autoplay=1';
493 }
494 return null;
495 }
496
497 // Helper function to open lightbox
498 function openLightbox(videoType, videoUrl, popupId, animation) {
499 const lightboxOverlay = $('#' + popupId);
500 const iframeWrapper = lightboxOverlay.find('.eel-video-popup-iframe-wrapper');
501 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
502
503 if (!lightboxOverlay.length) return;
504
505 // Prevent duplicate opening if already active
506 if (lightboxOverlay.hasClass('active')) {
507 return;
508 }
509
510 let embedHtml = '';
511
512 if (videoType === 'youtube') {
513 const embedUrl = getYouTubeEmbedUrl(videoUrl);
514 if (embedUrl) {
515 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
516 }
517 } else if (videoType === 'vimeo') {
518 const embedUrl = getVimeoEmbedUrl(videoUrl);
519 if (embedUrl) {
520 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
521 }
522 } else if (videoType === 'self_hosted') {
523 embedHtml = '<video src="' + videoUrl + '" controls autoplay></video>';
524 }
525
526 if (embedHtml) {
527 iframeWrapper.html(embedHtml);
528
529 // Apply animation if set
530 if (animation && animation.trim() !== '') {
531 // Remove any existing animation classes
532 const currentClasses = lightboxContent.attr('class') || '';
533 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
534 if (animationClasses) {
535 lightboxContent.removeClass(animationClasses.join(' '));
536 }
537 // Add new animation classes
538 lightboxContent.addClass('animated ' + animation.trim());
539 } else {
540 // Remove animation classes if no animation
541 const currentClasses = lightboxContent.attr('class') || '';
542 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
543 if (animationClasses) {
544 lightboxContent.removeClass(animationClasses.join(' '));
545 }
546 }
547
548 lightboxOverlay.addClass('active');
549 $('body').css('overflow', 'hidden');
550 }
551 }
552
553 // Close lightbox handler
554 $(document).on('click', '.eel-video-popup-close', function(e) {
555 e.preventDefault();
556 const lightboxOverlay = $(this).closest('.eel-video-popup-overlay');
557 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
558 lightboxOverlay.removeClass('active');
559 lightboxContent.removeClass('animated');
560 lightboxOverlay.find('.eel-video-popup-iframe-wrapper').html('');
561 $('body').css('overflow', '');
562 });
563
564 // Close lightbox on overlay click
565 $(document).on('click', '.eel-video-popup-overlay', function(e) {
566 if ($(e.target).hasClass('eel-video-popup-overlay')) {
567 const lightboxContent = $(this).find('.eel-video-popup-content');
568 $(this).removeClass('active');
569 lightboxContent.removeClass('animated');
570 $(this).find('.eel-video-popup-iframe-wrapper').html('');
571 $('body').css('overflow', '');
572 }
573 });
574
575 // Close lightbox on ESC key
576 $(document).on('keydown', function(e) {
577 if (e.keyCode === 27) { // ESC key
578 $('.eel-video-popup-overlay.active').each(function() {
579 const lightboxContent = $(this).find('.eel-video-popup-content');
580 $(this).removeClass('active');
581 lightboxContent.removeClass('animated');
582 $(this).find('.eel-video-popup-iframe-wrapper').html('');
583 $('body').css('overflow', '');
584 });
585 }
586 });
587
588 if (overlay.length) {
589 // Remove existing handler to prevent duplicate
590 overlay.off('click.eelVideoOverlay');
591 overlay.on('click.eelVideoOverlay', function(e) {
592 e.preventDefault();
593 e.stopPropagation();
594
595 const $overlay = $(this);
596 const useLightbox = $overlay.data('lightbox') === 'yes';
597 const videoType = $overlay.data('video-type');
598 const videoUrl = $overlay.data('video-url');
599 const popupId = $overlay.data('popup-id');
600 const animation = $overlay.data('animation') || '';
601
602 // If lightbox is enabled, open lightbox
603 if (useLightbox && videoType && videoUrl && popupId) {
604 // Check if lightbox is already open to prevent duplicate
605 const lightboxOverlay = $('#' + popupId);
606 if (lightboxOverlay.hasClass('active')) {
607 return;
608 }
609 openLightbox(videoType, videoUrl, popupId, animation);
610 return;
611 }
612
613 // Otherwise, play inline (original behavior)
614 // Self-hosted video play
615 if (videoEl.length) {
616 const video = videoEl.get(0);
617
618 // Function to play video
619 const playVideo = function() {
620 const playPromise = video.play();
621 if (playPromise !== undefined) {
622 playPromise.catch(function(error) {
623 console.log('Video play failed:', error);
624 // If play fails due to autoplay policy, try with muted
625 if (error.name === 'NotAllowedError' && !video.muted) {
626 video.muted = true;
627 video.play().then(function() {
628 // Unmute after play starts (if user wants sound)
629 setTimeout(function() {
630 video.muted = false;
631 }, 100);
632 }).catch(function(err) {
633 console.log('Video play with mute also failed:', err);
634 });
635 }
636 });
637 }
638 };
639
640 // Always try to load and play
641 if (video.readyState >= 2) {
642 // Video is already loaded, play immediately
643 playVideo();
644 } else {
645 // Video not loaded, load it first then play
646 video.load();
647 // Wait for video to be ready to play
648 const tryPlay = function() {
649 if (video.readyState >= 2) {
650 playVideo();
651 } else {
652 video.addEventListener('canplay', playVideo, { once: true });
653 video.addEventListener('loadeddata', playVideo, { once: true });
654 }
655 };
656 tryPlay();
657 }
658 }
659
660 // YouTube / Vimeo iframe autoplay
661 if (iframeEl.length) {
662 let src = iframeEl.attr('src');
663 if (src) {
664 // Check if it's YouTube or Vimeo
665 const isYouTube = src.indexOf('youtube.com') !== -1 || src.indexOf('youtu.be') !== -1;
666 const isVimeo = src.indexOf('vimeo.com') !== -1;
667
668 if (isYouTube || isVimeo) {
669 try {
670 // Use URL object for proper parsing
671 const url = new URL(src);
672
673 if (isYouTube) {
674 // YouTube: add autoplay, preserve original mute setting
675 url.searchParams.set('autoplay', '1');
676 // Only set mute=1 if it was already in the URL (preserve original setting)
677 // If mute was not in original URL, don't add it
678 if (!url.searchParams.has('mute')) {
679 // Don't add mute if it wasn't there originally
680 } else {
681 // Keep the original mute value
682 }
683 // Reload iframe with new src
684 iframeEl.attr('src', url.toString());
685 } else if (isVimeo) {
686 // Vimeo: add autoplay (Vimeo doesn't need mute for autoplay)
687 url.searchParams.set('autoplay', '1');
688 // Reload iframe with new src
689 iframeEl.attr('src', url.toString());
690 }
691 } catch (e) {
692 // Fallback for browsers that don't support URL constructor
693 // Remove existing autoplay parameter if present
694 src = src.replace(/[?&]autoplay=[^&]*/g, '');
695
696 if (isYouTube) {
697 // Check if mute parameter exists in original URL
698 const hasMute = /[?&]mute=/.test(src);
699 // Add autoplay=1
700 const separator = src.indexOf('?') === -1 ? '?' : '&';
701 src += separator + 'autoplay=1';
702 // Only add mute if it was already there (preserve original setting)
703 // Don't add mute if it wasn't in original URL
704 } else if (isVimeo) {
705 // Vimeo: just add autoplay=1
706 const separator = src.indexOf('?') === -1 ? '?' : '&';
707 src += separator + 'autoplay=1';
708 }
709
710 // Update src without clearing first
711 iframeEl.attr('src', src);
712 }
713 }
714 }
715 }
716
717 // Remove overlay after a small delay to ensure video starts
718 setTimeout(function() {
719 overlay.fadeOut(300, function() {
720 $(this).remove();
721 });
722 }, 200);
723 });
724 }
725
726 // Handle popup button clicks (for display_type = 'popup')
727 const popupBtn = wrapper.find('.entro-all-video-popup');
728 if (popupBtn.length) {
729 // Remove existing handler to prevent duplicate
730 popupBtn.off('click.eelVideoPopup');
731 popupBtn.on('click.eelVideoPopup', function(e) {
732 e.preventDefault();
733 e.stopPropagation();
734 const $btn = $(this);
735 const videoType = $btn.data('video-type');
736 const videoUrl = $btn.data('video-src');
737 const popupId = $btn.data('popup-id');
738 const lightboxOverlay = $('#' + popupId);
739 const animation = lightboxOverlay.data('animation') || '';
740
741 if (videoType && videoUrl && popupId) {
742 // Check if lightbox is already open to prevent duplicate
743 if (lightboxOverlay.hasClass('active')) {
744 return;
745 }
746 openLightbox(videoType, videoUrl, popupId, animation);
747 }
748 });
749 }
750 });
751
752 });
753
754 // Single Page Navigation
755 document.addEventListener('DOMContentLoaded', function () {
756 const navWrappers = document.querySelectorAll('.eel-single-nav-list');
757 if (!navWrappers.length) return;
758
759 navWrappers.forEach(function (wrapper) {
760
761 const navLinks = wrapper.querySelectorAll('.eel-nav-item a');
762 const navItems = wrapper.querySelectorAll('.eel-nav-item');
763
764 if (!navLinks.length) return;
765
766 wrapper.addEventListener('click', function (e) {
767
768 const link = e.target.closest('.eel-nav-item a');
769 if (!link || !wrapper.contains(link)) return;
770
771 const href = link.getAttribute('href');
772
773 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
774 return;
775 }
776
777 const target = document.querySelector(href);
778 if (!target) return;
779
780 e.preventDefault();
781
782 target.scrollIntoView({
783 behavior: 'smooth',
784 block: 'start'
785 });
786 });
787
788 /* ========= SCROLL → ACTIVE CHANGE ========= */
789 const sectionsMap = new Map();
790
791 navLinks.forEach(link => {
792 const href = link.getAttribute('href');
793
794 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
795 return;
796 }
797
798 const section = document.querySelector(href);
799 if (section) {
800 sectionsMap.set(section, href);
801 }
802 });
803
804 function setActive(href) {
805 navItems.forEach(item => item.classList.remove('active'));
806
807 navLinks.forEach(link => {
808 if (link.getAttribute('href') === href) {
809 link.closest('.eel-nav-item')?.classList.add('active');
810 }
811 });
812 }
813
814 const observer = new IntersectionObserver(
815 (entries) => {
816 entries.forEach(entry => {
817 if (entry.isIntersecting) {
818 const id = sectionsMap.get(entry.target);
819 if (id) setActive(id);
820 }
821 });
822 },
823 {
824 root: null,
825 rootMargin: '-40% 0px -40% 0px',
826 threshold: 0.1
827 }
828 );
829
830 sectionsMap.forEach((id, section) => {
831 observer.observe(section);
832 });
833
834 });
835
836 });
837
838 // Sticky Navigation single page
839
840 function applyStickyToContainer($container) {
841 if ($container.find('.elementor-widget-eel-single-nav').length === 0) {
842 return;
843 }
844
845 $container.addClass('eel-single-nav-sticky-enabled');
846 }
847
848 /* ===== Frontend ===== */
849 $(window).on('elementor/frontend/init', function () {
850 elementorFrontend.hooks.addAction(
851 'frontend/element_ready/container',
852 function ($scope) {
853 applyStickyToContainer($scope);
854 }
855 );
856 });
857
858 /* ===== Editor ===== */
859 if (window.elementor && elementor.isEditMode()) {
860 elementor.hooks.addAction('editor:init', function () {
861 elementorFrontend.hooks.addAction(
862 'frontend/element_ready/container',
863 function ($scope) {
864 applyStickyToContainer($scope);
865 }
866 );
867 });
868 }
869
870 // Mobile Menu Sidebar
871 if ($('.sidebar-on-mobile-single-nav').length) {
872 // Sidebar toggle
873 $('.eel-nav-menu-icon').on('click', function(e){
874 e.stopPropagation();
875 $('.sidebar-on-mobile-single-nav').toggleClass('easyel-open');
876 $('body').toggleClass('sidebar-on-mobile-single-nav-active');
877 });
878 // Click outside to close sidebar
879 $(document).on('click', function(){
880 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
881 $('body').removeClass('sidebar-on-mobile-single-nav-active');
882 $('.sidebar-on-mobile-single-nav ul.sub-menu').slideUp(300);
883 $('.sidebar-on-mobile-single-nav .sub-arrow').removeClass('active').attr('aria-expanded', false);
884 });
885
886 $('.sidebar-on-mobile-single-nav, .eel-nav-menu').on('click', 'li:not(.menu-item-has-children) a', function(e){
887 $('.sidebar-on-mobile-single-nav li a, .eel-nav-menu li a').removeClass('eel-active');
888 $(this).addClass('eel-active');
889 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
890 $('body').removeClass('sidebar-on-mobile-single-nav-active');
891 $('body').removeClass('sidebar-on-mobile-active');
892 });
893
894 // Prevent closing when clicking inside sidebar
895 $('.sidebar-on-mobile-single-nav').on('click', function(e){
896 e.stopPropagation();
897 });
898 }
899
900 jQuery(document).ready(function($){
901 var $sidebar = $('.sidebar-on-mobile-mega-nav');
902 var $body = $('body');
903
904 if(!$sidebar.length) return;
905
906 /* ========== Inject submenu icon ========== */
907 $sidebar.find('li.menu-item-has-children').each(function(){
908 if(!$(this).children('.submenu-parent-icon').length){
909 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>';
910 $(this).prepend(svgIcon);
911 }
912 });
913
914 // Open sidebar
915 $(document).on('click', '.eel-mega-menu-icon-mobile', function(e){
916 e.preventDefault();
917 e.stopPropagation();
918 $sidebar.addClass('easyel-open');
919 $body.addClass('sidebar-on-mobile-mega-nav-active');
920 });
921
922 // Close sidebar (icon)
923 $(document).on('click', '.eel-mega-menu-icon-close', function(e){
924 e.preventDefault();
925 e.stopPropagation();
926 $sidebar.removeClass('easyel-open');
927 $body.removeClass('sidebar-on-mobile-mega-nav-active');
928 });
929
930 // Click outside sidebar (overlay)
931 $(document).on('click', function(){
932 $sidebar.removeClass('easyel-open');
933 $body.removeClass('sidebar-on-mobile-mega-nav-active');
934 });
935
936 // Prevent sidebar clicks from closing
937 $sidebar.on('click', function(e){
938 if (!$(e.target).closest('.eel-mega-menu-icon-close').length) {
939 e.stopPropagation();
940 }
941 });
942
943 /* ========== Submenu toggle ========== */
944 $('.submenu-parent-icon').on('click', function(e){
945 e.preventDefault();
946 e.stopPropagation();
947
948 var $li = $(this).closest('li.menu-item-has-children');
949 var $submenu = $li.children('ul.sub-menu');
950
951 // close other submenus
952 $li.siblings('li.menu-item-has-children')
953 .removeClass('eel-sub-open')
954 .children('ul.sub-menu').slideUp(300);
955
956 $li.siblings('li.menu-item-has-children')
957 .children('.submenu-parent-icon').removeClass('active');
958
959 // toggle current
960 $submenu.slideToggle(300);
961 $li.toggleClass('eel-sub-open');
962 $(this).toggleClass('active');
963 });
964 });
965
966 jQuery(window).on('elementor/frontend/init', function() {
967 elementorFrontend.hooks.addAction('frontend/element_ready/eel-vertical-navigation.default', function($scope) {
968
969 var $sidebar = $scope.find('.sidebar-on-mobile-vertical-nav');
970 var $body = jQuery('body');
971
972 if($sidebar.length) {
973 $sidebar.find('li.menu-item-has-children').each(function(){
974 if(!jQuery(this).children('.submenu-parent-icon').length){
975 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>';
976 jQuery(this).prepend(svgIcon);
977 }
978 });
979
980 $scope.on('click', '.eel-vertical-menu-icon-mobile', function(e){
981 e.preventDefault();
982 e.stopPropagation();
983 $sidebar.addClass('easyel-open');
984 $body.addClass('sidebar-on-mobile-vertical-nav-active');
985 });
986
987 $scope.on('click', '.eel-vertical-menu-icon-close', function(e){
988 e.preventDefault();
989 e.stopPropagation();
990 closeSidebar();
991 });
992
993 jQuery(document).on('click', function(e){
994 if (!jQuery(e.target).closest('.sidebar-on-mobile-vertical-nav, .eel-vertical-menu-icon-mobile').length) {
995 closeSidebar();
996 }
997 });
998
999 function closeSidebar() {
1000 $sidebar.removeClass('easyel-open');
1001 $body.removeClass('sidebar-on-mobile-vertical-nav-active');
1002 }
1003
1004 /* ========== Submenu Toggle (Accordion) ========== */
1005 $scope.find('.submenu-parent-icon').off('click').on('click', function(e){
1006 if (window.innerWidth <= 991) {
1007 e.preventDefault();
1008 e.stopPropagation();
1009
1010 var $this = jQuery(this);
1011 var $li = $this.closest('li.menu-item-has-children');
1012 var $submenu = $li.children('ul.sub-menu');
1013 $li.siblings('li.menu-item-has-children').each(function(){
1014 var $sibling = jQuery(this);
1015 $sibling.removeClass('eel-sub-open is-open-vertical');
1016 $sibling.children('ul.sub-menu').slideUp(300);
1017 $sibling.children('.submenu-parent-icon').removeClass('active');
1018 $sibling.find('> a').removeClass('eel-vertical-open');
1019 });
1020 if ($li.hasClass('eel-sub-open')) {
1021 $submenu.slideUp(300);
1022 $li.removeClass('eel-sub-open is-open-vertical');
1023 $this.removeClass('active');
1024 $li.find('> a').removeClass('eel-vertical-open');
1025 } else {
1026 $submenu.slideDown(300);
1027 $li.addClass('eel-sub-open is-open-vertical');
1028 $this.addClass('active');
1029 $li.find('> a').addClass('eel-vertical-open');
1030 }
1031 }
1032 });
1033 }
1034 });
1035 });
1036
1037 })(jQuery);
1038
1039 (function ($) {
1040 function eelMegaNavigationInit() {
1041 $('.elementor-widget-eel-mega-navigation')
1042 .parent()
1043 .addClass('parant-eel-mega-static');
1044 }
1045 // Frontend
1046 $(window).on('load', function () {
1047 eelMegaNavigationInit();
1048 });
1049
1050 // Elementor Editor
1051 $(window).on('elementor/frontend/init', function () {
1052 if (elementorFrontend.isEditMode()) {
1053 eelMegaNavigationInit();
1054 }
1055 elementorFrontend.hooks.addAction(
1056 'frontend/element_ready/eel-mega-navigation.default',
1057 eelMegaNavigationInit
1058 );
1059 });
1060
1061 })(jQuery);
1062
1063
1064
1065 (function($){
1066
1067 let eelObserverAttached = false;
1068
1069 function updateMegaMenuActive() {
1070 const $mega = $('.easyel--elementor-template-mega-menu');
1071 if (!$mega.length) return;
1072
1073 const $parent = $mega.parent();
1074
1075 if ($mega.hasClass('easyel-mega--current')) {
1076 $parent.addClass('easyel-mega--current-active menu-item-has-children');
1077 } else {
1078 $parent.removeClass('easyel-mega--current-active menu-item-has-children');
1079 }
1080 }
1081
1082 function updateElementorPositions() {
1083 if ($('.easyel-mega--current-active').length) {
1084 $('header .elementor-element').css('position', 'static');
1085 $('.easyel-mega--current-active .elementor-element').css('position', '');
1086 } else {
1087 $('header .elementor-element').css('position', '');
1088 }
1089 }
1090
1091 function attachObserverOnce() {
1092 if (eelObserverAttached) return;
1093 eelObserverAttached = true;
1094
1095 const observer = new MutationObserver(() => {
1096 updateMegaMenuActive();
1097 updateElementorPositions();
1098 });
1099
1100 observer.observe(document.body, {
1101 attributes: true,
1102 subtree: true,
1103 attributeFilter: ['class']
1104 });
1105 }
1106
1107 function initMegaMenuJS(scope) {
1108 if (!scope.find('.elementor-widget-eel-navigation-menu').length) return;
1109
1110 updateMegaMenuActive();
1111 updateElementorPositions();
1112 attachObserverOnce();
1113 }
1114
1115 // Frontend
1116 $(window).on('load', function(){
1117 initMegaMenuJS($(document.body));
1118 });
1119
1120 // Elementor Editor
1121 $(window).on('elementor/frontend/init', function () {
1122 elementorFrontend.hooks.addAction(
1123 'frontend/element_ready/eel-navigation-menu.default',
1124 function($scope){
1125 initMegaMenuJS($scope);
1126 }
1127 );
1128 });
1129
1130
1131 // Image Comparison
1132 var eelImageBeforeAfter = function ($scope, $) {
1133 var $container = $scope.find(".eel_comparison-container");
1134 if (!$container.length) {
1135 return;
1136 }
1137 $container.each(function () {
1138 var $this = $(this);
1139 var offset = $this.data("offset") || 0.5;
1140 var orientation = $this.data("orientation") || "horizontal";
1141 var before_text = $this.data("before_label") || "Before";
1142 var after_text = $this.data("after_label") || "After";
1143 var initeel_comparison = function() {
1144 if ($.isFunction($.fn.eel_comparison)) {
1145 $this.eel_comparison({
1146 default_offset_pct: offset,
1147 orientation: orientation,
1148 before_label: before_text,
1149 after_label: after_text,
1150 no_overlay: false,
1151 move_slider_on_hover: false,
1152 click_to_move: true
1153 });
1154 }
1155 };
1156 if (document.readyState === 'complete') {
1157 initeel_comparison();
1158 } else {
1159 $(window).on('load', initeel_comparison);
1160 }
1161 });
1162 };
1163 $(window).on('elementor/frontend/init', function () {
1164 elementorFrontend.hooks.addAction('frontend/element_ready/eel-image-before-after.default', eelImageBeforeAfter);
1165 });
1166
1167
1168 jQuery(window).on('elementor/frontend/init', function() {
1169 elementorFrontend.hooks.addAction('frontend/element_ready/eel-vertical-navigation.default', function($scope) {
1170 const menuContainer = $scope.find('.eel-vertical-verticalmenu.eel_click');
1171 if (menuContainer.length) {
1172 const icons = $scope.find('.submenu-parent-icon');
1173
1174 icons.on('click', function(e) {
1175 e.preventDefault();
1176 e.stopPropagation();
1177
1178 const $this = jQuery(this);
1179 const parentLi = $this.closest('li');
1180 const subMenu = parentLi.find('> .sub-menu.eel_click');
1181 const parentLink = $this.closest('a');
1182
1183 if (subMenu.length === 0) return;
1184
1185 if (parentLi.hasClass('is-open-vertical')) {
1186 subMenu.css('max-height', subMenu[0].scrollHeight + 'px');
1187 setTimeout(() => {
1188 subMenu.css({
1189 'max-height': '0',
1190 'opacity': '0'
1191 });
1192 }, 10);
1193
1194 parentLi.removeClass('is-open-vertical');
1195 parentLink.removeClass('eel-vertical-open');
1196 } else {
1197 const siblings = parentLi.siblings('.is-open-vertical');
1198 siblings.each(function() {
1199 const siblingSub = jQuery(this).find('> .sub-menu.eel_click');
1200 siblingSub.css({
1201 'max-height': '0',
1202 'opacity': '0'
1203 });
1204 jQuery(this).removeClass('is-open-vertical');
1205 jQuery(this).find('> a').removeClass('eel-vertical-open');
1206 });
1207
1208 parentLi.addClass('is-open-vertical');
1209 parentLink.addClass('eel-vertical-open');
1210 subMenu.css({
1211 'opacity': '1',
1212 'max-height': subMenu[0].scrollHeight + 'px'
1213 });
1214
1215 subMenu.one('transitionend', function() {
1216 if (parentLi.hasClass('is-open-vertical')) {
1217 subMenu.css('max-height', 'none');
1218 }
1219 });
1220 }
1221 });
1222 }
1223 });
1224 });
1225
1226 })(jQuery);
1227
1228
1229
1230