/** * ToolsOfIndia.com — Tool Engine v4 (te.js) * Complete calculator logic for all tools + generic fallback * Exposes window.ToolEngine */ (function() { 'use strict'; // ─── Number formatting helpers ────────────────────────────────────────────── function fi(n) { if (n === null || n === undefined || isNaN(n)) return '0'; var neg = n < 0, abs = Math.abs(n).toFixed(2), p = abs.split('.'); var i = p[0], l3 = i.slice(-3), r = i.slice(0, -3); if (r) i = r.replace(/\B(?=(\d{2})+(?!\d))/g, ',') + ',' + l3; return (neg ? '-Rs ' : 'Rs ') + i + '.' + p[1]; } function fn(n) { if (!n && n !== 0) return '0'; return Math.round(n).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function fp(n) { return Number(n).toFixed(2) + '%'; } // ─── Generic / fallback calculator ────────────────────────────────────────── /** * renderTool — unified dispatcher. * If a specific calculator exists for the slug, use it. * Otherwise render a simple generic calculator (Enter Value → Calculate). */ function renderTool(slug, container) { if (tools[slug]) { tools[slug].render(container); return; } // Generic fallback: Enter Value → Calculate → Show formatted result var id = slug.replace(/[^a-z0-9-]/g, ''); container.innerHTML = '
' + '
' + '' + ''; document.getElementById('g-' + id + '-btn').onclick = function() { var v = parseFloat(document.getElementById('g-' + id + '-in').value) || 0; var r = document.getElementById('g-' + id + '-res'); r.style.display = 'block'; r.innerHTML = '
Value' + fi(v) + '
'; }; } // ─── All tool calculators ─────────────────────────────────────────────────── var tools = { 'gst-calculator': { render: function(c) { c.innerHTML = '
' + '
' + ['5','12','18','28'].map(function(v){return '';}).join('') + '
' + '
' + '' + '' + '
' + '' + ''; document.getElementById('gst-btn').onclick = function() { var amt = parseFloat(document.getElementById('gst-amt').value) || 0; var rate = parseFloat(document.querySelector('input[name="gst"]:checked').value) || 18; var type = document.querySelector('input[name="gst-type"]:checked').value; var gst, net, total; if (type === 'excl') { net = amt; gst = amt * rate / 100; total = amt + gst; } else { total = amt; gst = amt * rate / (100 + rate); net = amt - gst; } var r = document.getElementById('gst-res'); r.style.display = 'block'; r.innerHTML = '
Net Amount'+fi(net)+'
' + '
GST ('+rate+'%)'+fi(gst)+'
' + '
CGST (half)'+fi(gst/2)+'
' + '
SGST (half)'+fi(gst/2)+'
' + '
Total'+fi(total)+'
'; }; } }, 'tds-calculator': { render: function(c) { c.innerHTML = '
' + '
' + '
' + '' + ''; document.getElementById('tds-btn').onclick = function() { var sal = parseFloat(document.getElementById('tds-sal').value) || 0; var d80c = Math.min(parseFloat(document.getElementById('tds-80c').value) || 0, 150000); var d80d = Math.min(parseFloat(document.getElementById('tds-80d').value) || 0, 25000); var taxable = Math.max(0, sal - 50000 - d80c - d80d); var tax = 0; if (taxable > 10000000) tax = (taxable - 10000000) * 0.30 + 112500; else if (taxable > 5000000) tax = (taxable - 5000000) * 0.20 + 12500; else if (taxable > 250000) tax = (taxable - 250000) * 0.05; var cess = tax * 0.04; var total = tax + cess; document.getElementById('tds-res').style.display = 'block'; document.getElementById('tds-res').innerHTML = '
Gross Salary'+fi(sal)+'
' + '
Standard Deduction'+fi(50000)+'
' + '
Total Deductions'+fi(d80c+d80d)+'
' + '
Taxable Income'+fi(taxable)+'
' + '
Income Tax'+fi(tax)+'
' + '
Health & Edu Cess (4%)'+fi(cess)+'
' + '
Total TDS'+fi(total)+'
' + '
Monthly TDS'+fi(total/12)+'
'; }; } }, 'sip-calculator': { render: function(c) { c.innerHTML = '
1005,0001,00,000
' + '
1%12%30%
' + '
11040
' + '' + ''; ['amt','ret','yr'].forEach(function(k){ document.getElementById('sip-'+k).oninput = function(){ var v = this.value; if(k==='amt') document.getElementById('sip-amt-v').textContent = Number(v).toLocaleString('en-IN'); else document.getElementById('sip-'+k+'-v').textContent = v + (k==='yr'?' yrs':'%'); }; }); document.getElementById('sip-btn').onclick = function() { var m = parseFloat(document.getElementById('sip-amt').value) || 0; var r = (parseFloat(document.getElementById('sip-ret').value) || 0) / 12 / 100; var y = parseInt(document.getElementById('sip-yr').value) || 0; var c = 0, ti = 0; for(var i=0; i' + '
Expected Amount'+fi(c)+'
' + '
Total Returns'+fi(ret)+'
'; }; } }, 'emi-calculator': { render: function(c) { c.innerHTML = '
10K50,00,0001Cr
' + '
1%8.5%25%
' + '
12040
' + '' + ''; ['p','r','n'].forEach(function(k){ document.getElementById('emi-'+k).oninput = function(){ var v = this.value; var el = document.getElementById('emi-'+k+'-v'); if(k==='p') el.textContent = Number(v).toLocaleString('en-IN'); else if(k==='r') el.textContent = v+'%'; else el.textContent = v; }; }); document.getElementById('emi-btn').onclick = function() { var P = parseFloat(document.getElementById('emi-p').value) || 0; var ar = parseFloat(document.getElementById('emi-r').value) || 0; var N = (parseInt(document.getElementById('emi-n').value) || 1) * 12; var mr = ar / 12 / 100; var emi = P * mr * Math.pow(1+mr,N) / (Math.pow(1+mr,N)-1); if(ar===0) emi = P/N; var tp = emi * N, ti = tp - P; document.getElementById('emi-res').style.display = 'block'; document.getElementById('emi-res').innerHTML = '
'+fi(emi)+'/month
' + '
Monthly EMI
' + '
Loan Amount'+fi(P)+'
' + '
Total Interest'+fi(ti)+'
' + '
Total Payment'+fi(tp)+'
'; }; } }, 'salary-calculator': { render: function(c) { c.innerHTML = '
1.2L12,00,00050L
' + '
30%40%60%
' + '' + ''; document.getElementById('sal-ctc').oninput = function(){ document.getElementById('sal-ctc-v').textContent = Number(this.value).toLocaleString('en-IN'); }; document.getElementById('sal-basic').oninput = function(){ document.getElementById('sal-basic-v').textContent = this.value+'%'; }; document.getElementById('sal-btn').onclick = function() { var ctc = parseFloat(document.getElementById('sal-ctc').value) || 0; var bp = (parseFloat(document.getElementById('sal-basic').value) || 40) / 100; var basic = ctc * bp; var hra = basic * 0.5; var pf = Math.min(basic * 0.12, 1500*12); var gratuity = basic * 0.0481; var profTax = ctc > 600000 ? 2500 : 1800; var taxable = ctc - 50000 - pf; var tax = 0; if(taxable > 500000) tax = (taxable-500000)*0.20 + 12500; else if(taxable > 250000) tax = (taxable-250000)*0.05; tax = tax * 1.04; var ded = pf + profTax + tax; var inhand = (ctc - ded) / 12; document.getElementById('sal-res').style.display = 'block'; document.getElementById('sal-res').innerHTML = '
'+fi(inhand)+'/month
' + '
Monthly In-Hand
' + '
CTC'+fi(ctc)+'
' + '
Basic'+fi(basic)+'
' + '
HRA'+fi(hra)+'
' + '
PF'+fi(pf)+'
' + '
Gratuity'+fi(gratuity)+'
' + '
Professional Tax'+fi(profTax)+'
' + '
Income Tax'+fi(tax)+'
' + '
Annual In-Hand'+fi(ctc-ded)+'
'; }; } }, 'ppf-calculator': { render: function(c) { c.innerHTML = '
50050,0001.5L
' + '
151530
' + '' + ''; document.getElementById('ppf-amt').oninput = function(){ document.getElementById('ppf-amt-v').textContent = Number(this.value).toLocaleString('en-IN'); }; document.getElementById('ppf-yr').oninput = function(){ document.getElementById('ppf-yr-v').textContent = this.value; }; document.getElementById('ppf-btn').onclick = function() { var yr = parseInt(document.getElementById('ppf-yr').value) || 15; var amt = parseFloat(document.getElementById('ppf-amt').value) || 0; var rate = 0.071, total = 0, corpus = 0; for(var y=0; y' + '
Maturity Amount'+fi(corpus)+'
' + '
Interest Earned'+fi(corpus-total)+'
'; }; } }, 'epf-calculator': { render: function(c) { c.innerHTML = '
' + '
12040
' + '' + ''; document.getElementById('epf-yr').oninput = function(){ document.getElementById('epf-yr-v').textContent = this.value; }; document.getElementById('epf-btn').onclick = function() { var sal = parseFloat(document.getElementById('epf-sal').value) || 0; var yr = parseInt(document.getElementById('epf-yr').value) || 20; var mr = 0.0815/12, ee = sal*0.12, er = sal*0.12, c=0, ti=0; for(var m=0; m' + '
EPF Corpus'+fi(c)+'
' + '
Interest Earned'+fi(c-ti)+'
'; }; } }, 'mutual-fund-calculator': { render: function(c) { c.innerHTML = '
1K1,00,0005Cr
' + '
1%12%30%
' + '
11040
' + '' + ''; ['amt','ret','yr'].forEach(function(k){ document.getElementById('mf-'+k).oninput = function(){ var v = this.value; if(k==='amt') document.getElementById('mf-amt-v').textContent = Number(v).toLocaleString('en-IN'); else document.getElementById('mf-'+k+'-v').textContent = v + (k==='yr'?' yrs':'%'); }; }); document.getElementById('mf-btn').onclick = function() { var p = parseFloat(document.getElementById('mf-amt').value) || 0; var r = (parseFloat(document.getElementById('mf-ret').value) || 0) / 100; var y = parseInt(document.getElementById('mf-yr').value) || 0; var a = p * Math.pow(1+r, y); document.getElementById('mf-res').style.display = 'block'; document.getElementById('mf-res').innerHTML = '
Invested Amount'+fi(p)+'
' + '
Expected Amount'+fi(a)+'
' + '
Total Returns'+fi(a-p)+'
' + '
CAGR'+fp(r*100)+'
'; }; } }, 'qr-generator': { render: function(c) { c.innerHTML = '
' + '' + ''; document.getElementById('qr-btn').onclick = function() { var txt = encodeURIComponent(document.getElementById('qr-txt').value || 'https://toolsofindia.com'); var url = 'https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl='+txt; document.getElementById('qr-res').style.display = 'block'; document.getElementById('qr-res').innerHTML = 'QR Code'; }; } }, 'password-generator': { render: function(c) { c.innerHTML = '
' + '
' + '' + '' + '' + '' + '
' + '' + ''; document.getElementById('pw-len').oninput = function(){ document.getElementById('pw-len-v').textContent = this.value; }; document.getElementById('pw-btn').onclick = function() { var len = parseInt(document.getElementById('pw-len').value) || 12; var chars = ''; if(document.getElementById('pw-upper').checked) chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; if(document.getElementById('pw-lower').checked) chars += 'abcdefghijklmnopqrstuvwxyz'; if(document.getElementById('pw-num').checked) chars += '0123456789'; if(document.getElementById('pw-sym').checked) chars += '!@#$%^&*()_+-=[]{}|;:,.<>?'; if(!chars) chars = 'abcdefghijklmnopqrstuvwxyz'; var pw = ''; for(var i=0; i' + '
' + '
'+label+' ('+entropy.toFixed(0)+' bits)
'; }; } }, 'bmi-calculator': { render: function(c) { c.innerHTML = '
100170250
' + '
2070200
' + '' + ''; document.getElementById('bmi-h').oninput = function(){ document.getElementById('bmi-h-v').textContent = this.value; }; document.getElementById('bmi-w').oninput = function(){ document.getElementById('bmi-w-v').textContent = this.value; }; document.getElementById('bmi-btn').onclick = function() { var h = (parseFloat(document.getElementById('bmi-h').value) || 170) / 100; var w = parseFloat(document.getElementById('bmi-w').value) || 70; var bmi = w / (h * h); var cat = bmi < 18.5 ? 'Underweight' : bmi < 25 ? 'Normal' : bmi < 30 ? 'Overweight' : 'Obese'; var col = bmi < 18.5 ? '#3b82f6' : bmi < 25 ? '#10b981' : bmi < 30 ? '#f59e0b' : '#ef4444'; document.getElementById('bmi-res').style.display = 'block'; document.getElementById('bmi-res').innerHTML = '
'+bmi.toFixed(1)+'
' + '
'+cat+'
' + '
Ideal: '+(18.5*h*h).toFixed(1)+' - '+(24.9*h*h).toFixed(1)+' kg
'; }; } }, 'word-counter': { render: function(c) { c.innerHTML = '
' + '
'; document.getElementById('wc-txt').oninput = function() { var t = this.value; var words = t.trim() ? t.trim().split(/\s+/).length : 0; var chars = t.length; var charsNoSpace = t.replace(/\s/g,'').length; var sentences = t.split(/[.!?]+/).filter(function(s){return s.trim().length>0;}).length; var paras = t.split(/\n\s*\n/).filter(function(p){return p.trim().length>0;}).length; document.getElementById('wc-res').innerHTML = '
' + '
'+words+'
Words
' + '
'+chars+'
Characters
' + '
'+sentences+'
Sentences
' + '
'+paras+'
Paragraphs
' + '
'+charsNoSpace+'
Chars (no space)
' + '
'+Math.ceil(words/200)+'
Read (min)
' + '
'; }; } }, 'age-calculator': { render: function(c) { var today = new Date(); var defY = today.getFullYear()-25, defM = String(today.getMonth()+1).padStart(2,'0'), defD = String(today.getDate()).padStart(2,'0'); c.innerHTML = '
' + '' + ''; document.getElementById('age-btn').onclick = function() { var dob = new Date(document.getElementById('age-dob').value); if(isNaN(dob.getTime())) return; var now = new Date(); var y = now.getFullYear() - dob.getFullYear(); var m = now.getMonth() - dob.getMonth(); var d = now.getDate() - dob.getDate(); if(d < 0) { m--; d += new Date(now.getFullYear(), now.getMonth(), 0).getDate(); } if(m < 0) { y--; m += 12; } var totalD = Math.floor((now - dob) / (1000*60*60*24)); document.getElementById('age-res').style.display = 'block'; document.getElementById('age-res').innerHTML = '
' + '
'+y+'
Years
' + '
'+m+'
Months
' + '
'+d+'
Days
' + '
You have been alive for '+fn(totalD)+' days
'; }; } }, 'case-converter': { render: function(c) { c.innerHTML = '
' + '
' + '' + '' + '' + '' + '' + '
' + '
Characters: 0 | Words: 0
'; document.getElementById('cc-txt').oninput = function() { var t = this.value, w = t.trim() ? t.trim().split(/\s+/).length : 0; document.getElementById('cc-stats').textContent = 'Characters: '+t.length+' | Words: '+w; }; } }, 'unit-converter': { render: function(c) { var units = {Length:[{v:'m',l:'Meter'},{v:'km',l:'Kilometer'},{v:'cm',l:'Centimeter'},{v:'mm',l:'Millimeter'},{v:'ft',l:'Foot'},{v:'in',l:'Inch'}], Weight:[{v:'kg',l:'Kilogram'},{v:'g',l:'Gram'},{v:'lb',l:'Pound'},{v:'oz',l:'Ounce'}], Temperature:[{v:'c',l:'Celsius'},{v:'f',l:'Fahrenheit'},{v:'k',l:'Kelvin'}], Area:[{v:'sqm',l:'Sq Meter'},{v:'sqft',l:'Sq Foot'},{v:'acre',l:'Acre'},{v:'ha',l:'Hectare'}]}; var factors = {m:1,km:0.001,cm:100,mm:1000,ft:3.28084,in:39.3701,kg:1,g:1000,lb:2.20462,oz:35.274, sqm:1,sqft:10.7639,acre:0.000247105,ha:0.0001,c:1,f:1,k:1}; c.innerHTML = '
' + '
' + '
' + '
' + '
-
'; function pop(cat) { var u = units[cat] || []; var f = document.getElementById('uc-from'), t = document.getElementById('uc-to'); f.innerHTML = ''; t.innerHTML = ''; u.forEach(function(x,i){ f.innerHTML += ''; t.innerHTML += ''; }); if(u.length>1) t.value = u[1].v; convert(); } function convert() { var cat = document.getElementById('uc-cat').value; var from = document.getElementById('uc-from').value; var to = document.getElementById('uc-to').value; var v = parseFloat(document.getElementById('uc-val').value) || 0; if(cat === 'Temperature') { var cels = from==='c'?v:from==='f'?(v-32)*5/9:v-273.15; document.getElementById('uc-res').textContent = to==='c'?cels.toFixed(2):to==='f'?(cels*9/5+32).toFixed(2):(cels+273.15).toFixed(2); } else { document.getElementById('uc-res').textContent = (v * (factors[to]||1) / (factors[from]||1)).toFixed(6); } } document.getElementById('uc-cat').onchange = function(){ pop(this.value); }; document.getElementById('uc-from').onchange = convert; document.getElementById('uc-to').onchange = convert; document.getElementById('uc-val').oninput = convert; pop('Length'); } }, 'upi-link-generator': { render: function(c) { c.innerHTML = '
' + '
' + '
' + '' + ''; document.getElementById('upi-btn').onclick = function() { var id = document.getElementById('upi-id').value || 'name@upi'; var name = document.getElementById('upi-name').value || ''; var amt = document.getElementById('upi-amt').value || ''; var link = 'upi://pay?pa='+encodeURIComponent(id)+'&pn='+encodeURIComponent(name)+'&am='+amt+'&cu=INR'; var qr = 'https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl='+encodeURIComponent(link); document.getElementById('upi-res').style.display = 'block'; document.getElementById('upi-res').innerHTML = '
UPI QR
' + '
'+link+'
'; }; } } }; // ─── ToolEngine public API ─────────────────────────────────────────────────── var ToolEngine = { init: function(config) { config = config || window.__TOOL_CONFIG || {}; var slug = config.slug || ''; var container = document.getElementById('tool-container'); if (!container) { container = document.querySelector('.tool-container'); } if (!container) return; renderTool(slug, container); }, renderTool: renderTool, tools: tools }; window.ToolEngine = ToolEngine; // Auto-init on DOMContentLoaded if __TOOL_CONFIG is set document.addEventListener('DOMContentLoaded', function() { if (window.__TOOL_CONFIG) { ToolEngine.init(window.__TOOL_CONFIG); } }); })();