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

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

298 lines 14.2 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 BTNS = [
5 'MC','MR','MS','M+','M−',
6 '2nd','π','e','C','',
7 '','','√x','ʸ√x','1/x',
8 'sin','cos','tan','log','ln',
9 'sin⁻¹','cos⁻¹','tan⁻¹','10ˣ','',
10 '(',')', '%','÷','',
11 '7','8','9','×','',
12 '4','5','6','','',
13 '1','2','3','+','',
14 '±','0','.','=',''
15 ];
16
17 function initApp(app) {
18 var opts;
19 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch(e) { return; }
20
21 var _typoKeys = {
22 family:'font-family', weight:'font-weight', style:'font-style',
23 decoration:'text-decoration', transform:'text-transform',
24 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
25 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
26 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
27 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
28 };
29 function typoCssVarsForEl(el, obj, prefix) {
30 if (!obj || typeof obj !== 'object') return;
31 Object.keys(_typoKeys).forEach(function(k) {
32 var v = obj[k];
33 if (v === undefined || v === '' || v === null) return;
34 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
35 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
36 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
37 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
38 el.style.setProperty(prefix + _typoKeys[k], String(v));
39 });
40 }
41
42 var accent = opts.accentColor || '#6c3fb5';
43 var cardBg = opts.cardBg || '#1a1a2e';
44 var dispBg = opts.displayBg || '#0d0d1a';
45 var dispClr = opts.displayColor || '#ffffff';
46 var cardR = (opts.cardRadius || 20) + 'px';
47 var btnR = (opts.btnRadius || 10) + 'px';
48 var btnSz = (opts.btnSize || 15) + 'px';
49 var dispSz = (opts.displaySize || 36) + 'px';
50 var maxW = (opts.maxWidth || 420) + 'px';
51 var ptop = (opts.paddingTop || 60) + 'px';
52 var pbot = (opts.paddingBottom|| 60) + 'px';
53 var histMax = opts.historyMax || 10;
54 var prec = opts.precision || 10;
55
56 var display = '0';
57 var expr = '';
58 var memory = 0;
59 var angleMode = opts.angleMode || 'deg';
60 var history = [];
61
62 app.style.paddingTop = ptop;
63 app.style.paddingBottom = pbot;
64 if (opts.sectionBg) app.style.background = opts.sectionBg;
65 typoCssVarsForEl(app, opts.titleTypo, '--bksc-tt-');
66 typoCssVarsForEl(app, opts.subtitleTypo, '--bksc-st-');
67
68 /* Header */
69 if (opts.showTitle && opts.title) {
70 var hdr = document.createElement('div');
71 hdr.className = 'bkbg-sc-header';
72 var ttl = document.createElement('div');
73 ttl.className = 'bkbg-sc-title';
74 ttl.textContent = opts.title;
75 if (opts.titleColor) ttl.style.color = opts.titleColor;
76 hdr.appendChild(ttl);
77 if (opts.showSubtitle && opts.subtitle) {
78 var sub = document.createElement('div');
79 sub.className = 'bkbg-sc-subtitle';
80 sub.textContent = opts.subtitle;
81 if (opts.subtitleColor) sub.style.color = opts.subtitleColor;
82 hdr.appendChild(sub);
83 }
84 app.appendChild(hdr);
85 }
86
87 /* Calc body */
88 var calc = document.createElement('div');
89 calc.className = 'bkbg-sc-calc';
90 Object.assign(calc.style, {background:cardBg, borderRadius:cardR, maxWidth:maxW});
91 app.appendChild(calc);
92
93 /* Top bar */
94 var topbar = document.createElement('div');
95 topbar.className = 'bkbg-sc-topbar';
96 calc.appendChild(topbar);
97
98 var angleToggle = document.createElement('div');
99 angleToggle.className = 'bkbg-sc-angle-toggle';
100 ['deg','rad'].forEach(function(m) {
101 var b = document.createElement('button');
102 b.className = 'bkbg-sc-angle-btn';
103 b.textContent = m.toUpperCase();
104 b.dataset.mode = m;
105 b.addEventListener('click', function() {
106 angleMode = m;
107 angleToggle.querySelectorAll('.bkbg-sc-angle-btn').forEach(function(x){
108 var active = x.dataset.mode === angleMode;
109 x.style.background = active ? accent : 'rgba(255,255,255,.1)';
110 x.style.color = active ? '#fff' : 'rgba(255,255,255,.5)';
111 });
112 });
113 b.style.background = m === angleMode ? accent : 'rgba(255,255,255,.1)';
114 b.style.color = m === angleMode ? '#fff' : 'rgba(255,255,255,.5)';
115 angleToggle.appendChild(b);
116 });
117 topbar.appendChild(angleToggle);
118
119 var memEl = document.createElement('div');
120 memEl.className = 'bkbg-sc-mem-indicator';
121 if (opts.memColor) memEl.style.color = opts.memColor;
122 if (opts.showMemory !== false) topbar.appendChild(memEl);
123
124 /* Expression */
125 var exprEl = document.createElement('div');
126 exprEl.className = 'bkbg-sc-expr';
127 calc.appendChild(exprEl);
128
129 /* Display */
130 var dispEl = document.createElement('div');
131 dispEl.className = 'bkbg-sc-display';
132 Object.assign(dispEl.style, {background:dispBg, color:dispClr, fontSize:dispSz});
133 dispEl.textContent = '0';
134 calc.appendChild(dispEl);
135
136 /* Button grid */
137 var grid = document.createElement('div');
138 grid.className = 'bkbg-sc-grid';
139 calc.appendChild(grid);
140
141 /* History */
142 var histEl, histList;
143 if (opts.showHistory !== false) {
144 histEl = document.createElement('div');
145 histEl.className = 'bkbg-sc-history';
146 histEl.style.display = 'none';
147 if (opts.historyBg) histEl.style.background = opts.historyBg;
148 var hLabel = document.createElement('div');
149 hLabel.className = 'bkbg-sc-history-label';
150 hLabel.textContent = 'History';
151 histEl.appendChild(hLabel);
152 histList = document.createElement('div');
153 histEl.appendChild(histList);
154 calc.appendChild(histEl);
155 }
156
157 /* State update functions */
158 function updateDisplay() {
159 dispEl.textContent = display;
160 exprEl.textContent = expr || '\u00a0';
161 if (opts.showMemory !== false) memEl.textContent = memory !== 0 ? 'M: ' + memory : '';
162 }
163
164 function addHistory(entry) {
165 if (!histEl) return;
166 history.unshift({expr:entry});
167 if (history.length > histMax) history.pop();
168 histList.innerHTML = '';
169 history.forEach(function(h) {
170 var row = document.createElement('div');
171 row.className = 'bkbg-sc-history-entry';
172 if (opts.historyColor) row.style.color = opts.historyColor;
173 row.textContent = h.expr;
174 row.addEventListener('click', function(){
175 var parts = h.expr.split('=');
176 if (parts.length > 1) { display = parts[parts.length-1]; updateDisplay(); }
177 });
178 histList.appendChild(row);
179 });
180 histEl.style.display = 'block';
181 }
182
183 function evaluateExpr(e) {
184 try {
185 var toRad = function(v){ return angleMode==='deg' ? v*Math.PI/180 : v; };
186 var safe = e
187 .replace(/×/g,'*').replace(/÷/g,'/')
188 .replace(//g,'-').replace(/π/g,'('+Math.PI+')')
189 .replace(/\be\b/g,'('+Math.E+')');
190 var r = Function('"use strict"; return (' + safe + ')')();
191 if (!isFinite(r)) return 'Error';
192 return (parseFloat(r.toPrecision(prec))).toString();
193 } catch(err) { return 'Error'; }
194 }
195
196 function handleBtn(lbl) {
197 if (lbl === '') return;
198 var num = parseFloat(display) || 0;
199 var toRad = function(v){ return angleMode==='deg' ? v*Math.PI/180 : v; };
200 var fromRad = function(v){ return angleMode==='deg' ? v*180/Math.PI : v; };
201 var p = function(v){ return (parseFloat(v.toPrecision(prec))+''); };
202
203 if (lbl === 'C') { display='0'; expr=''; updateDisplay(); return; }
204 if (lbl === '') { display=display.length>1?display.slice(0,-1):'0'; updateDisplay(); return; }
205 if (lbl === '±') { display=display.startsWith('-')?display.slice(1):('-'+display); updateDisplay(); return; }
206 if (lbl === 'π') { display=p(Math.PI); updateDisplay(); return; }
207 if (lbl === 'e') { display=p(Math.E); updateDisplay(); return; }
208 if (lbl === '=') {
209 var full = expr + display;
210 var res = evaluateExpr(full);
211 if (opts.showHistory !== false) addHistory(full + ' = ' + res);
212 expr=''; display=res; updateDisplay(); return;
213 }
214 if (lbl === 'MC') { memory=0; updateDisplay(); return; }
215 if (lbl === 'MR') { display=memory.toString(); updateDisplay(); return; }
216 if (lbl === 'MS') { memory=num; updateDisplay(); return; }
217 if (lbl === 'M+') { memory+=num; updateDisplay(); return; }
218 if (lbl === 'M−') { memory-=num; updateDisplay(); return; }
219 if (lbl === '2nd') return; // shift handled visually
220
221 var UNARY = {
222 '': function(v){ return p(v*v); },
223 '√x': function(v){ return p(Math.sqrt(v)); },
224 '1/x': function(v){ return p(1/v); },
225 'sin': function(v){ return p(Math.sin(toRad(v))); },
226 'cos': function(v){ return p(Math.cos(toRad(v))); },
227 'tan': function(v){ return p(Math.tan(toRad(v))); },
228 'sin⁻¹': function(v){ return p(fromRad(Math.asin(v))); },
229 'cos⁻¹': function(v){ return p(fromRad(Math.acos(v))); },
230 'tan⁻¹': function(v){ return p(fromRad(Math.atan(v))); },
231 'log': function(v){ return p(Math.log10(v)); },
232 'ln': function(v){ return p(Math.log(v)); },
233 '10ˣ': function(v){ return p(Math.pow(10,v)); },
234 '': function(v){ return p(Math.exp(v)); },
235 '%': function(v){ return p(v/100); }
236 };
237 if (UNARY[lbl]) { display=UNARY[lbl](num); updateDisplay(); return; }
238
239 var OPS = ['+','','×','÷','','ʸ√x'];
240 if (OPS.includes(lbl)) { expr=expr+display+lbl; display='0'; updateDisplay(); return; }
241 if (lbl==='('||lbl===')') { expr+=lbl; updateDisplay(); return; }
242
243 // Digits and decimal
244 if (display==='0'||display==='Error') { display=lbl; }
245 else { if (lbl==='.'&&display.includes('.')) return; display+=lbl; }
246 updateDisplay();
247 }
248
249 /* Create buttons */
250 function getBtnClass(lbl) {
251 if (lbl==='=') return 'bkbg-sc-btn bkbg-sc-btn-eq';
252 if (lbl==='C'||lbl==='') return 'bkbg-sc-btn bkbg-sc-btn-clear';
253 if (['MC','MR','MS','M+','M−'].includes(lbl)) return 'bkbg-sc-btn bkbg-sc-btn-mem';
254 if (['+','','×','÷','%','','ʸ√x','(',')'].includes(lbl)) return 'bkbg-sc-btn bkbg-sc-btn-op';
255 if (['0','1','2','3','4','5','6','7','8','9','.','±'].includes(lbl)) return 'bkbg-sc-btn bkbg-sc-btn-num';
256 return 'bkbg-sc-btn bkbg-sc-btn-fn';
257 }
258 function getBtnStyle(lbl) {
259 var s = {fontSize:btnSz, borderRadius:btnR};
260 if (lbl==='=') { s.background=opts.btnEqBg||accent; s.color=opts.btnEqColor||'#fff'; }
261 else if (lbl==='C'||lbl==='') { s.background=opts.btnClearBg||'#7f1d1d'; s.color=opts.btnClearColor||'#fecaca'; }
262 else if (['MC','MR','MS','M+','M−'].includes(lbl)){ s.background=opts.btnFnBg||'#1e2a4a'; s.color=opts.memColor||'#86efac'; }
263 else if (['+','','×','÷','%','','ʸ√x','(',')'].includes(lbl)){ s.background=opts.btnOpBg||'#3d2d6a'; s.color=opts.btnOpColor||'#c4b5fd'; }
264 else if (['0','1','2','3','4','5','6','7','8','9','.','±'].includes(lbl)){ s.background=opts.btnNumBg||'#2d2d4a'; s.color=opts.btnNumColor||'#fff'; }
265 else { s.background=opts.btnFnBg||'#1e2a4a'; s.color=opts.btnFnColor||'#93c5fd'; }
266 return s;
267 }
268
269 BTNS.forEach(function(lbl) {
270 if (lbl === '') { grid.appendChild(document.createElement('div')); return; }
271 var btn = document.createElement('button');
272 btn.className = getBtnClass(lbl);
273 btn.textContent = lbl;
274 var st = getBtnStyle(lbl);
275 Object.assign(btn.style, st);
276 btn.addEventListener('click', function(){ handleBtn(lbl); });
277 grid.appendChild(btn);
278 });
279
280 /* Keyboard support */
281 document.addEventListener('keydown', function(ev) {
282 if (!app.closest('body')) return;
283 var map = {
284 'Enter':'=','Backspace':'','Escape':'C',
285 '+':'+','-':'','*':'×','/':'÷','%':'%',
286 '(':'(', ')':')'
287 };
288 var key = ev.key;
289 if (map[key]) { ev.preventDefault(); handleBtn(map[key]); return; }
290 if (/^[0-9\.]$/.test(key)) { ev.preventDefault(); handleBtn(key); }
291 });
292
293 updateDisplay();
294 }
295
296 document.querySelectorAll('.bkbg-sc-app').forEach(initApp);
297 })();
298