OVH Cloud OVH Cloud

Comment détecter le changement de doc dans un iframe

33 réponses
Avatar
Asterbing
Bonjour. J'ai posé un problème dans comp.lang.javascript mais n'aboutis
pas. Tout est dit dans le fichier HTML dont je copies le contenu ci-
dessous (désolé, c'est en anglais parce que prévu pour un ng anglais à
l'origine ; je peux traduire si utile). Vos lumières m'intéressent.

-- DEBUT DE COPIE --
<html>
<head>
<title>Check Statistics</title>
<script type="text/javascript" language="JavaScript"><!--
var f = document.getElementById("stats");

function WaitStats4Checking(){
if (f.document.readyState == "complete"){Check();}
else{setTimeout("WaitStats4Checking()",50);}}

function GetStats(){
var f = document.getElementById("stats");
f.setAttribute("src","/cgi-bin/getstats.exe");
WaitStats4Checking();}
//--></script>
</head>
<body>
<p>Initially, the iframe contains help.htm which just says "Not any
statistic loaded. Click 'Get Statistics'" for which a heigh of 20px is
enough.
<br><br>
When user click on the 'Get Statistics' link, the GetStats() javascript
function run the getstats.exe CGI script which returns a generated
document in iframe.
<br><br>
When this generated document is well loaded in iframe (not before), the
Check() javascript function should be launched.
<br><br>
Current problem is that (f.document.readyState == "complete") is always
true even if generated document is not fully loaded.
<br><br>
How to solve this ? Maybe going through onreadystatechange to launch
WaitStats4Checking() rather than at the end of GetStats(), but how ?</p>

<a href="#" onclick="GetStats();">Get Statistics</a>

<div style="position: absolute; visibility: visible; top: 300px; left:
15px; height: auto; width: 731px; padding: 5px; overflow: hidden;
background: white; color: #000000">
<iframe id="stats" width=720 height=20 src="help.htm" frameborder="yes"
scrolling="no"></iframe>
</div>
</body></html>
-- FIN DE COPIE --

Merci par avance :)

10 réponses

1 2 3 4
Avatar
Asterbing
In article <44157e06$0$26772$,
says...
onload = function()
{
var f = document.getElementById('stats');
f.onload = function(e) { this.Check(); };
[quoted text muted]
};




Bon, je n'ai pas tout suivi entre ton code et celui d'ASM, mais est-ce
que ceci indique d'ajouter un onload au iframe fonctionnant dans tous
navigateurs majeurs (IE4+,NN,FF,Opera) ?

Sinon, pour te répondre, ASM, le contenu de Check() n'a aucune
importance dans le sujet, je veut seulement la déclencher à chaque
changement de doc généré dans le iframe. Mais, puisque tu insiste, volà
ce que cette fct fait : 1) elle adapte la hauteur du iframe au document
2) elle fait quelques calculs de résumé qu'elle affiche en popup 3) elle
ouvre à d'autre fonctionnalités à partir de ces calculs.

Voilà, voilou !


Avatar
ASM

il faut utiliser 'onload'
pour s'assurer du chargement de quoique ce soit.


