Convert clickable divs to buttons or add role="button" for keyboard accessibility

This commit is contained in:
2026-04-16 07:59:57 +08:00
parent 220dbaa683
commit 090acbd66b
12 changed files with 75 additions and 47 deletions
+2 -2
View File
@@ -48,7 +48,7 @@ class AccountForm {
/** /**
* The control of the base account * The control of the base account
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#baseControl; #baseControl;
@@ -60,7 +60,7 @@ class AccountForm {
/** /**
* The base account * The base account
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#base; #base;
@@ -701,12 +701,23 @@ class DebitCreditSubForm {
this.#element.classList.add("accounting-not-empty"); this.#element.classList.add("accounting-not-empty");
this.currency.form.lineItemEditor.onAddNew(this); this.currency.form.lineItemEditor.onAddNew(this);
}; };
this.#element.role = "button";
this.#element.tabIndex = 0;
this.#element.onkeydown = (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
this.#element.click();
}
};
} else { } else {
this.#element.classList.add("accounting-not-empty"); this.#element.classList.add("accounting-not-empty");
this.#element.classList.remove("accounting-clickable"); this.#element.classList.remove("accounting-clickable");
delete this.#element.dataset.bsToggle; delete this.#element.dataset.bsToggle;
delete this.#element.dataset.bsTarget; delete this.#element.dataset.bsTarget;
this.#element.onclick = null; this.#element.onclick = null;
this.#element.removeAttribute("role");
this.#element.tabIndex = -1;
this.#element.onkeydown = null;
} }
setElementShown(this.#content, this.lineItems.length !== 0); setElementShown(this.#content, this.lineItems.length !== 0);
} }
@@ -986,6 +997,12 @@ class LineItemSubForm {
this.#element.parentElement.removeChild(this.#element); this.#element.parentElement.removeChild(this.#element);
this.debitCreditSubForm.deleteLineItem(this); this.debitCreditSubForm.deleteLineItem(this);
}; };
this.#control.onkeydown = (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
this.#control.click();
}
};
} }
/** /**
@@ -66,13 +66,13 @@ class JournalEntryLineItemEditor {
/** /**
* The control of the original line item * The control of the original line item
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#originalLineItemControl; #originalLineItemControl;
/** /**
* The original line item * The original line item
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#originalLineItemText; #originalLineItemText;
@@ -90,13 +90,13 @@ class JournalEntryLineItemEditor {
/** /**
* The control of the description * The control of the description
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#descriptionControl; #descriptionControl;
/** /**
* The description * The description
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#descriptionText; #descriptionText;
@@ -108,13 +108,13 @@ class JournalEntryLineItemEditor {
/** /**
* The control of the account * The control of the account
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#accountControl; #accountControl;
/** /**
* The account * The account
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#accountText; #accountText;
+17 -6
View File
@@ -298,6 +298,14 @@ class RecurringExpenseIncomeSubForm {
this.#element.dataset.bsTarget = `#${this.editor.modal.id}`; this.#element.dataset.bsTarget = `#${this.editor.modal.id}`;
this.#element.onclick = () => this.editor.onAddNew(); this.#element.onclick = () => this.editor.onAddNew();
this.#content.classList.add("d-none"); this.#content.classList.add("d-none");
this.#element.role = "button";
this.#element.tabIndex = 0;
this.#element.onkeydown = (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
this.#element.click();
}
};
} else { } else {
this.#element.classList.add("accounting-not-empty"); this.#element.classList.add("accounting-not-empty");
this.#element.classList.remove("accounting-clickable"); this.#element.classList.remove("accounting-clickable");
@@ -305,6 +313,9 @@ class RecurringExpenseIncomeSubForm {
delete this.#element.dataset.bsTarget; delete this.#element.dataset.bsTarget;
this.#element.onclick = null; this.#element.onclick = null;
this.#content.classList.remove("d-none"); this.#content.classList.remove("d-none");
this.#element.removeAttribute("role");
this.#element.tabIndex = -1;
this.#element.onkeydown = null;
} }
} }
@@ -375,7 +386,7 @@ class RecurringItemSubForm {
/** /**
* The control * The control
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#control; #control;
@@ -399,7 +410,7 @@ class RecurringItemSubForm {
/** /**
* The text display of the name * The text display of the name
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#nameText; #nameText;
@@ -411,7 +422,7 @@ class RecurringItemSubForm {
/** /**
* The text display of the account * The text display of the account
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#accountText; #accountText;
@@ -423,7 +434,7 @@ class RecurringItemSubForm {
/** /**
* The text display of the description template * The text display of the description template
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#descriptionTemplateText; #descriptionTemplateText;
@@ -595,13 +606,13 @@ class RecurringItemEditor {
/** /**
* The control of the account * The control of the account
* @type {HTMLDivElement} * @type {HTMLButtonElement}
*/ */
#accountControl; #accountControl;
/** /**
* The text display of the account * The text display of the account
* @type {HTMLDivElement} * @type {HTMLSpanElement}
*/ */
#accountContainer; #accountContainer;
@@ -41,9 +41,9 @@ First written: 2023/2/1
{% endif %} {% endif %}
<div class="form-floating mb-3"> <div class="form-floating mb-3">
<input id="accounting-base-code" type="hidden" name="base_code" value="{{ form.base_code.data|accounting_default }}"> <input id="accounting-base-code" type="hidden" name="base_code" value="{{ form.base_code.data|accounting_default }}">
<div id="accounting-base-control" class="form-control accounting-clickable accounting-material-text-field {% if form.base_code.data %} accounting-not-empty {% endif %} {% if form.base_code.errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-base-selector-modal"> <button id="accounting-base-control" class="form-control text-start accounting-material-text-field {% if form.base_code.data %} accounting-not-empty {% endif %} {% if form.base_code.errors %} is-invalid {% endif %}" type="button" data-bs-toggle="modal" data-bs-target="#accounting-base-selector-modal">
<label class="form-label" for="accounting-base">{{ A_("Base account") }}</label> <span class="form-label">{{ A_("Base account") }}</span>
<div id="accounting-base"> <span id="accounting-base">
{% if form.base_code.data %} {% if form.base_code.data %}
{% if form.base_code.errors %} {% if form.base_code.errors %}
{{ A_("(Unknown)") }} {{ A_("(Unknown)") }}
@@ -51,8 +51,8 @@ First written: 2023/2/1
{{ form.selected_base }} {{ form.selected_base }}
{% endif %} {% endif %}
{% endif %} {% endif %}
</div> </span>
</div> </button>
<div id="accounting-base-error" class="invalid-feedback">{% if form.base_code.errors %}{{ form.base_code.errors[0] }}{% endif %}</div> <div id="accounting-base-error" class="invalid-feedback">{% if form.base_code.errors %}{{ form.base_code.errors[0] }}{% endif %}</div>
</div> </div>
@@ -20,8 +20,8 @@ Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/21 First written: 2023/3/21
#} #}
<div class="mb-2"> <div class="mb-2">
<div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}" class="form-control accounting-material-text-field {% if line_item_forms %} accounting-not-empty {% else %} accounting-clickable {% endif %} {% if debit_errors %} is-invalid {% endif %}"> <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}" class="form-control accounting-material-text-field {% if line_item_forms %} accounting-not-empty {% else %} accounting-clickable {% endif %} {% if debit_errors %} is-invalid {% endif %}" {% if line_item_forms %} tabindex="-1" {% else %} role="button" tabindex="0" {% endif %}>
<label class="form-label" for="accounting-currency-{{ currency_index }}-{{ debit_credit }}">{{ header }}</label> <span class="form-label">{{ header }}</span>
<div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-content" class="mt-2 {% if not line_item_forms %} d-none {% endif %}"> <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-content" class="mt-2 {% if not line_item_forms %} d-none {% endif %}">
<ul id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-list" class="list-group accounting-line-item-list"> <ul id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-list" class="list-group accounting-line-item-list">
{% for line_item_form in line_item_forms %} {% for line_item_form in line_item_forms %}
@@ -30,7 +30,7 @@ First written: 2023/2/25
<input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" value="{{ form.description.data|accounting_default }}"> <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" value="{{ form.description.data|accounting_default }}">
<input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" value="{{ form.amount.data|accounting_journal_entry_format_amount_input }}" data-min="{{ form.offset_total|accounting_default("0") }}"> <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" value="{{ form.amount.data|accounting_journal_entry_format_amount_input }}" data-min="{{ form.offset_total|accounting_default("0") }}">
<div class="accounting-line-item-content"> <div class="accounting-line-item-content">
<div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-control" class="form-control clickable d-flex justify-content-between {% if form.all_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-control" class="form-control clickable d-flex justify-content-between {% if form.all_errors %} is-invalid {% endif %}" role="button" tabindex="0" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">
<div> <div>
<div class="small"> <div class="small">
<span id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-account-text-code" class="d-none d-md-inline">{{ form.account_code.data|accounting_default }}</span> <span id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-account-text-code" class="d-none d-md-inline">{{ form.account_code.data|accounting_default }}</span>
@@ -31,10 +31,10 @@ First written: 2023/2/25
<div class="modal-body"> <div class="modal-body">
<div id="accounting-line-item-editor-original-line-item-container" class="d-flex justify-content-between mb-3"> <div id="accounting-line-item-editor-original-line-item-container" class="d-flex justify-content-between mb-3">
<div class="accounting-line-item-editor-original-line-item-content"> <div class="accounting-line-item-editor-original-line-item-content">
<div id="accounting-line-item-editor-original-line-item-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target="#accounting-original-line-item-selector-modal"> <button id="accounting-line-item-editor-original-line-item-control" class="form-control text-start accounting-material-text-field" type="button" data-bs-toggle="modal" data-bs-target="#accounting-original-line-item-selector-modal">
<label class="form-label" for="accounting-line-item-editor-original-line-item">{{ A_("Original Line Item") }}</label> <span class="form-label">{{ A_("Original Line Item") }}</span>
<div id="accounting-line-item-editor-original-line-item"></div> <span id="accounting-line-item-editor-original-line-item"></span>
</div> </button>
<div id="accounting-line-item-editor-original-line-item-error" class="invalid-feedback"></div> <div id="accounting-line-item-editor-original-line-item-error" class="invalid-feedback"></div>
</div> </div>
@@ -46,18 +46,18 @@ First written: 2023/2/25
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div id="accounting-line-item-editor-description-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target=""> <button id="accounting-line-item-editor-description-control" class="form-control text-start accounting-material-text-field" type="button" data-bs-toggle="modal" data-bs-target="">
<label class="form-label" for="accounting-line-item-editor-description">{{ A_("Description") }}</label> <span class="form-label">{{ A_("Description") }}</span>
<div id="accounting-line-item-editor-description"></div> <span id="accounting-line-item-editor-description"></span>
</div> </button>
<div id="accounting-line-item-editor-description-error" class="invalid-feedback"></div> <div id="accounting-line-item-editor-description-error" class="invalid-feedback"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div id="accounting-line-item-editor-account-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target=""> <button id="accounting-line-item-editor-account-control" class="form-control text-start accounting-material-text-field" type="button" data-bs-toggle="modal" data-bs-target="">
<label class="form-label" for="accounting-line-item-editor-account">{{ A_("Account") }}</label> <span class="form-label">{{ A_("Account") }}</span>
<div id="accounting-line-item-editor-account"></div> <span id="accounting-line-item-editor-account"></span>
</div> </button>
<div id="accounting-line-item-editor-account-error" class="invalid-feedback"></div> <div id="accounting-line-item-editor-account-error" class="invalid-feedback"></div>
</div> </div>
@@ -19,8 +19,8 @@ form-recurring-expense-income.html: The recurring expense or income sub-form in
Author: imacat@mail.imacat.idv.tw (imacat) Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/22 First written: 2023/3/22
#} #}
<div id="accounting-recurring-{{ expense_income }}" class="form-control mb-3 accounting-material-text-field {% if recurring_items %} accounting-not-empty {% else %} accounting-clickable {% endif %}"> <div id="accounting-recurring-{{ expense_income }}" class="form-control mb-3 accounting-material-text-field {% if recurring_items %} accounting-not-empty {% else %} accounting-clickable {% endif %}" {% if recurring_items %} tabindex="-1" {% else %} role="button" tabindex="0" {% endif %}>
<label class="form-label" for="accounting-recurring-{{ expense_income }}">{{ label }}</label> <span class="form-label">{{ label }}</span>
<div id="accounting-recurring-{{ expense_income }}-content" class="{% if not recurring_items %} d-none {% endif %}"> <div id="accounting-recurring-{{ expense_income }}-content" class="{% if not recurring_items %} d-none {% endif %}">
<ul id="accounting-recurring-{{ expense_income }}-list" class="list-group mb-2 mt-2"> <ul id="accounting-recurring-{{ expense_income }}-list" class="list-group mb-2 mt-2">
{% for recurring_item in recurring_items %} {% for recurring_item in recurring_items %}
@@ -27,11 +27,11 @@ First written: 2023/3/22
<input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-description_template" value="{{ form.description_template.data|accounting_default }}"> <input id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template" type="hidden" name="recurring-{{ expense_income }}-{{ item_index }}-description_template" value="{{ form.description_template.data|accounting_default }}">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div class="w-100"> <div class="w-100">
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-control" class="form-control accounting-clickable {% if form.all_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal"> <button id="accounting-recurring-{{ expense_income }}-{{ item_index }}-control" class="form-control text-start {% if form.all_errors %} is-invalid {% endif %}" type="button" data-bs-toggle="modal" data-bs-target="#accounting-recurring-item-editor-{{ expense_income }}-modal">
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-account-text" class="small">{{ form.account_text|accounting_default }}</div> <span id="accounting-recurring-{{ expense_income }}-{{ item_index }}-account-text" class="d-block small">{{ form.account_text|accounting_default }}</span>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-name-text">{{ form.name.data|accounting_default }}</div> <span id="accounting-recurring-{{ expense_income }}-{{ item_index }}-name-text" class="d-block">{{ form.name.data|accounting_default }}</span>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template-text" class="small">{{ form.description_template.data|accounting_default }}</div> <span id="accounting-recurring-{{ expense_income }}-{{ item_index }}-description-template-text" class="d-block small">{{ form.description_template.data|accounting_default }}</span>
</div> </button>
<div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-error" class="invalid-feedback">{% if form.all_errors %}{{ form.all_errors[0] }}{% endif %}</div> <div id="accounting-recurring-{{ expense_income }}-{{ item_index }}-error" class="invalid-feedback">{% if form.all_errors %}{{ form.all_errors[0] }}{% endif %}</div>
</div> </div>
@@ -36,10 +36,10 @@ First written: 2023/3/22
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div id="accounting-recurring-item-editor-{{ expense_income }}-account-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target="#accounting-recurring-accounting-selector-{{ expense_income }}-modal"> <button id="accounting-recurring-item-editor-{{ expense_income }}-account-control" class="form-control text-start accounting-material-text-field" type="button" data-bs-toggle="modal" data-bs-target="#accounting-recurring-accounting-selector-{{ expense_income }}-modal">
<label class="form-label" for="accounting-recurring-item-editor-{{ expense_income }}-account">{{ A_("Account") }}</label> <span class="form-label">{{ A_("Account") }}</span>
<div id="accounting-recurring-item-editor-{{ expense_income }}-account"></div> <span id="accounting-recurring-item-editor-{{ expense_income }}-account"></span>
</div> </button>
<div id="accounting-recurring-item-editor-{{ expense_income }}-account-error" class="invalid-feedback"></div> <div id="accounting-recurring-item-editor-{{ expense_income }}-account-error" class="invalid-feedback"></div>
</div> </div>
@@ -59,10 +59,10 @@ First written: 2023/3/8
</li> </li>
{% endfor %} {% endfor %}
<li> <li>
<span class="dropdown-item {% if report.report_chooser.is_search %} active {% endif %} accounting-clickable" data-bs-toggle="modal" data-bs-target="#accounting-search-modal"> <button class="dropdown-item {% if report.report_chooser.is_search %} active {% endif %}" type="button" data-bs-toggle="modal" data-bs-target="#accounting-search-modal">
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i> <i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
{{ A_("Search") }} {{ A_("Search") }}
</span> </button>
</li> </li>
</ul> </ul>
</div> </div>