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:
2025-09-07 20:52:02 +02:00
parent eb2ffa296b
commit 615affcc2d
19 changed files with 629 additions and 20 deletions

1
.gitignore vendored
View File

@@ -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

View File

@@ -0,0 +1,7 @@
applets:
- id: "vat-calculator"
resources:
scripts:
- "applet://vat-calculator.mjs"
stylesheets:
- "applet://vat-calculator.css"

View File

@@ -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/"

View File

@@ -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"

View 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."

View File

@@ -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"

View 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&emsp;(Vers le plus proche)"
rounding.mode.up: "Loin de zéro&emsp;(Arrondi au supérieur)"
rounding.mode.down: "Vers zéro&emsp;(Arrondi à l'inférieur)"
rounding.mode.ceil: "Vers l'infini&emsp;(Par plafond)"
rounding.mode.floor: "Vers moins l'infini&emsp;(Par plancher)"
rounding.mode.up.half: "Loin de zéro si équidistant&emsp;(Demi supérieur)"
rounding.mode.down.half: "Vers zéro si équidistant&emsp;(Demi inférieur)"
rounding.mode.even.half: "Vers le pair si équidistant&emsp;(Demi pair)"
rounding.mode.ceil.half: "Vers l'infini&emsp;(Demi plafond)"
rounding.mode.floor.half: "Vers moins l'infini&emsp;(Demi plancher)"
#rounding.mode.up.half: "Vers le plus proche, loin de zéro si équidistant&emsp;(Demi supérieur)"
#rounding.mode.down.half: "Vers le plus proche, vers zéro si équidistant&emsp;(Demi inférieur)"
#rounding.mode.even.half: "Vers le plus proche, vers le pair si équidistant&emsp;(Demi pair)"
#rounding.mode.ceil.half: "Vers le plus proche, vers l'infini&emsp;(Demi plafond)"
#rounding.mode.floor.half: "Vers le plus proche, vers moins l'infini&emsp;(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."

View 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"

View File

@@ -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

View File

@@ -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"
} }
} }

View File

@@ -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

View File

@@ -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);
}

View 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] }} %&emsp;({{ 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 %}

View File

@@ -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") }}">

View File

@@ -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,