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 / percentage-calculator / frontend.js

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

278 lines 11.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
4 var _typoKeys = {
5 family: '-ff', sizeDesktop: '-fs', sizeTablet: '-fs-tab', sizeMobile: '-fs-mob',
6 weight: '-fw', style: '-fst', decoration: '-td', transform: '-tt',
7 letterSpacing: '-ls', lineHeight: '-lh'
8 };
9 function typoCssVarsForEl(el, obj, prefix) {
10 if (!obj) return;
11 Object.keys(_typoKeys).forEach(function (k) {
12 var v = obj[k]; if (v === undefined || v === '') return;
13 var u = (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile')
14 ? (String(v).match(/[a-z%]/i) ? v : v + 'px')
15 : (k === 'lineHeight' ? String(v) : v);
16 el.style.setProperty(prefix + _typoKeys[k], u);
17 });
18 }
19
20 function fmtNum(n, dp) {
21 if (isNaN(n) || !isFinite(n)) return '';
22 var fixed = parseFloat(n.toFixed(dp !== undefined ? dp : 4));
23 return fixed.toLocaleString('en-US', { maximumFractionDigits: dp !== undefined ? dp : 4 });
24 }
25
26 function buildApp(app) {
27 var opts = {};
28 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch (e) {}
29
30 var accent = opts.accentColor || '#6c3fb5';
31 var cardBg = opts.cardBg || '#ffffff';
32 var tabActBg = opts.tabActiveBg || accent;
33 var tabActClr = opts.tabActiveColor || '#ffffff';
34 var tabInaBg = opts.tabInactiveBg || '#f3f4f6';
35 var tabInaClr = opts.tabInactiveColor|| '#374151';
36 var resultBg = opts.resultBg || '#f5f3ff';
37 var resultBdr = opts.resultBorder || '#ede9fe';
38 var resultClr = opts.resultColor || accent;
39 var titleClr = opts.titleColor || '#1e1b4b';
40 var subClr = opts.subtitleColor || '#6b7280';
41 var labelClr = opts.labelColor || '#374151';
42 var cRadius = (opts.cardRadius !== undefined ? opts.cardRadius : 16) + 'px';
43 var tRadius = (opts.tabRadius !== undefined ? opts.tabRadius : 99) + 'px';
44 var iRadius = (opts.inputRadius !== undefined ? opts.inputRadius: 8) + 'px';
45 var maxW = (opts.maxWidth || 600) + 'px';
46 var ptop = (opts.paddingTop !== undefined ? opts.paddingTop : 60) + 'px';
47 var pbot = (opts.paddingBottom!== undefined ? opts.paddingBottom : 60) + 'px';
48
49 var TABS = [
50 opts.mode1Label || '% of Number',
51 opts.mode2Label || 'Find %',
52 opts.mode3Label || '% Change',
53 ];
54
55 var currentMode = 0;
56
57 /* Card */
58 var card = document.createElement('div');
59 card.className = 'bkbg-pct-card';
60 card.style.cssText = [
61 'background:' + cardBg,
62 'border-radius:' + cRadius,
63 'padding-top:' + ptop,
64 'padding-bottom:' + pbot,
65 'padding-left:32px',
66 'padding-right:32px',
67 'max-width:' + maxW,
68 'margin:0 auto',
69 ].join(';');
70 app.innerHTML = '';
71 app.appendChild(card);
72
73 /* Title */
74 if (opts.showTitle !== false && opts.title) {
75 var h2 = document.createElement('h2');
76 h2.className = 'bkbg-pct-title';
77 h2.style.color = titleClr;
78 typoCssVarsForEl(h2, opts.titleTypo, '--bkbg-pct-title');
79 h2.textContent = opts.title;
80 card.appendChild(h2);
81 }
82
83 /* Subtitle */
84 if (opts.showSubtitle !== false && opts.subtitle) {
85 var sub = document.createElement('p');
86 sub.className = 'bkbg-pct-subtitle';
87 sub.style.color = subClr;
88 typoCssVarsForEl(sub, opts.subtitleTypo, '--bkbg-pct-subtitle');
89 sub.textContent = opts.subtitle;
90 card.appendChild(sub);
91 }
92
93 /* Tabs */
94 var tabsDiv = document.createElement('div');
95 tabsDiv.className = 'bkbg-pct-tabs';
96 card.appendChild(tabsDiv);
97
98 /* Input area */
99 var inputArea = document.createElement('div');
100 card.appendChild(inputArea);
101
102 /* Result */
103 var resultBox = document.createElement('div');
104 resultBox.className = 'bkbg-pct-result';
105 resultBox.style.cssText = 'background:' + resultBg + ';border:1.5px solid ' + resultBdr + ';border-radius:' + cRadius;
106 var resultFormula = document.createElement('div');
107 resultFormula.className = 'bkbg-pct-result-formula';
108 var resultNum = document.createElement('div');
109 resultNum.className = 'bkbg-pct-result-num';
110 resultNum.style.color = resultClr;
111 typoCssVarsForEl(resultNum, opts.resultTypo, '--bkbg-pct-result');
112 resultNum.textContent = '';
113 var resultDir = document.createElement('div');
114 resultDir.className = 'bkbg-pct-result-dir';
115 resultDir.style.display = 'none';
116 resultBox.appendChild(resultFormula);
117 resultBox.appendChild(resultNum);
118 resultBox.appendChild(resultDir);
119 card.appendChild(resultBox);
120
121 /* ── Input builders ─────────────────────────────────────────────── */
122 function mkInput(placeholder) {
123 var inp = document.createElement('input');
124 inp.type = 'number';
125 inp.className = 'bkbg-pct-input';
126 inp.placeholder = placeholder;
127 inp.step = 'any';
128 inp.style.cssText = 'border-radius:' + iRadius;
129 return inp;
130 }
131
132 function mkLabel(text) {
133 var lbl = document.createElement('label');
134 lbl.className = 'bkbg-pct-label';
135 lbl.style.color = labelClr;
136 lbl.textContent = text;
137 return lbl;
138 }
139
140 function mkSep(text) {
141 var s = document.createElement('span');
142 s.className = 'bkbg-pct-sep';
143 s.textContent = text;
144 return s;
145 }
146
147 var inputs = {};
148
149 function buildMode0() {
150 inputArea.innerHTML = '';
151 var row = document.createElement('div');
152 row.className = 'bkbg-pct-row';
153 var f1 = document.createElement('div'); f1.className = 'bkbg-pct-field shrink';
154 var pct = mkInput('25'); inputs.m0p = pct;
155 f1.appendChild(mkLabel('%'));
156 f1.appendChild(pct);
157 var f2 = document.createElement('div'); f2.className = 'bkbg-pct-field grow';
158 var num = mkInput('200'); inputs.m0n = num;
159 f2.appendChild(mkLabel('Number'));
160 f2.appendChild(num);
161 row.appendChild(f1);
162 row.appendChild(mkSep('% of'));
163 row.appendChild(f2);
164 inputArea.appendChild(row);
165 [pct, num].forEach(function (i) { i.addEventListener('input', compute); });
166 }
167
168 function buildMode1() {
169 inputArea.innerHTML = '';
170 var row = document.createElement('div');
171 row.className = 'bkbg-pct-row';
172 var f1 = document.createElement('div'); f1.className = 'bkbg-pct-field grow';
173 var x = mkInput('50'); inputs.m1x = x;
174 f1.appendChild(mkLabel('Value'));
175 f1.appendChild(x);
176 var f2 = document.createElement('div'); f2.className = 'bkbg-pct-field grow';
177 var y = mkInput('200'); inputs.m1y = y;
178 f2.appendChild(mkLabel('Total'));
179 f2.appendChild(y);
180 row.appendChild(f1);
181 row.appendChild(mkSep('is _% of'));
182 row.appendChild(f2);
183 inputArea.appendChild(row);
184 [x, y].forEach(function (i) { i.addEventListener('input', compute); });
185 }
186
187 function buildMode2() {
188 inputArea.innerHTML = '';
189 var row = document.createElement('div');
190 row.className = 'bkbg-pct-row';
191 var f1 = document.createElement('div'); f1.className = 'bkbg-pct-field grow';
192 var x = mkInput('100'); inputs.m2x = x;
193 f1.appendChild(mkLabel('From'));
194 f1.appendChild(x);
195 var f2 = document.createElement('div'); f2.className = 'bkbg-pct-field grow';
196 var y = mkInput('150'); inputs.m2y = y;
197 f2.appendChild(mkLabel('To'));
198 f2.appendChild(y);
199 row.appendChild(f1);
200 row.appendChild(mkSep(''));
201 row.appendChild(f2);
202 inputArea.appendChild(row);
203 [x, y].forEach(function (i) { i.addEventListener('input', compute); });
204 }
205
206 function compute() {
207 var result, formula, dir = null;
208 if (currentMode === 0) {
209 var p = parseFloat(inputs.m0p && inputs.m0p.value) || 0;
210 var n = parseFloat(inputs.m0n && inputs.m0n.value) || 0;
211 result = (p / 100) * n;
212 formula = p + '% of ' + n + ' =';
213 } else if (currentMode === 1) {
214 var x1 = parseFloat(inputs.m1x && inputs.m1x.value);
215 var y1 = parseFloat(inputs.m1y && inputs.m1y.value);
216 result = (x1 / y1) * 100;
217 formula = x1 + ' is ___% of ' + y1;
218 } else {
219 var x2 = parseFloat(inputs.m2x && inputs.m2x.value);
220 var y2 = parseFloat(inputs.m2y && inputs.m2y.value);
221 result = ((y2 - x2) / Math.abs(x2)) * 100;
222 formula = 'Change from ' + x2 + ' to ' + y2;
223 if (!isNaN(result) && isFinite(result)) dir = result >= 0 ? 'increase' : 'decrease';
224 }
225
226 var valid = !isNaN(result) && isFinite(result);
227 var clr = dir ? (dir === 'increase' ? '#16a34a' : '#dc2626') : resultClr;
228
229 resultFormula.textContent = formula || '';
230 if (valid) {
231 if (currentMode === 0) resultNum.textContent = fmtNum(result, 4);
232 else if (currentMode === 1) resultNum.textContent = fmtNum(result, 2) + '%';
233 else resultNum.textContent = (result >= 0 ? '+' : '') + fmtNum(result, 2) + '%';
234 } else {
235 resultNum.textContent = '';
236 }
237 resultNum.style.color = clr;
238 if (dir) {
239 resultDir.style.display = 'block';
240 resultDir.style.color = clr;
241 resultDir.textContent = dir === 'increase' ? '▲ Increase' : '▼ Decrease';
242 } else {
243 resultDir.style.display = 'none';
244 }
245 }
246
247 /* ── Build tabs ─────────────────────────────────────────────────── */
248 var tabBtns = [];
249 TABS.forEach(function (label, idx) {
250 var btn = document.createElement('button');
251 btn.className = 'bkbg-pct-tab';
252 btn.textContent = label;
253 btn.style.cssText = 'border-radius:' + tRadius;
254 btn.style.background = idx === 0 ? tabActBg : tabInaBg;
255 btn.style.color = idx === 0 ? tabActClr : tabInaClr;
256 btn.addEventListener('click', function () {
257 currentMode = idx;
258 tabBtns.forEach(function (b, i) {
259 b.style.background = i === idx ? tabActBg : tabInaBg;
260 b.style.color = i === idx ? tabActClr : tabInaClr;
261 });
262 if (idx === 0) buildMode0();
263 else if (idx === 1) buildMode1();
264 else buildMode2();
265 compute();
266 });
267 tabBtns.push(btn);
268 tabsDiv.appendChild(btn);
269 });
270
271 /* Init */
272 buildMode0();
273 compute();
274 }
275
276 document.querySelectorAll('.bkbg-pct-app').forEach(buildApp);
277 })();
278