Sauf que avec IE il faut utiliser le onreadystatechange :(


IE Windows alors ?
(pas regardé ce que IE Mac fait de onreadystatechange)

--
Stephane Moriaux et son [moins] vieux Mac


Avatar
ASM

mais ceci en vieux code devrait en faire autant :

onload = function () {
var f = document.getElementById("stats");
f.onload = function() { f.Check; };
}



Houla attention là.

f étant un objet DOM, la closure créée ici (en plus d'être une référence
circulaire)


ce dont j'ai tenté d'avertir.

est pile poil le type de structure qui provoque des fuites
mémoires avec IE si on n'y prend pas garde.


casse bonbons jusqu'au bout ce IE quoi !

http://blogs.msdn.com/ie/archive/2005/06/21/431376.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp


Ensuite attention aux (), f.Check; ca indique qu'on veut la référence
ici et donc ben c'est complètement en erreur puisque en réalité il
faudrait appeler la fonction. ==> f.Check();


ha oui, j'ai posté un peu vite et les () ont été oubliées
et autant, j'avais au départ :

f.onload = f.Check;

C'eût-il été OK ? (en dehors du pb de boucle)

En modèle traditionnel on a aucun problème avec la variable this et donc
on peut faire this.Check() (si on considère que Check() fait parti du
scope d'application de la iframe référencée par f)

onload = function()
{
var f = document.getElementById('stats');
f.onload = function(e) { this.Check(); };
};

Ceci dit, je crois qu'on s'éloigne du problème initial.


ça fait rien, tte révision est utile :-)

et pourquoi le 'e' dans : function(e) ?


--
Stephane Moriaux et son [moins] vieux Mac


Avatar
Laurent Vilday

Bonjour. J'ai posé un problème dans comp.lang.javascript mais n'aboutis
pas. Tout est dit dans le fichier HTML dont je copies le contenu ci-
dessous (désolé, c'est en anglais parce que prévu pour un ng anglais à
l'origine ; je peux traduire si utile). Vos lumières m'intéressent.


Humm, on est pas assez bien pour ne mériter qu'un copié/collé ?
D'ailleurs il semblerait que ASM et moi n'ayons pas compris la même
chose à ton problème, preuve qu'un problème mal enoncé ne peut recevoir
que des solutions approximatives.

<script type="text/javascript" language="JavaScript"><!--


language est deprecated. Utilises seulement type="text/javascript"
et c'est quoi cette manie du <!-- ? c'est très laid et obsolète imo

var f = document.getElementById("stats");
function WaitStats4Checking(){
if (f.document.readyState == "complete"){Check();}
else{setTimeout("WaitStats4Checking()",50);}}


pourquoi avoir défini f (var f) en dehors de WaitStats4Checking ? C'est
le genre de pratique qui conduit très facilement par inadvertance à des
fuites mémoires qu'on voit même pas.

Se baser sur un timeout pour détecter les chargement c'est imo mal, il
vaut mieux utiliser les events dédiés à ça : onload pour quasiment tous
les navigateurs et onreadystatechange pour IE

function GetStats(){
var f = document.getElementById("stats");
f.setAttribute("src","/cgi-bin/getstats.exe");
WaitStats4Checking();}


Là, ta fonction GetStats() ne retourne rien. C'est mal puisque tu
l'utilises comme handler sur un lien <a>. Tu dois *impérativement*
retourné false si tu veux pas suivre ton lien <a href="#"> (voir FAQ)

When user click on the 'Get Statistics' link, the GetStats() javascript
function run the getstats.exe CGI script which returns a generated
document in iframe.


Comment est retourné ce document ? Je veux dire, est-ce que le CGI
getstats.exe ferait pas des trucs bizarres sur la sortie standard avec
des ouvertures/fermetures de connection étranges ?
Est-ce que c'est possible d'avoir une démo en ligne pour avoir accès à
un environment plus proche de ce que tu as ?

When this generated document is well loaded in iframe (not before), the
Check() javascript function should be launched.


ok donc pour IE
iframe.onreadystatechange = function()
{
if (this.readyState == 'complete') { Check(); }
};

pour les autres
iframe.onload = Check;

Current problem is that (f.document.readyState == "complete") is always
true even if generated document is not fully loaded.


Humm, comme tu as vu, j'aurai eu tendance à placer le gestionnaire sur
la iframe et pas sur le document. Mais j'ai probablement tort (et dans
ce cas je me plante totalement. J'vais me faire une petite page de test,
mais sans savoir ce que retourne exactement ton CGI (et sans savoir
comment) ca va être dur de reproduire ton problème)

How to solve this ? Maybe going through onreadystatechange to launch
WaitStats4Checking() rather than at the end of GetStats(), but how ?</p>


Je pense qu'il faut abandonner l'idée du timeout, c'est à mon avis la
mauvaise direction à prendre.

http://mokhet.com/tests/xbrowser_onload_iframe.html
(attention, le chargement de iframeA.html est volontairement long a
éxécuter pour essayer de se rapprocher d'un éventuel CGI, mais bon)

<script type="text/javascript">
var ie = false; /*@cc_on ie = true; @*/
function $(id) { return document.getElementById(id); }
function loadIFrame(id, source)
{
// on récupère l'objet iframe à partir de l'id fourni
var iframe = $(id);
// si l'objet est introuvable, abandon du processus
if (!iframe)
{
alert('Iframe introuvable');
return false;
}
// place le gestionnaire. Spécial pour IE forcemment :(
if (ie)
{
iframe.onreadystatechange = _statechange;
}
else
{
iframe.onload = _onload;
}
// applique la source
iframe.src = source;
// annule le suivi du lien cliqué
return false;
}

function _statechange(evt)
{
// this represente la iframe puisque on est en modèle d'event
// traditionnel et même IE (mac aussi je pense), oh bonheur
// est capable de transmettre correctement le scope
// d'application et l'évent généré
if (this.readyState == "complete")
{
// appel de _completeLoad en utilisant :
// 1) this (la iframe) comme scope d'application
// 2) evt (l'event) comme paramètre
_onload.call(this, evt);
}
}

function _onload(evt)
{
$('res').innerHTML = 'Chargement terminé de ' + this.src;
// on enlève les référence cycliques au cas où le garbage collector
// pête un cable
this.onload = null;
this.onreadystatechange = null;
}
</script>
</head>
<body>

<iframe id="ifr" style="width:100%; height:200px;"></iframe>

<a href="#" onclick="return loadIFrame('ifr', 'iframeA.html');">A</a>
<a href="#" onclick="return loadIFrame('ifr', 'iframeB.html');">B</a>

<div id="res">Zone de résultat</div>

Est-ce que ça t'orientes ou est-ce que je suis à côté ?

--
laurent

Avatar
ASM
In article <44157e06$0$26772$,
says...

1) elle adapte la hauteur du iframe au document


c'est ABSOLUMENT interdit !
c'est encore un "à la va comme je te pousse" à la IE
(et encore ! je crois bien que celui Mac n'est pas d'accord)
(il agrandit l'iframe mais pas son contenu, de mémoire)

2) elle fait quelques calculs de résumé qu'elle affiche en popup


ça c'est si mon anti-popup est désactivé ...

3) elle ouvre à d'autre fonctionnalités à partir de ces calculs.



