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 / currency-converter / frontend.js

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

297 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 /* ── Static indicative rates (USD base) ─────────────────────────────── */
5 var USD_RATES = {
6 USD:1,EUR:0.92,GBP:0.79,JPY:149.5,CAD:1.36,AUD:1.53,CHF:0.90,CNY:7.24,
7 INR:83.1,MXN:17.15,BRL:4.97,KRW:1325,SGD:1.34,HKD:7.82,NOK:10.58,SEK:10.42,
8 DKK:6.88,NZD:1.63,ZAR:18.63,TRY:32.6,RUB:90.5,PLN:4.03,THB:35.1,MYR:4.72,
9 IDR:15650,PHP:56.5,AED:3.67,SAR:3.75,EGP:30.9,NGN:1490,
10 };
11
12 var CURRENCY_NAMES = {
13 USD:'US Dollar',EUR:'Euro',GBP:'British Pound',JPY:'Japanese Yen',CAD:'Canadian Dollar',
14 AUD:'Australian Dollar',CHF:'Swiss Franc',CNY:'Chinese Yuan',INR:'Indian Rupee',
15 MXN:'Mexican Peso',BRL:'Brazilian Real',KRW:'South Korean Won',SGD:'Singapore Dollar',
16 HKD:'Hong Kong Dollar',NOK:'Norwegian Krone',SEK:'Swedish Krona',DKK:'Danish Krone',
17 NZD:'New Zealand Dollar',ZAR:'South African Rand',TRY:'Turkish Lira',RUB:'Russian Ruble',
18 PLN:'Polish Zloty',THB:'Thai Baht',MYR:'Malaysian Ringgit',IDR:'Indonesian Rupiah',
19 PHP:'Philippine Peso',AED:'UAE Dirham',SAR:'Saudi Riyal',EGP:'Egyptian Pound',NGN:'Nigerian Naira',
20 };
21
22 function convert(amount, from, to) {
23 if (!USD_RATES[from] || !USD_RATES[to]) return 0;
24 return (amount / USD_RATES[from]) * USD_RATES[to];
25 }
26
27 function fmtNum(val) {
28 if (isNaN(val) || val === null) return '';
29 if (val >= 1000) return val.toLocaleString('en-US', { maximumFractionDigits: 2 });
30 return val.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 4 });
31 }
32
33 function cname(code) { return CURRENCY_NAMES[code] || code; }
34
35 /* ── Typography CSS-var helper ─────────────────────────────────────── */
36 function typoCssVarsForEl(typo, prefix, el) {
37 if (!typo || typeof typo !== 'object') return;
38 var map = {
39 family:'font-family', weight:'font-weight', style:'font-style',
40 transform:'text-transform', decoration:'text-decoration',
41 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m', sizeUnit:'font-size-unit',
42 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m', lineHeightUnit:'line-height-unit',
43 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m', letterSpacingUnit:'letter-spacing-unit',
44 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m', wordSpacingUnit:'word-spacing-unit'
45 };
46 Object.keys(map).forEach(function(k) {
47 if (typo[k] !== undefined && typo[k] !== '') {
48 var v = typo[k];
49 var css = map[k];
50 if (css.indexOf('size-d') !== -1 || css.indexOf('size-t') !== -1 || css.indexOf('size-m') !== -1 ||
51 css.indexOf('height-d') !== -1 || css.indexOf('height-t') !== -1 || css.indexOf('height-m') !== -1 ||
52 css.indexOf('spacing-d') !== -1 || css.indexOf('spacing-t') !== -1 || css.indexOf('spacing-m') !== -1) {
53 var unitKey = css.replace(/-[dtm]$/, '-unit');
54 var unit = '';
55 Object.keys(map).forEach(function(k2) { if (map[k2] === unitKey && typo[k2]) unit = typo[k2]; });
56 if (!unit) unit = css.indexOf('size') !== -1 ? 'px' : '';
57 v = v + unit;
58 }
59 el.style.setProperty(prefix + css, v);
60 }
61 });
62 }
63
64 /* ── Build select options ─────────────────────────────────────────── */
65 function buildSelectOptions(sel, selected) {
66 sel.innerHTML = '';
67 Object.keys(USD_RATES).forEach(function (code) {
68 var opt = document.createElement('option');
69 opt.value = code;
70 opt.textContent = code + '' + cname(code);
71 if (code === selected) opt.selected = true;
72 sel.appendChild(opt);
73 });
74 }
75
76 /* ── Main builder ─────────────────────────────────────────────────── */
77 function buildApp(app) {
78 var opts = {};
79 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch (e) {}
80
81 var accent = opts.accentColor || '#6c3fb5';
82 var cardBg = opts.cardBg || '#ffffff';
83 var resultBg = opts.resultBg || '#f5f3ff';
84 var resultBdr = opts.resultBorder || '#ede9fe';
85 var resultClr = opts.resultColor || accent;
86 var labelColor = opts.labelColor || '#374151';
87 var titleColor = opts.titleColor || '#1e1b4b';
88 var subColor = opts.subtitleColor || '#6b7280';
89 var pairBg = opts.quickPairBg || '#f3f4f6';
90 var pairColor = opts.quickPairColor|| '#374151';
91 var cRadius = (opts.cardRadius !== undefined ? opts.cardRadius : 16) + 'px';
92 var maxW = (opts.maxWidth || 580) + 'px';
93 var ptop = (opts.paddingTop !== undefined ? opts.paddingTop : 60) + 'px';
94 var pbot = (opts.paddingBottom!== undefined ? opts.paddingBottom : 60) + 'px';
95 var titleSize = (opts.titleSize || 26) + 'px';
96 var resultSize = (opts.resultSize || 40) + 'px';
97 var quickPairs = opts.quickPairs || [];
98
99 var fromCur = opts.defaultFrom || 'USD';
100 var toCur = opts.defaultTo || 'EUR';
101 var amount = opts.defaultAmount || 100;
102
103 /* Card */
104 var card = document.createElement('div');
105 card.className = 'bkbg-cc-card';
106 card.style.cssText = [
107 'background:' + cardBg,
108 'border-radius:' + cRadius,
109 'padding-top:'+ ptop,
110 'padding-bottom:' + pbot,
111 'max-width:' + maxW,
112 ].join(';');
113 app.innerHTML = '';
114 app.appendChild(card);
115
116 /* Apply typography CSS vars on card */
117 card.style.setProperty('--bkbg-cc-ttl-fs', titleSize);
118 card.style.setProperty('--bkbg-cc-res-fs', resultSize);
119 typoCssVarsForEl(opts.typoTitle, '--bkbg-cc-ttl-', card);
120 typoCssVarsForEl(opts.typoResult, '--bkbg-cc-res-', card);
121
122 /* Title */
123 if (opts.showTitle && opts.title) {
124 var h2 = document.createElement('h2');
125 h2.className = 'bkbg-cc-title';
126 h2.textContent = opts.title;
127 h2.style.color = titleColor;
128 card.appendChild(h2);
129 }
130
131 /* Subtitle */
132 if (opts.showSubtitle && opts.subtitle) {
133 var sub = document.createElement('p');
134 sub.className = 'bkbg-cc-subtitle';
135 sub.textContent = opts.subtitle;
136 sub.style.color = subColor;
137 card.appendChild(sub);
138 }
139
140 /* Quick pairs */
141 var pairsDiv;
142 if (opts.showQuickPairs && quickPairs.length) {
143 pairsDiv = document.createElement('div');
144 pairsDiv.className = 'bkbg-cc-pairs';
145 card.appendChild(pairsDiv);
146 }
147
148 /* Convert row: amount + swap + to */
149 var row = document.createElement('div');
150 row.className = 'bkbg-cc-convert-row';
151 card.appendChild(row);
152
153 /* Amount */
154 var amtGroup = document.createElement('div');
155 amtGroup.className = 'bkbg-cc-field-group';
156 var amtLabel = document.createElement('label');
157 amtLabel.textContent = 'Amount';
158 amtLabel.style.color = labelColor;
159 var amtInput = document.createElement('input');
160 amtInput.type = 'number';
161 amtInput.className = 'bkbg-cc-amount-input';
162 amtInput.value = amount;
163 amtInput.min = '0';
164 amtInput.step = 'any';
165 amtGroup.appendChild(amtLabel);
166 amtGroup.appendChild(amtInput);
167 row.appendChild(amtGroup);
168
169 /* Swap */
170 var swapBtn;
171 if (opts.showSwapBtn) {
172 swapBtn = document.createElement('button');
173 swapBtn.className = 'bkbg-cc-swap';
174 swapBtn.textContent = '';
175 swapBtn.style.borderColor = accent;
176 swapBtn.style.color = accent;
177 row.appendChild(swapBtn);
178 } else {
179 var arrow = document.createElement('div');
180 arrow.textContent = '';
181 arrow.style.cssText = 'align-self:flex-end;padding:10px 4px;font-size:20px;color:#9ca3af';
182 row.appendChild(arrow);
183 }
184
185 /* To select */
186 var toGroup = document.createElement('div');
187 toGroup.className = 'bkbg-cc-field-group';
188 var toLabel = document.createElement('label');
189 toLabel.textContent = 'To';
190 toLabel.style.color = labelColor;
191 var toSel = document.createElement('select');
192 toSel.className = 'bkbg-cc-select';
193 buildSelectOptions(toSel, toCur);
194 toGroup.appendChild(toLabel);
195 toGroup.appendChild(toSel);
196 row.appendChild(toGroup);
197
198 /* From — full width row */
199 var fromRow = document.createElement('div');
200 fromRow.className = 'bkbg-cc-from-row';
201 var fromLabel = document.createElement('label');
202 fromLabel.textContent = 'From Currency';
203 fromLabel.style.color = labelColor;
204 var fromSel = document.createElement('select');
205 fromSel.className = 'bkbg-cc-select';
206 buildSelectOptions(fromSel, fromCur);
207 fromRow.appendChild(fromLabel);
208 fromRow.appendChild(fromSel);
209 card.appendChild(fromRow);
210
211 /* Result box */
212 var resultBox = document.createElement('div');
213 resultBox.className = 'bkbg-cc-result';
214 resultBox.style.cssText = 'background:' + resultBg + ';border:1.5px solid ' + resultBdr + ';border-radius:' + cRadius;
215 var resLabel = document.createElement('div');
216 resLabel.className = 'bkbg-cc-result-label';
217 var resNum = document.createElement('div');
218 resNum.className = 'bkbg-cc-result-num';
219 resNum.style.color = resultClr;
220 var resRate = document.createElement('div');
221 resRate.className = 'bkbg-cc-result-rate';
222 resultBox.appendChild(resLabel);
223 resultBox.appendChild(resNum);
224 resultBox.appendChild(resRate);
225 card.appendChild(resultBox);
226
227 /* Disclaimer */
228 if (opts.showDisclaimer && opts.disclaimer) {
229 var dis = document.createElement('p');
230 dis.className = 'bkbg-cc-disclaimer';
231 dis.textContent = opts.disclaimer;
232 card.appendChild(dis);
233 }
234
235 /* ── Update result ──────────────────────────────────────────────── */
236 function updateResult() {
237 var amt = parseFloat(amtInput.value) || 0;
238 var fr = fromSel.value;
239 var to = toSel.value;
240 var res = convert(amt, fr, to);
241 var rate = convert(1, fr, to);
242 resLabel.textContent = amt + ' ' + fr + ' equals';
243 resNum.textContent = fmtNum(res) + ' ' + to;
244 resRate.textContent = '1 ' + fr + ' = ' + fmtNum(rate) + ' ' + to;
245 /* update quick pair active state */
246 if (pairsDiv) {
247 pairsDiv.querySelectorAll('.bkbg-cc-pair-btn').forEach(function (btn) {
248 var active = btn.dataset.from === fr && btn.dataset.to === to;
249 btn.classList.toggle('active', active);
250 btn.style.background = active ? accent : pairBg;
251 btn.style.color = active ? '#fff' : pairColor;
252 });
253 }
254 }
255
256 /* ── Quick pairs buttons ────────────────────────────────────────── */
257 if (pairsDiv && quickPairs.length) {
258 quickPairs.forEach(function (pair) {
259 var btn = document.createElement('button');
260 btn.className = 'bkbg-cc-pair-btn';
261 btn.dataset.from = pair[0];
262 btn.dataset.to = pair[1];
263 btn.textContent = pair[0] + '/' + pair[1];
264 btn.style.background = (pair[0] === fromCur && pair[1] === toCur) ? accent : pairBg;
265 btn.style.color = (pair[0] === fromCur && pair[1] === toCur) ? '#fff' : pairColor;
266 btn.addEventListener('click', function () {
267 fromSel.value = pair[0];
268 toSel.value = pair[1];
269 updateResult();
270 });
271 pairsDiv.appendChild(btn);
272 });
273 }
274
275 /* ── Swap ─────────────────────────────────────────────────────── */
276 if (swapBtn) {
277 swapBtn.addEventListener('click', function () {
278 var tmp = fromSel.value;
279 fromSel.value = toSel.value;
280 toSel.value = tmp;
281 updateResult();
282 });
283 }
284
285 /* ── Events ───────────────────────────────────────────────────── */
286 amtInput.addEventListener('input', updateResult);
287 fromSel.addEventListener('change', updateResult);
288 toSel.addEventListener('change', updateResult);
289
290 /* Initial render */
291 updateResult();
292 }
293
294 /* ── Init all instances ───────────────────────────────────────────── */
295 document.querySelectorAll('.bkbg-cc-app').forEach(buildApp);
296 })();
297