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

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