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

1,046 lines 36.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 $(window).on('elementor/frontend/init', function () {
306
307 function checkStickySection() {
308 const stickySection = document.querySelector('.eel-sticky-section');
309 if (stickySection) {
310 document.body.classList.add('sticky-enabled-overlap');
311 } else {
312 document.body.classList.remove('sticky-enabled-overlap');
313 }
314 }
315
316 checkStickySection();
317
318 const observer = new MutationObserver(checkStickySection);
319 observer.observe(document.body, { childList: true, subtree: true });
320 });
321
322
323
324 $(window).on('elementor/frontend/init', function () {
325 function initReveal_ad($scope) {
326 const revealElements = $scope.find(".eel-img-advance-wrap");
327 const revealAnimate = (el) => {
328 const target = el.querySelector(".eel-advance-img-main");
329 if(target && !target.classList.contains("el-reveal-animate")) {
330 target.classList.add("el-reveal-animate");
331 }
332 };
333 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
334 if(isEditor){
335 revealElements.each(function(){
336 revealAnimate(this);
337 });
338 } else {
339 const observer = new IntersectionObserver((entries, obs) => {
340 entries.forEach(entry => {
341 if(entry.isIntersecting){
342 revealAnimate(entry.target);
343 obs.unobserve(entry.target);
344 }
345 });
346 }, { threshold: 0.3 });
347
348 revealElements.each(function(){
349 observer.observe(this);
350 });
351
352 // Lenis safe
353 if (window.Lenis && typeof window.Lenis.raf === 'function') {
354 window.Lenis.raf(() => {});
355 }
356 }
357 }
358
359 elementorFrontend.hooks.addAction(
360 'frontend/element_ready/eel-advance-image.default',
361 initReveal_ad
362 );
363
364 function initReveal($scope) {
365 const revealElements = $scope.find(".eel-img-reveal-wrap");
366
367 const revealAnimate = (el) => {
368 const target = el.querySelector(".eel-reveal-img-main");
369 if(target && !target.classList.contains("el-reveal-animate")) {
370 target.classList.add("el-reveal-animate");
371 }
372 };
373
374 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
375
376 if(isEditor){
377 revealElements.each(function(){
378 revealAnimate(this);
379 });
380 } else {
381 const observer = new IntersectionObserver((entries, obs) => {
382 entries.forEach(entry => {
383 if(entry.isIntersecting){
384 revealAnimate(entry.target);
385 obs.unobserve(entry.target);
386 }
387 });
388 }, { threshold: 0.3 });
389
390 revealElements.each(function(){
391 observer.observe(this);
392 });
393
394 // Lenis safe
395 if (window.Lenis && typeof window.Lenis.raf === 'function') {
396 window.Lenis.raf(() => {});
397 }
398 }
399 }
400
401 elementorFrontend.hooks.addAction(
402 'frontend/element_ready/eel-image-reveal.default',
403 initReveal
404 );
405
406 });
407
408
409 $(window).on("elementor/frontend/init", function () {
410 var EasyJarallax = function ($scope, $) {
411 var $wrappers = $scope.hasClass('eele-has-jarallax') ? $scope : $scope.find('.eele-has-jarallax, .eele-inner-jarallax');
412 if (!$wrappers.length) return;
413
414 $wrappers.each(function () {
415 var $wrapper = $(this);
416 var bg = $wrapper.data('jarallax-bg');
417 var speed = $wrapper.data('jarallax-speed') || 0.5;
418 if (!bg) return;
419
420 var $jarallaxDiv = $wrapper.find('.jarallax');
421 if ($jarallaxDiv.length === 0) {
422 var jarallaxMarkup = '<div class="jarallax eele-jarallax-bg" data-speed="' + speed + '">\
423 <img class="jarallax-img" src="' + bg + '" alt="" decoding="async">\
424 </div>';
425 $wrapper.append(jarallaxMarkup);
426 $jarallaxDiv = $wrapper.find('.jarallax');
427 }
428
429 // Initialize jarallax with Mac-friendly settings
430 $jarallaxDiv.each(function () {
431 jarallax(this, {
432 speed: $(this).data('speed'),
433 imgPosition: '50% 50%',
434 imgRepeat: 'no-repeat',
435 imgSize: 'cover',
436 disableVideo: /iPad|iPhone|iPod/.test(navigator.userAgent),
437 zIndex: -100
438 });
439 });
440 });
441 };
442 elementorFrontend.hooks.addAction("frontend/element_ready/global", EasyJarallax);
443 });
444
445
446
447 jQuery(window).on('elementor/frontend/init', function() {
448
449 elementorFrontend.hooks.addAction('frontend/element_ready/eel-video-popup.default', function($scope, $) {
450
451 const wrapper = $scope.find('.eel-video-popup-wrapper');
452 const overlay = wrapper.find('.eel-video-overlay');
453 // Find video element (try with class first, then without)
454 let videoEl = wrapper.find('video.eel-normal-video');
455 if (!videoEl.length) {
456 videoEl = wrapper.find('video');
457 }
458 // Find iframe element (try with class first, then without)
459 let iframeEl = wrapper.find('iframe.eel-normal-video');
460 if (!iframeEl.length) {
461 iframeEl = wrapper.find('iframe');
462 }
463
464 // Helper function to get YouTube embed URL
465 function getYouTubeEmbedUrl(url) {
466 const regExp = /(?:v=|\/)([0-9A-Za-z_-]{11}).*/;
467 const match = url.match(regExp);
468 if (match && match[1]) {
469 return 'https://www.youtube.com/embed/' + match[1] + '?autoplay=1';
470 }
471 return null;
472 }
473
474 // Helper function to get Vimeo embed URL
475 function getVimeoEmbedUrl(url) {
476 const match = url.match(/(\d+)/);
477 if (match && match[1]) {
478 return 'https://player.vimeo.com/video/' + match[1] + '?autoplay=1';
479 }
480 return null;
481 }
482
483 // Helper function to open lightbox
484 function openLightbox(videoType, videoUrl, popupId, animation) {
485 const lightboxOverlay = $('#' + popupId);
486 const iframeWrapper = lightboxOverlay.find('.eel-video-popup-iframe-wrapper');
487 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
488
489 if (!lightboxOverlay.length) return;
490
491 // Prevent duplicate opening if already active
492 if (lightboxOverlay.hasClass('active')) {
493 return;
494 }
495
496 let embedHtml = '';
497
498 if (videoType === 'youtube') {
499 const embedUrl = getYouTubeEmbedUrl(videoUrl);
500 if (embedUrl) {
501 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
502 }
503 } else if (videoType === 'vimeo') {
504 const embedUrl = getVimeoEmbedUrl(videoUrl);
505 if (embedUrl) {
506 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
507 }
508 } else if (videoType === 'self_hosted') {
509 embedHtml = '<video src="' + videoUrl + '" controls autoplay></video>';
510 }
511
512 if (embedHtml) {
513 iframeWrapper.html(embedHtml);
514
515 // Apply animation if set
516 if (animation && animation.trim() !== '') {
517 // Remove any existing animation classes
518 const currentClasses = lightboxContent.attr('class') || '';
519 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
520 if (animationClasses) {
521 lightboxContent.removeClass(animationClasses.join(' '));
522 }
523 // Add new animation classes
524 lightboxContent.addClass('animated ' + animation.trim());
525 } else {
526 // Remove animation classes if no animation
527 const currentClasses = lightboxContent.attr('class') || '';
528 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
529 if (animationClasses) {
530 lightboxContent.removeClass(animationClasses.join(' '));
531 }
532 }
533
534 lightboxOverlay.addClass('active');
535 $('body').css('overflow', 'hidden');
536 }
537 }
538
539 // Close lightbox handler
540 $(document).on('click', '.eel-video-popup-close', function(e) {
541 e.preventDefault();
542 const lightboxOverlay = $(this).closest('.eel-video-popup-overlay');
543 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
544 lightboxOverlay.removeClass('active');
545 lightboxContent.removeClass('animated');
546 lightboxOverlay.find('.eel-video-popup-iframe-wrapper').html('');
547 $('body').css('overflow', '');
548 });
549
550 // Close lightbox on overlay click
551 $(document).on('click', '.eel-video-popup-overlay', function(e) {
552 if ($(e.target).hasClass('eel-video-popup-overlay')) {
553 const lightboxContent = $(this).find('.eel-video-popup-content');
554 $(this).removeClass('active');
555 lightboxContent.removeClass('animated');
556 $(this).find('.eel-video-popup-iframe-wrapper').html('');
557 $('body').css('overflow', '');
558 }
559 });
560
561 // Close lightbox on ESC key
562 $(document).on('keydown', function(e) {
563 if (e.keyCode === 27) { // ESC key
564 $('.eel-video-popup-overlay.active').each(function() {
565 const lightboxContent = $(this).find('.eel-video-popup-content');
566 $(this).removeClass('active');
567 lightboxContent.removeClass('animated');
568 $(this).find('.eel-video-popup-iframe-wrapper').html('');
569 $('body').css('overflow', '');
570 });
571 }
572 });
573
574 if (overlay.length) {
575 // Remove existing handler to prevent duplicate
576 overlay.off('click.eelVideoOverlay');
577 overlay.on('click.eelVideoOverlay', function(e) {
578 e.preventDefault();
579 e.stopPropagation();
580
581 const $overlay = $(this);
582 const useLightbox = $overlay.data('lightbox') === 'yes';
583 const videoType = $overlay.data('video-type');
584 const videoUrl = $overlay.data('video-url');
585 const popupId = $overlay.data('popup-id');
586 const animation = $overlay.data('animation') || '';
587
588 // If lightbox is enabled, open lightbox
589 if (useLightbox && videoType && videoUrl && popupId) {
590 // Check if lightbox is already open to prevent duplicate
591 const lightboxOverlay = $('#' + popupId);
592 if (lightboxOverlay.hasClass('active')) {
593 return;
594 }
595 openLightbox(videoType, videoUrl, popupId, animation);
596 return;
597 }
598
599 // Otherwise, play inline (original behavior)
600 // Self-hosted video play
601 if (videoEl.length) {
602 const video = videoEl.get(0);
603
604 // Function to play video
605 const playVideo = function() {
606 const playPromise = video.play();
607 if (playPromise !== undefined) {
608 playPromise.catch(function(error) {
609 console.log('Video play failed:', error);
610 // If play fails due to autoplay policy, try with muted
611 if (error.name === 'NotAllowedError' && !video.muted) {
612 video.muted = true;
613 video.play().then(function() {
614 // Unmute after play starts (if user wants sound)
615 setTimeout(function() {
616 video.muted = false;
617 }, 100);
618 }).catch(function(err) {
619 console.log('Video play with mute also failed:', err);
620 });
621 }
622 });
623 }
624 };
625
626 // Always try to load and play
627 if (video.readyState >= 2) {
628 // Video is already loaded, play immediately
629 playVideo();
630 } else {
631 // Video not loaded, load it first then play
632 video.load();
633 // Wait for video to be ready to play
634 const tryPlay = function() {
635 if (video.readyState >= 2) {
636 playVideo();
637 } else {
638 video.addEventListener('canplay', playVideo, { once: true });
639 video.addEventListener('loadeddata', playVideo, { once: true });
640 }
641 };
642 tryPlay();
643 }
644 }
645
646 // YouTube / Vimeo iframe autoplay
647 if (iframeEl.length) {
648 let src = iframeEl.attr('src');
649 if (src) {
650 // Check if it's YouTube or Vimeo
651 const isYouTube = src.indexOf('youtube.com') !== -1 || src.indexOf('youtu.be') !== -1;
652 const isVimeo = src.indexOf('vimeo.com') !== -1;
653
654 if (isYouTube || isVimeo) {
655 try {
656 // Use URL object for proper parsing
657 const url = new URL(src);
658
659 if (isYouTube) {
660 // YouTube: add autoplay, preserve original mute setting
661 url.searchParams.set('autoplay', '1');
662 // Only set mute=1 if it was already in the URL (preserve original setting)
663 // If mute was not in original URL, don't add it
664 if (!url.searchParams.has('mute')) {
665 // Don't add mute if it wasn't there originally
666 } else {
667 // Keep the original mute value
668 }
669 // Reload iframe with new src
670 iframeEl.attr('src', url.toString());
671 } else if (isVimeo) {
672 // Vimeo: add autoplay (Vimeo doesn't need mute for autoplay)
673 url.searchParams.set('autoplay', '1');
674 // Reload iframe with new src
675 iframeEl.attr('src', url.toString());
676 }
677 } catch (e) {
678 // Fallback for browsers that don't support URL constructor
679 // Remove existing autoplay parameter if present
680 src = src.replace(/[?&]autoplay=[^&]*/g, '');
681
682 if (isYouTube) {
683 // Check if mute parameter exists in original URL
684 const hasMute = /[?&]mute=/.test(src);
685 // Add autoplay=1
686 const separator = src.indexOf('?') === -1 ? '?' : '&';
687 src += separator + 'autoplay=1';
688 // Only add mute if it was already there (preserve original setting)
689 // Don't add mute if it wasn't in original URL
690 } else if (isVimeo) {
691 // Vimeo: just add autoplay=1
692 const separator = src.indexOf('?') === -1 ? '?' : '&';
693 src += separator + 'autoplay=1';
694 }
695
696 // Update src without clearing first
697 iframeEl.attr('src', src);
698 }
699 }
700 }
701 }
702
703 // Remove overlay after a small delay to ensure video starts
704 setTimeout(function() {
705 overlay.fadeOut(300, function() {
706 $(this).remove();
707 });
708 }, 200);
709 });
710 }
711
712 // Handle popup button clicks (for display_type = 'popup')
713 const popupBtn = wrapper.find('.entro-all-video-popup');
714 if (popupBtn.length) {
715 // Remove existing handler to prevent duplicate
716 popupBtn.off('click.eelVideoPopup');
717 popupBtn.on('click.eelVideoPopup', function(e) {
718 e.preventDefault();
719 e.stopPropagation();
720 const $btn = $(this);
721 const videoType = $btn.data('video-type');
722 const videoUrl = $btn.data('video-src');
723 const popupId = $btn.data('popup-id');
724 const lightboxOverlay = $('#' + popupId);
725 const animation = lightboxOverlay.data('animation') || '';
726
727 if (videoType && videoUrl && popupId) {
728 // Check if lightbox is already open to prevent duplicate
729 if (lightboxOverlay.hasClass('active')) {
730 return;
731 }
732 openLightbox(videoType, videoUrl, popupId, animation);
733 }
734 });
735 }
736 });
737
738 });
739
740 // Single Page Navigation
741 document.addEventListener('DOMContentLoaded', function () {
742 const navWrappers = document.querySelectorAll('.eel-single-nav-list');
743 if (!navWrappers.length) return;
744
745 navWrappers.forEach(function (wrapper) {
746
747 const navLinks = wrapper.querySelectorAll('.eel-nav-item a');
748 const navItems = wrapper.querySelectorAll('.eel-nav-item');
749
750 if (!navLinks.length) return;
751
752 wrapper.addEventListener('click', function (e) {
753
754 const link = e.target.closest('.eel-nav-item a');
755 if (!link || !wrapper.contains(link)) return;
756
757 const href = link.getAttribute('href');
758
759 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
760 return;
761 }
762
763 const target = document.querySelector(href);
764 if (!target) return;
765
766 e.preventDefault();
767
768 target.scrollIntoView({
769 behavior: 'smooth',
770 block: 'start'
771 });
772 });
773
774 /* ========= SCROLL → ACTIVE CHANGE ========= */
775 const sectionsMap = new Map();
776
777 navLinks.forEach(link => {
778 const href = link.getAttribute('href');
779
780 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
781 return;
782 }
783
784 const section = document.querySelector(href);
785 if (section) {
786 sectionsMap.set(section, href);
787 }
788 });
789
790 function setActive(href) {
791 navItems.forEach(item => item.classList.remove('active'));
792
793 navLinks.forEach(link => {
794 if (link.getAttribute('href') === href) {
795 link.closest('.eel-nav-item')?.classList.add('active');
796 }
797 });
798 }
799
800 const observer = new IntersectionObserver(
801 (entries) => {
802 entries.forEach(entry => {
803 if (entry.isIntersecting) {
804 const id = sectionsMap.get(entry.target);
805 if (id) setActive(id);
806 }
807 });
808 },
809 {
810 root: null,
811 rootMargin: '-40% 0px -40% 0px',
812 threshold: 0.1
813 }
814 );
815
816 sectionsMap.forEach((id, section) => {
817 observer.observe(section);
818 });
819
820 });
821
822 });
823
824 // Sticky Navigation single page
825
826 function applyStickyToContainer($container) {
827 if ($container.find('.elementor-widget-eel-single-nav').length === 0) {
828 return;
829 }
830
831 $container.addClass('eel-single-nav-sticky-enabled');
832 }
833
834 /* ===== Frontend ===== */
835 $(window).on('elementor/frontend/init', function () {
836 elementorFrontend.hooks.addAction(
837 'frontend/element_ready/container',
838 function ($scope) {
839 applyStickyToContainer($scope);
840 }
841 );
842 });
843
844 /* ===== Editor ===== */
845 if (window.elementor && elementor.isEditMode()) {
846 elementor.hooks.addAction('editor:init', function () {
847 elementorFrontend.hooks.addAction(
848 'frontend/element_ready/container',
849 function ($scope) {
850 applyStickyToContainer($scope);
851 }
852 );
853 });
854 }
855
856 // Mobile Menu Sidebar
857 if ($('.sidebar-on-mobile-single-nav').length) {
858 // Sidebar toggle
859 $('.eel-nav-menu-icon').on('click', function(e){
860 e.stopPropagation();
861 $('.sidebar-on-mobile-single-nav').toggleClass('easyel-open');
862 $('body').toggleClass('sidebar-on-mobile-single-nav-active');
863 });
864 // Click outside to close sidebar
865 $(document).on('click', function(){
866 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
867 $('body').removeClass('sidebar-on-mobile-single-nav-active');
868 $('.sidebar-on-mobile-single-nav ul.sub-menu').slideUp(300);
869 $('.sidebar-on-mobile-single-nav .sub-arrow').removeClass('active').attr('aria-expanded', false);
870 });
871
872 $('.sidebar-on-mobile-single-nav, .eel-nav-menu').on('click', 'li:not(.menu-item-has-children) a', function(e){
873 $('.sidebar-on-mobile-single-nav li a, .eel-nav-menu li a').removeClass('eel-active');
874 $(this).addClass('eel-active');
875 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
876 $('body').removeClass('sidebar-on-mobile-single-nav-active');
877 $('body').removeClass('sidebar-on-mobile-active');
878 });
879
880 // Prevent closing when clicking inside sidebar
881 $('.sidebar-on-mobile-single-nav').on('click', function(e){
882 e.stopPropagation();
883 });
884 }
885
886 jQuery(document).ready(function($){
887 var $sidebar = $('.sidebar-on-mobile-mega-nav');
888 var $body = $('body');
889
890 if(!$sidebar.length) return;
891
892 /* ========== Inject submenu icon ========== */
893 $sidebar.find('li.menu-item-has-children').each(function(){
894 if(!$(this).children('.submenu-parent-icon').length){
895 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>';
896 $(this).prepend(svgIcon);
897 }
898 });
899
900 // Open sidebar
901 $(document).on('click', '.eel-mega-menu-icon-mobile', function(e){
902 e.preventDefault();
903 e.stopPropagation();
904 $sidebar.addClass('easyel-open');
905 $body.addClass('sidebar-on-mobile-mega-nav-active');
906 });
907
908 // Close sidebar (icon)
909 $(document).on('click', '.eel-mega-menu-icon-close', function(e){
910 e.preventDefault();
911 e.stopPropagation();
912 $sidebar.removeClass('easyel-open');
913 $body.removeClass('sidebar-on-mobile-mega-nav-active');
914 });
915
916 // Click outside sidebar (overlay)
917 $(document).on('click', function(){
918 $sidebar.removeClass('easyel-open');
919 $body.removeClass('sidebar-on-mobile-mega-nav-active');
920 });
921
922 // Prevent sidebar clicks from closing
923 $sidebar.on('click', function(e){
924 if (!$(e.target).closest('.eel-mega-menu-icon-close').length) {
925 e.stopPropagation();
926 }
927 });
928
929 /* ========== Submenu toggle ========== */
930 $('.submenu-parent-icon').on('click', function(e){
931 e.preventDefault();
932 e.stopPropagation();
933
934 var $li = $(this).closest('li.menu-item-has-children');
935 var $submenu = $li.children('ul.sub-menu');
936
937 // close other submenus
938 $li.siblings('li.menu-item-has-children')
939 .removeClass('eel-sub-open')
940 .children('ul.sub-menu').slideUp(300);
941
942 $li.siblings('li.menu-item-has-children')
943 .children('.submenu-parent-icon').removeClass('active');
944
945 // toggle current
946 $submenu.slideToggle(300);
947 $li.toggleClass('eel-sub-open');
948 $(this).toggleClass('active');
949 });
950 });
951
952 })(jQuery);
953
954 (function ($) {
955 function eelMegaNavigationInit() {
956 $('.elementor-widget-eel-mega-navigation')
957 .parent()
958 .addClass('parant-eel-mega-static');
959 }
960 // Frontend
961 $(window).on('load', function () {
962 eelMegaNavigationInit();
963 });
964
965 // Elementor Editor
966 $(window).on('elementor/frontend/init', function () {
967 if (elementorFrontend.isEditMode()) {
968 eelMegaNavigationInit();
969 }
970 elementorFrontend.hooks.addAction(
971 'frontend/element_ready/eel-mega-navigation.default',
972 eelMegaNavigationInit
973 );
974 });
975
976 })(jQuery);
977
978
979
980 (function($){
981
982 let eelObserverAttached = false;
983
984 function updateMegaMenuActive() {
985 const $mega = $('.easyel--elementor-template-mega-menu');
986 if (!$mega.length) return;
987
988 const $parent = $mega.parent();
989
990 if ($mega.hasClass('easyel-mega--current')) {
991 $parent.addClass('easyel-mega--current-active menu-item-has-children');
992 } else {
993 $parent.removeClass('easyel-mega--current-active menu-item-has-children');
994 }
995 }
996
997 function updateElementorPositions() {
998 if ($('.easyel-mega--current-active').length) {
999 $('header .elementor-element').css('position', 'static');
1000 $('.easyel-mega--current-active .elementor-element').css('position', '');
1001 } else {
1002 $('header .elementor-element').css('position', '');
1003 }
1004 }
1005
1006 function attachObserverOnce() {
1007 if (eelObserverAttached) return;
1008 eelObserverAttached = true;
1009
1010 const observer = new MutationObserver(() => {
1011 updateMegaMenuActive();
1012 updateElementorPositions();
1013 });
1014
1015 observer.observe(document.body, {
1016 attributes: true,
1017 subtree: true,
1018 attributeFilter: ['class']
1019 });
1020 }
1021
1022 function initMegaMenuJS(scope) {
1023 if (!scope.find('.elementor-widget-eel-navigation-menu').length) return;
1024
1025 updateMegaMenuActive();
1026 updateElementorPositions();
1027 attachObserverOnce();
1028 }
1029
1030 // Frontend
1031 $(window).on('load', function(){
1032 initMegaMenuJS($(document.body));
1033 });
1034
1035 // Elementor Editor
1036 $(window).on('elementor/frontend/init', function () {
1037 elementorFrontend.hooks.addAction(
1038 'frontend/element_ready/eel-navigation-menu.default',
1039 function($scope){
1040 initMegaMenuJS($scope);
1041 }
1042 );
1043 });
1044
1045 })(jQuery);
1046