11550 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

Tout est dans le titre, mon alert ne fonctionne pas et je ne comprends pas...


	function main() {
		var y;
		var init_y;
		var init_top;
		var init_height;
		var current_id; //la variable qui pose problème
		var last_id;
		var thumb_id;
	
		var addEvent = listener;
		addEvent(document, 'mouseover', actif);
		addEvent(document, 'keypress', actif);
	}

	function listener(obj,evType,fn)
	{
		if(obj.addEventListener)
		{
			obj.addEventListener(evType,fn,false);
		} 
		else if(obj.attachEvent)
		{
			obj.attachEvent("on"+evType,fn) ;
		}
	} 

	function actif(e){
		var el= e.target||e.srcElement;
		if(!el.tagName)
		{
			el=el.parentNode;
		}
		
		if(current_id)
		{
			alert('test');
		}
	} 


Pourquoi le teste d'existence de la variable current_id ne fonctionne-t-il pas? J'ai supposé que cela venait du fait qu'elle n'a pas été créée, mais si je rajoute "current_id = '';" après avoir déclaré var "current_id;", ça ne change rien...

Pour situer l'idée de mon script, c'est que je vais avoir besoin de récupérer l'ancien id avant de faire un "current_id = el.id;"...

Heeelp!
Modifié par xephres (28 Jan 2010 - 11:58)
Je vais supposer que ton code commence par main() (jusque la je prends pas trop de risque). En javascript tu n'as pas de block-scope, mais un function-scope.

Donc quand tu déclare une variable dans le corps d'une fonction, son scope est égal à cette fonction. Et lorsque tu déclare une fonction dans une fonction, celle ci à accès au scope de la fonction parente via la __scope__ chain.

Donc dans ton premier exemple, les évènements se déroulent dans cet ordre :

- entrée de main() dans la stack d'execution : un oblet d'activation est créé, les variables dont "current_id" sont initialisées (le JavascriptIdentifier est réservé avec la valeur undefined)
- les instructions de main sont éxecutées séquentiellement, tes deux appels à la fonction listener sont executés
- fin d'execution de main(), main() avec son objet d'activation et son scope sortent de la stack d'execution
- ton évènement est déclenché
- actif() est placé dans la stack d'execution -> objet d'activation -> initialisations des variables
- aucun JavascriptIdentifier correspondant à "current_id" n'est trouvé dans le scope de actif() > on remonte la __scope__ chain et on tombe sur l'objet global > aucun JavascriptIdentifier correspondant à "current_id" n'est trouvé dans le scope global
- un JavascriptIdentifier est initialisé dans le scope global, il renvoit undefined
- undefined se caste en false
- et la c'est le drame.

Tu as donc fait deux erreurs :
- tu perds le scope dans lequel est déclaré ta variable > solution soit tu fais une closure, soit tu déclare ta variable ailleurs
- tu n'as jamais attribué de valeur à ta variable, donc elle sera tout le temps évaluée à undefined et castée en false.
function main() { 
	var y; 
	var init_y; 
	var init_top; 
	var init_height; 
	var current_id = true; //ou n'importe quoi qui ne se caste pas en false 
	var last_id; 
	var thumb_id; 
 
	var addEvent = listener;
	
	function actif(e){
		
		// en déclarant ta fonction ici,
		// sa __scope__ chain contiendra
		// le scope de main() et donc tu
		// pourra résoudre ta référence
		// vers "current_id"
		// c'est ce que l'on appelle
		// une "closure" > go google
		
		var el= e.target||e.srcElement; 
		if(!el.tagName) 
		{ 
			el=el.parentNode; 
		} 
		 
		if(current_id) 
		{ 
			alert('test'); 
		} 
	}  
	
	addEvent(document, 'mouseover', actif); 
	addEvent(document, 'keypress', actif); 
} 

function listener(obj,evType,fn) 
{ 
	if(obj.addEventListener) 
	{ 
		obj.addEventListener(evType,fn,false); 
	}  
	else if(obj.attachEvent) 
	{ 
		obj.attachEvent("on"+evType,fn) ; 
	} 
}


