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
|
||||
|
||||
# Temp
|
||||
static/resources/DecimalJs*
|
||||
static/resources/SortableJS
|
||||
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/excel-password-remover/"
|
||||
- "/tools/uuid-generator/"
|
||||
- "/tools/vat-calculator/"
|
||||
|
@@ -91,3 +91,19 @@ format.json: "JSON"
|
||||
format.yaml: "YAML"
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
:end
|
||||
|
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"minify": "^10.2.0",
|
||||
"rollup": "^3.27.2",
|
||||
"rollup": "^4.48.1",
|
||||
"sass": "^1.63.6",
|
||||
"terser": "^5.19.0",
|
||||
"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)
|
||||
// License: Public Domain (This code)
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
function postProcessNumber(desiredCount, min = null, max = null) {
|
||||
if (desiredCount === null) {
|
||||
desiredCount = 1;
|
||||
}
|
||||
@@ -34,3 +20,37 @@ export function getInputCount(eInput, min = null, max = null) {
|
||||
|
||||
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 }}/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="{{ 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(''))
|
||||
|
||||
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(
|
||||
lang_dir,
|
||||
domain_key,
|
||||
@@ -51,7 +51,7 @@ def reload_strings(strings_root: str) -> None:
|
||||
)
|
||||
|
||||
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(
|
||||
lang_dir,
|
||||
domain_key,
|
||||
|
Reference in New Issue
Block a user