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

1,033 lines 35.3 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
724
725
726 // Single Page Navigation
727 document.addEventListener('DOMContentLoaded', function () {
728 const navWrappers = document.querySelectorAll('.eel-single-nav-list');
729 if (!navWrappers.length) return;
730
731 navWrappers.forEach(function (wrapper) {
732
733 const navLinks = wrapper.querySelectorAll('.eel-nav-item a');
734 const navItems = wrapper.querySelectorAll('.eel-nav-item');
735
736 if (!navLinks.length) return;
737
738 /* ========= CLICK → SMOOTH SCROLL ========= */
739 wrapper.addEventListener('click', function (e) {
740
741 const link = e.target.closest('.eel-nav-item a');
742 if (!link || !wrapper.contains(link)) return;
743
744 const href = link.getAttribute('href');
745
746 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
747 return;
748 }
749
750 const target = document.querySelector(href);
751 if (!target) return;
752
753 e.preventDefault();
754
755 target.scrollIntoView({
756 behavior: 'smooth',
757 block: 'start'
758 });
759 });
760
761 /* ========= SCROLL → ACTIVE CHANGE ========= */
762 const sectionsMap = new Map();
763
764 navLinks.forEach(link => {
765 const href = link.getAttribute('href');
766
767 if (!href || href === '#' || !href.startsWith('#') || href.length === 1) {
768 return;
769 }
770
771 const section = document.querySelector(href);
772 if (section) {
773 sectionsMap.set(section, href);
774 }
775 });
776
777 function setActive(href) {
778 navItems.forEach(item => item.classList.remove('active'));
779
780 navLinks.forEach(link => {
781 if (link.getAttribute('href') === href) {
782 link.closest('.eel-nav-item')?.classList.add('active');
783 }
784 });
785 }
786
787 const observer = new IntersectionObserver(
788 (entries) => {
789 entries.forEach(entry => {
790 if (entry.isIntersecting) {
791 const id = sectionsMap.get(entry.target);
792 if (id) setActive(id);
793 }
794 });
795 },
796 {
797 root: null,
798 rootMargin: '-40% 0px -40% 0px',
799 threshold: 0.1
800 }
801 );
802
803 sectionsMap.forEach((id, section) => {
804 observer.observe(section);
805 });
806
807 });
808
809 });
810
811 // Sticky Navigation single page
812
813 function applyStickyToContainer($container) {
814 if ($container.find('.elementor-widget-eel-single-nav').length === 0) {
815 return;
816 }
817
818 $container.addClass('eel-single-nav-sticky-enabled');
819 }
820
821 /* ===== Frontend ===== */
822 $(window).on('elementor/frontend/init', function () {
823 elementorFrontend.hooks.addAction(
824 'frontend/element_ready/container',
825 function ($scope) {
826 applyStickyToContainer($scope);
827 }
828 );
829 });
830
831 /* ===== Editor ===== */
832 if (window.elementor && elementor.isEditMode()) {
833 elementor.hooks.addAction('editor:init', function () {
834 elementorFrontend.hooks.addAction(
835 'frontend/element_ready/container',
836 function ($scope) {
837 applyStickyToContainer($scope);
838 }
839 );
840 });
841 }
842
843 // Mobile Menu Sidebar
844 if ($('.sidebar-on-mobile-single-nav').length) {
845 // Sidebar toggle
846 $('.eel-nav-menu-icon').on('click', function(e){
847 e.stopPropagation();
848 $('.sidebar-on-mobile-single-nav').toggleClass('easyel-open');
849 $('body').toggleClass('sidebar-on-mobile-single-nav-active');
850 });
851 // Click outside to close sidebar
852 $(document).on('click', function(){
853 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
854 $('body').removeClass('sidebar-on-mobile-single-nav-active');
855 $('.sidebar-on-mobile-single-nav ul.sub-menu').slideUp(300);
856 $('.sidebar-on-mobile-single-nav .sub-arrow').removeClass('active').attr('aria-expanded', false);
857 });
858
859 $('.sidebar-on-mobile-single-nav, .eel-nav-menu').on('click', 'li:not(.menu-item-has-children) a', function(e){
860 $('.sidebar-on-mobile-single-nav li a, .eel-nav-menu li a').removeClass('eel-active');
861 $(this).addClass('eel-active');
862 $('.sidebar-on-mobile-single-nav').removeClass('easyel-open');
863 $('body').removeClass('sidebar-on-mobile-single-nav-active');
864 $('body').removeClass('sidebar-on-mobile-active');
865 });
866
867 // Prevent closing when clicking inside sidebar
868 $('.sidebar-on-mobile-single-nav').on('click', function(e){
869 e.stopPropagation();
870 });
871 }
872
873 jQuery(document).ready(function($){
874 var $sidebar = $('.sidebar-on-mobile-mega-nav');
875 var $body = $('body');
876
877 if(!$sidebar.length) return;
878
879 /* ========== Inject submenu icon ========== */
880 $sidebar.find('li.menu-item-has-children').each(function(){
881 if(!$(this).children('.submenu-parent-icon').length){
882 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>';
883 $(this).prepend(svgIcon);
884 }
885 });
886
887 // Open sidebar
888 $(document).on('click', '.eel-mega-menu-icon-mobile', function(e){
889 e.preventDefault();
890 e.stopPropagation();
891 $sidebar.addClass('easyel-open');
892 $body.addClass('sidebar-on-mobile-mega-nav-active');
893 });
894
895 // Close sidebar (icon)
896 $(document).on('click', '.eel-mega-menu-icon-close', function(e){
897 e.preventDefault();
898 e.stopPropagation();
899 $sidebar.removeClass('easyel-open');
900 $body.removeClass('sidebar-on-mobile-mega-nav-active');
901 });
902
903 // Click outside sidebar (overlay)
904 $(document).on('click', function(){
905 $sidebar.removeClass('easyel-open');
906 $body.removeClass('sidebar-on-mobile-mega-nav-active');
907 });
908
909 // Prevent sidebar clicks from closing
910 $sidebar.on('click', function(e){
911 if (!$(e.target).closest('.eel-mega-menu-icon-close').length) {
912 e.stopPropagation();
913 }
914 });
915
916 /* ========== Submenu toggle ========== */
917 $('.submenu-parent-icon').on('click', function(e){
918 e.preventDefault();
919 e.stopPropagation();
920
921 var $li = $(this).closest('li.menu-item-has-children');
922 var $submenu = $li.children('ul.sub-menu');
923
924 // close other submenus
925 $li.siblings('li.menu-item-has-children')
926 .removeClass('eel-sub-open')
927 .children('ul.sub-menu').slideUp(300);
928
929 $li.siblings('li.menu-item-has-children')
930 .children('.submenu-parent-icon').removeClass('active');
931
932 // toggle current
933 $submenu.slideToggle(300);
934 $li.toggleClass('eel-sub-open');
935 $(this).toggleClass('active');
936 });
937 });
938
939 })(jQuery);
940
941 (function ($) {
942 function eelMegaNavigationInit() {
943 $('.elementor-widget-eel-mega-navigation')
944 .parent()
945 .addClass('parant-eel-mega-static');
946 }
947 // Frontend
948 $(window).on('load', function () {
949 eelMegaNavigationInit();
950 });
951
952 // Elementor Editor
953 $(window).on('elementor/frontend/init', function () {
954 if (elementorFrontend.isEditMode()) {
955 eelMegaNavigationInit();
956 }
957 elementorFrontend.hooks.addAction(
958 'frontend/element_ready/eel-mega-navigation.default',
959 eelMegaNavigationInit
960 );
961 });
962
963 })(jQuery);
964
965
966
967 (function($){
968
969 let eelObserverAttached = false;
970
971 function updateMegaMenuActive() {
972 const $mega = $('.easyel--elementor-template-mega-menu');
973 if (!$mega.length) return;
974
975 const $parent = $mega.parent();
976
977 if ($mega.hasClass('easyel-mega--current')) {
978 $parent.addClass('easyel-mega--current-active menu-item-has-children');
979 } else {
980 $parent.removeClass('easyel-mega--current-active menu-item-has-children');
981 }
982 }
983
984 function updateElementorPositions() {
985 if ($('.easyel-mega--current-active').length) {
986 $('header .elementor-element').css('position', 'static');
987 $('.easyel-mega--current-active .elementor-element').css('position', '');
988 } else {
989 $('header .elementor-element').css('position', '');
990 }
991 }
992
993 function attachObserverOnce() {
994 if (eelObserverAttached) return;
995 eelObserverAttached = true;
996
997 const observer = new MutationObserver(() => {
998 updateMegaMenuActive();
999 updateElementorPositions();
1000 });
1001
1002 observer.observe(document.body, {
1003 attributes: true,
1004 subtree: true,
1005 attributeFilter: ['class']
1006 });
1007 }
1008
1009 function initMegaMenuJS(scope) {
1010 if (!scope.find('.elementor-widget-eel-navigation-menu').length) return;
1011
1012 updateMegaMenuActive();
1013 updateElementorPositions();
1014 attachObserverOnce();
1015 }
1016
1017 // Frontend
1018 $(window).on('load', function(){
1019 initMegaMenuJS($(document.body));
1020 });
1021
1022 // Elementor Editor
1023 $(window).on('elementor/frontend/init', function () {
1024 elementorFrontend.hooks.addAction(
1025 'frontend/element_ready/eel-navigation-menu.default',
1026 function($scope){
1027 initMegaMenuJS($scope);
1028 }
1029 );
1030 });
1031
1032 })(jQuery);
1033