PS : c'est saoulant les modos ont cloturé mon compte bugmenot... Smiley fache C'est si flippant que ça de faire un forum public ? Je vois pas pourquoi il faudrait obligatoirement s'inscrire pour poster.
Modifié par MonsieurY (27 Jan 2010 - 17:12)
MonsieurY a écrit :
c'est saoulant les modos ont cloturé mon compte bugmenot... Smiley fache C'est si flippant que ça de faire un forum public ? Je vois pas pourquoi il faudrait obligatoirement s'inscrire pour poster.
Parce que ce compte bugmenot permettait à plusieurs personnes de poster avec le même pseudo et que c'est toujours mieux (du point de vue des modos) de savoir à qui on s'adresse (1 pseudo = 1 être humain).

D'autre part ce type d'outils peut avoir du sens pour un forum dont le contenu n'est pas accessible sans être au préalable inscrit mais ça n'est pas le cas d'Alsacréations qui n'oblige à s'inscrire que lorsqu'on souhaite poster.

Pas compris ta phrase "C'est si flippant que ça de faire un forum public ?" Smiley confuse En quoi ce forum n'est pas public ?

Autresinon : c'est si flippant que ça de s'inscrire ?
Tu as juste à inventer un pseudo et ton email ne sert qu'à vérifier que tu n'est pas un robot spammeur (il n'apparaît dans ton profil que si tu le souhaites).
Modifié par Heyoan (27 Jan 2010 - 17:24)
Un forum public pour moi c'est où l'on peut poster sans inscription.
Je ne suis jamais sur le même poste et à chaque fois j'oublie ce genre de mot de passe dont l'importance n'est pas capitale. > résultat j'ai bien du déjà créer une douzaine de compte sur alsa. Sans compter tout les messages auxquels je n'ai pas répondu faute de motivation.

Vous ne voudriez pas faire un système plus flexible avec juste une question anti-spam ?
MonsieurY a écrit :
Un forum public pour moi c'est où l'on peut poster sans inscription.
Comme quoi chacun a sa définition : pour moi c'est un forum dont le contenu est accessible à tous.

MonsieurY a écrit :
Je ne suis jamais sur le même poste et à chaque fois j'oublie ce genre de mot de passe dont l'importance n'est pas capitale. > résultat j'ai bien du déjà créer une douzaine de compte sur alsa. Sans compter tout les messages auxquels je n'ai pas répondu faute de motivation.
En gros bugmenot ne te sert qu'à te rappeler ton mot de passe ? Si c'est le cas je suppose qu'il existe des services en ligne qui proposent la même chose. Tu pourrais aussi (puisque ça n'est pas capital) utiliser toujours le même mot de passe pour ce type de comptes ou encore utiliser le même mot de passe que ton login.
Par ailleurs c'est justement la signature "Viendez tous chez bugmenot et vous n'aurez pas à vous inscrire pour poster sur Alsa" qui avait attiré mon attention. J'en conclus donc que ce n'est pas seulement une question de mot de passe à se rappeler mais aussi (et surtout ?) une démarche intellectuelle anti-casse coui... bonbons.

MonsieurY a écrit :
Vous ne voudriez pas faire un système plus flexible avec juste une question anti-spam ?
Et gonfler tout le monde avec une question anti-spam à chaque post alors qu'il suffit de se connecter une fois pour toutes ?
Heyoan a écrit :
J'en conclus donc que ce n'est pas seulement une question de mot de passe à se rappeler mais aussi (et surtout ?) une démarche intellectuelle anti-casse coui... bonbons.


Bah oui, je suppose que je ne suis pas le seul dans ce cas là.

Heyoan a écrit :
Et gonfler tout le monde avec une question anti-spam à chaque post alors qu'il suffit de se connecter une fois pour toutes ?


Non, juste les utilisateurs non-loggués / confirmés. Ca marche bien sur la quasi totalité des blogs, et plein d'autres sites, pourquoi pas ici.
Au pire un bon gros AnonymousCoward à la Slashdot. Smiley lol

N'empêche que c'est une tournure d'esprit typiquement occidentale cette obsession pour les inscriptions/comptes utilisateur. Il doit y avoir un facteur culturel qui nous empêche de concevoir une communauté autrement.

