11485 sujets

JavaScript, DOM et API Web HTML5

Pages :
(reprise du message précédent)

chmel a écrit :
La page test de Dean Edwards donne 10 erreurs au validateur
Je ne vois pas le rapport entre le fait que sa page de test soit invalide et que sa méthode le soit...

Si tu avais lu ce qu'il propose, tu saurais que la partie HTML se limite à une inclusion de script tout à fait banale.
chmel a écrit :
Concernant notre sujet, on peut initialiser sans "load" :
- En écrivant le script dans le body, après les éléments auquels le script se rattache. C'est valide mais on l'évite souvent pour une question de convention, je crois.
C'est invalide en XHTML 1.1.
chmel a écrit :
- Au premier mouvement de la souris ou du clavier comme ici
Je préfère nettement une solution comme celle de Dean Edwards, qui me parait plus propre...
Eldebaran a écrit :
C'est invalide en XHTML 1.1....

Merci pour l'info car j'ai du mal avec l'anglais et il manque des traductions . document.write c'est valide en XHTML 1.1 ?
Modifié par chmel (11 Nov 2006 - 14:21)
chmel a écrit :
Merci pour l'info car j'ai du mal avec l'anglais et il manque des traductions . document.write c'est valide en XHTML 1.1 ?
Ca ne fonctionne normalement pas avec du XHTML servi en tant que application/xhtml+xml. Dans ce cas-là, il suffit d'utiliser des commentaires conditionnels HTML comme dans la première version ou alors de passer par le DOM.

Ce qui est intéressant, c'est l'évènement "DOMContentLoaded" pour Firefox et Opera et l'attribut "defer" pour IE.
chmel a écrit :

Merci pour l'info car j'ai du mal avec l'anglais et il manque des traductions . document.write c'est valide en XHTML 1.1 ?

Ca devrait être valide nulle part... Le problème de document.write est qu'on ne maîtrise pas toujours l'endroit où on write... Du coup le DOM peut être complètement chamboulé...
Bonjour
Pour revenir à la question initiale voir sur ce même site le "tuto" suivant

Séparer le comportement de la structure
Par Peter-Paul Koch

qui explique les choses très clairement et très simplement
Hello

J'ai pas mal de hits provenant de ce post, j'imagine que c'est une question récurrente qui interpelle beaucoup de monde. La méthode que j'évoque dans le post lié plus haut ( ici ) m'a jusqu'ici satisfait et si vous avez déjà testé et rencontré des problèmes cela m'intéresserait que vous m'en informiez.

Je suppose cependant que mon post pourrait être plus clair Smiley rolleyes , alors si vous avez des questions, welcome.

Pour revenir au pourquoi de cette méthode :

- que ce soit en assignant window.onload par javascript ou l'attribut onload de body dans la source html, le gros problème est que le script ne sera invoqué que lorsque *tous* les éléments seront chargés. Cela veut dire que si une applet flash de youtube tarde à venir ou que les stats Xiti pédalent dans la semoule, le script mettra pas mal de temps avant de s'exécuter.

- insérer dans l'HTML du javascript qui manipule directement le DOM est risqué, car le modèle de la page n'est pas encore chargé. Il ne trouvera pas les éléments recherchés ou pire, buggera le browser. document.write est heureusement assez safe à ce niveau c'est pourquoi je l'utilise pour afficher de l'HTML qui ne doît apparaître que si javascript est activé.

ce n'est pas risqué et rapide parce que :
- ce n'est exécuté que lorsque l'HTML a fini d'être chargé et "construit" par le browser. En revanche, les images et autres sources lentes peuvent continuer à se charger pendant ce temps ; l'exécution du script ne les attendra pas.

- la fonction de démarrage appelée via l'évènement "onload" de l'image d'attente peut se trouver dans un script externe référencé dans la partie <head> du document. Le javascript se trouvant dans l'html n'est pas exécuté tant que ceux figurant dans le <head> ne sont pas chargés.

- l'image peut servir de feedback visuel à l'utilisateur, au cas où, par exemple, le javascript à exécuter met à jour des informations dont il a besoin sur la page, ou lui demande son mot de passe, fait une requête ajax, etc.

Concernant l'inquiétude sur les standards, j'ai bien peur qu'il n'en existe tout simplement pas quand il s'agit de manipuler le DOM avec le javascript. Le seul standard est de facto, c'est de répondre à l'attente du marché en s'assurant que cela fonctionne parfaitement sous Firefox 1.x/2.x, IE6/7 et Safari et Opera si on les a sous la main ( molo avec le gourdin si je dis une atrocité ). Quand à IE5.5 et autres antiquités, pitié Smiley biggol , vaut mieux prévoir un "mode sans échec" c'est à dire que la page fonctionne tout aussi bien, mais peut-être moins confortable, sans javascript du tout.
Salut,

