Hallo Felix,
so, ich habe jetzt eine Testseite gemacht, die so aussieht (kann sie gerade nicht auf meine Homepage hochladen):
<!doctype html>
<html>
<head>
<script type="module">
import { ConfirmationButton } from "./modules/ConfirmationButton.js";
for (const btn of document.querySelectorAll("button.autoconfirm")) {
new ConfirmationButton(btn);
}
const deleteButton = document.querySelector("#deleteMarked")
deleteButton.addEventListener("click", () => alert("Weg damit!"););
deleteButton.addEventListener("cancel", () => alert("Na, dann nicht!"));
</script>
</head>
<body>
<h1>Testseite für den Confirmation-Button</h1>
<p>Sie haben drölf Dokumente markiert
<button id="deleteMarked" class="autoconfirm" data-prompt=" - wirklich Löschen?" type="button">Löschen</button></p>
</body>
</html>
Das ist der Wireframe für das Widget und keine Produktionsseite, Gunnar! Erzähl also bitte nichts von lang oder meta viewport oder sonstigem Kram. Erzählen kannst Du mir, ob und wie der Autoconfirm-Button noch ariasiert werden muss, damit die Zugänglichkeit gewahrt bleibt.
Wenn diese HTML Datei im Ordner /foo ist, dann erwartet sie das zu importierende Script im Ordner /foo/modules. Das Loader-Script muss type="module" sein, damit es importieren kann. Damit geht ein defer-Loading einher, also erst, wenn das DOM bereit ist.
Ich hätte auch so vorgehen können, dass ich die Autoconfirm-Buttons automatisch vom Widget suchen lasse. Aber ich finde, dass hier das DOT-Prinzip wichtig ist: Do One Thing. Der Konstruktor macht aus einem button einen Autoconfirm-Button. Weiter nichts. Das Auffinden der Buttons ist Another Thing. Das Registrieren von Eventhandlern auf den Buttons ebenfalls, damit muss sich das Widget nicht befassen.
Was das Widget tut, ist das Triggern eines cancel-Events, wenn der Abbrechen-Button gedrückt wird. Das gehört zum Verhalten des Autoconfirm-Buttons. Aber das Registrieren von Handlern nicht.
Das Script modules/ConfirmationButton.js sieht so aus:
export class ConfirmationButton {
static #defaults = {
confirmationClass: 'confirming',
inline: true,
confirmPrompt: "Wirklich löschen?",
cancelText: "Abbrechen",
};
// todo: static API zum Setzen der Defailts
#confirmedButton;
#cancelPrompt;
#cancelButton;
#settings;
constructor(button, settings) {
if (!button instanceof HTMLButtonElement)
throw new TypeError("This class can only be used for button elements");
this.#confirmedButton = button;
// defaults-Objekt als Prototyp für das settings-Objekt verwenden
this.#settings = Object.create(ConfirmationButton.#defaults);
// dann die übergebenen Settings hineinkopieren.
Object.assign(this.#settings, settings);
if (button.dataset.prompt)
this.#settings.confirmPrompt = button.dataset.prompt;
if (button.dataset.cancel)
this.#settings.cancelText = button.dataset.cancel;
const promptText = this.#settings.confirmPrompt;
const cancelText = this.#settings.cancelText;
this.#cancelButton = document.createElement("button");
this.#cancelButton.type = "button";
this.#cancelButton.textContent = cancelText;
this.#cancelButton.style.marginLeft = this.#cancelButton.style.marginRight = "0.5em";
this.#cancelPrompt = document.createElement("span");
this.#cancelPrompt.textContent = this.#settings.confirmPrompt;
this.#showCancelGroup(false);
this.#confirmedButton.insertAdjacentElement("beforebegin", this.#cancelPrompt);
this.#confirmedButton.insertAdjacentElement("beforebegin", this.#cancelButton);
this.#confirmedButton.addEventListener("click",
this.#handleConfirmRequest.bind(this));
this.#cancelButton.addEventListener("click",
this.#handleCancelRequest.bind(this));
}
#handleConfirmRequest(event) {
if (!this.#confirmedButton.classList.toggle(this.#settings.confirmationClass)) {
this.#showCancelGroup(false);
return;
}
this.#showCancelGroup(true);
event.stopImmediatePropagation();
event.preventDefault();
}
#handleCancelRequest(event) {
this.#confirmedButton.classList.remove(this.#settings.confirmationClass);
this.#showCancelGroup(false);
this.#confirmedButton.dispatchEvent(
new Event("cancel", { bubbles: true, cancelable: true })
);
}
#showCancelGroup(show) {
this.#cancelPrompt.hidden = !show;
this.#cancelButton.hidden = !show;
}
}
Ob das jetzt besser ist als dein Ansatz, sei dahingestellt. Aber so würde ich es halt machen.
Rolf
sumpsi - posui - obstruxi