/**
* 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 =
'
Enter Value '
+ '
'
+ 'Calculate '
+ '
';
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 = 'Amount
'
+ ''
+ ''
+ 'Calculate GST '
+ '
';
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 = 'Annual Salary
'
+ 'Section 80C Deductions
'
+ 'Section 80D (Health Insurance)
'
+ 'Calculate TDS '
+ '
';
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 = ''
+ ''
+ ''
+ 'Calculate SIP '
+ '
';
['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; iTotal Invested '+fi(ti)+' '
+ 'Expected Amount '+fi(c)+'
'
+ 'Total Returns '+fi(ret)+'
';
};
}
},
'emi-calculator': {
render: function(c) {
c.innerHTML = ''
+ ''
+ ''
+ 'Calculate EMI '
+ '
';
['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 = ''
+ ''
+ 'Calculate Salary '
+ '
';
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 = ''
+ ''
+ 'Calculate PPF '
+ '
';
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; yTotal Invested '+fi(total)+' '
+ 'Maturity Amount '+fi(corpus)+'
'
+ 'Interest Earned '+fi(corpus-total)+'
';
};
}
},
'epf-calculator': {
render: function(c) {
c.innerHTML = 'Monthly Salary (Basic+DA)
'
+ ''
+ 'Calculate EPF '
+ '
';
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; mTotal Contributions '+fi(ti)+' '
+ 'EPF Corpus '+fi(c)+'
'
+ 'Interest Earned '+fi(c-ti)+'
';
};
}
},
'mutual-fund-calculator': {
render: function(c) {
c.innerHTML = ''
+ ''
+ ''
+ 'Calculate '
+ '
';
['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 = 'Text or URL
'
+ 'Generate QR '
+ '
';
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 = ' ';
};
}
},
'password-generator': {
render: function(c) {
c.innerHTML = 'Length: 12
'
+ ''
+ ' A-Z '
+ ' a-z '
+ ' 0-9 '
+ ' !@#$ '
+ '
'
+ 'Generate Password '
+ '
';
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'+pw+''
+ ''
+ ''+label+' ('+entropy.toFixed(0)+' bits)
';
};
}
},
'bmi-calculator': {
render: function(c) {
c.innerHTML = ''
+ ''
+ 'Calculate BMI '
+ '
';
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 = ''
+ '
'
+ '
'
+ '
'
+ '
'
+ '
'+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 = 'Date of Birth
'
+ 'Calculate Age '
+ '
';
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 = 'You have been alive for '+fn(totalD)+' days
';
};
}
},
'case-converter': {
render: function(c) {
c.innerHTML = '
'
+ ''
+ 'UPPERCASE '
+ 'lowercase '
+ 'Title Case '
+ 'Sentence case '
+ 'tOGGLE cASE '
+ '
'
+ '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 = 'Category '
+ Object.keys(units).map(function(k){return ''+k+' ';}).join('')
+ '
'
+ 'From
'
+ 'Value
'
+ 'To
'
+ '';
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 += ''+x.l+' '; t.innerHTML += ''+x.l+' '; });
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 = 'UPI ID
'
+ 'Name
'
+ 'Amount (Rs)
'
+ 'Generate UPI Link '
+ '
';
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 = ''
+ ''+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);
}
});
})();