Franchement, je ne suis pas convaincu par ta méthode.

Rien ne garantit que ton image sera chargée avant les autres éléments de la page, on risque donc d'attendre inutilement avant d'exécuter la fonction. Ca ajoute une requête HTTP inutile pour récupérer l'image. C'est intrusif puisque qu'il faut placer l'élément <script> dans le <body>. De plus, ça force à ajouter une image en plus du fichier JavaScript sur le serveur.

A choisir, je préfère :
- L'élément <script> placé après les éléments dont on a besoin, qui contient juste l'appel à la fonction (c'est aussi intrusif, mais ça n'a pas les autres inconvénients).
- L'événement propriétaire DOMContentLoaded pour Firefox et Opera.
- La solution onAvailable de YUI.

Peter Michaux a écrit récemment un article (en anglais) très intéressant à ce sujet. Il pèse le pour et le contre des différentes solutions, entre autres celle de Dean Edwards, évoquée dans ce sujet.
Modifié par Julien Royer (20 Feb 2007 - 15:58)
Salut, merci pour ta réponse.

Ok pour l'argument de l'ordre de chargement de l'image.

Mais : je me base sur le principe que l'image est locale. Question de relativisme, l'image locale sera chargée aussi vite que la page HTML la contenant ; ce qui inquiète dans le cas d'un window.onload, c'est qu'on dépend de la vitesse de chargement des sources externes.

L'argument de la requête inutile et de l'attente due à l'ordre de chargement tombe assez vite quand on sait qu'après la première requête, l'image sera évidemment en cache. Qu'on n'aime pas mettre une image qui sert à rien, Ok ... dans mon contexte je fais d'une pierre deux coups en affichant une image sobre qui signale qu'un traitement est en cours.

Pour l'intrusivité, bof. Le code est valide et facilement insérable dans les templates de layout de son environnement favori, et si on préfère on créera sa fonction php/asp/ruby qui cachera ces détails ; bref on le fait une fois pour toutes et tout le reste du traitement se passe dans sa fonction .js. L'intrusivité dont on s'inquiète, c'est de se retrouver avec des onclick, des onload, onmouseover un peu partout et de manière répétitive dans son code ; ici c'est pas pour une fois surtout si on n'a pas le choix, et que le but du script démarré est d'installer ces events lors de son initialisation.

Pour tes solutions :

- l'élément script après les éléments dont on a besoin ( c'est pas intrusif du<script> dans le <body> ? Smiley biggrin ) m'a déjà fait des beaux bugs sous IE6 et firefox 1.x. J'insérais pas mal d'éléments, pourtant à l'intérieur d'éléments déjà parsés, ça n'affichait pas d'erreur par contre le browser buggait : affichage décalé, plantage complet, etc.

- l'event propre à firefox et opera, ok mais quid des autres navigateurs ? le but n'est-il pas une solution portable ?

- Yahoo! UI Library :

Je ne connaissais pas et il faut avouer qu'ils n'y vont pas de main morte. J'encourage volontiers l'usage de libraries palliant le manque de consistance des browsers à ce niveau car le problème est complexe. Ça évite de se prendre la tête, par contre ça commence à devenir lourd si on se base déjà sur d'autres libraries qui malheureusement ne répondent pas à ce problème ( dans mon cas : prototype.js ).

J'ai jeté un oeil à sa méthode c'est assez acharné : toutes les 20 millisecondes, il fait différentes vérifications sur l'élément concerné, sur des détails qui concernent de près la manière dont le browser construit le modèle DOM ( il regarde si ce qui se trouve autour de l'élément est bien chargé, etc ... ). Suffisamment souple, astucieux et complexe pour ne pas le refaire soi-même. Par contre je ne connais pas la qualité du reste de cette library, c'est à voir selon ses besoins. Si on est prêt à utiliser et lire la documentation de cette library yahoo, il ne faut pas hésiter.

Tiens, j'avais pas encore lu l'article de Peter Michaux. Effectivement il explique ce "DOM Polling" de la YUI que je viens de décortiquer.

