11550 sujets

JavaScript, DOM et API Web HTML5

Bonjour, (je pose ici mais peut-être aurais-je dû le faire dans le forum WEB 2.0 Smiley ohwell


EDIT: J'ai trouvé la vraie question : comment détecter que le DOM est en cours de modification ?


Je crée une arborescence (web 2.0).

Voici l'image qui permettra de mieux me faire comprendre :
upload/8062-arbo.png
Concernant l'image, le bouton + a été cliqué ce qui a permis d'afficher le formulaire permettant d'indiquer le nom d'un sous dossier à ajouter. Chaque bouton est associé à un div contenant un formulaire.

Pour chaque dossier, quatre images sont alignées et chacune permet d'afficher une div (div1, div2, etc...) lorsque l'utilisateur clique dessus. Je les apellerais image1, image2, etc...

Donc après clic sur image1, le bloc div1 s'affiche (c'est une div qui est masquée par défaut (display : none).
Après clic de l'image1 , la classe affectée au div1 est supprimée et le style display : block lui est ajouté via du javascript (jQuery pour être exact).

Lorsque l'utilisateur clique sur une autre image, par exemple sur image2 afin d'afficher le bloc div2, le bloc précédemment affiché (donc div1) doit être masqué à nouveau (le style est supprimé et la classe qui permet de masquer l'élément est réaffectée à div1). Le bloc div2 s'affiche de la même façon que le bloc1 s'était affiché.

Cela fonctionne très bien sauf que... Smiley ohwell si l'utilisateur clique sur image1 puis tout de suite après sur image2 (du même dossier ou un autre) avant que la modification de la classe ne soit terminée, je me retrouve avec les blocs 1 et 2 qui s'affichent. On pourrait croire que le changement de la classe est presque instantané mais le traitement prend une seconde ce qui laisse le temps de cliquer sur d'autres images. Cela est dû au fait que je vérifie avant d'afficher le div correspondant à l'image si aucun autre div n'a été affiché dans l'arborescence. J'ai fait une boucle et en fait j'itère sur chaque div contenant un formulaire pour vérifier si la classe "masquer" est présente. Si ce n'est pas le cas, je l'ajoute et ainsi le bloc est masqué.

Mon problème est que lorsqu'un bloc est "en cours d'affichage", c'est à dire que sa classe est en train d'être modifiée, mon itération vérifie la classe et "constate" qu'elle est encore sur "masquer" ce qui fait que je me retrouve avec deux blocs affichés.

J'espère avoir fait preuve de clarté Smiley confus

Donc je souhaite savoir comment résoudre mon problème. J'avais pensé à désactiver le clic de souris pendant 1 seconde mais cette solution ne me plaît pas. Sinon j'avais pensé à lancer mon itération une seconde après le clic sur l'image mais cela pose un problème avec les utilisateurs qui sont impatients ou enfin à vérifier que la modification du DOM en cours est terminée.

Quelqu'un aurait-il une idée à me communiquer ?

Merci

EDIT par Felipe: édition des balises BBCode, évite d'utiliser l'une de celles que tu as utilisé, c'est un "bug" assez marrant du Forum que tu as (re)trouvé par inadvertance Smiley lol
Modifié par Felipe (08 Feb 2009 - 18:20)
Bonjour,

Comme d'hab... je n'ai pas forcément tout compris au problème et en plus jquery... connais pas !

However...

Si je reformule ce que j'ai compris :

Tu as un traitement js T1 qui peut durer et tu ne souhaites pas qu'un événement survenant enclenche un autre traitement T2 alors que T1 n'est pas encore terminé ?

C'est cela ?

Si c'est cela alors j'ai moi aussi été confronté à ce problème et l'ai résolu de façon bête :

- Au début de T1, je set une variable disons T1Running à 1 et je la reset en fin de T1,
- Au début de T2, si T1Running est à 1, je setTimeout sur T2 et si T1Running est à 0 alors je déroule le traitement de T2.

Un genre de lock en quelque sorte. Il faut juste faire gaffe aux possibilités de dead-lock si tu a plusieurs traitements susceptibles de positionner / tester le même lock.

EDIT : Je me rend compte maintenant que... je ne répond pas à ta vraie question...
Mais... bon... je laisse... au cas où cela répondrait à ta fausse...
Modifié par aCOSwt (09 Feb 2009 - 09:51)
Tu pourrais faire en sorte d'attendre que toute exécution soit terminée avant de lancer ton traitement. Avec PrototypeJS, il existe la fonction defer() qui s'applique à une fonction et qui la lance une fois que tout le reste est terminé. Avec jQuery je ne sais pas s'il y un équivalent, mais c'est assez simple à mettre en œuvre en Javascript natif :
setTimeout(laFonctionAExecuterALaFin, 0);
Pourquoi ne pas stocker le bouton actif dans une variable (par exemple selectedAction) au moment où tu l'affiche ?
Comme ça, tu n'a plus besoin de faire une recherche, tu as juste à regarder dans cette variable quel bouton est actif (et tu peux au passage stocker dans le bouton le div qui y correspond, ça te fait en prime un accès direct au div pour modifier son style).