PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / testimonial-carousel / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/testimonial-carousel/frontend.js

93 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* Testimonial Carousel — frontend.js */
2 ( function () {
3 function initCarousel( wrap ) {
4 const slides = wrap.querySelectorAll( '.bktc-slide' );
5 if ( ! slides.length ) return;
6
7 const autoplay = wrap.dataset.autoplay === '1';
8 const speed = parseInt( wrap.dataset.speed ) || 3500;
9 const loop = wrap.dataset.loop === '1';
10 const pauseHover = wrap.dataset.hover === '1';
11 const showDots = wrap.dataset.dots === '1';
12
13 let current = 0;
14 let timer = null;
15
16 /* Build dots */
17 if ( showDots ) {
18 const dotsWrap = wrap.querySelector( '.bktc-dots' );
19 if ( dotsWrap ) {
20 slides.forEach( (_, i) => {
21 const dot = document.createElement( 'button' );
22 dot.className = 'bktc-dot' + ( i === 0 ? ' bktc-dot-active' : '' );
23 dot.addEventListener( 'click', () => goTo(i) );
24 dotsWrap.appendChild( dot );
25 } );
26 }
27 }
28
29 function updateDots() {
30 const dots = wrap.querySelectorAll( '.bktc-dot' );
31 dots.forEach( (d, i) => d.classList.toggle( 'bktc-dot-active', i === current ) );
32 }
33
34 function goTo( idx ) {
35 slides[ current ].classList.remove( 'bktc-active' );
36 if ( loop ) {
37 current = ( idx + slides.length ) % slides.length;
38 } else {
39 current = Math.max( 0, Math.min( idx, slides.length - 1 ) );
40 }
41 slides[ current ].classList.add( 'bktc-active' );
42 updateDots();
43 }
44
45 function next() { goTo( current + 1 ); }
46 function prev() { goTo( current - 1 ); }
47
48 /* Arrows */
49 const prevBtn = wrap.querySelector( '.bktc-prev' );
50 const nextBtn = wrap.querySelector( '.bktc-next' );
51 if ( prevBtn ) prevBtn.addEventListener( 'click', () => { clearInterval(timer); prev(); startAutoplay(); } );
52 if ( nextBtn ) nextBtn.addEventListener( 'click', () => { clearInterval(timer); next(); startAutoplay(); } );
53
54 /* Keyboard */
55 wrap.setAttribute( 'tabindex', '0' );
56 wrap.addEventListener( 'keydown', function (e) {
57 if ( e.key === 'ArrowLeft' ) { clearInterval(timer); prev(); startAutoplay(); }
58 if ( e.key === 'ArrowRight' ) { clearInterval(timer); next(); startAutoplay(); }
59 } );
60
61 /* Touch swipe */
62 let touchStartX = 0;
63 wrap.addEventListener( 'touchstart', e => { touchStartX = e.changedTouches[0].clientX; }, { passive: true } );
64 wrap.addEventListener( 'touchend', e => {
65 const dx = e.changedTouches[0].clientX - touchStartX;
66 if ( Math.abs(dx) > 40 ) { clearInterval(timer); ( dx < 0 ? next : prev )(); startAutoplay(); }
67 }, { passive: true } );
68
69 function startAutoplay() {
70 if ( ! autoplay ) return;
71 clearInterval( timer );
72 timer = setInterval( next, speed );
73 }
74
75 if ( pauseHover ) {
76 wrap.addEventListener( 'mouseenter', () => clearInterval(timer) );
77 wrap.addEventListener( 'mouseleave', startAutoplay );
78 }
79
80 startAutoplay();
81 }
82
83 function init() {
84 document.querySelectorAll( '.bktc-wrap[data-autoplay]' ).forEach( initCarousel );
85 }
86
87 if ( document.readyState === 'loading' ) {
88 document.addEventListener( 'DOMContentLoaded', init );
89 } else {
90 init();
91 }
92 } )();
93