' + field + unitLabel + '
';
}).join('');
var primaryHTML = '';
if (primary.length > 0) {
var p = primary[0];
primaryHTML = '' + esc(p.label) + '
' +
'—' +
(p.unit ? ' ' + esc(p.unit) + '' : '') +
'
' + esc(p0.label) + '
' +
'—' +
(p0.unit ? ' ' + esc(p0.unit) + '' : '') +
'
' + secondary.map(function(o) {
return '';
}).join('') + '
';
}
var formulaHTML = cfg.formula_display
? '' + esc(o.label) + '
' +
'—
' +
(o.unit ? '' + esc(o.unit) + '
' : '') +
'' + esc(cfg.formula_display) + '
' : '';
var notesHTML = cfg.notes
? '' + esc(cfg.notes) + '
' : '';
return '' +
'
';
}
/* ---- Calculation runner ---- */
function runCalc(uid, cfg) {
var inputs = cfg.inputs || [];
var outputs = cfg.outputs || [];
var vars = {};
inputs.forEach(function(inp) {
var el = document.getElementById('prc_' + uid + '_' + inp.id);
if (!el) return;
vars[inp.id] = parseFloat(el.value);
if (isNaN(vars[inp.id])) vars[inp.id] = inp.default || 0;
});
outputs.forEach(function(out) {
var el = document.getElementById('prc_' + uid + '_out_' + out.id);
if (!el) return;
var result = evalFormula(out.formula, vars);
var precision = out.precision !== undefined ? out.precision : null;
var display;
if (isNaN(result) || !isFinite(result)) {
display = isFinite(result) ? '—' : (result > 0 ? '∞' : '-∞');
} else if (precision !== null) {
display = result.toFixed(precision);
} else {
// Smart formatting: strip unit from fmt() result
display = fmt(result);
}
el.textContent = display;
});
}
/* ---- Public API ---- */
window.PrcEngine = {
_configs: {},
calc: function(uid) {
var cfg = this._configs[uid];
if (cfg) runCalc(uid, cfg);
},
init: function(el) {
var cfg;
try { cfg = JSON.parse(el.getAttribute('data-config')); }
catch(e) { el.innerHTML = '' +
'
' +
'' + esc(cfg.title || 'Calculator') + '
' + (cfg.desc ? '' + esc(cfg.desc) + '
' : '') + '' +
'
' +
'' +
'
' +
'' +
'
' +
'Inputs
' +
inputsHTML +
'' +
'
' +
'Results
' +
primaryHTML +
secHTML +
formulaHTML +
notesHTML +
'Invalid calculator config
'; return; } var uid = 'c' + (++_uid); this._configs[uid] = cfg; el.innerHTML = buildUI(uid, cfg); runCalc(uid, cfg); } }; /* ---- Auto-init on DOMContentLoaded ---- */ function initAll() { document.querySelectorAll('.pr-calc-auto[data-config]').forEach(function(el) { PrcEngine.init(el); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAll); } else { initAll(); } /* ---- Extra CSS for engine-specific elements ---- */ var style = document.createElement('style'); style.textContent = [ '.pr-field { margin-bottom: 14px; }', '.pr-field label { display:block; font-size:.75em; color:var(--pr-muted); text-transform:uppercase; letter-spacing:.06em; margin-bottom:4px; }', '.pr-field-input { width:100%; background:var(--pr-bg); color:var(--pr-text); border:1px solid var(--pr-border); padding:8px 10px; font-family:var(--pr-mono); font-size:.95em; box-sizing:border-box; border-radius:0; }', '.pr-field-input:focus { border-color:var(--pr-accent); outline:none; }', 'select.pr-field-input option { background:var(--pr-surface); color:var(--pr-text); }', '.pr-field-unit { font-size:.75em; color:var(--pr-muted); margin-left:6px; }', '.pr-result-main { background:var(--pr-surface2); border:1px solid var(--pr-border); border-left:3px solid var(--pr-green); padding:16px; margin-bottom:10px; }', '.pr-result-main .label { font-size:.7em; color:var(--pr-muted); text-transform:uppercase; letter-spacing:.08em; margin-bottom:4px; }', '.pr-result-main .value { font-size:2.2em; color:var(--pr-green); font-family:var(--pr-mono); line-height:1.1; }', '.pr-result-main .unit { font-size:.85em; color:var(--pr-muted); margin-left:4px; }', '.pr-result-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:8px; margin-top:8px; }', '.pr-result-item { background:var(--pr-surface2); border:1px solid var(--pr-border); padding:10px 12px; }', '.pr-result-item .label { font-size:.68em; color:var(--pr-muted); text-transform:uppercase; letter-spacing:.06em; margin-bottom:2px; }', '.pr-result-item .value { font-size:1.15em; color:var(--pr-accent); font-family:var(--pr-mono); word-break:break-all; }', '.pr-formula { background:var(--pr-bg); border:1px solid var(--pr-border); border-left:3px solid var(--pr-muted); padding:10px 14px; font-size:.8em; color:var(--pr-muted); margin-top:12px; }', '.pr-note { font-size:.75em; color:var(--pr-muted); border-top:1px solid var(--pr-border); margin-top:12px; padding-top:10px; line-height:1.5; }', '.pr-calc-grid { display:grid; grid-template-columns:1fr 1fr; gap:28px; }', '@media(max-width:640px){ .pr-calc-grid { grid-template-columns:1fr; } }', ].join('\n'); document.head.appendChild(style); })();