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 / stock-ticker / frontend.js

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

354 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3 var _typoKeys = {
4 family:'font-family', weight:'font-weight', style:'font-style',
5 decoration:'text-decoration', transform:'text-transform',
6 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
7 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
8 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
9 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
10 };
11 function typoCssVarsForEl(el, obj, prefix) {
12 if (!obj || typeof obj !== 'object') return;
13 Object.keys(_typoKeys).forEach(function (k) {
14 var v = obj[k];
15 if (v === undefined || v === '' || v === null) return;
16 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
17 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
18 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
19 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
20 el.style.setProperty(prefix + _typoKeys[k], String(v));
21 });
22 }
23
24 var CGBASE = 'https://api.coingecko.com/api/v3';
25
26 function fmt(n, sym) {
27 if (n === undefined || n === null) return sym + '?';
28 if (n >= 1000) return sym + n.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 0 });
29 if (n >= 1) return sym + n.toFixed(2);
30 return sym + n.toFixed(4);
31 }
32
33 function fmtBig(n) {
34 if (!n) return 'N/A';
35 if (n >= 1e12) return '$' + (n / 1e12).toFixed(2) + 'T';
36 if (n >= 1e9) return '$' + (n / 1e9).toFixed(2) + 'B';
37 if (n >= 1e6) return '$' + (n / 1e6).toFixed(2) + 'M';
38 return '$' + n.toLocaleString();
39 }
40
41 function initTicker(appEl) {
42 var raw = appEl.dataset.opts;
43 if (!raw) return;
44 var opts;
45 try { opts = JSON.parse(raw); } catch (e) { return; }
46
47 var sym = opts.currencySymbol || '$';
48 var css = opts.currency || 'usd';
49 var coins = (opts.coins || 'bitcoin,ethereum,solana').split(',').map(function (s) { return s.trim(); }).filter(Boolean);
50 var layout = opts.layout || 'ticker';
51
52 // ── Build outer wrapper ──────────────────────────────────────
53 var wrap = document.createElement('div');
54 wrap.className = 'bkbg-st-wrap';
55 wrap.style.borderRadius = (opts.borderRadius || 12) + 'px';
56 wrap.style.overflow = 'hidden';
57 wrap.style.backgroundColor = opts.bgColor || '#0f172a';
58 wrap.style.color = opts.textColor || '#e2e8f0';
59 typoCssVarsForEl(wrap, opts.textTypo, '--bkstk-tx-');
60 wrap.style.setProperty('--bkstk-tx-fw', String(opts.fontWeight || 600));
61 wrap.style.setProperty('--bkstk-tx-lh', String(opts.lineHeight || 1.4));
62
63 var contentEl = document.createElement('div');
64 contentEl.innerHTML = '<div class="bkbg-st-loading">Loading live prices…</div>';
65 wrap.appendChild(contentEl);
66
67 var footer = document.createElement('div');
68 footer.className = 'bkbg-st-footer';
69 footer.style.color = opts.textColor || '#e2e8f0';
70 footer.textContent = 'Data: CoinGecko API · Updates every ' + (opts.refreshInterval || 60) + 's';
71 wrap.appendChild(footer);
72
73 appEl.parentNode.replaceChild(wrap, appEl);
74
75 // ── Fetch from CoinGecko ─────────────────────────────────────
76 function fetchData() {
77 var url = CGBASE + '/coins/markets?vs_currency=' + css +
78 '&ids=' + coins.join(',') +
79 '&order=market_cap_desc&per_page=50&page=1' +
80 '&sparkline=false&price_change_percentage=24h';
81
82 fetch(url)
83 .then(function (r) {
84 if (!r.ok) throw new Error('HTTP ' + r.status);
85 return r.json();
86 })
87 .then(function (data) { render(data); })
88 .catch(function (err) {
89 contentEl.innerHTML = '<div class="bkbg-st-error">⚠ Unable to load prices. (' + err.message + ')</div>';
90 });
91 }
92
93 // ── Render ───────────────────────────────────────────────────
94 function render(data) {
95 if (layout === 'ticker') renderTicker(data);
96 else if (layout === 'cards') renderCards(data);
97 else renderTable(data);
98 }
99
100 function renderTicker(data) {
101 var outer = document.createElement('div');
102 outer.className = 'bkbg-st-ticker-outer';
103 outer.style.backgroundColor = opts.bgColor || '#0f172a';
104 outer.style.minHeight = '44px';
105
106 if (opts.showLabel) {
107 var badge = document.createElement('div');
108 badge.className = 'bkbg-st-live-badge';
109 badge.style.backgroundColor = opts.accentColor || '#38bdf8';
110 badge.style.color = '#fff';
111 var dot = document.createElement('span');
112 dot.className = 'bkbg-st-live-dot';
113 badge.appendChild(dot);
114 badge.appendChild(document.createTextNode(opts.labelText || 'LIVE'));
115 outer.appendChild(badge);
116 }
117
118 var track = document.createElement('div');
119 track.className = 'bkbg-st-ticker-track';
120 track.style.animationDuration = (opts.tickerSpeed || 40) + 's';
121
122 function buildItems(arr) {
123 var frag = document.createDocumentFragment();
124 arr.forEach(function (coin) {
125 var item = document.createElement('span');
126 item.className = 'bkbg-st-item';
127
128 if (opts.showIcons && coin.image) {
129 var img = document.createElement('img');
130 img.src = coin.image;
131 img.alt = coin.symbol;
132 img.className = 'bkbg-st-img-icon';
133 item.appendChild(img);
134 }
135
136 if (opts.showSymbol) {
137 var sym2 = document.createElement('span');
138 sym2.className = 'bkbg-st-symbol';
139 sym2.textContent = coin.symbol.toUpperCase();
140 item.appendChild(sym2);
141 }
142
143 var priceEl = document.createElement('span');
144 priceEl.className = 'bkbg-st-price';
145 priceEl.textContent = fmt(coin.current_price, sym);
146 item.appendChild(priceEl);
147
148 if (opts.showChange) {
149 var ch = coin.price_change_percentage_24h;
150 var chEl = document.createElement('span');
151 chEl.className = ch >= 0 ? 'bkbg-st-change-up' : 'bkbg-st-change-down';
152 chEl.style.color = ch >= 0 ? (opts.upColor || '#22c55e') : (opts.downColor || '#ef4444');
153 chEl.textContent = (ch >= 0 ? '▲ +' : '') + (ch ? ch.toFixed(2) : '0.00') + '%';
154 item.appendChild(chEl);
155 }
156
157 var sep = document.createElement('span');
158 sep.className = 'bkbg-st-sep';
159 sep.textContent = '|';
160 item.appendChild(sep);
161
162 frag.appendChild(item);
163 });
164 return frag;
165 }
166
167 // Duplicate for seamless loop
168 track.appendChild(buildItems(data));
169 track.appendChild(buildItems(data));
170
171 if (opts.pauseOnHover) {
172 outer.addEventListener('mouseenter', function () { track.classList.add('bkbg-st-paused'); });
173 outer.addEventListener('mouseleave', function () { track.classList.remove('bkbg-st-paused'); });
174 }
175
176 outer.appendChild(track);
177 contentEl.innerHTML = '';
178 contentEl.appendChild(outer);
179 }
180
181 function renderCards(data) {
182 var grid = document.createElement('div');
183 grid.className = 'bkbg-st-cards';
184 grid.style.gridTemplateColumns = 'repeat(' + (opts.cardColumns || 3) + ', 1fr)';
185 grid.style.borderRadius = (opts.borderRadius || 12) + 'px';
186 grid.style.padding = '16px';
187
188 data.forEach(function (coin) {
189 var card = document.createElement('div');
190 card.className = 'bkbg-st-card';
191 card.style.backgroundColor = opts.cardBg || '#1e293b';
192 card.style.borderRadius = (opts.borderRadius || 12) + 'px';
193 card.style.border = '1px solid ' + (opts.borderColor || '#334155');
194 card.style.color = opts.textColor || '#e2e8f0';
195
196 var header = document.createElement('div');
197 header.className = 'bkbg-st-card-header';
198
199 if (opts.showIcons && coin.image) {
200 var img = document.createElement('img');
201 img.src = coin.image; img.alt = coin.symbol;
202 img.className = 'bkbg-st-card-icon';
203 header.appendChild(img);
204 }
205
206 var nameWrap = document.createElement('div');
207 var nameEl = document.createElement('div');
208 nameEl.className = 'bkbg-st-card-name';
209 nameEl.textContent = coin.name;
210 nameWrap.appendChild(nameEl);
211 if (opts.showSymbol) {
212 var symEl = document.createElement('div');
213 symEl.className = 'bkbg-st-card-sym';
214 symEl.textContent = coin.symbol.toUpperCase();
215 nameWrap.appendChild(symEl);
216 }
217 header.appendChild(nameWrap);
218 card.appendChild(header);
219
220 var priceEl = document.createElement('div');
221 priceEl.className = 'bkbg-st-card-price';
222 priceEl.style.fontSize = (opts.fontSize + 2 || 16) + 'px';
223 priceEl.textContent = fmt(coin.current_price, sym);
224 card.appendChild(priceEl);
225
226 if (opts.showChange) {
227 var ch = coin.price_change_percentage_24h;
228 var chEl = document.createElement('div');
229 chEl.className = 'bkbg-st-card-change';
230 chEl.style.color = ch >= 0 ? (opts.upColor || '#22c55e') : (opts.downColor || '#ef4444');
231 chEl.textContent = (ch >= 0 ? '▲ +' : '') + (ch ? ch.toFixed(2) : '0.00') + '%';
232 card.appendChild(chEl);
233 }
234
235 if (opts.showMarketCap || opts.showVolume) {
236 var meta = document.createElement('div');
237 meta.className = 'bkbg-st-card-meta';
238 meta.style.color = opts.textColor || '#e2e8f0';
239 if (opts.showMarketCap) { var mc = document.createElement('span'); mc.textContent = 'MCap: ' + fmtBig(coin.market_cap); meta.appendChild(mc); }
240 if (opts.showVolume) { var vol = document.createElement('span'); vol.textContent = 'Vol: ' + fmtBig(coin.total_volume); meta.appendChild(vol); }
241 card.appendChild(meta);
242 }
243
244 grid.appendChild(card);
245 });
246
247 contentEl.innerHTML = '';
248 contentEl.appendChild(grid);
249 }
250
251 function renderTable(data) {
252 var tableWrap = document.createElement('div');
253 tableWrap.className = 'bkbg-st-table-wrap';
254 tableWrap.style.borderRadius = (opts.borderRadius || 12) + 'px';
255
256 var table = document.createElement('table');
257 table.className = 'bkbg-st-table';
258 table.style.color = opts.textColor || '#e2e8f0';
259 table.style.backgroundColor = opts.bgColor || '#0f172a';
260
261 var thead = document.createElement('thead');
262 var hrow = document.createElement('tr');
263 hrow.style.borderBottom = '1px solid ' + (opts.borderColor || '#334155');
264 hrow.style.opacity = '0.7';
265
266 function th(txt) {
267 var td = document.createElement('th');
268 td.textContent = txt;
269 td.style.fontWeight = 600;
270 td.style.padding = '10px 14px';
271 return td;
272 }
273
274 hrow.appendChild(th('Asset'));
275 hrow.appendChild(th('Price'));
276 if (opts.showChange) hrow.appendChild(th('24h'));
277 if (opts.showMarketCap) hrow.appendChild(th('Mkt Cap'));
278 if (opts.showVolume) hrow.appendChild(th('Volume'));
279 thead.appendChild(hrow);
280 table.appendChild(thead);
281
282 var tbody = document.createElement('tbody');
283 data.forEach(function (coin, i) {
284 var row = document.createElement('tr');
285 row.style.borderBottom = '1px solid ' + (opts.borderColor || '#334155');
286 if (i % 2) row.style.background = 'rgba(255,255,255,0.02)';
287
288 function td(inner) {
289 var cell = document.createElement('td');
290 cell.style.padding = '10px 14px';
291 if (typeof inner === 'string') cell.textContent = inner;
292 else cell.appendChild(inner);
293 return cell;
294 }
295
296 var assetWrap = document.createElement('div');
297 assetWrap.style.display = 'flex';
298 assetWrap.style.alignItems = 'center';
299 assetWrap.style.gap = '8px';
300 if (opts.showIcons && coin.image) {
301 var img = document.createElement('img'); img.src = coin.image; img.alt = coin.symbol;
302 img.style.width = '20px'; img.style.height = '20px'; img.style.borderRadius = '50%';
303 assetWrap.appendChild(img);
304 }
305 var n = document.createElement('strong'); n.textContent = coin.name; assetWrap.appendChild(n);
306 if (opts.showSymbol) {
307 var sp = document.createElement('span'); sp.textContent = coin.symbol.toUpperCase();
308 sp.style.opacity = '0.5'; sp.style.fontSize = '11px'; assetWrap.appendChild(sp);
309 }
310 row.appendChild(td(assetWrap));
311
312 var priceCell = td(fmt(coin.current_price, sym));
313 priceCell.style.textAlign = 'right';
314 priceCell.style.fontWeight = '700';
315 row.appendChild(priceCell);
316
317 if (opts.showChange) {
318 var ch = coin.price_change_percentage_24h;
319 var chTd = td((ch >= 0 ? '▲ +' : '') + (ch ? ch.toFixed(2) : '0.00') + '%');
320 chTd.style.textAlign = 'right';
321 chTd.style.color = ch >= 0 ? (opts.upColor || '#22c55e') : (opts.downColor || '#ef4444');
322 row.appendChild(chTd);
323 }
324
325 if (opts.showMarketCap) {
326 var mct = td(fmtBig(coin.market_cap)); mct.style.textAlign = 'right'; mct.style.opacity = '0.7'; row.appendChild(mct);
327 }
328 if (opts.showVolume) {
329 var vt = td(fmtBig(coin.total_volume)); vt.style.textAlign = 'right'; vt.style.opacity = '0.7'; row.appendChild(vt);
330 }
331 tbody.appendChild(row);
332 });
333
334 table.appendChild(tbody);
335 tableWrap.appendChild(table);
336 contentEl.innerHTML = '';
337 contentEl.appendChild(tableWrap);
338 }
339
340 // ── Init & refresh ───────────────────────────────────────────
341 fetchData();
342 var interval = parseInt(opts.refreshInterval, 10) || 60;
343 setInterval(fetchData, interval * 1000);
344 }
345
346 document.addEventListener('DOMContentLoaded', function () {
347 document.querySelectorAll('.bkbg-st-app').forEach(initTicker);
348 });
349
350 if (document.readyState === 'complete' || document.readyState === 'interactive') {
351 document.querySelectorAll('.bkbg-st-app').forEach(initTicker);
352 }
353 })();
354