PageSourceSearch

https://listwithclever.com/wp-content/plugins/lwc-ai-clever-blocks…a5d9de7689f8ad97cbd3a31b3f0b30874933b299fd5

js listwithclever.com collected 2026-10-02 11:05:19 UTC 5,624 bytes, 159 lines download raw bytes

1/**
2 * iBuyer KPI Cards — block-local behavior.
3 *
4 * Progressive enhancement only. The server renders the final figures, so the
5 * card is complete and correct without this script. When the card scrolls into
6 * view, any metric value that is a plainly formatted thousands number counts up
7 * to the figure already in the markup. A value the script cannot reproduce
8 * character for character is left exactly as the editor typed it.
9 *
10 * Skipped entirely for readers who prefer reduced motion. Initializes once per
11 * block root and releases its observer when the root leaves its document.
12 *
13 * Frontend only: block.json registers this as viewScript, so ACF editor
14 * previews show the static server-rendered values. The clvr-tooltip element in
15 * the highlight row is driven by the shared runtime, not by this file.
16 */
17(function () {
18    'use strict';
19
20    var ROOT_SELECTOR = '.ibuyer-kpi-cards-block.clvr-scope[data-ibuyer-kpi-cards]';
21    var DURATION = 1200;
22    var instances = new WeakMap();
23
24    /**
25     * Split "$313,500" into its prefix, numeric value and suffix, but only when
26     * the number can be re-rendered to exactly the original digits. Anything
27     * else returns null so the value is never silently reformatted.
28     */
29    function parseValue(text) {
30        var match = text.match(/^(\D*)(\d[\d,]*)(\D*)$/);
31        if (!match) {
32            return null;
33        }
34        var digits = match[2];
35        var amount = parseInt(digits.replace(/,/g, ''), 10);
36        if (!isFinite(amount) || amount < 1000) {
37            return null;
38        }
39        if (amount.toLocaleString('en-US') !== digits) {
40            return null;
41        }
42        return { prefix: match[1], amount: amount, suffix: match[3] };
43    }
44
45    function init(root) {
46        if (!root || !root.matches || !root.matches(ROOT_SELECTOR) || !root.isConnected) {
47            return null;
48        }
49        var doc = root.ownerDocument;
50        var win = doc.defaultView;
51        if (!win) {
52            return null;
53        }
54        var previous = instances.get(root);
55        if (previous && previous.document === doc) {
56            return previous;
57        }
58        if (previous) {
59            previous.destroy();
60        }
61
62        var reduceMotion = win.matchMedia && win.matchMedia('(prefers-reduced-motion: reduce)').matches;
63        var frames = [];
64        var observer = null;
65
66        var controller = {
67            document: doc,
68            destroy: function () {
69                if (observer) {
70                    observer.disconnect();
71                    observer = null;
72                }
73                frames.forEach(function (id) { win.cancelAnimationFrame(id); });
74                frames = [];
75                instances.delete(root);
76            }
77        };
78        instances.set(root, controller);
79
80        if (reduceMotion || typeof win.IntersectionObserver !== 'function') {
81            return controller;
82        }
83
84        // Only values inside this instance, never a nested independent scope.
85        var targets = Array.prototype.filter.call(
86            root.querySelectorAll('[data-kpi-count]'),
87            function (el) { return el.closest('.clvr-scope') === root; }
88        );
89
90        var animatable = targets.map(function (el) {
91            var parsed = parseValue(el.textContent.trim());
92            return parsed ? { el: el, parsed: parsed } : null;
93        }).filter(Boolean);
94
95        if (animatable.length === 0) {
96            return controller;
97        }
98
99        function animate(entry) {
100            var el = entry.el;
101            var parsed = entry.parsed;
102            var started = 0;
103
104            function step(now) {
105                if (!el.isConnected || el.ownerDocument !== doc) {
106                    return;
107                }
108                if (!started) {
109                    started = now;
110                }
111                var progress = Math.min((now - started) / DURATION, 1);
112                var eased = 1 - Math.pow(1 - progress, 3);
113                var current = Math.round(parsed.amount * eased);
114                el.textContent = parsed.prefix + current.toLocaleStr
114ing('en-US') + parsed.suffix;
115                if (progress < 1) {
116                    frames.push(win.requestAnimationFrame(step));
117                }
118            }
119
120            frames.push(win.requestAnimationFrame(step));
121        }
122
123        observer = new win.IntersectionObserver(function (entries) {
124            entries.forEach(function (observed) {
125                if (!observed.isIntersecting) {
126                    return;
127                }
128                observer.unobserve(observed.target);
129                var entry = animatable.filter(function (candidate) {
130                    return candidate.el === observed.target;
131                })[0];
132                if (entry) {
133                    animate(entry);
134                }
135            });
136        }, { threshold: 0.3 });
137
138        animatable.forEach(function (entry) { observer.observe(entry.el); });
139
140        return controller;
141    }
142
143    function initWithin(container) {
144        if (!container || !container.querySelectorAll) {
145            return;
146        }
147        if (container.matches && container.matches(ROOT_SELECTOR)) {
148            init(container);
149        }
150        Array.prototype.forEach.call(container.querySelectorAll(ROOT_SELECTOR), init);
151    }
152
153    // Frontend: the script is deferred, so the DOM is parsed.
154    if (document.readyState === 'loading') {
155        document.addEventListener('DOMContentLoaded', function () { initWithin(document); }, { once: true });
156    } else {
157        initWithin(document);
158    }
159})();

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.