--
Stephane Moriaux et son [moins] vieux Mac

Avatar
Laurent Vilday
onload = function()
{
var f = document.getElementById('stats');
f.onload = function(e) { this.Check(); };
};

Ceci dit, je crois qu'on s'éloigne du problème initial.


ça fait rien, tte révision est utile :-)


J'ai toujours peur de faire de rectifier parce que peur d'être mal
interprété, toujours peur d'avoir à m'excuser d'avoir pas suffisemment
arrondi les angles pour faire comprendre ce que je veux dire sans avoir
l'air pédant ou arrogant. Donc généralement je me tais, mais là bien que
sachant que c'était que des bêtes typos lors de la rédaction, j'ai
préféré intervenir parce que tu es un peu la FAQ de fciwa :D et que tes
écrits sont comme une bible pour certains lecteurs. Donc plutôt que de
laisser les lecteurs retenir une erreur j'ai pensé qu'il fallait
rectifier. Tiens tu vois, je suis à la limite (comme d'hab) d'annuler ce
post, grr, je rêve du jour ou je saurais m'exprimer clairement sans être
obligé d'en écrire autant. grrrr.

et pourquoi le 'e' dans : function(e) ?


Une question d'habitude je dirais, puisque on est en modèle traditionnel
de gestion des events, on a accès à l'event dans le premier paramètre et
même avec IE ça passe donc autant en profiter :)

--
laurent


Avatar
Laurent Vilday

... la FAQ de fciwa ...


Pfff idiot, c'est fclj ici.

bon allez, je sors

--
laurent

Avatar
ASM

J'ai toujours peur de faire de rectifier parce que peur d'être mal
interprété,


il est seulement dommage que tu n'interviennes pas plus.
J'ai une grosse tendance à approximativer (autodidacte)
et tes precisions (toujours très éclairées) ne sauraient n'être qu'un plus.

--
Stephane Moriaux et son [moins] vieux Mac

Avatar
ASM

http://mokhet.com/tests/xbrowser_onload_iframe.html


j'ai comme l'impression que 'onreadystatechange'
n'est pas interprété par mon IE Mac , bien que ça ne semble pas
occasionner d'erreur
-> le div "res" ne change pas

à moins que ceci :
if (this.readyState == "complete")
ne soit incompris ?



--
Stephane Moriaux et son [moins] vieux Mac

Avatar
Asterbing
In article <441588e0$0$21289$,
says...
(il agrandit l'iframe mais pas son contenu, de mémoire)



C'est bien ce que j'ai dit : ma fct check(), parmi d'autres choses,
ajuste la hauteur de l'iframe à son contenu. Enfin, je n'ai aucun pb
avec ce point-ci, ça marche sans pb. Ma question n'a rien à voir avec le
contenu de Check().

1 2 3 4