Bref ! Je pense qu'au moins on tombe d'accord sur la library de yahoo Smiley lol Perso j'en reste à ma méthode parce qu'elle fonctionne partout, correspond à mes besoins et ne m'oblige pas à intégrer une library supplémentaire à mes projets. Et oui, l'intégration logicielle c'est le mal du siècle ...
Modifié par aikii (20 Feb 2007 - 17:32)
aikii a écrit :
l'élément script après les éléments dont on a besoin ( c'est pas intrusif du<script> dans le <body> ? Smiley biggrin
Euh, ben je l'ai dit, non ? Smiley langue
Julien Royer a écrit :
- L'élément <script> placé après les éléments dont on a besoin, qui contient juste l'appel à la fonction (c'est aussi intrusif, mais ça n'a pas les autres inconvénients).
aikii a écrit :
) m'a déjà fait des beaux bugs sous IE6 et firefox 1.x. J'insérais pas mal d'éléments, pourtant à l'intérieur d'éléments déjà parsés, ça n'affichait pas d'erreur par contre le browser buggait : affichage décalé, plantage complet, etc.
Euh, là je ne suis pas sûr que l'on se soit compris. Je n'ai jamais eu de problème en insérant un élément script appelant une fonction dans une page HTML (pas n'importe où, bien entendu, mais juste avant le tag de fermeture </body> par exemple) :
<script type="text/javascript">init();</script>
</body>
Encore une fois, c'est aussi intrusif que ta solution, mais ça n'a pas les autres inconvénients (en plus, ça évite l'utilisation de document.write).
Modifié par Julien Royer (20 Feb 2007 - 17:49)
Hum, c'était de l'humour : me dire que mon script dans le body c'est instrusif et là-dessus me le ressortir encore tout chaud comme solution Smiley angry

Mais je pense pas que ça soit un problème. L'intrusivité devient gênant quand on capture les events en attribut des éléments concernés. Bref.

Chez moi le <script> qui agit tout de suite pose problème dans ce cas : j'ai un script qui charge en AJAX des articles à afficher, et ajoute ceux-ci à l'intérieur d'un élément qui est déjà déclaré et fermé plus haut. Le problème c'est que c'est asynchrone et j'ai l'impression que le DOM risque d'être encore "instable" au moment de la réponse. Dans mon cas, le contenu ajouté est bien affiché. Mais parfois, si je scrolle ma page ou que je sélectionne du texte c'est une vraie catastrophe, les éléments disparaissent, ça se décale, voire ça plante le browser. Si j'attends le chargement d'une image avant de lancer cette manipulation, alors ça va mieux. Je suppose que le onAvailable de l'API yahoo donnera également un résultat stable dans ces conditions particulières.
Modifié par aikii (20 Feb 2007 - 18:05)
aikii a écrit :
Hum, c'était de l'humour : me dire que mon script dans le body c'est instrusif et là-dessus me le ressortir encore tout chaud comme solution Smiley angry
Ben oui justement, une solution qui a cet inconvénient mais pas les autres... Enfin bref, je dois manquer d'humour aujourd'hui...
aikii a écrit :
Je suppose que le onAvailable de l'API yahoo donnera également un résultat stable dans ces conditions particulières.
Je ne vois pas pourquoi. onAvailable attend que le contenu dont tu as besoin ait fini d'être parsé. La fait de placer le <script> après les éléments à parser revient au même...

Je n'ai jamais observé le problème que tu décris, mais j'imagine que dans ce cas, ta solution est judicieuse.
Je ne sais pas si je me suis bien exprimé mais je voulais vraiment dire que la library YUI donne un résultat correct et attendu.
aikii a écrit :
Je ne sais pas si je me suis bien exprimé mais je voulais vraiment dire que la library YUI donne un résultat correct et attendu.
Ah OK. Et est-ce que tu as illustration du problème causé par la fonction appelée directement dans un élément script ?
ça serait super, n'est-ce pas, seulement mes expérimentations datent de septembre Smiley bawling Pas possible de me souvenir des circonstances exactes ( quel browser, quelle version ? ). Je n'arrive pas à reproduire le bug et je n'ai pas IE sous la main sans être sûr qu'il est fautif, et ça n'arrivait pas systématiquement non plus alors que c'était plusieurs reload sur exactement la même page ...

Bref je ne peux qu'expliquer ce que je cherchais à faire. Ça va être longuet Smiley lol

Le but est de détecter quand l'utilisateur scrolle jusqu'en bas de la page, ce que je fais grâce à un timer qui poll l'état actuel. Quand le visiteur est proche de la fin, un appel AJAX va chercher d'autres articles et les insère après les autres, dans le même conteneur.

Il faut donc, à partir d'un moment donné, que je commence ce timer régulier qui vérifie l'état de la fenêtre. window.onload pas acceptable pour les raisons qu'on sait. J'insère un <script> en fin de page ( c'est à dire, forcément, après l'élément dans lequel on est censé insérer les nouveaux articles ), pensant m'en tirer à bon compte. C'est là que si je faisais défiler la page directement vers la fin, j'obtenais des bugs. Les circonstances sont particulières : le script n'insère pas directement dans l'objet déjà parsé ; il ne fait qu'installer un timer qui réagira quelques centiemes de secondes plus tard. J'en ai conclu que d'une manière ou d'une autre, après le parsing de la page le browser fait un traitement quelconque ( indexation des id, réorganisation en mémoire de l'arbre, que sais-je ? ).

Bref conclusion : le <script> me sert à exécuter le code après l'élément à changer sans passer par un window.onload ; le document.write me permet d'insérer mon image à cet endroit, et à ne pas l'afficher du tout si javascript est désactivé. Empiriquement, je me suis dit qu'un onload sur une image interviendrait quand le DOM était prêt à subir mes modifications.

Je suppose que les poll de YUI sont du même ordre. Je pense que si ils s'y prennent de cette manière, les auteurs ont dû aussi se ramasser un bug quelconque. J'ai vu que les tests vérifient les propriétés des éléments voisins à l'élément concerné ; je suppose que d'une manière ou d'une autre, le diagnostic de l'élément en lui même ne suffit pas, par quelques tests réguliers ils vérifient l'état de santé du modèle DOM chargé en mémoire. Quand c'est bon, les fonctions concernées sont enfin appelées.

Voilà. Une dernière note à propos de YUI, il est distribué sous licence BSD. Il est donc tout à fait possible et légal d'isoler et de distribuer le code de onAvailable sous n'importe quelle forme, ça peut en intéresser plus d'un qui n'a pas envie d'importer toute la library dans son projet pour autant.
A priori, le fait de tester l'existence de l'élément suivant dans l'arbre est juste une manière de vérifier que le parsing de l'élément que l'on surveille est terminé (c'est d'ailleurs expliqué dans l'article dont j'ai donné le lien). Pour ça, c'est assez similaire à la technique de l'élément script en bas de page. Mais bon, étant donné que l'on fonctionne avec un timer, peut-être que le navigateur attend que l'arbre DOM soit dans un état stable avant de nous donner la main.
Bonjours à tous,
Aprés avoir tourné ce probléme dans plusieurs sens, j'ai fini par employer cette solution qui me semble la plus simple:


function init() {

if(!document.getElementById || !document.createElement)return;
if (arguments.callee.done) return;
arguments.callee.done = true;
  
startEvents();

}

/* for Mozilla & Opera*/
if (document.addEventListener) {
       document.addEventListener("DOMContentLoaded", init, false);
}

/* For Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            clearInterval(_timer);
            init();
        }
    }, 10);
}

window.onload = init; 


Comme vous remarquerez, je n'ai rien inventé c'est exactement celle de Dan Edwards. Vous remarquerez aussi qu' il n'y a pas le code étrange pour ie. En fait je le rejoute dans le html de la façon suivante:


  <!--[if IE 6]>
    <link href="squelettes/styles/design_ie.css" rel="stylesheet" type="text/css" />
    <script defer type="text/javascript" src="scripts/load_ie.js"></script>
  <![endif]-->


C'est beaucoup plus clair à mon goût est comme il y en général un feuille de style pour ie, cela ne fait qu'un ligne de code à rajouter au lieu de 10 lignes de signe chinois, de plus si vous avez un script spécial pour ie6 (comme le support du png, que j'utilise quasiment tout le temps) vous pouvez de cette maniére ne l'adresser qu'à ie6, comme ça:


<!--[if lte IE 6]>
   <link href="squelettes/styles/design_ie.css" rel="stylesheet" type="text/css" />
   <script defer type="text/javascript" src="scripts/load_ie6.js"></script>
<![endif]-->

<!--[if gte IE 7]>
   <script defer type="text/javascript" id="ie7" src="scripts/load_ie7.js"></script>
<![endif]-->


Du coup ie 7 ne se tape pas le script du png pour ie6, et c'est super de pouvoir faire ces logos ou titres en png Smiley biggrin .

Donc je nomme ce script load.js et je le met dés que j'utilise js.
Comme j'utilise des scripts différents celon les pages, je met ça en haut de mes pages xhtml:


<script type="text/javascript" src="scripts/load.js"></script>
<script type="text/javascript" src="scripts/fonctiondelapage.js"></script>

<script type="text/javascript">
<!--
function startEvents(){
   initMachin();
   initTruc();
}
//-->
</script>


ça permet de charger et d'executer exactement et seulement ce qu'on à envie, et d'être sur que se soit charger avant les images et les flashs sur les navigateurs principaux. Jusque là je n'ai pas eu de bug de la méthode. Par contre quand j'utilise des scripts externes, je cherche la fonction init pour le rajouter à ma liste. Je pense que c'est mieux que "addEvent" parceque ça permet de faire profiter de la méthode de chargement "immediat" à tout les scripts de la page.

Un autre méthode est d'utiliser les behaviors, mais c'est un poil plus lent au chargement et un poil plus compliqué (on voit un cour instant les png gris par exemple).

Par exemple sur cette page l'idée c'était de faire quelquechose de trés doux, avec des coins arrondis (avec niftyCube), des affichages progressifs et des titres en png, ce sont normalment que des techniques lourdes et pénible à utiliser mais sur cette page toute simple cela passe plutot bien et cela a était trés rapide à faire (surtout les coins arrondis Smiley biggrin , 30 minutes) grâce à cette technique. Par exemple avant je n'utilisait pas niftyCube à cause de l'effet de décalage puis de saut à chargement, avec cette technique c'est déjà mieux. Sur d'autre site j'ai des flash un peu lourd et pourtant tout les comportements dynamique sont casi imediatement disponibles.
Modifié par matmat (22 Feb 2007 - 04:48)
Évidemment, le résultat le plus pro s'obtient en traitant de façon différente chaque browser, mais il faut être motivé Smiley smile

Petites questions :

- Dans ton premier extrait tu défères l'exécution de "init" pour mozilla et safari, suite à quoi tu l'enregistres tout de même dans window.onload ( pour l'exécuter par défaut dans d'éventuels autre browsers, je suppose ). Tu vas donc finir par l'exécuter deux fois ce qui peut poser problème, mieux vaut ne pas oublier de faire un test du genre if (init_done) return ; else init_done = true ; ( avec var init_done = false ; déclaré global plus haut ).
- Je comprends que tu ne veuilles pas spécialement t'encombrer dans la library YUI, mais par curiosité as-tu testé les performances de onAvailable par rapport à ta solution ?

Je viens là-dessus de réaliser le pourquoi d'un bug que j'avais sous safari : j'ai sur ma page, dans une sidebar, un extrait d'article avec un lien "lire la suite". La taille de cette box est fixée en hauteur. En javascript au chargement, je teste si par hasard mon texte était assez court pour pouvoir entièrement s'afficher dans la box, auquel cas je cache le lien "lire la suite". Le problème c'est que parfois il cachait le lien alors que le texte était trop grand. Mais je viens de tilter : le script s'exécute avant que la stylesheet ne soit chargée, du coup les tailles ne sont pas bonnes au moment du test ! Plutôt qu'un window.onload toujours un peu aléatoire, je crois que je vais passer par un timer qui reteste plusieurs fois ...

Conclusion concernant mon bug : vouloir démarrer un script le plus tôt possible c'est bien mais il faut faire attention aux cas où on a besoin d'attendre que les éléments affectant le layout soient chargés.
aikii a écrit :
- Dans ton premier extrait tu défères l'exécution de "init" pour mozilla et safari, suite à quoi tu l'enregistres tout de même dans window.onload ( pour l'exécuter par défaut dans d'éventuels autre browsers, je suppose ). Tu vas donc finir par l'exécuter deux fois ce qui peut poser problème, mieux vaut ne pas oublier de faire un test du genre if (init_done) return ; else init_done = true ; ( avec var init_done = false ; déclaré global plus haut ).
Euh ouais, c'est dans la solution de Dean Edwards :
if (arguments.callee.done) return;

arguments.callee.done = true;
aikii a écrit :
Conclusion concernant mon bug : vouloir démarrer un script le plus tôt possible c'est bien mais il faut faire attention aux cas où on a besoin d'attendre que les éléments affectant le layout soient chargés.
Euh oui, logique. Smiley cligne

Dans ce cas, je trouve quand même qu'il faut savoir accepter le décalage du "onload"...
Mince, j'ai un peu trop vite lu pour le flag done.

Pour le onload, en effet après avoir testé j'ai pu constater que mon bug est enfin corrigé. Disons que c'était perturbant que seul safari ait été affecté, et comme j'exécute pas mal de trucs javascript au chargement de ma page, je n'avais pas fait le rapprochement. Pas toujours facile de faire abstraction entre contenu, traitement et présentation Smiley sweatdrop
aikii a écrit :
Pas toujours facile de faire abstraction entre contenu, traitement et présentation Smiley sweatdrop
En effet, c'est un éternel problème pour les développeurs Web. Smiley smile
Modifié par Julien Royer (22 Feb 2007 - 17:00)
Pages :