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

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