----
Post scriptum : ça me rapelle une anecdote sur le blocage psychologique qu'on fait sur les comptes : j'ai fait découvrir à un collègue dev bugmenot il y a peu de temps, et il m'a regardé avec des yeux ronds en me disant "T'es sûr que c'est bien légal ?" J'ai failli exploser de rire. Smiley biggrin
Modifié par MonsieurY (27 Jan 2010 - 17:56)
MonsieurY a écrit :
N'empêche que c'est une tournure d'esprit typiquement occidentale cette obsession pour les inscriptions/comptes utilisateur. Il doit y avoir un facteur culturel qui nous empêche de concevoir une communauté autrement.
Peut-être effectivement.

Quoi qu'il en soit j'aime bien "reconnaître" un habitué par son pseudo et au fil des années un lien se crée (lui je l'aime Smiley amour / lui je le déteste Smiley diablo ). Je pense également (pour l'avoir vu ailleurs) que l'anonymat permet trop facilement de se lâcher (injures, mépris, etc.) et qu'une inscription invite à plus de "responsabilité" dans ses propos... même si je reconnais que les (tes ?) interventions du pseudo bugmenot sont globalement de qualité et mesurées.
Oh... Ok... Smiley bawling Merci...

Dommage... Je n'ai plus qu'à trouver une autre méthode... Ça aurait pourtant été bien pratique...

Dites, c'est moi, ou ça n'est pas logique d'accepter current_id = el.id; et de cracher à la gueule du développeur lorsqu'il teste if(current_id) (qui en toute logique devrait simple retourner "false" ou " Smiley vide ").

Peut-être est-ce que je manque d'expérience mais il me semble que ni l'AS3 ni le PHP ne font ça, si?
Modifié par xephres (27 Jan 2010 - 18:51)
xephres a écrit :
Oh... Ok... Smiley bawling Merci...

Dommage... Je n'ai plus qu'à trouver une autre méthode... Ça aurait pourtant été bien pratique...


Je vais me répéter, mais renseigne toi sur les closures, c'est la clé de ton problème.

xephres a écrit :
Dites, c'est moi, ou ça n'est pas logique d'accepter current_id = el.id; et de cracher à la gueule du développeur lorsqu'il teste if(current_id) (qui en toute logique devrait simple retourner "false" ou " Smiley vide ").


J'aurai tendance à te dire qu'en as3 c'est pareil, mais j'ai beaucoup plus l'habitude de l'as2, donc je peux me tromper.

En js, une instruction d'assignement sera toujours honorée, car les variables sont globales par défaut : si elle n'est pas déclarée dans le scope, on remonte la __scope__ chain jusqu'à l'ultime maillon qu'est l'espace global.
De plus une variable qui n'existe pas (où plutôt à laquelle on a pas assignée de valeur, car si tu suis bien, toutes les variables existent dans l'espace global) te renvera "undefined" et non pas null false ou "".

Donc si tu fais "current_id = el.id;" puis "if(current_id)" et que tu ne rentre pas dans ta condition cela peut vouloir dire trois choses :

- el.id à une valeur qui se caste en false
- el.id n'existe pas et donc par défaut vaut undefined qui se caste en false
- le current_id que tu adresse au moment de l'assignement n'est pas dans le même scope que l'évaluation de ta condition : ce sont deux JavascriptIdentifier distincts qui pointent vers deux valeurs en mémoire différentes.

PS : je relis, et je ne suis pas sûr d'avoir bien compris, quand tu dis "cracher à la gueule", tu veux dire que ça te lève une erreur ?
Modifié par MonsieurY (27 Jan 2010 - 20:14)
a écrit :
PS : je relis, et je ne suis pas sûr d'avoir bien compris, quand tu dis "cracher à la gueule", tu veux dire que ça te lève une erreur ?


Lol, nan, c'est juste que ça me vexe :-p

On peut faire current_id = el.id; mais ajouter if(current_id){ alert('test'); } avant suffit pour que ça ne fonctionne plus... Ma réaction du moment était kalimerol(ol)esque Smiley lol


