/* The Mia! Accounting Flask Project * currency-form.js: The JavaScript for the currency form */ /* Copyright (c) 2023 imacat. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Author: imacat@mail.imacat.idv.tw (imacat) * First written: 2023/2/6 */ "use strict"; // Initializes the page JavaScript. document.addEventListener("DOMContentLoaded", () => { CurrencyForm.initialize(); }); /** * The currency form. * * @private */ class CurrencyForm { /** * The form. * @type {HTMLFormElement} */ #formElement; /** * The code * @type {HTMLInputElement} */ #code; /** * The error message of the code * @type {HTMLDivElement} */ #codeError; /** * The name * @type {HTMLInputElement} */ #name; /** * The error message of the name * @type {HTMLDivElement} */ #nameError; /** * Constructs the currency form. * */ constructor() { this.#formElement = document.getElementById("accounting-form"); this.#code = document.getElementById("accounting-code"); this.#codeError = document.getElementById("accounting-code-error"); this.#name = document.getElementById("accounting-name"); this.#nameError = document.getElementById("accounting-name-error"); this.#code.onchange = () => { this.#validateCode().then(); }; this.#name.onchange = () => { this.#validateName(); }; this.#formElement.onsubmit = () => { this.#validate().then((isValid) => { if (isValid) { this.#formElement.submit(); } }); return false; }; } /** * Validates the form. * * @returns {Promise} true if valid, or false otherwise */ async #validate() { let isValid = true; isValid = await this.#validateCode() && isValid; isValid = this.#validateName() && isValid; return isValid; } /** * Validates the code. * * @param changeEvent {Event} the change event, if invoked from onchange * @returns {Promise} true if valid, or false otherwise */ async #validateCode(changeEvent = null) { this.#code.value = this.#code.value.trim(); if (this.#code.value === "") { this.#code.classList.add("is-invalid"); this.#codeError.innerText = A_("Please fill in the code."); return false; } const blocklist = JSON.parse(this.#code.dataset.blocklist); if (blocklist.includes(this.#code.value)) { this.#code.classList.add("is-invalid"); this.#codeError.innerText = A_("This code is not available."); return false; } if (!this.#code.value.match(/^[A-Z]{3}$/)) { this.#code.classList.add("is-invalid"); this.#codeError.innerText = A_("Code can only be composed of 3 upper-cased letters."); return false; } const original = this.#code.dataset.original; if (original === "" || this.#code.value !== original) { const response = await fetch(`${this.#code.dataset.existsUrl}?q=${encodeURIComponent(this.#code.value)}`); const data = await response.json(); if (data["exists"]) { this.#code.classList.add("is-invalid"); this.#codeError.innerText = A_("Code conflicts with another currency."); return false; } } this.#code.classList.remove("is-invalid"); this.#codeError.innerText = ""; return true; } /** * Validates the name. * * @returns {boolean} true if valid, or false otherwise */ #validateName() { this.#name.value = this.#name.value.trim(); if (this.#name.value === "") { this.#name.classList.add("is-invalid"); this.#nameError.innerText = A_("Please fill in the name."); return false; } this.#name.classList.remove("is-invalid"); this.#nameError.innerText = ""; return true; } /** * The form * @type {CurrencyForm} */ static #form; /** * Initializes the currency form. * */ static initialize() { this.#form = new CurrencyForm(); } }