Skip to content

Commit 3a3164a

Browse files
committed
Use the DOM as the source of truth
1 parent a3e4e17 commit 3a3164a

File tree

4 files changed

+103
-57
lines changed

4 files changed

+103
-57
lines changed

ts/WoltLabSuite/WebComponent/woltlab-core-label-picker.ts

Lines changed: 89 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,39 @@
11
{
22
class WoltlabCoreLabelPickerElement extends HTMLElement {
3+
#button: HTMLButtonElement | undefined = undefined;
4+
#input: HTMLInputElement | undefined = undefined;
35
#labels: Map<number, string> | undefined = undefined;
4-
#name: string = "";
5-
#selected: number = 0;
66

77
connectedCallback() {
88
this.#setupLabels();
99

1010
this.innerHTML = "";
1111

12-
const selected = parseInt(this.getAttribute("selected")!);
13-
this.removeAttribute("selected");
14-
if (!Number.isNaN(selected)) {
15-
this.selected = selected;
12+
if (!this.value) {
13+
this.value = 0;
1614
}
1715

18-
const name = this.getAttribute("name")!;
19-
this.removeAttribute("name");
20-
if (this.#name === "") {
21-
this.#name = name || "labelIDs[]";
16+
if (!this.name) {
17+
this.name = "labelIDs";
2218
}
2319

2420
this.classList.add("dropdown");
2521

26-
const button = document.createElement("button");
27-
button.type = "button";
28-
button.classList.add("dropdownToggle");
29-
button.append(this.#getLabel(this.selected));
30-
31-
const dropdownMenu = document.createElement("ol");
32-
dropdownMenu.classList.add("dropdownMenu");
33-
34-
const input = document.createElement("input");
35-
input.type = "hidden";
36-
input.name = this.name;
37-
input.value = "0";
38-
39-
for (const [labelId, html] of this.#labels!) {
40-
const button2 = document.createElement("button");
41-
button2.type = "button";
42-
button2.innerHTML = html;
43-
button2.addEventListener("click", () => {
44-
this.selected = labelId;
45-
46-
button.innerHTML = "";
47-
button.append(this.#getLabel(this.selected));
48-
49-
input.value = this.#selected.toString();
50-
});
22+
if (this.#button === undefined) {
23+
this.#button = document.createElement("button");
24+
this.#button.type = "button";
25+
this.#button.classList.add("dropdownToggle");
26+
this.#button.append(this.#getLabel(this.value));
27+
}
5128

52-
const listItem = document.createElement("li");
53-
listItem.append(button2);
54-
dropdownMenu.append(listItem);
29+
if (this.#input === undefined) {
30+
this.#input = document.createElement("input");
31+
this.#input.type = "hidden";
32+
this.#input.name = this.name;
33+
this.#input.value = this.value.toString();
5534
}
5635

57-
this.append(button, dropdownMenu, input);
36+
this.append(this.#button, this.#buildSelection(), this.#input);
5837
}
5938

6039
#setupLabels(): void {
@@ -88,20 +67,84 @@
8867
return template.content.cloneNode(true);
8968
}
9069

91-
get selected(): number {
92-
return this.#selected;
70+
#buildSelection(): HTMLElement {
71+
const dropdownMenu = document.createElement("ol");
72+
dropdownMenu.classList.add("dropdownMenu");
73+
74+
for (const [labelId, html] of this.#labels!) {
75+
dropdownMenu.append(this.#createListItem(labelId, html));
76+
}
77+
78+
if (!this.required) {
79+
const divider = document.createElement("li");
80+
divider.classList.add("dropdownDivider");
81+
82+
const emptySelection = this.#createListItem(0, this.#getEmptyLabel().outerHTML);
83+
dropdownMenu.append(divider, emptySelection);
84+
}
85+
86+
return dropdownMenu;
87+
}
88+
89+
#createListItem(labelId: number, html: string): HTMLLIElement {
90+
const button = document.createElement("button");
91+
button.type = "button";
92+
button.innerHTML = html;
93+
button.addEventListener("click", () => {
94+
this.value = labelId;
95+
});
96+
97+
const listItem = document.createElement("li");
98+
listItem.append(button);
99+
100+
return listItem;
93101
}
94102

95-
set selected(selected: number) {
96-
if (this.#labels?.has(selected)) {
97-
this.#selected = selected;
103+
get value(): number {
104+
return parseInt(this.getAttribute("value") || "");
105+
}
98106

99-
// TODO: update the button label
107+
set value(value: number) {
108+
if (value !== 0 && !this.#labels?.has(value)) {
109+
throw new Error(`There is no label with the id ${value}.`);
110+
}
111+
112+
this.setAttribute("value", value.toString());
113+
114+
if (this.#button !== undefined && this.#input !== undefined) {
115+
this.#button.innerHTML = "";
116+
this.#button.append(this.#getLabel(this.value));
117+
118+
this.#input.value = value.toString();
100119
}
101120
}
102121

103122
get name(): string {
104-
return this.#name;
123+
return this.getAttribute("name") || "";
124+
}
125+
126+
set name(name: string) {
127+
if (name === "") {
128+
throw new Error("The name cannot be empty.");
129+
}
130+
131+
this.setAttribute("name", name);
132+
133+
if (this.#input !== undefined) {
134+
this.#input.name = name;
135+
}
136+
}
137+
138+
get required(): boolean {
139+
return this.hasAttribute("required");
140+
}
141+
142+
set required(required: boolean) {
143+
if (required) {
144+
this.setAttribute("required", "");
145+
} else {
146+
this.removeAttribute("required");
147+
}
105148
}
106149
}
107150

0 commit comments

Comments
 (0)