Wprowadzenie
Chociaż wyraźnie stwierdziłem w pytaniu, że odpowiedź nie powinna obejmować JavaScript, wszystkie odpowiedzi działały z JavaScript.
Ponieważ wydaje się, że jest to błąd przeglądarki Firefox, a większość odpowiedzi przesłanych w tym momencie wymagałaby również zmiany reszty mojego kodu, postanowiłem utworzyć skrypt, który można uruchomić raz, poradzi sobie ze wszystkimi etykietami niezależnie od tego, kiedy są dodawane do domeny i będą miały najmniejszy wpływ na moje inne skrypty.
Rozwiązanie - przykład
var mutationConfiguration = {
attributes: true,
childList: true
};
if (document.readyState === "complete") onLoad();
else addEventListener("load", onLoad);
var managingDoms = [];
function onLoad() {
document.querySelectorAll("label[for]").forEach(manageLabel);
if (typeof MutationObserver === "function") {
var observer = new MutationObserver(function(list) {
list.forEach(function(item) {
({
"attributes": function() {
if (!(item.target instanceof HTMLLabelElement)) return;
if (item.attributeName === "for") manageLabel(item.target);
},
"childList": function() {
item.addedNodes.forEach(function(newNode) {
if (!(newNode instanceof HTMLLabelElement)) return;
if (newNode.hasAttribute("for")) manageLabel(newNode);
});
}
}[item.type])();
});
});
observer.observe(document.body, mutationConfiguration);
}
}
function manageLabel(label) {
if (managingDoms.includes(label)) return;
label.addEventListener("click", onLabelClick);
managingDoms.push(label);
}
function onLabelClick(event) {
if (event.defaultPrevented) return;
var id = this.getAttribute("for");
var target = document.getElementById(id);
if (target !== null) {
this.removeAttribute("for");
var self = this;
target.click();
target.focus();
setTimeout(function() {
self.setAttribute("for", id);
}, 0);
}
}
label {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding: 10px;
border: 1px solid black;
cursor: pointer;
}
<input type="checkbox" id="a">
<input type="text" id="b">
<label for="a">A</label>
<script>
setTimeout(function() {
var label = document.createElement("label");
label.setAttribute("for", "b");
label.textContent = "b";
document.body.appendChild(label);
}, 3E3);
</script>
Wyjaśnienie
onLabelClick
Funkcja onLabelClickmusi być wywoływana za każdym razem, gdy kliknięta zostanie etykieta, sprawdzi, czy etykieta ma odpowiedni element wejściowy. Jeśli tak, to będzie go wyzwolić, usunąć foratrybut etykiety tak, że przeglądarki nie ma błędu nie będzie re-trigger go, a następnie użyć setTimeoutw 0mscelu dodania forplecy atrybutu raz impreza przepuszcza się w górę. Oznacza to, event.preventDefaultże nie trzeba dzwonić, dlatego żadne inne działania / zdarzenia nie zostaną anulowane. Również jeśli muszę zastąpić tę funkcję, muszę tylko dodać detektor zdarzeń, który wywołuje Event#preventDefaultlub usuwa foratrybut.
manageLabel
FunkcjamanageLabelakceptuje etykietę sprawdza, czy został już dodany detektor zdarzeń, aby uniknąć ponownego dodania go, dodaje detektor, jeśli nie został jeszcze dodany, i dodaje go do listy etykiet, którymi zarządzano.
onLoad
Funkcja onLoadmusi zostać wywołana, gdy strona zostanie załadowana, aby manageLabelmożna było wywołać funkcję dla wszystkich etykiet w DOM w tym momencie. Funkcja używa także MutationObserver do przechwytywania dodawanych etykiet po uruchomieniu obciążenia (i uruchomieniu skryptu).
Powyższy kod został zoptymalizowany przez Martina Barkera .