Blague à part, je ne vois pas comment faire...

Si je créée et appelle, dans le main, une fonction anonyme (function (){current_id = "bla";})(); il ne reconnait toujours pas l'existence du current_id. Si j'essaye de faire que cette fonction soit appelée lors du load (document ou window), même résultat. Le scope ne passe pas... Smiley bawling

Le pire avec tout ça, c'est que je sens gros comme une maison, que si on me donne la solution, je vais me dire que c'était tellement évident qu'il y a de quoi se pendre (soit vexé²)...

Le truc, c'est que je tiens à séparer aux maximum les fonctions selon leur rôle, faire du code facile à lire et à comprendre. Donc mettre la fonction directement dans le main me pose un problème...
Modifié par xephres (27 Jan 2010 - 21:18)
Si tu ne veux pas déclarer ton callback dans ton main, il te reste la solution de faire une closure avec un wrapper en changeant la signature de ton callback. Du code vaut mille mots :

function main() { 
	var current_id = "tartiflette"; // "tartiflette" se caste en true
 
	var addEvent = listener;
	
	var wrapper = function(e){ actif(e, current_id) }
	
	addEvent(document, 'mouseover', wrapper); 
	addEvent(document, 'keypress', wrapper); 
} 

function listener(obj,evType,fn) 
{ 
	if(obj.addEventListener) 
	{ 
		obj.addEventListener(evType,fn,false); 
	}  
	else if(obj.attachEvent) 
	{ 
		obj.attachEvent("on"+evType,fn) ; 
	} 
}  

function actif(e, cid){ 
	var el= e.target||e.srcElement; 
	if(!el.tagName) 
	{ 
		el=el.parentNode; 
	} 
	 
	if(cid) 
	{ 
		alert('test'); 
	} 
}  


Sinon, l'autre solution serait de sortir current_id du scope de main. Pose toi la question : est-ce que c'est une valeur amenée à être changée (par autre chose que tes callbacks) au court de l'exécution de ton programme ?
Si oui, alors il faut que tu la sorte, tu en fais une propriété d'un objet, un membre pseudo-statique, tout dépends de ce que tu veux faire.

Par contre si la valeur est fixe, alors garde la dans le scope de main, cela te fera un membre privé accessible uniquement par ton callback (qui est le wrapper, et non plus actif, nuance importante).
Salut,

On peut accroché actif au main, non ?

function main(){
	var current_id = "plop",
		addEvent = listener; //???

	this.wrapper = actif;

	addEvent(document, 'mouseover', wrapper);
	addEvent(document, 'keypress', wrapper);
}


Tel quel, il n'y a aucun moyen de changer wrapper, ça doit pas causer de problèmes.
Non, ça ne marche pas, il fau que la déclaration de ta fonction soit DANS le corps de ta fonction parente. Tu ne peux pas gruger.

La ce que tu fais c'est simplement résoudre une référence, mais l'objet d'activation de actif() et son scope ont déjà étés créés bien avant. Le scope de main() n'est pas dans la __scope__ chain de actif().

Je vous conseille cet article, c'est le plus pointu et complet que j'ai jamais lu sur le sujet :
http://www.jibbering.com/faq/faq_notes/closures.html#clIRExSc
Ok, merci...

Finalement, ça m'a permis de voir qu'il y avait une erreur dans mon approche, j'ai pu résoudre le problème sans conserver cette variable.

En fait, je n'avais pas besoin de conserver la valeur, il me suffisait d'utiliser un keyup au bon endroit pour résoudre mon problème.

Explication rapide : je n'arrivais pas à activer la détection d'évènement, suite à un changement de propriété de display sur une div. Je faisais passer de none à block (pour un menu avec sous-menu (toggle) avec navigation au clavier)

Le problème, à ce moment là, c'est que le détecteur reste en quelque sorte sur la version précédente de la page. Il ne détectait donc pas la div passée à "block" mais l'élement pré-existant suivant.

En ajoutant un écouteur au keyup, sur le document, la solution vient toute seule.
Modifié par xephres (28 Jan 2010 - 11:58)