User:TedSwippet/Interactive calculator

 "use strict";

var twr = { name: 'twr', fields: [ {id: 'l1tw',  label: 'L1TW:',  init: 3.9,  match:/^[\d\.]+%?$/, format: '{}%'}, {id: 'l2tw',  label: 'L2TW:',  init: 30,   match:/^[\d\.]+%?$/, format: '{}%'}, {id: 'yield', label: 'Yield:', init: 2,    match:/^[\d\.]+%?$/, format: '{}%'}, {id: 'ter',   label: 'TER:',   init: 0.08, match:/^[\d\.]+%?$/, format: '{}%'}, {id: 'result', label: 'TWR =', format: '{}%'} ], compute: function(v) { if (v.yield * (1 - v.l1tw/100) >= v.ter) v.result = (v.yield * v.l1tw/100) + ((v.yield * (1 - v.l1tw/100) - v.ter) * v.l2tw/100); else v.result = NaN; v.result = v.result.toFixed(4); } };

var calc = { styles: { field: 'border-style: solid; border-width: 1px; background-color: #ffffff', button: 'border-style: solid; border-width: 1px; background-color: #dcdcdc; padding: 4px; cursor: pointer' },

generate_table: function(name) { var models = calc._models, sequence = calc._sequence, namespace = calc._namespace;

var prefix = namespace + '-' + sequence + '-'; var invoke = namespace + ".calculate('" + prefix + "', '" + name + "')";

var fields = models[name].fields; var styles = calc.styles; var table = '[table id="' + prefix + 'table" class="wikitable"][tbody]' + '[tr]'; for (var field of fields) { if ('init' in field) { var init = field.format.replace('{}', field.init); table += '[td]' + field.label + ' ' + '[input type="text" style="' + styles.field + '" size="6" id="' + prefix + field.id + '"' + ' value="' + init + '" onchange="' + invoke + '" /]' + '[/td]'; }   }    field = fields[fields.length - 1]; table += '[/tr][tr]' + '[td][button style="' + styles.button + '" onclick="' + invoke + '"]Calculate[/button][/td]' + '[td]' + field.label + ' ' + '[input type="text" style="' + styles.field + '" size="6" id="' + prefix + field.id + '" readonly]' + '[/td]' + '[/tr]' + '[/tbody][/table]'; table = table.replace(/\[/g, '<').replace(/\]/g, '>'); if ('log' in calc) console.log(table); return table; },

calculate: function(prefix, name) { var models = calc._models, sequence = calc._sequence, namespace = calc._namespace;

var fields = models[name].fields;

function get_values { var values = {}; for (var field of fields) { var value = document.getElementById(prefix + field.id).value; if (value.trim.match(field.match)) values[field.id] = parseFloat(value); else values[field.id] = NaN; }     return values; }

function set_values(values) { for (var id in values) { var value = values[id]; for (var field of fields) { if (field.id == id) { if (!isNaN(value)) value = field.format.replace('{}', value); else value = 'Error!'; }       }        document.getElementById(prefix + id).value = value; }   }

var values = get_values; models[name].compute(values); if ('log' in calc) console.table(values); set_values(values); },

write: function(string) { var scripts = document.getElementsByTagName('script'); var this_script = scripts[scripts.length - 1]; this_script.insertAdjacentHTML('beforebegin', string); },

register: function(model, namespace) { if (!calc._models) calc._models = {}; calc._models[model.name] = model;

if (!calc._counter) calc._counter = 0; calc._sequence = ++calc._counter;

calc._namespace = namespace; calc.write(calc.generate_table(model.name)); } };

if ('calc_implementation' in window) calc = window.calc_implementation; else window.calc_implementation = calc;

calc.register(twr, 'calc'); {{Documentation|content= This template calculates a Tax Withholding Ratio (TWR) for an ETF when held by a US nonresident alien, from values entered into the page by the user. The definition of TWR is:

TWR = (Yield × L1TW) + ((Yield × (1 - L1TW) - TER) × L2TW)

Where:
 * L1TW: Percentage of tax withholding by a security's home country on dividends distributed by that security to the fund (Level 1).
 * L2TW: Percentage of tax withholding by the country where the fund is domiciled on the dividends distributed to the investor by the fund (Level 2).
 * Yield: Annual yield of the fund.
 * TER: The fund's Total Expense Ratio.

This template uses JavaScript to provide live in-page calculations. The computed TWR is updated on pressing the 'Calculate' button, or when the user changes any of the input values.

Usage
Invoke with:

This template takes no arguments. The default input values are currently hardcoded. This template may be transcluded multiple times on a single page.

Examples
}}