W ramach naszej witryny stosujemy pliki cookies zgodnie z Polityką Cookie. Zasady przechowywania lub dostępu plików cookie możesz zmienić w swojej przeglądarce.
X

mywebcases
.com



Blog

Geekowy blog o łamigłówkach, JavaScript i wszystkim, co ciekawe.

WTFriday: IE, WHY?

Tech stuff - WTFriday -
napisał Jakub Caban

Siedzi, pracujesz, robisz coś. A tu nagle Internet Explorer! I oczywiście jedno wielkie "WTF?" przy próbach zrozumienia jego dziwactw. Historia prawdziwa.

Sprawa świeża, bo dotknęła mnie dokładnie wczoraj. Zamiast bowiem jak cywilizowany człowiek usiąść sobie wieczorem przy piwku i filmie zmuszony zostałem usiąść przy piwku i... IE! A moja mina po znalezieniu rozwiązania wyglądała mniej więcej tak:

WTF IE

Ale dobra - od początku.

To nie działa!

Oczywiście wszystko jak zawsze zaczęło się od zgłoszeń błędu, z których nic nie wynika. Coś w stylu "nie działa mi", "nie bangla" etc etc. W końcu udało się stwierdzić, że problem leży w przeglądarce. A jak problem leży w przeglądarce, to zawsze chodzi o Internet Explorer. No może prawie zawsze, ale jak ktoś używa innej przeglądarki, to wie, że należy zgłaszając błąd o niej wspomnieć. Użytkownicy IE oczywiście nie wiedzą o istnieniu innych przeglądarek (bo przecież jak by wiedzieli, to by ich używali...). Ba! Nawet nie wiedzą, że są różne wersje IE! Dlaczego więc mieliby zwracać na to uwagę?

Ale żeby nie było wracamy do tematu. I żeby nie było, że psioczę na stare wersje IE - problem opisany zaraz występuje w każdej wersji IE do 10 włącznie (na tejże sam testowałem, bo innych nie mam na notebooku).

Dosyć szybko doszedłem do tego, że problem jest gdzieś w takiej oto niewinnej metodzie:

Send: function(action, form){
 this.inel.innerHTML = "<h2>Wysyłanie...</h2>";
 var data = [], el;
 for(var i=0; el=form.elements[i]; i++){
 if(el.type == "text" || el.tagName == "TEXTAREA" || el.tagName == "SELECT"){
 data.push(el.name+"="+encodeURIComponent(el.value));
 }else if(el.checked){
 data.push(el.name+"="+encodeURIComponent(el.value));
 }
 }
 callMePost('voter.php?action='+action, data.join("&"), function(o){
 Voter.Loaded(o);
 }, true);
 },

Wygląda bardzo niewinnie, prawda? Pobieramy parametr action, który jest po prostu stringiem oraz form, który jest obiektem formularza HTML-owego. Następnie ustawiamy zawartość elementu z this.inel na komunikat o wysyłaniu, iterujemy po elementach formularza, aby stworzyć odpowiednie dane, które na końcu przesyłamy przez AJAX metodą POST i wykonujemy metodę Voter.Loaded na wyniku.

Co tu może nie działać? No ja nie wiem - Chrome, FF, Opera i wszystkie inne badziewia nie mają z tym problemu. Tylko cudowne IE się buntuje. Zacząłem więc szukać, console.log-ować (nie lubię, oj bardzo nie lubię developerek w IE).

Żeby zrozumieć dwa kroki do przodu warto jeszcze pokazać, jak wywoływana jest ta metoda:

<form> [cokolwiek]
 <a class="fr" href="#" onclick="Voter.Send('choose', this.parentNode); return false;">...</a>

A to wszystko wewnątrz elementu, do którego odwołujemy się jako this.inel z metody Send.

Co na to IE?

