blob: b55f275321b4c41a61517c2b810681212cdea6df [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
import {DomUtils} from "./tobago-utils";
class TreeListbox extends HTMLElement {
constructor() {
super();
}
connectedCallback(): void {
this.applySelected();
for (const listbox of this.listboxes) {
if (!listbox.disabled) {
listbox.addEventListener("change", this.select.bind(this));
}
}
}
private select(event: Event): void {
const listbox = event.currentTarget as HTMLSelectElement;
this.unselectDescendants(listbox);
this.setSelected();
this.applySelected();
}
private unselectDescendants(select: HTMLSelectElement): void {
let unselect: boolean = false;
for (const listbox of this.listboxes) {
if (unselect) {
const checkedOption = listbox.querySelector<HTMLOptionElement>("option:checked");
if (checkedOption) {
checkedOption.selected = false;
}
} else if (listbox.id === select.id) {
unselect = true;
}
}
}
private setSelected(): void {
const selected: number[] = [];
for (const level of this.levelElements) {
const checkedOption: HTMLOptionElement = level
.querySelector(".tobago-treeListbox-select:not(.d-none) option:checked");
if (checkedOption) {
selected.push(checkedOption.index);
}
}
this.hiddenInput.value = JSON.stringify(selected);
}
private applySelected(): void {
const selected: number[] = JSON.parse(this.hiddenInput.value);
let nextActiveSelect: HTMLSelectElement = this.querySelector(".tobago-treeListbox-select");
const levelElements = this.levelElements;
for (let i = 0; i < levelElements.length; i++) {
const level = levelElements[i];
for (const select of this.getSelectElements(level)) {
if ((nextActiveSelect !== null && select.id === nextActiveSelect.id)
|| (nextActiveSelect === null && select.disabled)) {
const check: number = i < selected.length ? selected[i] : null;
this.show(select, check);
nextActiveSelect = this.getNextActiveSelect(select, check);
} else {
this.hide(select);
}
}
}
}
private getSelectElements(level: HTMLDivElement): NodeListOf<HTMLSelectElement> {
return level.querySelectorAll<HTMLSelectElement>(".tobago-treeListbox-select");
}
private getNextActiveSelect(select: HTMLSelectElement, check: number): HTMLSelectElement {
if (check !== null) {
const option = select.querySelectorAll("option")[check];
return this.querySelector(DomUtils.escapeClientId(option.id + DomUtils.SUB_COMPONENT_SEP + "parent"));
} else {
return null;
}
}
private show(select: HTMLSelectElement, check: number): void {
select.classList.remove("d-none");
const checkedOption = select.querySelector<HTMLOptionElement>("option:checked");
if (checkedOption && checkedOption.index !== check) {
checkedOption.selected = false;
}
if (check !== null && checkedOption.index !== check) {
select.querySelectorAll("option")[check].selected = true;
}
}
private hide(select: HTMLSelectElement): void {
select.classList.add("d-none");
const checkedOption = select.querySelector<HTMLOptionElement>("option:checked");
if (checkedOption) {
checkedOption.selected = false;
}
}
private get listboxes(): NodeListOf<HTMLSelectElement> {
return this.querySelectorAll(".tobago-treeListbox-select");
}
private get levelElements(): NodeListOf<HTMLDivElement> {
return this.querySelectorAll(".tobago-treeListbox-level");
}
private get hiddenInput(): HTMLInputElement {
return this.querySelector(DomUtils.escapeClientId(this.id + DomUtils.SUB_COMPONENT_SEP + "selected"));
}
}
document.addEventListener("DOMContentLoaded", function (event: Event): void {
window.customElements.define("tobago-tree-listbox", TreeListbox);
});