Added the JavaScript BaseAccountOption class to object-ize the base account options in the account form.

This commit is contained in:
依瑪貓 2023-03-24 00:35:50 +08:00
parent 5b4f57d0b3
commit 821059fa80

View File

@ -131,13 +131,12 @@ class AccountForm {
/** /**
* Sets the base account. * Sets the base account.
* *
* @param code {string} the base account code * @param account {BaseAccountOption} the selected base account
* @param text {string} the text for the base account
*/ */
setBaseAccount(code, text) { setBaseAccount(account) {
this.#baseCode.value = code; this.#baseCode.value = account.code;
this.#base.innerText = text; this.#base.innerText = account.text;
if (["1", "2", "3"].includes(code.substring(0, 1))) { if (["1", "2", "3"].includes(account.code.substring(0, 1))) {
this.#isNeedOffsetControl.classList.remove("d-none"); this.#isNeedOffsetControl.classList.remove("d-none");
this.#isNeedOffset.disabled = false; this.#isNeedOffset.disabled = false;
} else { } else {
@ -225,7 +224,7 @@ class BaseAccountSelector {
* The account form * The account form
* @type {AccountForm} * @type {AccountForm}
*/ */
#form; form;
/** /**
* The selector modal * The selector modal
@ -253,7 +252,7 @@ class BaseAccountSelector {
/** /**
* The options * The options
* @type {HTMLLIElement[]} * @type {BaseAccountOption[]}
*/ */
#options; #options;
@ -269,67 +268,40 @@ class BaseAccountSelector {
* @param form {AccountForm} the form * @param form {AccountForm} the form
*/ */
constructor(form) { constructor(form) {
this.#form = form; this.form = form;
this.#modal = document.getElementById("accounting-base-selector-modal"); this.#modal = document.getElementById("accounting-base-selector-modal");
this.#query = document.getElementById("accounting-base-selector-query"); this.#query = document.getElementById("accounting-base-selector-query");
this.#optionList = document.getElementById("accounting-base-selector-option-list");
// noinspection JSValidateTypes
this.#options = Array.from(document.getElementsByClassName("accounting-base-selector-option"));
this.#clearButton = document.getElementById("accounting-base-selector-clear");
this.#queryNoResult = document.getElementById("accounting-base-selector-option-no-result"); this.#queryNoResult = document.getElementById("accounting-base-selector-option-no-result");
this.#modal.addEventListener("hidden.bs.modal", () => { this.#optionList = document.getElementById("accounting-base-selector-option-list");
this.#form.onBaseAccountSelectorClosed(); this.#options = Array.from(document.getElementsByClassName("accounting-base-selector-option")).map((element) => new BaseAccountOption(this, element));
}); this.#clearButton = document.getElementById("accounting-base-selector-clear");
for (const option of this.#options) {
option.onclick = () => { this.#modal.addEventListener("hidden.bs.modal", () => this.form.onBaseAccountSelectorClosed());
this.#form.setBaseAccount(option.dataset.code, option.dataset.text); this.#query.oninput = () => this.#filterOptions();
}; this.#clearButton.onclick = () => this.form.clearBaseAccount();
}
this.#clearButton.onclick = () => {
this.#form.clearBaseAccount();
};
this.#initializeBaseAccountQuery();
} }
/** /**
* Initializes the query. * Filters the options.
* *
*/ */
#initializeBaseAccountQuery() { #filterOptions() {
this.#query.addEventListener("input", () => { let hasAnyMatched = false;
if (this.#query.value === "") { for (const option of this.#options) {
for (const option of this.#options) { if (option.isMatched(this.#query.value)) {
option.classList.remove("d-none"); option.setShown(true);
} hasAnyMatched = true;
this.#optionList.classList.remove("d-none");
this.#queryNoResult.classList.add("d-none");
return
}
let hasAnyMatched = false;
for (const option of this.#options) {
const queryValues = JSON.parse(option.dataset.queryValues);
let isMatched = false;
for (const queryValue of queryValues) {
if (queryValue.toLowerCase().includes(this.#query.value.toLowerCase())) {
isMatched = true;
break;
}
}
if (isMatched) {
option.classList.remove("d-none");
hasAnyMatched = true;
} else {
option.classList.add("d-none");
}
}
if (!hasAnyMatched) {
this.#optionList.classList.add("d-none");
this.#queryNoResult.classList.remove("d-none");
} else { } else {
this.#optionList.classList.remove("d-none"); option.setShown(false);
this.#queryNoResult.classList.add("d-none");
} }
}); }
if (!hasAnyMatched) {
this.#optionList.classList.add("d-none");
this.#queryNoResult.classList.remove("d-none");
} else {
this.#optionList.classList.remove("d-none");
this.#queryNoResult.classList.add("d-none");
}
} }
/** /**
@ -338,12 +310,10 @@ class BaseAccountSelector {
* @param baseCode {string} the active base code * @param baseCode {string} the active base code
*/ */
onOpen(baseCode) { onOpen(baseCode) {
this.#query.value = "";
this.#filterOptions();
for (const option of this.#options) { for (const option of this.#options) {
if (option.dataset.code === baseCode) { option.setActive(option.code === baseCode);
option.classList.add("active");
} else {
option.classList.remove("active");
}
} }
if (baseCode === "") { if (baseCode === "") {
this.#clearButton.classList.add("btn-secondary") this.#clearButton.classList.add("btn-secondary")
@ -356,3 +326,100 @@ class BaseAccountSelector {
} }
} }
} }
/**
* A basic account option.
*
*/
class BaseAccountOption {
/**
* The base account selector
* @type {BaseAccountSelector}
*/
#selector;
/**
* The element
* @type {HTMLLIElement}
*/
#element;
/**
* The account code
* @type {string}
*/
code;
/**
* The account text
* @type {string}
*/
text;
/**
* The values to query against
* @type {string[]}
*/
#queryValues;
/**
* Constructs the account in the account selector for the recurring item editor.
*
* @param selector {BaseAccountSelector} the base account selector
* @param element {HTMLLIElement} the element
*/
constructor(selector, element) {
this.#selector = selector;
this.#element = element;
this.code = element.dataset.code;
this.text = element.dataset.text;
this.#queryValues = JSON.parse(element.dataset.queryValues);
this.#element.onclick = () => this.#selector.form.setBaseAccount(this);
}
/**
* Returns whether the account matches the query.
*
* @param query {string} the query term
* @return {boolean} true if the option matches, or false otherwise
*/
isMatched(query) {
if (query === "") {
return true;
}
for (const queryValue of this.#queryValues) {
if (queryValue.toLowerCase().includes(query.toLowerCase())) {
return true;
}
}
return false;
}
/**
* Sets whether the option is shown.
*
* @param isShown {boolean} true to show, or false otherwise
*/
setShown(isShown) {
if (isShown) {
this.#element.classList.remove("d-none");
} else {
this.#element.classList.add("d-none");
}
}
/**
* Sets whether the option is active.
*
* @param isActive {boolean} true if active, or false otherwise
*/
setActive(isActive) {
if (isActive) {
this.#element.classList.add("active");
} else {
this.#element.classList.remove("active");
}
}
}