Added VAT calculator tool and applet, Cleaned up launch logs and DOM trash
Update .gitignore, vat-calculator.yml, and 17 more files...
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,5 +14,6 @@ node_modules/
|
|||||||
*.ai
|
*.ai
|
||||||
|
|
||||||
# Temp
|
# Temp
|
||||||
|
static/resources/DecimalJs*
|
||||||
static/resources/SortableJS
|
static/resources/SortableJS
|
||||||
static/resources/Standalone
|
static/resources/Standalone
|
||||||
|
7
data/applets/vat-calculator.yml
Normal file
7
data/applets/vat-calculator.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
applets:
|
||||||
|
- id: "vat-calculator"
|
||||||
|
resources:
|
||||||
|
scripts:
|
||||||
|
- "applet://vat-calculator.mjs"
|
||||||
|
stylesheets:
|
||||||
|
- "applet://vat-calculator.css"
|
@@ -14,3 +14,4 @@
|
|||||||
- "/tools/iban-generator/"
|
- "/tools/iban-generator/"
|
||||||
- "/tools/excel-password-remover/"
|
- "/tools/excel-password-remover/"
|
||||||
- "/tools/uuid-generator/"
|
- "/tools/uuid-generator/"
|
||||||
|
- "/tools/vat-calculator/"
|
||||||
|
@@ -91,3 +91,19 @@ format.json: "JSON"
|
|||||||
format.yaml: "YAML"
|
format.yaml: "YAML"
|
||||||
|
|
||||||
action.generate: "Generate"
|
action.generate: "Generate"
|
||||||
|
|
||||||
|
country.afghanistan: "Afghanistan"
|
||||||
|
country.albania: "Albania"
|
||||||
|
country.algeria: "Algeria"
|
||||||
|
country.andorra: "Andorra"
|
||||||
|
country.angola: "Angola"
|
||||||
|
country.anguilla: "Anguilla"
|
||||||
|
country.argentina: "Argentina"
|
||||||
|
country.australia: "Australia"
|
||||||
|
country.austria: "Austria"
|
||||||
|
country.azerbaijan: "Azerbaijan"
|
||||||
|
country.bahamas: "Bahamas"
|
||||||
|
|
||||||
|
country.belgium: "Belgium"
|
||||||
|
|
||||||
|
country.luxembourg: "Luxembourg"
|
||||||
|
50
data/strings/en/vat-calculator.yml
Normal file
50
data/strings/en/vat-calculator.yml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# EN - VAT Calculator
|
||||||
|
|
||||||
|
meta.title: "VAT Calculator"
|
||||||
|
meta.description: "Simple VAT calculator with a selection of common rates for over X countries."
|
||||||
|
|
||||||
|
preset.label: "Official rates"
|
||||||
|
|
||||||
|
option.detailed: "Show VAT rate types"
|
||||||
|
|
||||||
|
radio.rate: "VAT rate: "
|
||||||
|
radio.untaxed: "Excl. VAT: "
|
||||||
|
radio.taxed: "Incl. VAT: "
|
||||||
|
|
||||||
|
text.radio.explanation: "The selected radio input indicates the automatically calculated field."
|
||||||
|
|
||||||
|
rate.option.custom: "Custom rate"
|
||||||
|
|
||||||
|
rate.type.standard: "Standard"
|
||||||
|
rate.type.intermediate: "Intermediate"
|
||||||
|
rate.type.reduced: "Reduced"
|
||||||
|
rate.type.reduced.super: "Super reduced"
|
||||||
|
|
||||||
|
option.decimal-places: "Decimal places count"
|
||||||
|
option.trim-zeroes: "Trim trailing zeroes"
|
||||||
|
|
||||||
|
rounding.mode.label: "Rounding mode"
|
||||||
|
|
||||||
|
rounding.mode.group.regular: "Regular rounding"
|
||||||
|
rounding.mode.group.half: "Half rounding (Towards nearest neighbour)"
|
||||||
|
|
||||||
|
rounding.mode.up: "Away from zero (Up)"
|
||||||
|
rounding.mode.down: "Towards zero (Down)"
|
||||||
|
rounding.mode.ceil: "Towards infinity (Ceil)"
|
||||||
|
rounding.mode.floor: "Towards negative infinity (Floor)"
|
||||||
|
|
||||||
|
rounding.mode.up.half: "Away from zero if equidistant (Half up)"
|
||||||
|
rounding.mode.down.half: "Towards zero if equidistant (Half down)"
|
||||||
|
rounding.mode.even.half: "Towards even neighbour if equidistant (Half even)"
|
||||||
|
rounding.mode.ceil.half: "Towards infinity if equidistant (Half ceil)"
|
||||||
|
rounding.mode.floor.half: "Towards negative infinity if equidistant (Half floor)"
|
||||||
|
|
||||||
|
#rounding.mode.up.half: "Towards nearest neighbour, away from zero if equidistant (Half up)"
|
||||||
|
#rounding.mode.down.half: "Towards nearest neighbour, towards zero if equidistant (Half down)"
|
||||||
|
#rounding.mode.even.half: "Towards nearest neighbour, towards even neighbour if equidistant (Half even)"
|
||||||
|
#rounding.mode.ceil.half: "Towards nearest neighbour, towards infinity if equidistant (Half ceil)"
|
||||||
|
#rounding.mode.floor.half: "Towards nearest neighbour, towards negative infinity if equidistant (Half floor)"
|
||||||
|
|
||||||
|
license.text.1: "This tool uses the <a href=\"https://github.com/MikeMcl/decimal.js-light\">decimal.js-light</a>
|
||||||
|
library, which is licensed under the <a href=\"https://github.com/MikeMcl/decimal.js-light/blob/master/LICENCE.md\">MIT license</a>."
|
||||||
|
license.text.2: "The rest of this tool's code is released in the public domain."
|
@@ -91,3 +91,7 @@ format.json: "JSON"
|
|||||||
format.yaml: "YAML"
|
format.yaml: "YAML"
|
||||||
|
|
||||||
action.generate: "Générer"
|
action.generate: "Générer"
|
||||||
|
|
||||||
|
country.belgium: "Belgique"
|
||||||
|
|
||||||
|
country.luxembourg: "Luxembourg"
|
||||||
|
50
data/strings/fr/vat-calculator.yml
Normal file
50
data/strings/fr/vat-calculator.yml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# FR - VAT Calculator
|
||||||
|
|
||||||
|
meta.title: "Calculateur de TVA"
|
||||||
|
meta.description: "Simple calculateur de TVA avec une selection de taux communs pour plus de X pays."
|
||||||
|
|
||||||
|
preset.label: "Taux officiel"
|
||||||
|
|
||||||
|
option.detailed: "Afficher le type de TVA"
|
||||||
|
|
||||||
|
radio.rate: "Taux: "
|
||||||
|
radio.untaxed: "<abbr title=\"Hors Taxe sur la Valeur Ajoutée\">HTVA</abbr>: "
|
||||||
|
radio.taxed: "<abbr title=\"Toutes Taxes Comprises\">TTC</abbr>: "
|
||||||
|
|
||||||
|
text.radio.explanation: "Le cercle en vert indique la valeur automatiquement calculée."
|
||||||
|
|
||||||
|
rate.option.custom: "Taux personalisé"
|
||||||
|
|
||||||
|
rate.type.standard: "Standard"
|
||||||
|
rate.type.intermediate: "Intermédiaire"
|
||||||
|
rate.type.reduced: "Réduit"
|
||||||
|
rate.type.reduced.super: "Super réduit"
|
||||||
|
|
||||||
|
option.decimal-places: "Nombre de décimales"
|
||||||
|
option.trim-zeroes: "Supprimer les zéros de fin"
|
||||||
|
|
||||||
|
rounding.mode.label: "Type d'arrondi"
|
||||||
|
|
||||||
|
rounding.mode.group.regular: "Arrondis classiques"
|
||||||
|
rounding.mode.group.half: "Demi-arrondis (Vers le plus proche)"
|
||||||
|
|
||||||
|
rounding.mode.up: "Loin de zéro (Arrondi au supérieur)"
|
||||||
|
rounding.mode.down: "Vers zéro (Arrondi à l'inférieur)"
|
||||||
|
rounding.mode.ceil: "Vers l'infini (Par plafond)"
|
||||||
|
rounding.mode.floor: "Vers moins l'infini (Par plancher)"
|
||||||
|
|
||||||
|
rounding.mode.up.half: "Loin de zéro si équidistant (Demi supérieur)"
|
||||||
|
rounding.mode.down.half: "Vers zéro si équidistant (Demi inférieur)"
|
||||||
|
rounding.mode.even.half: "Vers le pair si équidistant (Demi pair)"
|
||||||
|
rounding.mode.ceil.half: "Vers l'infini (Demi plafond)"
|
||||||
|
rounding.mode.floor.half: "Vers moins l'infini (Demi plancher)"
|
||||||
|
|
||||||
|
#rounding.mode.up.half: "Vers le plus proche, loin de zéro si équidistant (Demi supérieur)"
|
||||||
|
#rounding.mode.down.half: "Vers le plus proche, vers zéro si équidistant (Demi inférieur)"
|
||||||
|
#rounding.mode.even.half: "Vers le plus proche, vers le pair si équidistant (Demi pair)"
|
||||||
|
#rounding.mode.ceil.half: "Vers le plus proche, vers l'infini (Demi plafond)"
|
||||||
|
#rounding.mode.floor.half: "Vers le plus proche, vers moins l'infini (Demi plancher)"
|
||||||
|
|
||||||
|
license.text.1: "Cet outil utilise la bibliothèque <a href=\"https://github.com/MikeMcl/decimal.js-light\">decimal.js-light</a>,
|
||||||
|
qui est distribuée sous licence <a href=\"https://github.com/MikeMcl/decimal.js-light/blob/master/LICENCE.md\">MIT</a>."
|
||||||
|
license.text.2: "Le reste du code de cet outil est placé dans le domaine public."
|
31
data/tools/vat-calculator.yml
Normal file
31
data/tools/vat-calculator.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
tools:
|
||||||
|
- id: "vat-calculator"
|
||||||
|
applet_id: "vat-calculator"
|
||||||
|
metadata:
|
||||||
|
head:
|
||||||
|
title_key: "meta.title"
|
||||||
|
description_key: "meta.description"
|
||||||
|
opengraph:
|
||||||
|
title_key: "meta.title"
|
||||||
|
description_key: "meta.description"
|
||||||
|
type: null
|
||||||
|
url: null
|
||||||
|
image_url: "/resources/NibblePoker/images/tools/vat-calculator/main-quiet.png"
|
||||||
|
image_type: null
|
||||||
|
twitter:
|
||||||
|
title_key: "meta.title"
|
||||||
|
description_key: "meta.description"
|
||||||
|
index:
|
||||||
|
priority: 500
|
||||||
|
enable: true
|
||||||
|
title_key: "meta.title"
|
||||||
|
preamble_key: "meta.description"
|
||||||
|
image_url: "/resources/NibblePoker/images/tools/vat-calculator/main-quiet.png"
|
||||||
|
image_alt_key: ""
|
||||||
|
general:
|
||||||
|
icon: "fab fa-python"
|
||||||
|
title_key: "meta.title"
|
||||||
|
subtitle_key: "article.subtitle"
|
||||||
|
tags:
|
||||||
|
- "calculator"
|
@@ -93,6 +93,16 @@ call "%~dp0node_modules\.bin\rollup" png-analyser.mjs --file png-analyser.js
|
|||||||
call "%~dp0node_modules\.bin\terser" png-analyser.js -c -m -o png-analyser.min.js
|
call "%~dp0node_modules\.bin\terser" png-analyser.js -c -m -o png-analyser.min.js
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
||||||
|
:js-vatcalculator-minify
|
||||||
|
echo Minifying VAT Calculator
|
||||||
|
pushd %CD%
|
||||||
|
cd %~dp0\..\static\resources\NibblePoker\applets\vat-calculator\
|
||||||
|
echo ^> static\resources\NibblePoker\applets\vat-calculator\vat-calculator.mjs
|
||||||
|
call "%~dp0node_modules\.bin\rollup" vat-calculator.mjs --file vat-calculator.js
|
||||||
|
call "%~dp0node_modules\.bin\terser" vat-calculator.js -c -m -o vat-calculator.min.js
|
||||||
|
popd
|
||||||
|
|
||||||
:js-nibblepoker-end
|
:js-nibblepoker-end
|
||||||
|
|
||||||
:end
|
:end
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"minify": "^10.2.0",
|
"minify": "^10.2.0",
|
||||||
"rollup": "^3.27.2",
|
"rollup": "^4.48.1",
|
||||||
"sass": "^1.63.6",
|
"sass": "^1.63.6",
|
||||||
"terser": "^5.19.0",
|
"terser": "^5.19.0",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"html-minifier-terser": "^7.2.0"
|
"html-minifier-terser": "^7.2.0",
|
||||||
|
"browserify": "^17.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,248 @@
|
|||||||
|
import {initCore} from "../../js/nibblepoker-core.mjs";
|
||||||
|
//import {Decimal} from "../../../DecimalJs/10.6.0/decimal.mjs";
|
||||||
|
import {Decimal} from "../../../DecimalJs-Light/2.5.1/decimal.mjs";
|
||||||
|
import {getInputCount, getInputNumber} from "../../libs/input-utils.mjs";
|
||||||
|
|
||||||
|
// Tool-centric stuff
|
||||||
|
{
|
||||||
|
initCore();
|
||||||
|
|
||||||
|
const classesReadonly = ["bkgd-gray"];
|
||||||
|
|
||||||
|
const calcRadioGroupName = "vat_calc_target";
|
||||||
|
|
||||||
|
/** @type {HTMLLabelElement} */
|
||||||
|
const ePresetShortLabel = document.querySelector("label[for=vat-calculator-preset-short]");
|
||||||
|
/** @type {HTMLSelectElement} */
|
||||||
|
const ePresetShortSelect = document.getElementById("vat-calculator-preset-short");
|
||||||
|
|
||||||
|
/** @type {HTMLLabelElement} */
|
||||||
|
const ePresetDetailedLabel = document.querySelector("label[for=vat-calculator-preset-detailed]");
|
||||||
|
/** @type {HTMLSelectElement} */
|
||||||
|
const ePresetDetailedSelect = document.getElementById("vat-calculator-preset-detailed");
|
||||||
|
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCheckboxDetailedPreset = document.getElementById("vat-calculator-detailed-presets");
|
||||||
|
|
||||||
|
/** @type {HTMLSpanElement} */
|
||||||
|
const ePresetEchoedCountry = document.getElementById("vat-calculator-preset-country-echo");
|
||||||
|
|
||||||
|
/** @type {HTMLButtonElement} */
|
||||||
|
const eButtonDecimalPlacesMinus = document.getElementById("vat-calculator-decimal-places-minus");
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eInputDecimalPlaces = document.getElementById("vat-calculator-option-decimal-places");
|
||||||
|
/** @type {HTMLButtonElement} */
|
||||||
|
const eButtonDecimalPlacesPlus = document.getElementById("vat-calculator-decimal-places-plus");
|
||||||
|
|
||||||
|
/* #vat-calculator-detailed-trim-zeroes */
|
||||||
|
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcRateRadio = document.getElementById("vat-calculator-radio-rate");
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcRateInput = document.getElementById("vat-calculator-input-rate");
|
||||||
|
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcUntaxedRadio = document.getElementById("vat-calculator-radio-untaxed");
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcUntaxedInput = document.getElementById("vat-calculator-input-untaxed");
|
||||||
|
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcTaxedRadio = document.getElementById("vat-calculator-radio-taxed");
|
||||||
|
/** @type {HTMLInputElement} */
|
||||||
|
const eCalcTaxedInput = document.getElementById("vat-calculator-input-taxed");
|
||||||
|
|
||||||
|
/** @type {HTMLSelectElement} */
|
||||||
|
const eRoundingModeSelect = document.getElementById("vat-calculator-rounding-mode");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the switch between the short and detailed standard rates selects
|
||||||
|
*/
|
||||||
|
function handlePresetDetailLevelChange() {
|
||||||
|
ePresetShortLabel.hidden = eCheckboxDetailedPreset.checked;
|
||||||
|
ePresetShortSelect.hidden = eCheckboxDetailedPreset.checked;
|
||||||
|
ePresetDetailedLabel.hidden = !eCheckboxDetailedPreset.checked;
|
||||||
|
ePresetDetailedSelect.hidden = !eCheckboxDetailedPreset.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} */
|
||||||
|
function getDecimalPlaces() {
|
||||||
|
return getInputCount(eInputDecimalPlaces, 0, 99);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDecimalPlacesDesiredCount(difference = 0) {
|
||||||
|
if (difference !== 0) {
|
||||||
|
eInputDecimalPlaces.value = getInputCount(eInputDecimalPlaces, 0, 99) + difference;
|
||||||
|
}
|
||||||
|
eInputDecimalPlaces.value = getInputCount(eInputDecimalPlaces, 0, 99);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the locking and unlocking of the calculator input fields.
|
||||||
|
* @param eInput {HTMLInputElement}
|
||||||
|
* @param isLocked {boolean}
|
||||||
|
*/
|
||||||
|
function setCalcFieldLockStatus(eInput, isLocked) {
|
||||||
|
eInput.readOnly = isLocked;
|
||||||
|
classesReadonly.forEach((roClass) => {
|
||||||
|
eInput.classList.remove(roClass);
|
||||||
|
if(isLocked) {
|
||||||
|
eInput.classList.add(roClass);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCalcValueChange() {
|
||||||
|
let vatRate = getInputNumber(eCalcRateInput);
|
||||||
|
let untaxedValue = getInputNumber(eCalcUntaxedInput);
|
||||||
|
let taxedValue = getInputNumber(eCalcTaxedInput);
|
||||||
|
|
||||||
|
if(eCalcRateRadio.checked) {
|
||||||
|
if(untaxedValue === null || taxedValue === null || isNaN(untaxedValue) || isNaN(taxedValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
untaxedValue = new Decimal(eCalcUntaxedInput.value);
|
||||||
|
taxedValue = new Decimal(eCalcTaxedInput.value);
|
||||||
|
|
||||||
|
eCalcRateInput.value = taxedValue
|
||||||
|
.minus(untaxedValue)
|
||||||
|
.div(untaxedValue)
|
||||||
|
.times(100)
|
||||||
|
.toDecimalPlaces(getDecimalPlaces());
|
||||||
|
} else if(eCalcUntaxedRadio.checked) {
|
||||||
|
if(vatRate === null || taxedValue === null || isNaN(vatRate) || isNaN(taxedValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vatRate = new Decimal(eCalcRateInput.value).dividedBy(100).plus(1);
|
||||||
|
taxedValue = new Decimal(eCalcTaxedInput.value);
|
||||||
|
|
||||||
|
eCalcUntaxedInput.value = taxedValue
|
||||||
|
.dividedBy(vatRate)
|
||||||
|
.toDecimalPlaces(getDecimalPlaces());
|
||||||
|
} else if(eCalcTaxedRadio.checked) {
|
||||||
|
if(vatRate === null || untaxedValue === null || isNaN(vatRate) || isNaN(untaxedValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vatRate = new Decimal(eCalcRateInput.value).dividedBy(100).plus(1);
|
||||||
|
untaxedValue = new Decimal(eCalcUntaxedInput.value);
|
||||||
|
|
||||||
|
eCalcTaxedInput.value = untaxedValue
|
||||||
|
.times(vatRate)
|
||||||
|
.toDecimalPlaces(getDecimalPlaces());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDecimalConfigChange() {
|
||||||
|
Decimal.set({
|
||||||
|
rounding: getInputCount(eRoundingModeSelect, 0, 8),
|
||||||
|
precision: 99,
|
||||||
|
defaults: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePresetChange() {
|
||||||
|
if(ePresetShortSelect.value.length > 0) {
|
||||||
|
let eSelectedOption = ePresetShortSelect.querySelector('option:checked');
|
||||||
|
if(eSelectedOption === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let eSelectedOptionGroup = eSelectedOption.closest('optgroup');
|
||||||
|
if(eSelectedOptionGroup === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ePresetEchoedCountry.innerHTML = eSelectedOptionGroup.label;
|
||||||
|
} else {
|
||||||
|
ePresetEchoedCountry.innerHTML = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
// Handling the detailed rate toggle
|
||||||
|
eCheckboxDetailedPreset.addEventListener("click", function () {
|
||||||
|
handlePresetDetailLevelChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handling the rate select input
|
||||||
|
ePresetShortSelect.addEventListener("change", function () {
|
||||||
|
ePresetDetailedSelect.selectedIndex = ePresetShortSelect.selectedIndex;
|
||||||
|
eCalcRateInput.value = ePresetShortSelect.value;
|
||||||
|
handlePresetChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
ePresetDetailedSelect.addEventListener("change", function () {
|
||||||
|
ePresetShortSelect.selectedIndex = ePresetDetailedSelect.selectedIndex;
|
||||||
|
eCalcRateInput.value = ePresetDetailedSelect.value;
|
||||||
|
handlePresetChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handling calc radio input change
|
||||||
|
document.addEventListener("change", (e) => {
|
||||||
|
if (e.target.type === "radio" && e.target.name === calcRadioGroupName) {
|
||||||
|
setCalcFieldLockStatus(eCalcRateInput, e.target.value === "0");
|
||||||
|
setCalcFieldLockStatus(eCalcUntaxedInput, e.target.value === "1");
|
||||||
|
setCalcFieldLockStatus(eCalcTaxedInput, e.target.value === "2");
|
||||||
|
|
||||||
|
ePresetDetailedSelect.disabled = e.target === eCalcRateRadio;
|
||||||
|
ePresetShortSelect.disabled = e.target === eCalcRateRadio;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
eCalcRateRadio.addEventListener("change", function () {
|
||||||
|
ePresetShortSelect.selectedIndex = 0;
|
||||||
|
ePresetDetailedSelect.selectedIndex = 0;
|
||||||
|
handlePresetChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handling decimal places options
|
||||||
|
eButtonDecimalPlacesMinus.addEventListener("click", function () {
|
||||||
|
changeDecimalPlacesDesiredCount(-1);
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
eButtonDecimalPlacesPlus.addEventListener("click", function () {
|
||||||
|
changeDecimalPlacesDesiredCount(1);
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
eInputDecimalPlaces.addEventListener("change", function() {
|
||||||
|
changeDecimalPlacesDesiredCount(0);
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
eInputDecimalPlaces.addEventListener("mousewheel", function(e) {
|
||||||
|
// Handling wheel scroll on count field.
|
||||||
|
if(e.wheelDelta < 0) {
|
||||||
|
changeDecimalPlacesDesiredCount(-1);
|
||||||
|
} else {
|
||||||
|
changeDecimalPlacesDesiredCount(1);
|
||||||
|
}
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handling other DecimalJs config fields
|
||||||
|
eRoundingModeSelect.addEventListener("change", function() {
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handling the calculator field changes
|
||||||
|
eCalcRateInput.addEventListener("change", function() {
|
||||||
|
ePresetShortSelect.selectedIndex = 0;
|
||||||
|
ePresetDetailedSelect.selectedIndex = 0;
|
||||||
|
handleCalcValueChange();
|
||||||
|
handlePresetChange();
|
||||||
|
});
|
||||||
|
eCalcUntaxedInput.addEventListener("change", function() {
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
eCalcTaxedInput.addEventListener("change", function() {
|
||||||
|
handleCalcValueChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
handlePresetDetailLevelChange();
|
||||||
|
handleDecimalConfigChange();
|
||||||
|
handlePresetChange();
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@@ -2,21 +2,7 @@
|
|||||||
// Author: Herwin Bozet (@NibblePoker)
|
// Author: Herwin Bozet (@NibblePoker)
|
||||||
// License: Public Domain (This code)
|
// License: Public Domain (This code)
|
||||||
|
|
||||||
/**
|
function postProcessNumber(desiredCount, min = null, max = null) {
|
||||||
* Retrieves the number from an `HTMLInputElement`
|
|
||||||
* @param eInput {HTMLInputElement} The `HTMLInputElement` from which the value will be retrieved.
|
|
||||||
* @param min {number|null} If given, sets a minimum the value can have when returned.
|
|
||||||
* @param max {number|null} If given, sets a maximum the value can have when returned.
|
|
||||||
* @returns {number} The value from the given `HTMLInputElement`, or `1` if no valid one was given.
|
|
||||||
*/
|
|
||||||
export function getInputCount(eInput, min = null, max = null) {
|
|
||||||
let desiredCount = null;
|
|
||||||
try {
|
|
||||||
desiredCount = parseInt(eInput.value);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desiredCount === null) {
|
if (desiredCount === null) {
|
||||||
desiredCount = 1;
|
desiredCount = 1;
|
||||||
}
|
}
|
||||||
@@ -34,3 +20,37 @@ export function getInputCount(eInput, min = null, max = null) {
|
|||||||
|
|
||||||
return desiredCount;
|
return desiredCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the integer number from an `HTMLInputElement`
|
||||||
|
* @param eInput {HTMLInputElement|HTMLSelectElement} The `HTMLInputElement` from which the value will be retrieved.
|
||||||
|
* @param min {number|null} If given, sets a minimum the value can have when returned.
|
||||||
|
* @param max {number|null} If given, sets a maximum the value can have when returned.
|
||||||
|
* @returns {number|NaN} The value from the given `HTMLInputElement`, or `1` if no valid one was given.
|
||||||
|
*/
|
||||||
|
export function getInputCount(eInput, min = null, max = null) {
|
||||||
|
let desiredCount = null;
|
||||||
|
try {
|
||||||
|
desiredCount = parseInt(eInput.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
return postProcessNumber(desiredCount, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the float number from an `HTMLInputElement`
|
||||||
|
* @param eInput {HTMLInputElement|HTMLSelectElement} The `HTMLInputElement` from which the value will be retrieved.
|
||||||
|
* @param min {number|null} If given, sets a minimum the value can have when returned.
|
||||||
|
* @param max {number|null} If given, sets a maximum the value can have when returned.
|
||||||
|
* @returns {number|NaN} The value from the given `HTMLInputElement`, or `1` if no valid one was given.
|
||||||
|
*/
|
||||||
|
export function getInputNumber(eInput, min = null, max = null) {
|
||||||
|
let desiredCount = null;
|
||||||
|
try {
|
||||||
|
desiredCount = parseFloat(eInput.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
return postProcessNumber(desiredCount, min, max);
|
||||||
|
}
|
||||||
|
170
templates/applets/vat-calculator.jinja
Normal file
170
templates/applets/vat-calculator.jinja
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
|
||||||
|
{%
|
||||||
|
set all_vat_data = [
|
||||||
|
["afghanistan", [[10, "standard"]],
|
||||||
|
"https://ard.gov.af/file_download/432/FAQs+of+VAT+English.pdf"],
|
||||||
|
["belgium", [[6, "reduced"],[12, "intermediate"],[21, "standard"]],
|
||||||
|
"https://finance.belgium.be/en/enterprises/vat/vat-obligation/rates-and-calculation/vat-rates"],
|
||||||
|
["luxembourg", [[3, "reduced.super"],[8, "reduced"],[14, "intermediate"],[17, "standard"]],
|
||||||
|
"https://logistics.public.lu/en/formalities-procedures/taxes/value-added-tax/national-operations.html"],
|
||||||
|
]
|
||||||
|
%}
|
||||||
|
|
||||||
|
<label for="vat-calculator-preset-short" class="mr-xxs">
|
||||||
|
{{ l10n("preset.label", "vat-calculator", user_lang) }}:
|
||||||
|
</label>
|
||||||
|
<select name="vat-calculator-preset-short" id="vat-calculator-preset-short" class="p-xxs border r-s">
|
||||||
|
<option value="" selected>{{ l10n("rate.option.custom", "vat-calculator", user_lang) }}</option>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{% for country_vat_data in all_vat_data %}
|
||||||
|
<optgroup label="{{ l10n("country." + country_vat_data[0], "commons", user_lang) }}">
|
||||||
|
|
||||||
|
{% for country_vat_rate in country_vat_data[1] %}
|
||||||
|
<option value="{{ country_vat_rate[0] }}">
|
||||||
|
{{ country_vat_rate[0] }} %
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</optgroup>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="vat-calculator-preset-detailed" class="mr-xxs" hidden>
|
||||||
|
{{ l10n("preset.label", "vat-calculator", user_lang) }}:
|
||||||
|
</label>
|
||||||
|
<select name="vat-calculator-preset-detailed" id="vat-calculator-preset-detailed" class="p-xxs border r-s" hidden>
|
||||||
|
<option value="" selected>{{ l10n("rate.option.custom", "vat-calculator", user_lang) }}</option>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{% for country_vat_data in all_vat_data %}
|
||||||
|
<optgroup label="{{ l10n("country." + country_vat_data[0], "commons", user_lang) }}">
|
||||||
|
|
||||||
|
{% for country_vat_rate in country_vat_data[1] %}
|
||||||
|
<option value="{{ country_vat_rate[0] }}">
|
||||||
|
{{ country_vat_rate[0] }} % ({{ l10n("rate.type." + country_vat_rate[1], "vat-calculator", user_lang) }})
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</optgroup>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span id="vat-calculator-preset-country-echo" class="t-muted ml-xs t-italic mobile-hide"></span>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<label for="vat-calculator-detailed-presets" class="mr-xxs">{{ l10n("option.detailed", "vat-calculator", user_lang) }}:</label>
|
||||||
|
<input id="vat-calculator-detailed-presets" class="r-m border cb-pretty" type="checkbox">
|
||||||
|
|
||||||
|
|
||||||
|
<hr class="subtle">
|
||||||
|
|
||||||
|
<!-- TODO: Implement iframe-able template for multi-instance applets on the same page -->
|
||||||
|
|
||||||
|
<table class="">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" id="vat-calculator-radio-rate" name="vat_calc_target" value="0"
|
||||||
|
class="radio-solid border mr-xxs radio-unchecked-subtle">
|
||||||
|
<label for="vat-calculator-radio-rate">
|
||||||
|
{{ l10n("radio.rate", "vat-calculator", user_lang) }}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<label for="vat-calculator-input-rate" class="mr-xs"></label>
|
||||||
|
<input id="vat-calculator-input-rate" class="p-xxs border r-s" type="number" min="0">
|
||||||
|
{% if not is_standalone %}<i class="fa-duotone fa-solid fa-percent ml-xxs t-muted"></i>{% else %}%{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="pt-xxs">
|
||||||
|
<input type="radio" id="vat-calculator-radio-untaxed" name="vat_calc_target" value="1"
|
||||||
|
class="radio-solid border mr-xxs radio-unchecked-subtle">
|
||||||
|
<label for="vat-calculator-radio-untaxed">
|
||||||
|
{{ l10n("radio.untaxed", "vat-calculator", user_lang) }}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td class="pt-xxs">
|
||||||
|
<label for="vat-calculator-input-untaxed" class="mr-xs"></label>
|
||||||
|
<input id="vat-calculator-input-untaxed" class="p-xxs border r-s" type="number" min="0">
|
||||||
|
{% if not is_standalone %}<i class="fa-duotone fa-solid fa-money-bill ml-xxs t-muted"></i>{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="pt-xxs">
|
||||||
|
<input type="radio" id="vat-calculator-radio-taxed" name="vat_calc_target" value="2"
|
||||||
|
class="radio-solid border mr-xxs radio-unchecked-subtle" checked>
|
||||||
|
<label for="vat-calculator-radio-taxed">
|
||||||
|
{{ l10n("radio.taxed", "vat-calculator", user_lang) }}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td class="pt-xxs">
|
||||||
|
<label for="vat-calculator-input-taxed" class="mr-xs"></label>
|
||||||
|
<input id="vat-calculator-input-taxed" class="p-xxs border r-s bkgd-gray" type="number" min="0" readonly>
|
||||||
|
{% if not is_standalone %}<i class="fa-duotone fa-solid fa-money-bill ml-xxs t-muted"></i>{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="t-muted ml-xs mt-xs t-italic">{{ l10n("text.radio.explanation", "vat-calculator", user_lang) }}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<hr class="subtle">
|
||||||
|
|
||||||
|
<label for="vat-calculator-rounding-mode" class="mr-xxs">
|
||||||
|
{{ l10n("rounding.mode.label", "vat-calculator", user_lang) }}:
|
||||||
|
</label>
|
||||||
|
<select name="vat-calculator-rounding-mode" id="vat-calculator-rounding-mode" class="p-xxs border r-s">
|
||||||
|
<optgroup label="{{ l10n("rounding.mode.group.regular", "vat-calculator", user_lang) }}">
|
||||||
|
<option value="0" selected>{{ l10n("rounding.mode.up", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="1">{{ l10n("rounding.mode.down", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="2">{{ l10n("rounding.mode.ceil", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="3">{{ l10n("rounding.mode.floor", "vat-calculator", user_lang) }}</option>
|
||||||
|
</optgroup>
|
||||||
|
|
||||||
|
<optgroup label="{{ l10n("rounding.mode.group.half", "vat-calculator", user_lang) }}">
|
||||||
|
<option value="4">{{ l10n("rounding.mode.up.half", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="5">{{ l10n("rounding.mode.down.half", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="6">{{ l10n("rounding.mode.even.half", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="7">{{ l10n("rounding.mode.ceil.half", "vat-calculator", user_lang) }}</option>
|
||||||
|
<option value="8">{{ l10n("rounding.mode.floor.half", "vat-calculator", user_lang) }}</option>
|
||||||
|
</optgroup>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<label for="vat-calculator-option-decimal-places" class="mr-xs">{{ l10n("option.decimal-places", "vat-calculator", user_lang) }}:</label>
|
||||||
|
|
||||||
|
<button id="vat-calculator-decimal-places-minus" class="p-xxs border br-0 rl-s {% if is_standalone %}px-xs{% endif %}">
|
||||||
|
{% if not is_standalone %}<i class="fa-duotone fa-solid fa-minus"></i>{% else %}-{% endif %}
|
||||||
|
</button>
|
||||||
|
<input id="vat-calculator-option-decimal-places" class="p-xxs border" type="number" value="2" min="0" max="99">
|
||||||
|
<button id="vat-calculator-decimal-places-plus" class="p-xxs border bl-0 rr-s {% if is_standalone %}px-xs{% endif %}">
|
||||||
|
{% if not is_standalone %}<i class="fa-duotone fa-solid fa-plus"></i>{% else %}+{% endif %}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<br hidden>
|
||||||
|
|
||||||
|
<label for="vat-calculator-detailed-trim-zeroes" class="mr-xxs" hidden>{{ l10n("option.trim-zeroes", "vat-calculator", user_lang) }}:</label>
|
||||||
|
<input id="vat-calculator-detailed-trim-zeroes" class="r-m border cb-pretty" type="checkbox" hidden>
|
||||||
|
|
||||||
|
|
||||||
|
<!--<hr class="subtle">
|
||||||
|
|
||||||
|
<details class="border bkgd-dark r-m mt-s">
|
||||||
|
<summary class="p-xs">Click to show/hide all classes</summary>
|
||||||
|
<div class="p-xs bt bkgd-grey">
|
||||||
|
<p>
|
||||||
|
<span class="code mr-xs">p-0</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</details>-->
|
||||||
|
|
||||||
|
{% if is_standalone %}
|
||||||
|
<hr class="subtle">
|
||||||
|
<p class="t-half-muted">
|
||||||
|
{{ l10n("license.text.1", "vat-calculator", user_lang) }}<br>
|
||||||
|
{{ l10n("license.text.2", "vat-calculator", user_lang) }}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/FontAwesomePro/6.7.2/css/all.min.css">
|
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/FontAwesomePro/6.7.2/css/all.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/NibblePoker/StandardCSS/nibblepoker.min.css">
|
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/NibblePoker/StandardCSS/nibblepoker.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/Quantum/Quantum.min.css">
|
<!--<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/Quantum/Quantum.min.css">-->
|
||||||
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/FamFamFam/FlagsExtended/famfamfam-flags.min.css">
|
<link rel="stylesheet" href="https://cdn.nibblepoker.{{ domain_tld }}/FamFamFam/FlagsExtended/famfamfam-flags.min.css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ url_for("static", filename="resources/NibblePoker/css/extra.css") }}">
|
<link rel="stylesheet" href="{{ url_for("static", filename="resources/NibblePoker/css/extra.css") }}">
|
||||||
|
@@ -43,7 +43,7 @@ def reload_strings(strings_root: str) -> None:
|
|||||||
domain_key = str(Path(lang_domain).with_suffix(''))
|
domain_key = str(Path(lang_domain).with_suffix(''))
|
||||||
|
|
||||||
if lang_domain.endswith(".json"):
|
if lang_domain.endswith(".json"):
|
||||||
print(f"Loading JSON lang data from '{lang_domain_path}'...")
|
#print(f"Loading JSON lang data from '{lang_domain_path}'...")
|
||||||
L10N.add_domain(
|
L10N.add_domain(
|
||||||
lang_dir,
|
lang_dir,
|
||||||
domain_key,
|
domain_key,
|
||||||
@@ -51,7 +51,7 @@ def reload_strings(strings_root: str) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if lang_domain.endswith(".yml"):
|
if lang_domain.endswith(".yml"):
|
||||||
print(f"Loading YAML lang data from '{lang_domain_path}'...")
|
#print(f"Loading YAML lang data from '{lang_domain_path}'...")
|
||||||
L10N.add_domain(
|
L10N.add_domain(
|
||||||
lang_dir,
|
lang_dir,
|
||||||
domain_key,
|
domain_key,
|
||||||
|
Reference in New Issue
Block a user