PluginProbe ʕ •ᴥ•ʔ
FrontBlocks for Gutenberg/GeneratePress / 1.1.0
FrontBlocks for Gutenberg/GeneratePress v1.1.0
trunk 0.2.0 0.2.1 0.2.2 0.2.3 0.2.4 0.2.5 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 ci-artifacts
frontblocks / assets / counter / frontblocks-counter-runtime.js
frontblocks / assets / counter Last commit date
frontblocks-counter-runtime.js 8 months ago frontblocks-counter.css 8 months ago frontblocks-counter.js 8 months ago
frontblocks-counter-runtime.js
83 lines
1 const COUNTER_CLASS = 'frontblocks-counter-active';
2
3 document.addEventListener('DOMContentLoaded', function() {
4 const counterElements = document.querySelectorAll(`.${COUNTER_CLASS}`);
5
6 if (counterElements.length === 0) return;
7
8 const runCounterAnimation = (element) => {
9 if (element.classList.contains('count-up-animated')) {
10 return;
11 }
12
13 const originalText = element.getAttribute('data-counter-target');
14 if (!originalText) return;
15
16 const animationDuration = parseInt(element.getAttribute('data-counter-duration'), 10) || 2000;
17 const customPrefix = element.getAttribute('data-counter-prefix') || '';
18 const customSuffix = element.getAttribute('data-counter-suffix') || '';
19
20 element.setAttribute('data-original-text', originalText);
21
22 const prefix = customPrefix || '';
23
24 let numberString = originalText;
25
26 const numberMatch = numberString.match(/[\d\.,]+/);
27 if (!numberMatch) return;
28
29 let targetString = numberMatch[0].replace(/[^0-9]/g, '');
30 const target = parseInt(targetString, 10);
31
32 if (isNaN(target) || target === 0) return;
33
34 let current = 0;
35 const interval = 10;
36 const steps = animationDuration / interval;
37 const stepValue = target / steps;
38
39 const timer = setInterval(() => {
40 current += stepValue;
41
42 if (current >= target) {
43 current = target;
44 clearInterval(timer);
45 element.classList.add('count-up-animated');
46 }
47
48 element.textContent = prefix + Math.floor(current).toLocaleString('en-US') + customSuffix;
49 }, interval);
50 };
51
52 const observerOptions = {
53 root: null,
54 rootMargin: '0px',
55 threshold: 0.5
56 };
57
58 const observer = new IntersectionObserver((entries, observer) => {
59 entries.forEach(entry => {
60 if (entry.isIntersecting) {
61 const element = entry.target;
62
63 if (!element.classList.contains('count-up-animated')) {
64 runCounterAnimation(element);
65 }
66
67 observer.unobserve(element);
68 }
69 });
70 }, observerOptions);
71
72 counterElements.forEach(counter => {
73 const fullTargetText = counter.getAttribute('data-counter-target');
74 if (!fullTargetText) return;
75
76 const customPrefix = counter.getAttribute('data-counter-prefix') || '';
77 const customSuffix = counter.getAttribute('data-counter-suffix') || '';
78
79 counter.textContent = customPrefix + '0' + customSuffix;
80
81 observer.observe(counter);
82 });
83 });