PluginProbe
Easy Elements for Elementor – Addons & Website Templates / 1.2.7
Easy Elements for Elementor – Addons & Website Templates v1.2.7
1.5.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.6 1.4.7 1.4.8 1.4.5 1.4.4 1.4.3 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 All 47 releases
easy-elements / assets / js / custom.js

custom.js in Easy Elements for Elementor – Addons & Website Templates 1.2.7, at assets/js/custom.js

628 lines 22.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
39 var effectOptions = {};
40
41 if (effect === 'cube') {
42 effectOptions = {
43 cubeEffect: {
44 shadow: cubeShadow,
45 slideShadows: cubeShadow,
46 shadowOffset: 20,
47 shadowScale: 0.94,
48 }
49 };
50 } else if (effect === 'coverflow') {
51 effectOptions = {
52 coverflowEffect: {
53 rotate: coverflowRotate,
54 stretch: coverflowStretch,
55 depth: 100,
56 modifier: 1,
57 slideShadows: true,
58 }
59 };
60 } else if (effect === 'flip') {
61 effectOptions = {
62 flipEffect: {
63 slideShadows: true,
64 limitRotation: true,
65 }
66 };
67 } else if (effect === 'cards') {
68 effectOptions = {
69 cardsEffect: {
70 slideShadows: true,
71 rotate: true,
72 perSlideOffset: 8,
73 }
74 };
75 } else if (effect === 'creative') {
76 var creativeStyle = $slider.data('creative-style') || 'default';
77 if (creativeStyle === 'zoom') {
78 effectOptions = {
79 creativeEffect: {
80 limitProgress: true,
81 prev: { scale: 1.1, opacity: 0, translate: [0, 0, 0] },
82 next: { scale: 1.6, opacity: 0, translate: [0, 0, 0] },
83 },
84 };
85 } else {
86 effectOptions = {
87 creativeEffect: {
88 limitProgress: true,
89 prev: { shadow: true, translate: [0, 0, -400] },
90 next: { translate: ['100%', 0, 0] },
91 },
92 };
93 }
94 } else if (effect === 'fade') {
95 effectOptions = {
96 fadeEffect: { crossFade: true }
97 };
98 }
99
100 // Loop handling tuned to avoid double-advance on loop edges
101 var totalSlides = $slider.find('.swiper-slide').length;
102 var isFade = effect === 'fade';
103 var visibleSlides = isFade ? 1 : slidesPerView;
104 var canLoop = totalSlides > visibleSlides;
105 var loopConfig = {};
106 if (loop && (canLoop || isFade)) {
107 loopConfig = {
108 loop: true,
109 loopAdditionalSlides: isFade ? totalSlides : 20,
110 loopedSlides: isFade ? totalSlides : Math.max(Math.ceil(visibleSlides), Math.min(totalSlides, 10))
111 };
112 } else {
113 loopConfig = { loop: false, rewind: !!loop };
114 }
115
116 var swiper = new Swiper($slider[0], {
117 ...loopConfig,
118 speed: speed,
119 effect: effect,
120 normalizeSlideIndex: true,
121 preventInteractionOnTransition: true,
122 simulateTouch: true,
123 touchRatio: 1,
124 grabCursor: true,
125 mousewheel: hasProgressBar ? {
126 enabled: true,
127 sensitivity: 1,
128 thresholdDelta: 50,
129 thresholdTime: 200,
130 releaseOnEdges: true,
131 invert: false,
132 forceToAxis: false,
133 eventsTarget: 'container'
134 } : false,
135 autoplay: autoplay ? {
136 delay: autoplayDelay,
137 disableOnInteraction: isFade ? true : false,
138 } : false,
139 slidesPerView: visibleSlides,
140 spaceBetween: isFade ? 0 : spaceBetween,
141 centeredSlides: isFade ? false : centeredSlides,
142 freeMode: freeMode,
143 pagination: paginationType && $pagination.length ? {
144 el: $pagination[0],
145 clickable: true,
146 type: paginationType,
147 renderBullet: function (index, className) {
148 let num = (index + 1).toString().padStart(2, '0');
149 return `<span class="${className}">${num}</span>`;
150 }
151 } : false,
152
153 // Progress bar for mouse scroll - only when swiper-pagination-progressbar class is present
154 progressbar: hasProgressBar ? {
155 el: '.swiper-progressbar',
156 type: 'progressbar',
157 } : false,
158
159 navigation: (!isFade) && navigation && ($nextButton.length || $prevButton.length) ? {
160 nextEl: $nextButton.length ? $nextButton[0] : null,
161 prevEl: $prevButton.length ? $prevButton[0] : null,
162 } : false,
163 breakpoints: {
164 0: {
165 slidesPerView: isFade ? 1 : slidesPerViewMobile,
166 },
167 768: {
168 slidesPerView: isFade ? 1 : slidesPerViewTablet,
169 },
170 1024: {
171 slidesPerView: isFade ? 1 : slidesPerView,
172 },
173 },
174 ...effectOptions,
175 });
176
177 // Fade: attach custom navigation so Next/Prev work
178 if (isFade && ($nextButton.length || $prevButton.length)) {
179 var isTransitioning = false;
180 swiper.on('transitionStart', function () { isTransitioning = true; });
181 swiper.on('transitionEnd', function () { isTransitioning = false; });
182 if ($nextButton.length) {
183 $nextButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
184 e.preventDefault();
185 e.stopPropagation();
186 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
187 if (isTransitioning || (swiper && swiper.animating)) return;
188 swiper.slideNext();
189 });
190 }
191 if ($prevButton.length) {
192 $prevButton.off('click.easyFadeNav').on('click.easyFadeNav', function (e) {
193 e.preventDefault();
194 e.stopPropagation();
195 if (swiper && swiper.autoplay && swiper.autoplay.stop) { swiper.autoplay.stop(); }
196 if (isTransitioning || (swiper && swiper.animating)) return;
197 swiper.slidePrev();
198 });
199 }
200 }
201
202 // Non-fade: if loop+autoplay, stop autoplay on manual nav to avoid double-advance
203 if (!isFade && loop && autoplay) {
204 if ($nextButton.length) {
205 $nextButton.on('click.easyStopAuto', function () {
206 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
207 swiper.autoplay.stop();
208 }
209 });
210 }
211 if ($prevButton.length) {
212 $prevButton.on('click.easyStopAuto', function () {
213 if (swiper && swiper.autoplay && swiper.autoplay.stop) {
214 swiper.autoplay.stop();
215 }
216 });
217 }
218 }
219 }
220
221 function addWidgetTypeToBody($scope) {
222 var widgetType = $scope.data('widget_type');
223 if (widgetType) {
224 var className = 'easy-eel-has-widget-' + widgetType.replace(/[^a-z0-9_-]/gi, '-').toLowerCase();
225 document.body.classList.add(className);
226 }
227 }
228
229 $(window).on('elementor/frontend/init', function () {
230
231 function checkStickySection() {
232 const stickySection = document.querySelector('.eel-sticky-section');
233 if (stickySection) {
234 document.body.classList.add('sticky-enabled-overlap');
235 } else {
236 document.body.classList.remove('sticky-enabled-overlap');
237 }
238 }
239
240 checkStickySection();
241
242 const observer = new MutationObserver(checkStickySection);
243 observer.observe(document.body, { childList: true, subtree: true });
244 });
245
246
247 function initReveal() {
248 const revealElements = document.querySelectorAll(".eel-img-reveal-wrap, .eel-img-advance-wrap");
249
250 const revealAnimate = (el) => {
251 const target = el.querySelector(".eel-reveal-img-main, .eel-advance-img-main");
252 if(target) target.classList.add("el-reveal-animate");
253 };
254
255 const isEditor = window.elementorFrontend && elementorFrontend.isEditMode && elementorFrontend.isEditMode();
256
257 if(isEditor){
258
259 revealElements.forEach(el => revealAnimate(el));
260 } else {
261
262 const observer = new IntersectionObserver((entries, obs) => {
263 entries.forEach(entry => {
264 if(entry.isIntersecting){
265 revealAnimate(entry.target);
266 obs.unobserve(entry.target);
267 }
268 });
269 }, { threshold: 0.3 });
270
271 revealElements.forEach(el => observer.observe(el));
272 }
273 }
274
275 $(window).on('elementor/frontend/init', function () {
276 elementorFrontend.hooks.addAction('frontend/element_ready/global', initBackPostSlider);
277 elementorFrontend.hooks.addAction('frontend/element_ready/global', addWidgetTypeToBody);
278 elementorFrontend.hooks.addAction('frontend/element_ready/global', initReveal);
279 });
280
281 document.addEventListener('DOMContentLoaded', function () {
282 // Remove motion effects inline styles
283 document.querySelectorAll('[data-settings]').forEach(function (element) {
284 let settings = element.getAttribute('data-settings');
285 if (settings.includes('motion_effects')) {
286 element.removeAttribute('data-settings');
287 }
288 });
289
290 // Remove any animation-related stylesheets
291 document.querySelectorAll('link').forEach(function (link) {
292 if (link.href.includes('animations') || link.href.includes('motion')) {
293 link.parentNode.removeChild(link);
294 }
295 });
296 });
297
298
299 $(window).on("elementor/frontend/init", function ($) {
300 var EasyJarallax = function ($scope, $) {
301 var $wrappers = $scope.hasClass('eele-has-jarallax') ? $scope : $scope.find('.eele-has-jarallax, .eele-inner-jarallax');
302 if (!$wrappers.length) return;
303 $wrappers.each(function () {
304 var $wrapper = $(this);
305 var bg = $wrapper.data('jarallax-bg');
306 var speed = $wrapper.data('jarallax-speed') || 0.5;
307 if (!bg) return;
308 // Check if jarallax div already exists
309 var $jarallaxDiv = $wrapper.find('.jarallax');
310 if ($jarallaxDiv.length === 0) {
311 var jarallaxMarkup = '<div class="jarallax eele-jarallax-bg" data-speed="' + speed + '">\
312 <img class="jarallax-img" src="' + bg + '" alt="">\
313 </div>';
314 $wrapper.append(jarallaxMarkup);
315 $jarallaxDiv = $wrapper.find('.jarallax');
316 }
317
318 // Initialize jarallax
319 $jarallaxDiv.each(function () {
320 jarallax(this, {
321 speed: $(this).data('speed')
322 });
323 });
324 });
325 };
326 elementorFrontend.hooks.addAction("frontend/element_ready/global", EasyJarallax);
327 });
328
329
330
331 jQuery(window).on('elementor/frontend/init', function() {
332
333 elementorFrontend.hooks.addAction('frontend/element_ready/eel-video-popup.default', function($scope, $) {
334
335 const wrapper = $scope.find('.eel-video-popup-wrapper');
336 const overlay = wrapper.find('.eel-video-overlay');
337 // Find video element (try with class first, then without)
338 let videoEl = wrapper.find('video.eel-normal-video');
339 if (!videoEl.length) {
340 videoEl = wrapper.find('video');
341 }
342 // Find iframe element (try with class first, then without)
343 let iframeEl = wrapper.find('iframe.eel-normal-video');
344 if (!iframeEl.length) {
345 iframeEl = wrapper.find('iframe');
346 }
347
348 // Helper function to get YouTube embed URL
349 function getYouTubeEmbedUrl(url) {
350 const regExp = /(?:v=|\/)([0-9A-Za-z_-]{11}).*/;
351 const match = url.match(regExp);
352 if (match && match[1]) {
353 return 'https://www.youtube.com/embed/' + match[1] + '?autoplay=1';
354 }
355 return null;
356 }
357
358 // Helper function to get Vimeo embed URL
359 function getVimeoEmbedUrl(url) {
360 const match = url.match(/(\d+)/);
361 if (match && match[1]) {
362 return 'https://player.vimeo.com/video/' + match[1] + '?autoplay=1';
363 }
364 return null;
365 }
366
367 // Helper function to open lightbox
368 function openLightbox(videoType, videoUrl, popupId, animation) {
369 const lightboxOverlay = $('#' + popupId);
370 const iframeWrapper = lightboxOverlay.find('.eel-video-popup-iframe-wrapper');
371 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
372
373 if (!lightboxOverlay.length) return;
374
375 // Prevent duplicate opening if already active
376 if (lightboxOverlay.hasClass('active')) {
377 return;
378 }
379
380 let embedHtml = '';
381
382 if (videoType === 'youtube') {
383 const embedUrl = getYouTubeEmbedUrl(videoUrl);
384 if (embedUrl) {
385 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
386 }
387 } else if (videoType === 'vimeo') {
388 const embedUrl = getVimeoEmbedUrl(videoUrl);
389 if (embedUrl) {
390 embedHtml = '<iframe src="' + embedUrl + '" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
391 }
392 } else if (videoType === 'self_hosted') {
393 embedHtml = '<video src="' + videoUrl + '" controls autoplay></video>';
394 }
395
396 if (embedHtml) {
397 iframeWrapper.html(embedHtml);
398
399 // Apply animation if set
400 if (animation && animation.trim() !== '') {
401 // Remove any existing animation classes
402 const currentClasses = lightboxContent.attr('class') || '';
403 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
404 if (animationClasses) {
405 lightboxContent.removeClass(animationClasses.join(' '));
406 }
407 // Add new animation classes
408 lightboxContent.addClass('animated ' + animation.trim());
409 } else {
410 // Remove animation classes if no animation
411 const currentClasses = lightboxContent.attr('class') || '';
412 const animationClasses = currentClasses.match(/\banimated\s+\S+/g);
413 if (animationClasses) {
414 lightboxContent.removeClass(animationClasses.join(' '));
415 }
416 }
417
418 lightboxOverlay.addClass('active');
419 $('body').css('overflow', 'hidden');
420 }
421 }
422
423 // Close lightbox handler
424 $(document).on('click', '.eel-video-popup-close', function(e) {
425 e.preventDefault();
426 const lightboxOverlay = $(this).closest('.eel-video-popup-overlay');
427 const lightboxContent = lightboxOverlay.find('.eel-video-popup-content');
428 lightboxOverlay.removeClass('active');
429 lightboxContent.removeClass('animated');
430 lightboxOverlay.find('.eel-video-popup-iframe-wrapper').html('');
431 $('body').css('overflow', '');
432 });
433
434 // Close lightbox on overlay click
435 $(document).on('click', '.eel-video-popup-overlay', function(e) {
436 if ($(e.target).hasClass('eel-video-popup-overlay')) {
437 const lightboxContent = $(this).find('.eel-video-popup-content');
438 $(this).removeClass('active');
439 lightboxContent.removeClass('animated');
440 $(this).find('.eel-video-popup-iframe-wrapper').html('');
441 $('body').css('overflow', '');
442 }
443 });
444
445 // Close lightbox on ESC key
446 $(document).on('keydown', function(e) {
447 if (e.keyCode === 27) { // ESC key
448 $('.eel-video-popup-overlay.active').each(function() {
449 const lightboxContent = $(this).find('.eel-video-popup-content');
450 $(this).removeClass('active');
451 lightboxContent.removeClass('animated');
452 $(this).find('.eel-video-popup-iframe-wrapper').html('');
453 $('body').css('overflow', '');
454 });
455 }
456 });
457
458 if (overlay.length) {
459 // Remove existing handler to prevent duplicate
460 overlay.off('click.eelVideoOverlay');
461 overlay.on('click.eelVideoOverlay', function(e) {
462 e.preventDefault();
463 e.stopPropagation();
464
465 const $overlay = $(this);
466 const useLightbox = $overlay.data('lightbox') === 'yes';
467 const videoType = $overlay.data('video-type');
468 const videoUrl = $overlay.data('video-url');
469 const popupId = $overlay.data('popup-id');
470 const animation = $overlay.data('animation') || '';
471
472 // If lightbox is enabled, open lightbox
473 if (useLightbox && videoType && videoUrl && popupId) {
474 // Check if lightbox is already open to prevent duplicate
475 const lightboxOverlay = $('#' + popupId);
476 if (lightboxOverlay.hasClass('active')) {
477 return;
478 }
479 openLightbox(videoType, videoUrl, popupId, animation);
480 return;
481 }
482
483 // Otherwise, play inline (original behavior)
484 // Self-hosted video play
485 if (videoEl.length) {
486 const video = videoEl.get(0);
487
488 // Function to play video
489 const playVideo = function() {
490 const playPromise = video.play();
491 if (playPromise !== undefined) {
492 playPromise.catch(function(error) {
493 console.log('Video play failed:', error);
494 // If play fails due to autoplay policy, try with muted
495 if (error.name === 'NotAllowedError' && !video.muted) {
496 video.muted = true;
497 video.play().then(function() {
498 // Unmute after play starts (if user wants sound)
499 setTimeout(function() {
500 video.muted = false;
501 }, 100);
502 }).catch(function(err) {
503 console.log('Video play with mute also failed:', err);
504 });
505 }
506 });
507 }
508 };
509
510 // Always try to load and play
511 if (video.readyState >= 2) {
512 // Video is already loaded, play immediately
513 playVideo();
514 } else {
515 // Video not loaded, load it first then play
516 video.load();
517 // Wait for video to be ready to play
518 const tryPlay = function() {
519 if (video.readyState >= 2) {
520 playVideo();
521 } else {
522 video.addEventListener('canplay', playVideo, { once: true });
523 video.addEventListener('loadeddata', playVideo, { once: true });
524 }
525 };
526 tryPlay();
527 }
528 }
529
530 // YouTube / Vimeo iframe autoplay
531 if (iframeEl.length) {
532 let src = iframeEl.attr('src');
533 if (src) {
534 // Check if it's YouTube or Vimeo
535 const isYouTube = src.indexOf('youtube.com') !== -1 || src.indexOf('youtu.be') !== -1;
536 const isVimeo = src.indexOf('vimeo.com') !== -1;
537
538 if (isYouTube || isVimeo) {
539 try {
540 // Use URL object for proper parsing
541 const url = new URL(src);
542
543 if (isYouTube) {
544 // YouTube: add autoplay, preserve original mute setting
545 url.searchParams.set('autoplay', '1');
546 // Only set mute=1 if it was already in the URL (preserve original setting)
547 // If mute was not in original URL, don't add it
548 if (!url.searchParams.has('mute')) {
549 // Don't add mute if it wasn't there originally
550 } else {
551 // Keep the original mute value
552 }
553 // Reload iframe with new src
554 iframeEl.attr('src', url.toString());
555 } else if (isVimeo) {
556 // Vimeo: add autoplay (Vimeo doesn't need mute for autoplay)
557 url.searchParams.set('autoplay', '1');
558 // Reload iframe with new src
559 iframeEl.attr('src', url.toString());
560 }
561 } catch (e) {
562 // Fallback for browsers that don't support URL constructor
563 // Remove existing autoplay parameter if present
564 src = src.replace(/[?&]autoplay=[^&]*/g, '');
565
566 if (isYouTube) {
567 // Check if mute parameter exists in original URL
568 const hasMute = /[?&]mute=/.test(src);
569 // Add autoplay=1
570 const separator = src.indexOf('?') === -1 ? '?' : '&';
571 src += separator + 'autoplay=1';
572 // Only add mute if it was already there (preserve original setting)
573 // Don't add mute if it wasn't in original URL
574 } else if (isVimeo) {
575 // Vimeo: just add autoplay=1
576 const separator = src.indexOf('?') === -1 ? '?' : '&';
577 src += separator + 'autoplay=1';
578 }
579
580 // Update src without clearing first
581 iframeEl.attr('src', src);
582 }
583 }
584 }
585 }
586
587 // Remove overlay after a small delay to ensure video starts
588 setTimeout(function() {
589 overlay.fadeOut(300, function() {
590 $(this).remove();
591 });
592 }, 200);
593 });
594 }
595
596 // Handle popup button clicks (for display_type = 'popup')
597 const popupBtn = wrapper.find('.entro-all-video-popup');
598 if (popupBtn.length) {
599 // Remove existing handler to prevent duplicate
600 popupBtn.off('click.eelVideoPopup');
601 popupBtn.on('click.eelVideoPopup', function(e) {
602 e.preventDefault();
603 e.stopPropagation();
604 const $btn = $(this);
605 const videoType = $btn.data('video-type');
606 const videoUrl = $btn.data('video-src');
607 const popupId = $btn.data('popup-id');
608 const lightboxOverlay = $('#' + popupId);
609 const animation = lightboxOverlay.data('animation') || '';
610
611 if (videoType && videoUrl && popupId) {
612 // Check if lightbox is already open to prevent duplicate
613 if (lightboxOverlay.hasClass('active')) {
614 return;
615 }
616 openLightbox(videoType, videoUrl, popupId, animation);
617 }
618 });
619 }
620 });
621
622 });
623
624 })(jQuery);
625
626
627
628