PageSourceSearch

https://ein-prat.com/wp-content/plugins/elementor-news-ticker-main/assets/js/news-ticker.js?ver=1.0.1

js ein-prat.com collected 2026-10-10 00:53:58 UTC 20,424 bytes, 554 lines download raw bytes

1(function($) {
2    'use strict';
3
4    var NewsTicker = {
5        init: function() {
6            $(window).on('elementor/frontend/init', function() {
7                elementorFrontend.hooks.addAction('frontend/element_ready/news_ticker.default', NewsTicker.initWidget);
8            });
9            
10            // Initialize on document ready for non-Elementor or initial load
11            $(document).ready(function() {
12                if (!window.elementorFrontend || !window.elementorFrontend.isEditMode()) {
13                    $('.news-ticker-wrapper').each(function() {
14                        NewsTicker.initWidget($(this).closest('.elementor-widget-news_ticker'));
15                    });
16                }
17            });
18        },
19
20        initWidget: function($scope) {
21            var $ticker = $scope.find('.news-ticker-wrapper');
22
23            if (!$ticker.length) {
24                return;
25            }
26
27            // Clean up any existing animations first
28            NewsTicker.destroy($ticker);
29
30            var animationType = $ticker.data('animation');
31            var speed = $ticker.data('speed') || 50;
32            var duration = $ticker.data('duration') || 3000;
33            var pauseOnHover = $ticker.data('pause') === true || $ticker.data('pause') === 'true';
34            var direction = $ticker.data('direction') || 'ltr';
35
36            switch(animationType) {
37                case 'scroll':
38                    NewsTicker.initScroll($ticker, speed, pauseOnHover);
39                    break;
40                case 'slide':
41                    NewsTicker.initSlide($ticker, duration, pauseOnHover, direction);
42                    break;
43                case 'fade':
44                    NewsTicker.initFade($ticker, duration, pauseOnHover);
45                    break;
46            }
47
48            // Initialize modal functionality
49            NewsTicker.initModal($ticker);
50        },
51
52        initModal: function($ticker) {
53            var $modal = $ticker.find('.news-ticker-modal');
54            var $modalImage = $modal.find('.news-ticker-modal-image');
55            var $modalClose = $modal.find('.news-ticker-modal-close');
56            var $modalOverlay = $modal.find('.news-ticker-modal-overlay');
57
58            // Remove any existing modal handlers first
59            $ticker.off('click.tickermodal');
60            $modalClose.off('click.tickermodal');
61            $modalOverlay.off('click.tickermodal');
62            $(document).off('keyup.tickermodal');
63
64            // Handle clicks on items with modal images using event delegation
65            $ticker.on('click.tickermodal', '.news-ticker-item.has-modal-image', function(e) {
66                e.preventDefault();
67                e.stopPropagation();
68
69                var $item = $(this);
70                var imageUrl = $item.data('modal-image');
71
72                console.log('Modal item clicked, image URL:', imageUrl);
73
74                if (imageUrl) {
75                    $modalImage.attr('src', imageUrl);
76                    $modal.css('display', 'flex').addClass('active');
77                    $('body').css('overflow', 'hidden');
78                    console.log('Modal opened');
79                }
80            });
81
82            // Close modal on close button click
83            $modalClose.on('click.tickermodal', function(e) {
84                e.preventDefault();
85                e.stopPropagation();
86                $modal.removeClass('active');
87                setTimeout(function() {
88                    $modal.css('display', 'none');
89                }, 300); // Match transition duration
90                $('body').css('overflow', '');
91            });
92
93            // Close modal on overlay click
94            $modalOverlay.on('click.tickermodal', function(e) {
95                e.preventDefault();
96                e.stopPropagation();
97                $modal.removeClass('active');
98                setTimeout(function() {
99                    $modal.css('display', 'none');
100                }, 300);
101                $('body').css('overflow', '');
102            });
103
104            // Close modal on ESC key
105            $(document).on('keyup.tickermodal', function(e) {
106                if (e.keyCode === 27 && $modal.hasClass('active')) {
107                    $modal.removeClass('active');
108                    setTimeout(function() {
109                        $modal.css('display', 'none');
110                    }, 300);
111                    $('body').css('overflow', '');
112                }
113            });
114
115            // Log modal setup
116            var modalItemsCount = $ticker.find('.news-ticker-item.has-modal-image').length;
117            console.log('Modal initialized. Items with modal images:', modalItemsCount);
118        },
119
120        initScroll: function($ticker, speed, pauseOnHover) {
121            var $wrapper = $ticker.find('.news-ticker-content-wrapper');
122            var $track = $wrapper.find('.news-ticker-content').first();
123
124            console.log('Init scroll - found track:', $track.length);
125
126            if (!$track.length) return;
127
128            var track = $track[0];
129            var wrapper = $wrapper[0];
130            var direction = $ticker.data('direction') || 'ltr';
131            var isRTL = direction === 'rtl';
132
133            // Check if mobile device
134            var isMobile = window.innerWidth <= 768;
135
136            // Calculate pixels per second - increase speed on mobile for better UX
137            // Mobile screens are smaller so content needs to move faster relative to viewport
138            var baseSpeed = speed * 2;
139            var pixelsPerSecond = isMobile ? baseSpeed * 1.5 : baseSpeed;
140
141            var animationId;
142            var currentPosition = 0;
143            var contentWidth = 0;
144            var isPaused = false;
145            var isAnimating = false;
146            var lastTime = 0;
147
148            // Touch/drag variables
149            var isDragging = false;
150            var touchStartX = 0;
151            var touchStartPosition = 0;
152            var lastTouchX = 0;
153            var dragVelocity = 0;
154            var lastDragTime = 0;
155
156            function initInfiniteScroll() {
157                // Remove any existing clones
158                $wrapper.find('.news-ticker-content').not(':first').remove();
159
160                // Get dimensions
161                var wrapperWidth = wrapper.offsetWidth;
162                contentWidth = track.offsetWidth;
163
164                if (contentWidth === 0) {
165                    console.log('Content width is 0, retrying...');
166                    setTimeout(initInfiniteScroll, 200);
167                    return;
168                }
169
170                // Calculate how many clones we need
171                var numClones = Math.ceil((wrapperWidth * 2) / contentWidth) + 1;
172                numClones = Math.max(numClones, 2);
173
174                console.log('Creating clones:', {
175                    wrapperWidth: wrapperWidth,
176                    contentWidth: contentWidth,
177                    numClones: numClones,
178                    pixelsPerSecond: pixelsPerSecond
179                });
180
181                // Create clones
182                for (var i = 0; i < numClones; i++) {
183                    var $clone = $track.clone();
184                    $clone.removeClass('news-ticker-content-original');
185                    $wrapper.append($clone);
186                }
187
188                // Set initial position
189                currentPosition = 0;
190                track.style.transform = 'translateX(' + currentPosition + 'px)';
191
192                console.log('Infinite scroll initialized');
193                startAnimation();
194            }
195
196            function startAnimation() {
197                if (isAnimating) return;
198                isAnimating = true;
199                lastTime = performance.now();
200
201                function animate(currentTime) {
202                    if (!isAnimating) return;
203
204                    if (isPaused) {
205                        lastTime = currentTime;
206                        animationId = requestAnimationFrame(animate);
207                        return;
208                    }
209
210                    var deltaTime = (currentTime - lastTime) / 1000;
211                    lastTime = currentTime;
212
213                    // Move based on direction
214                    if (isRTL) {
215                        currentPosition += pixelsPerSecond * deltaTime;
216                        if (currentPosition >= contentWidth) {
217                            currentPosition = currentPosition - contentWidth;
218                        }
219                    } else {
220                        currentPosition -= pixelsPerSecond * deltaTime;
221                        if (currentPosition <= -contentWidth) {
222                            currentPosition = currentPosition + contentWidth;
223                        }
224                    }
225
226                    // Apply transform to all content elements
227                    $wrapper.find('.news-ticker-content').each(function() {
228                        this.style.transform = 'translateX(' + currentPosition + 'px)';
229                    });
230
231                    animationId = requestAnimationFrame(animate);
232                }
233
234                animationId = requestAnimationFrame(animate);
235            }
236
237            function stopAnimation() {
238                isAnimating = false;
239                if (animationId) {
240                    cancelAnimationFrame(animationId);
241                    animationId = null;
242                }
243            }
244
245            // Pause on hover
246            if (pauseOnHover) {
247                $ticker.on('mouseenter', function() {
248                    isPaused = true;
249                });
250
251                $ticker.on('mouseleave', function() {
252                    isPaused = false;
253                });
254            }
255
256            // Touch drag functionality for mobile
257            function handleTouchStart(e) {
258                if (e.touches.length !== 1) return;
259
260                isDragging = true;
261                isPaused = true;
262                touchStartX = e.touches[0].clientX;
263                touchStartPosition = currentPosition;
264                lastTouchX = touchStartX;
265                lastDragTime = performance.now();
266                dragVelocity = 0;
267
268                // Prevent default to avoid page scroll while dragging
269                e.preventDefault();
270            }
271
272            function handleTouchMove(e) {
273                if (!isDragging || e.touches.length !== 1) return;
274
275                var touchX = e.touches[0].clientX;
276                var deltaX = touchX - touchStartX;
277                var now = performance.now();
278                var timeDelta = now - lastDragTime;
279
280                // Calculate velocity for momentum
281                if (timeDelta > 0) {
282                    dragVelocity = (touchX - lastTouchX) / timeDelta * 1000;
283                }
284
285                lastTouchX = touchX;
286                lastDragTime = now;
287
288                // Update position based on drag
289                var newPosition = touchStartPosition + deltaX;
290
291                // Keep position within bounds (wrap around)
292                if (newPosition >= contentWidth) {
293                    newPosition = newPosition - contentWidth;
294                } else if (newPosition <= -contentWidth) {
295                    newPosition = newPosition + contentWidth;
296                }
297
298                currentPosition = newPosition;
299
300                // Apply transform to all content elements
301                $wrapper.find('.news-ticker-content').each(function() {
302                    this.style.transform = 'translateX(' + currentPosition + 'px)';
303                });
304
305                e.preventDefault();
306            }
307
308            function handleTouchEnd(e) {
309                if (!isDragging) return;
310
311                isDragging = false;
312
313                // Apply momentum based on drag velocity
314                var momentum = dragVelocity * 0.1;
315                var targetPosition = currentPosition + momentum;
316
317                // Animate momentum smoothly
318                var momentumDuration = Math.abs(momentum) * 2;
319                var startTime = performance.now();
320                var startPosition = currentPosition;
321
322                function animateMomentum(now) {
323                    var elapsed = now - startTime;
324                    var progress = Math.min(elapsed / Math.max(momentumDuration, 100), 1);
325
326                    // Ease out
327                    var easeProgress = 1 - Math.pow(1 - progress, 3);
328
329                    currentPosition = startPosition + (targetPosition - startPosition) * easeProgress;
330
331                    // Wrap position
332                    if (currentPosition >= contentWidth) {
333                        currentPosition = currentPosition - contentWidth;
334                    } else if (currentPosition <= -contentWidth) {
335                        currentPosition = currentPosition + contentWidth;
336                    }
337
338                    $wrapper.find('.news-ticker-content').each(function() {
339                        this.style.transform = 'translateX(' + currentPosition + 'px)';
340                    });
341
342                    if (progress < 1) {
343                        requestAnimationFrame(animateMomentum);
344                    } else {
345                        // Resume auto-scroll after momentum ends
346                        setTimeout(function() {
347                            isPaused = false;
348                        }, 500);
349                    }
350                }
351
352                if (Math.abs(momentum) > 10) {
353                    requestAnimationFrame(animateMomentum);
354                } else {
355                    // Resume auto-scroll after short delay
356                    setTimeout(function() {
357                        isPaused = false;
358                    }, 500);
359                }
360            }
361
362            // Add touch event listeners
363            wrapper.addEventListener('touchstart', handleTouchStart, { passive: false });
364            wrapper.addEventListener('touchmove', handleTouchMove, { passive: false });
365            wrapper.addEventListener('touchend', handleTouchEnd, { passive: true });
366            wrapper.addEventListener('touchcancel', handleTouchEnd, { passive: true });
367
368            // Store cleanup functions
369            $ticker.data('touch-cleanup', function() {
370                wrapper.removeEventListener('touchstart', handleTouchStart);
371                wrapper.removeEventListener('touchmove', handleTouchMove);
372                wrapper.removeEventListener('touchend', handleTouchEnd);
373                wrapper.removeEventListener('touchcancel', handleTouchEnd);
374            });
375
376            // Handle window resize - recalculate speed for mobile/desktop switch
377            var resizeTimer;
378            $(window).on('resize.tickeranimation', function() {
379                clearTimeout(resizeTimer);
380                resizeTimer = setTimeout(function() {
381                    // Recalculate mobile state and speed
382                    isMobile = window.innerWidth <= 768;
383                    pixelsPerSecond = isMobile ? baseSpeed * 1.5 : baseSpeed;
384
385                    stopAnimation();
386                    initInfiniteScroll();
387                }, 250);
388            });
389
390            // Store stop function for cleanup
391            $ticker.data('stop-animation', stopAnimation);
392
393            // Initialize
394            initInfiniteScroll();
395        },
396
397        initSlide: function($ticker, duration, pauseOnHover, direction) {
398            var $items = $ticker.find('.news-ticker-item');
399            var currentIndex = 0;
400            var intervalId;
401            var isPaused = false;
402            var isAnimating = false;
403
404            if ($items.length === 0) {
405                return;
406            }
407
408            // Show first item
409            $items.eq(0).addClass('active');
410
411            function showNextItem() {
412                if (isPaused || isAnimating) {
413                    return;
414                }
415
416                isAnimating = true;
417                
418                var $current = $items.eq(currentIndex);
419                var nextIndex = (currentIndex + 1) % $items.length;
420                var $next = $items.eq(nextIndex);
421
422                // Start exit animation for current
423                $current.removeClass('active');
424                
425                // After a short delay, show next item
426                setTimeout(function() {
427                    $next.addClass('active');
428                    currentIndex = nextIndex;
429                    isAnimating = false;
430                }, 100);
431            }
432
433            // Start the slide animation - infinite loop
434            intervalId = setInterval(showNextItem, duration);
435
436            // Pause on hover
437            if (pauseOnHover) {
438                $ticker.on('mouseenter', function() {
439                    isPaused = true;
440                });
441                
442                $ticker.on('mouseleave', function() {
443                    isPaused = false;
444                });
445            }
446
447            // Store interval ID for cleanup
448            $ticker.data('ticker-interval', intervalId);
449        },
450
451        initFade: function($ticker, duration, pauseOnHover) {
452            var $items = $ticker.find('.news-ticker-item');
453            var currentIndex = 0;
454            var intervalId;
455            var isPaused = false;
456            var isAnimating = false;
457
458            if ($items.length === 0) {
459                return;
460            }
461
462            // Show first item
463            $items.eq(0).addClass('active');
464
465            function showNextItem() {
466                if (isPaused || isAnimating) {
467                    return;
468                }
469
470                isAnimating = true;
471                
472                var $current = $items.eq(currentIndex);
473                var nextIndex = (currentIndex + 1) % $items.length;
474                var $next = $items.eq(nextIndex);
475
476                // Fade out current
477                $current.removeClass('active');
478                
479                // After fade transition, show next item
480                setTimeout(function() {
481                    $next.addClass('active');
482                    currentIndex = nextIndex;
483                    isAnimating = false;
484                }, 500); // Match CSS transition duration
485            }
486
487            // Start the fade animation - infinite loop
488            intervalId = setInterval(showNextItem, duration);
489
490            // Pause on hover
491            if (pauseOnHover) {
492                $ticker.on('mouseenter', function() {
493                    isPaused = true;
494                });
495                
496                $ticker.on('mouseleave', function() {
497                    isPaused = false;
498                });
499            }
500
501            // Store interval ID for cleanup
502            $ticker.data('ticker-interval', intervalId);
503        },
504
505        // Cleanup function
506        destroy: function($ticker) {
507            var intervalId = $ticker.data('ticker-interval');
508            if (intervalId) {
509                clearInterval(intervalId);
510            }
511            var resetInterval = $ticker.data('reset-interval');
512            if (resetInterval) {
513                clearInterval(resetInterval);
514            }
515
516            // Stop requestAnimationFrame animation
517            var stopAnimation = $ticker.data('stop-animation');
518            if (stopAnimation && typeof stopAnimation === 'function') {
519                stopAnimation();
520            }
521
522            // Clean up touch event listeners
523            var touchCleanup = $ticker.data('touch-cleanup');
524            if (touchCleanup && typeof touchCleanup === 'function') {
525                touchCleanup();
526            }
527
528            // Remove cloned tracks
529            var $wrapper = $ticker.find('.news-ticker-content-wrapper');
530            $wrapper.find('.news-ticker-content').not(':first').remove();
531
532            // Remove animation styles
533            $wrapper.find('.news-ticker-content').css({
534                'animation': 'none',
535                'transform': '',
536                'animation-play-state': '',
537                'animation-duration': ''
538            });
539
540            // Only remove animation-related handlers, not modal handlers
541            $ticker.off('mouseenter mouseleave');
542            $(window).off('resize.tickeranimation');
543        }
544    };
545
546    // Initialize
547    NewsTicker.init();
548
549    // Cleanup on widget removal
550    $(document).on('remove', '.news-ticker-wrapper', function() {
551        NewsTicker.destroy($(this));
552    });
553
554})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.