| 1 |
document.addEventListener( 'DOMContentLoaded', function () { |
| 2 |
// news-ticker-slide and fade-------------------------------- |
| 3 |
const sliders = document.querySelectorAll( '.sps-news-ticker-slider' ); |
| 4 |
|
| 5 |
sliders?.forEach( ( slider ) => { |
| 6 |
const options = JSON.parse( |
| 7 |
slider.getAttribute( 'data-swiper-options' ) || '{}' |
| 8 |
); |
| 9 |
const parentContainer = slider.closest( '.sp-smart-post-swiper' ); |
| 10 |
const pauseButton = parentContainer.querySelector( '.sp-icon-toggle' ); |
| 11 |
|
| 12 |
if ( ! options ) { |
| 13 |
return; |
| 14 |
} |
| 15 |
if ( ! Object.keys( options ).length ) return; |
| 16 |
|
| 17 |
let tickerSwiper = new PCPSwiper( slider, options ); |
| 18 |
let updateSwiperPause = false; |
| 19 |
if ( pauseButton ) { |
| 20 |
pauseButton.addEventListener( 'click', () => { |
| 21 |
updateSwiperPause = ! updateSwiperPause; |
| 22 |
if ( updateSwiperPause ) { |
| 23 |
tickerSwiper.autoplay.stop(); |
| 24 |
} else { |
| 25 |
tickerSwiper.autoplay.start(); |
| 26 |
} |
| 27 |
} ); |
| 28 |
} |
| 29 |
} ); |
| 30 |
|
| 31 |
// news-ticker-ticker-------------------------------- |
| 32 |
const tickers = document.querySelectorAll( '.sp-news-ticker' ); |
| 33 |
tickers?.forEach( ( ticker ) => { |
| 34 |
const options = JSON.parse( |
| 35 |
ticker.getAttribute( 'data-options' ) || '{}' |
| 36 |
); |
| 37 |
|
| 38 |
const tickerSpeed = parseInt( options.speed ) || 3000; |
| 39 |
const pxPerSecond = ( 1000 * 250 ) / tickerSpeed; |
| 40 |
const direction = |
| 41 |
options.direction === 'left_to_right' ? 'right' : 'left'; |
| 42 |
const pauseOnHover = options.pauseOnHover; |
| 43 |
|
| 44 |
const wrapper = document.createElement( 'div' ); |
| 45 |
wrapper.classList.add( 'sp-marquee-inner' ); |
| 46 |
|
| 47 |
const originalHTML = ticker.innerHTML; |
| 48 |
wrapper.innerHTML = originalHTML + originalHTML; |
| 49 |
ticker.innerHTML = ''; |
| 50 |
ticker.appendChild( wrapper ); |
| 51 |
|
| 52 |
// Ensure inline-block for proper scroll width |
| 53 |
wrapper.style.whiteSpace = 'nowrap'; |
| 54 |
|
| 55 |
let scrollX = direction === 'left' ? 0 : -wrapper.scrollWidth / 2; |
| 56 |
let lastTimestamp = null; |
| 57 |
let rafId; |
| 58 |
|
| 59 |
function animate( timestamp ) { |
| 60 |
if ( ! lastTimestamp ) lastTimestamp = timestamp; |
| 61 |
const delta = ( timestamp - lastTimestamp ) / 1000; |
| 62 |
lastTimestamp = timestamp; |
| 63 |
|
| 64 |
const distance = pxPerSecond * delta; |
| 65 |
scrollX += direction === 'left' ? -distance : distance; |
| 66 |
|
| 67 |
wrapper.style.transform = `translateX(${ scrollX }px)`; |
| 68 |
|
| 69 |
// Reset logic based on scroll direction |
| 70 |
const halfWidth = wrapper.scrollWidth / 2; |
| 71 |
if ( direction === 'left' && Math.abs( scrollX ) >= halfWidth ) { |
| 72 |
scrollX = 0; |
| 73 |
} |
| 74 |
if ( direction === 'right' && scrollX >= 0 ) { |
| 75 |
scrollX = -halfWidth; |
| 76 |
} |
| 77 |
|
| 78 |
rafId = requestAnimationFrame( animate ); |
| 79 |
} |
| 80 |
|
| 81 |
rafId = requestAnimationFrame( animate ); |
| 82 |
|
| 83 |
if ( pauseOnHover ) { |
| 84 |
ticker.addEventListener( 'mouseenter', () => { |
| 85 |
cancelAnimationFrame( rafId ); |
| 86 |
} ); |
| 87 |
ticker.addEventListener( 'mouseleave', () => { |
| 88 |
lastTimestamp = null; |
| 89 |
rafId = requestAnimationFrame( animate ); |
| 90 |
} ); |
| 91 |
} |
| 92 |
} ); |
| 93 |
|
| 94 |
// news-ticker-typewriter-------------------------------- |
| 95 |
const elements = document.querySelectorAll( |
| 96 |
'.sps-news-ticker-typewriter-js' |
| 97 |
); |
| 98 |
|
| 99 |
elements?.forEach( ( el ) => { |
| 100 |
const posts = JSON.parse( el.dataset.posts || '[]' ); |
| 101 |
if ( ! posts.length ) return; |
| 102 |
|
| 103 |
let postIndex = 0; |
| 104 |
let charIndex = 0; |
| 105 |
let isDeleting = false; |
| 106 |
let currentText = ''; |
| 107 |
let lastTime = 0; |
| 108 |
let delay = 60; |
| 109 |
const titleEl = el.querySelector( '.sp-smart-post-ticker-title' ); |
| 110 |
const imgEl = el.querySelector( '.sp-ticker-img.sp-img-circle' ); |
| 111 |
//let paused = false; // Default value for Pause on Hover |
| 112 |
|
| 113 |
// el.addEventListener( 'mouseenter', () => { |
| 114 |
// paused = true; |
| 115 |
// } ); |
| 116 |
// el.addEventListener( 'mouseleave', () => { |
| 117 |
// paused = false; |
| 118 |
// } ); |
| 119 |
// Preload next image |
| 120 |
function preloadImage( index ) { |
| 121 |
const nextIndex = ( index + 1 ) % posts.length; |
| 122 |
if ( posts[ nextIndex ]?.thumbUrl ) { |
| 123 |
const img = new Image(); |
| 124 |
img.src = posts[ nextIndex ].thumbUrl; |
| 125 |
} |
| 126 |
} |
| 127 |
|
| 128 |
function updateText( timestamp ) { |
| 129 |
if ( ! lastTime ) lastTime = timestamp; |
| 130 |
|
| 131 |
const { title, url, target, thumbUrl } = posts[ postIndex ]; |
| 132 |
// Update image (only when changing posts) |
| 133 |
if ( ! isDeleting && charIndex === 0 && imgEl && thumbUrl ) { |
| 134 |
imgEl.style.opacity = '0'; |
| 135 |
setTimeout( () => { |
| 136 |
imgEl.src = thumbUrl; |
| 137 |
imgEl.alt = title; |
| 138 |
imgEl.style.opacity = '1'; |
| 139 |
}, 200 ); |
| 140 |
preloadImage( postIndex ); |
| 141 |
} |
| 142 |
|
| 143 |
const delta = timestamp - lastTime; |
| 144 |
if ( delta >= delay ) { |
| 145 |
// const { title, url, target, thumbUrl } = posts[ postIndex ]; |
| 146 |
|
| 147 |
if ( isDeleting ) { |
| 148 |
charIndex--; |
| 149 |
} else { |
| 150 |
charIndex++; |
| 151 |
} |
| 152 |
|
| 153 |
currentText = title.substring( 0, charIndex ); |
| 154 |
|
| 155 |
if ( titleEl ) { |
| 156 |
titleEl.innerText = currentText; // Update the visible text |
| 157 |
titleEl.href = url; // Update the link |
| 158 |
titleEl.target = target || '_self'; // Set target (e.g., _blank) |
| 159 |
} |
| 160 |
|
| 161 |
delay = isDeleting ? 20 : 60; |
| 162 |
|
| 163 |
if ( ! isDeleting && currentText === title ) { |
| 164 |
delay = 1500; // Pause after full text |
| 165 |
isDeleting = true; |
| 166 |
} else if ( isDeleting && charIndex === 0 ) { |
| 167 |
isDeleting = false; |
| 168 |
postIndex = ( postIndex + 1 ) % posts.length; |
| 169 |
delay = 800; // Pause before next word |
| 170 |
} |
| 171 |
|
| 172 |
lastTime = timestamp; |
| 173 |
} |
| 174 |
|
| 175 |
requestAnimationFrame( updateText ); |
| 176 |
} |
| 177 |
|
| 178 |
requestAnimationFrame( updateText ); |
| 179 |
} ); |
| 180 |
} ); |
| 181 |
|