Co pierwsze rzuciło mnie się w oczy, to brak danych wysyłanych przez POST przy zapytaniu z IE. No to ruszyłem husarią całą na Google myśląc "Ktoś musiał też mieć ten problem!". Niestety - poza miliardem wyników o tym, że komuś gdzieś w jQuery dane się nie wysyłają (kogoś to dziwi jeszcze?), to nic. Cicho... Głucho...

Wniosek - nie jest to oczywista i znana głupota IE. Grzebiemy dalej. Jak ten kod kopiowałem do konsoli w IE zamieniając form na document.forms[0] - wszystko bangla że aż miło... Wziąłem więc dodałem na początku metody przypisanie:

form = document.forms[0];

I cały zadowolony i pełen konsternacji poleciałem do IE zobaczyć, jak oszukałem system.

Nie zadziałało...

Przypadkowe olśnienie!

Dodałem więc sobie linijkę taką o:

Send: function(action, form){
 this.inel.innerHTML = "<h2>Wysyłanie...</h2>";
 console.log(form == document.forms[0]);

Zupełnie przypadkowo dokładnie w tym miejscu, w którym powinienem. Bowiem gdy tylko Firefox zwrócił mi na niej false - wiedziałem, że coś się dzieje. I przeanalizowałem zawartość zmiennej form po kolei:

Najpierw element A przekazuje do metody Send jako form swojego rodzica, czyli referencję obiektu DOM typu form. Następnie przez innerHTML nadpisane zostaje drzewo elementu, zawierające między innymi ten formularz. Dlatego document.forms[0] w tym momencie jest undefined. Ale my mamy cały czas referencję do starego formularza (którego po prostu nie ma w drzewie DOM). Garbage collector nie ma bowiem prawa w tym momencie usunąć z pamięci tych elementów, ponieważ istnieją jeszcze referencje do nich w wykonywanym właśnie skrypcie.

Co na to IE? W momencie nadpisania zawartości kontenera formularz jest usuwany z drzewa DOM. Poprawnie. Wszystkie jego elementy też są usuwane z drzewa DOM. Też poprawnie. Ale czemu są usunięte z mojej referencji form? Tego już za cholerę nie rozumiem. Bowiem form.elements cały czas poprawnie w IE zwraca HTMLElementCollection, ale o długości 0! Formularz został, ale jego elementy magicznie zniknęły...

W każdym razie wiedza o tym fakcie pozwoliła mi "poprawić" Send, aby uwzględniała fanaberie tej pseudo-przeglądarki:

Send: function(action, form){
 var data = [], el;
 for(var i=0; el=form.elements[i]; i++){
 if(el.type == "text" || el.tagName == "TEXTAREA" || el.tagName == "SELECT"){
 data.push(el.name+"="+encodeURIComponent(el.value));
 }else if(el.checked){
 data.push(el.name+"="+encodeURIComponent(el.value));
 }
 }
 this.inel.innerHTML = "<h2>Wysyłanie...</h2>";
 callMePost('voter.php?action='+action, data.join("&"), function(o){
 Voter.Loaded(o);
 }, true);
 },

Dziękuję za uwagę

Na koniec odpowiem na ewentualne zarzuty. Wiem, że używanie innerHTML zawsze daje potencjał do tego typu problemów. Ale wiemy, jak jest - najprostsze rozwiązania są najprzyjemniejsze. O ile działają. Bo potem znalezienie z pozoru banalnego problemu może wymagać bardzo wnikliwej analizy przepływu informacji i danych. Pominąłem bowiem wszelkie ślepe zaułki w rozumowaniu, które miałem w międzyczasie...

Z drugiej strony - każdego dnia człowiek się uczy czegoś nowego. Gdyby tylko wiedza o fanaberiach IE była przydatna gdziekolwiek indziej...

WTFriday
Typowe "WTF?!", na które można natknąć się pracując za dużo przy komputerze. Nieregularnie wydawane w piątki na poprawę humoru przed weekendem.

Podobne artykuły:

Skomentuj: