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 onLabelClick
musi 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ąć for
atrybut etykiety tak, że przeglądarki nie ma błędu nie będzie re-trigger go, a następnie użyć setTimeout
w 0ms
celu dodania for
plecy 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#preventDefault
lub usuwa for
atrybut.
manageLabel
FunkcjamanageLabel
akceptuje 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 onLoad
musi zostać wywołana, gdy strona zostanie załadowana, aby manageLabel
moż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 .