Zarys sytuacji:
Nie dysponuję PHP.
Na moim serwerze jest multum reklam i unikam przechodzenia od strony do strony - zamiast tego javascript modyfikuje aktualną stronę.
Sprawdzam działanie strony na IE oraz FF, używam FF.
Zrobiłem galerię miniaturek obrazków. Każda z nich w zdarzeniu onMouseDown wysyła index klikniętego obrazka i wywołuje coś, w czym ten obrazek się ukaże w pełnym wymiarze. To coś nazywam 'viewer' (bo zamierzam upublicznić swoje dokonanie za darmo na stronce, z której zaczerpnąłem układ kolorystyczny) i jest to początkowo ukryte, lecz istnieje od pierwszej chwili istnienia stronki. Najważniejszy element viewera to obrazek, w którym podmieniam SRC na takie, jakie aktualnie jest potrzebne.
Problem w skrócie:
Jak zrobić, by skrypt poczekał na załadowanie obrazka, który nakazał chwilę wcześniej załadować, aby pobrać jego rozmiary?
Ewentualnie: jak uzyskać 100% pewne rozmiary tego obrazka (bo sam obrazek nie jest mi potrzebny)?
Problem w całości:
Jestem w trakcie wykonywania funkcji javascript obsługującej ukazanie się obrazka i jego skalowanie i nie mogę jej przerwać.
Ustawiam wartość SRC na taką, jaka ma być i chciałbym, by skrypt zaczekał aż do załadowania obrazka, bym mógł sprawdzić, jakie są wymiary obrazu. Nie potrzebuję załadowanego obrazu, tylko jego pełne wymiary:
Kod
document.getElementById("viewer").src = imgPathNm; //imgPathNm = image's URL
ichangeinfo=new Object();
ichangeinfo.xi=document.getElementById("viewer").width;
ichangeinfo.yi=document.getElementById("viewer").height;
ichangeinfo.xr= f_clientWidth();;
ichangeinfo.yr= f_clientHeight();
ichangeinfo.stretch=false;
ichangeinfo.fullsize=false;
viewDeterm=new Object(); //the same as ichangeinfo, prepared for return values
viewDeterm = fitImgToRoom(ichangeinfo);
ichangeinfo=new Object();
ichangeinfo.xi=document.getElementById("viewer").width;
ichangeinfo.yi=document.getElementById("viewer").height;
ichangeinfo.xr= f_clientWidth();;
ichangeinfo.yr= f_clientHeight();
ichangeinfo.stretch=false;
ichangeinfo.fullsize=false;
viewDeterm=new Object(); //the same as ichangeinfo, prepared for return values
viewDeterm = fitImgToRoom(ichangeinfo);
Tymczasem IE - gdy nie zdąży załadować obrazka - (sprawdzałem lokalnie i raz na ok.10 prób się tak robi) zwraca rozmiar x=28, y=30 pixeli.(Firefox, gdy nie zdąży - zwraca 0,0).
Próbowałem to rozwiązać na 3 różne sposoby:
(1) poprzez zdarzenie onLoad w obrazku:
Kod
viewerReady = new Boolean(false);
<IMG class="overlay_image" id="viewer" src="" onLoad="setViewerAsReady();" />
................
function setViewerAsReady() { viewerReady = true; }
...............
document.getElementById("viewer").src = imgPathNm; //imgPathNm = image's URL
if (viewerReady==false) {alert("jeszcze nie");}
<IMG class="overlay_image" id="viewer" src="" onLoad="setViewerAsReady();" />
................
function setViewerAsReady() { viewerReady = true; }
...............
document.getElementById("viewer").src = imgPathNm; //imgPathNm = image's URL
if (viewerReady==false) {alert("jeszcze nie");}
ale ten sposób zawsze wywoła komunikat "jeszcze nie", choćby nie wiem ile czekać, bo funkcja jest obsługiwana jednowątkowo i zdarzenie onLoad obrazka wywoła się dopiero po niej... (chyba)
(2) poprzez właściwość .complete obrazka:
Kod
document.getElementById("viewer").src = imgPathNm;
var counter=0;
do
{
if ( document.getElementById("viewer").complete == true)
{ alert ("ok "+counter); break; }
counter++;
if (counter >= 40000) {alert("limit czasu"); break;}
}
while (true); //przykładowy limit, by uniknąć nieskończoności
alert (document.getElementById("viewer").width + "," + document.getElementById("viewer").height);
var counter=0;
do
{
if ( document.getElementById("viewer").complete == true)
{ alert ("ok "+counter); break; }
counter++;
if (counter >= 40000) {alert("limit czasu"); break;}
}
while (true); //przykładowy limit, by uniknąć nieskończoności
alert (document.getElementById("viewer").width + "," + document.getElementById("viewer").height);
ale to wydaje się zupełnie bezsensowne, bo po pierwsze pozornie zawiesza skrypt na czas ładowania, po drugie nawet obrazki, które mam na dysku i już je otwierałem, zacinają się raz na jakiś czas i wtedy w pętli pokazuje się "limit czasu", a już po kliknieciu OK i wyjściu poza nią pokazuje się zawsze poprawny wymiar.
Czyli to coś, co pozwala obrazkowi dojść do siebie to alert, który prawdopodobnie wzrusza jakoś kolejkę komunikatów (message queue). Obrazek jest albo od razu ok, albo nie "załaduje się" aż do końca działania takiej petli, nie ważne jak długo by ona działała. Jeśli ustawię jej trwanie na 10 sekund, to i tak nie da rady, mimo, że po nastawieniu na sekundę, upływie tej sekundy i kliknięciu OK wymiary wyświetlają się w porządku.
Widać, że to nie jest po prostu kwestia czasu, ale nie wiem, co to może być.
Stąd właśnie poszło moje pytanie, jak zrobić, by skrypt naprawdę poczekał.
Oczywiście docelowo nie będzie żadnych alertów, ale na razie zupełnie nie potrafię debugowac skryptów, więc tylko dzięki alertom wiem, dokąd się skrypt wykonał i co szwankuje, a dzięki temu odkryłem, że alert uzdrawia tą sytuację.
(3) poprzez zwykłą ordynarną pętlę opóźniającą, która działała lokalnie (na moim komputerze, nie poprzez serwer) w sumie najlepiej, tylko jest zupełnie nieelegancka a docelowo nie do przyjęcia:
Kod
document.getElementById("viewer").src = imgPathNm;
// here comes loop that makes delay between src=... assignation and reading of image dimmensions
// Without this IE sometimes gives image size= x:28,y:30
// (probably size of icon showed when no image available);
// FF sometimes gives 0,0
if ( ( (document.getElementById("viewer").width == 28) && (document.getElementById("viewer").height == 30) ) ||
( (document.getElementById("viewer").width == 0) && (document.getElementById("viewer").height == 0) ) )
{var inx=0; var abc=0; for (inx=0; x<10000; x++){abc++;} } //dummy loop, TODO: do it better
alert (document.getElementById("viewer").width + "," + document.getElementById("viewer").height);
// here comes loop that makes delay between src=... assignation and reading of image dimmensions
// Without this IE sometimes gives image size= x:28,y:30
// (probably size of icon showed when no image available);
// FF sometimes gives 0,0
if ( ( (document.getElementById("viewer").width == 28) && (document.getElementById("viewer").height == 30) ) ||
( (document.getElementById("viewer").width == 0) && (document.getElementById("viewer").height == 0) ) )
{var inx=0; var abc=0; for (inx=0; x<10000; x++){abc++;} } //dummy loop, TODO: do it better
alert (document.getElementById("viewer").width + "," + document.getElementById("viewer").height);
ale to też zawiesza przeglądarkę na jakis czas, z resztą jak załaduję stronkę na serwer, to nie będzie wiadomo, jaką wartość wpisać jako limit pętli. W każdym razie to mi działa.
Krótko mówiąc odrobiłem zadanie domowe, ale kołaczę się pomiędzy zawieszeniem przeglądarki, niepewnymi wynikami i niepoprawnym odczytem wymiarów obrazka. W necie są miliony wypowiedzi na tematy podobne do mojego, na samym irtorg jest kilkanaście stron linków do różnych takich pytań. Ale mój problem jest inny. bo nie potrzebuję obrazka, tylko jego naturalne wymiary w pixelach, a poza tym problem tkwi chyba w kolejce zdarzeń - brakuje mi czegoś takiego, jak dispatch(message) żeby funkcja mogłą na chwilę zawiesić swoje działanie i pozwolić przeglądarce obsłużyć inne (zewnętrzne) zdarzenia... Tak w każdym razie robiłem to w C++.
To jest taka moja zgadywanka, ale może jest tutaj ktoś, kto po prostu wie o co chodzi?
Ktoś pomoże? Z góry dzięki dla takiego.
http://www.sendspace.pl/file/UgQxiFaU/
^
w razie czego można pobrać i obejrzeć problem w praktyce, pamiętając iż występuje on raz na ok. 10 razy (u innych może być inaczej) i że po powiększeniu fotki nie da się na razie wrócić do poprzedniego widoku inaczej, niż przez F5