11524 sujets

JavaScript, DOM et API Web HTML5

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

C'est un peu au choix de chacun. Je trouve que ce qui compte surtout, c'est que tu puisses, si quelquechose ne fonctionne pas, te rencarder sans problème sur la fonction php qui est derrière. C'est surtout comme ça que je conçois l'Ajax. J'en fais un max en php et je viens compléter par quelques petites touches de js pour améliorer le comportement. J'y gagne en sûreté, en accessibilité mais aussi en mise en oeuvre (il y a beaucoup moins d'exceptions en php qu'en js, c'est plus simple à coder et je n'ai pas besoin de sortir un code monstrueux en js).

Ca veut dire, dans ton cas, que pour faire la lecture d'un fichier xml, je fais une fonction en php et lorsque je clique sur un lien pour accéder à la page contenant le code résultant, je peux, si je le souhaite, passer un argument à cette fonction php via XHR, ce qui me permet de rester sur la page précédente en la mettant à jour. XHR ne se limite qu'à l'appel et la réception des données... Je ne m'amuse pas à tout reconstruire derrière ; j'emploie l'existant. Si on ajoute document.implementation.createDocument, il faut alors, en plus et dans ce cas bien précis, traiter les données pour les afficher puisque je change de logique : je ne fais plus une requête mais je dois reproduire toute la mise en forme via js. (je ne prend pas la peine de le faire)
Modifié par koala64 (18 Apr 2007 - 15:42)
koala64 a écrit :
Ben si, c'est ce que je voulais dire. Smiley smile Tu peux en faire passer aussi bien en GET qu'en POST mais si on a qu'un fichier XML à charger, ce n'est à priori pas la peine de passer par XHR.
Je me suis mal exprimé : Ne peut-on pas passer des paramètres en GET avec la fonction "importNode" ?
a écrit :
XHR ne se limite qu'à l'appel et la réception des données... Je ne m'amuse pas à tout reconstruire derrière ; j'emploie l'existant.


Alors là je suis perdu, comment fais tu dans ce cas pour afficher les donnée reçu via XHR dans le html? Il faut quand même au minimum une fonction pour lire les balises du fichier xml et une autre pour mettre le contenu ainsi récupéré dans les balises correspondantes?
Modérateur
Julien Royer a écrit :
Je me suis mal exprimé : Ne peut-on pas passer des paramètres en GET avec la fonction "importNode" ?
Ce n'est pas vraiment un GET. On fait appel au noeud d'un autre fichier (après savoir si ça passe par l'url ou non, je ne saurais pas te répondre) mais comparé à XHR, c'est plutôt limité. On ne peut recevoir qu'un noeud de même que quand on sert de document.implementation.createDocument, on ne peut qu'insérer un fichier. Ce que je voulais dire, c'est qu'en envoyant un paramètre via XHR, le serveur peut traiter la réponse différemment suivant la valeur.

matmat a écrit :
Alors là je suis perdu, comment fais tu dans ce cas pour afficher les donnée reçu via XHR dans le html? Il faut quand même au minimum une fonction pour lire les balises du fichier xml et une autre pour mettre le contenu ainsi récupéré dans les balises correspondantes?
Bon, je t'ai fait un exemple... Ca va être un peu long à présenter ici mais comme tu voulais de l'Ajax, il faut bien ça. Smiley lol Tu peux tester Javascript actif ou non, ça passe dans les deux cas. Smiley smile

c'est parti ! Smiley biggrin

index.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<title>Exemple</title>
		<style type="text/css">/*<![CDATA[*/

@media screen, projection {
	form, p {
		width: 20em;
		padding: 1em;
		border: 2px solid #555;
		color: #58F;
		background-color: #222;
	}
	fieldset {
		border: 1px solid #58F;
	}
	#submit {
		margin-top: 1em;
	}
}

		/*]]>*/</style>
		<script type="text/javascript" src="ajax.js"></script>
	</head>

	<body>

		<form method="get" action="ajax.php5">
			<fieldset><legend>Choix d'une année entre 2002, 2004 et 2006</legend>
				<div>
					<label>Année : </label>
					<input type="text" name="annee" id="annee" />
				</div>
				<div>
					<input type="submit" id="submit" value="Transmettre" />
				</div>
			</fieldset>
		</form>

	</body>
</html>



ajax.xml
<?xml version="1.0" encoding="utf-8" ?>

<livres>
	<livre>
		<auteur>Steven Holner</auteur>
		<titre>XSLT par la pratique</titre>
		<annee>2002</annee>
		<editeur>Eyrolles</editeur>
		<genre>Programmation</genre>
		<ISBN>2-212-11040-5</ISBN>
	</livre>
	<livre>
		<auteur>Kate Mosse</auteur>
		<titre>Labyrinthe</titre>
		<annee>2006</annee>
		<editeur>JC Lattès</editeur>
		<genre>Roman</genre>
		<ISBN>2-7096-2583-0</ISBN>
	</livre>
	<livre>
		<auteur>Jack Vance</auteur>
		<titre>Emphyrio &#038; autres aventures</titre>
		<annee>2004</annee>
		<editeur>DENOEL</editeur>
		<genre>Science Fiction</genre>
		<ISBN>2.207.25429.1</ISBN>
	</livre>
</livres>



ajax.js
(function() {

var k64 =
{
	bXHRSupport: (typeof XMLHttpRequest != "undefined"),

	bActiveXSupport: (window.ActiveXObject),

	aMSXML: ["Microsoft.XMLHTTP",
		"MSXML2.XMLHTTP", "MSXML2.XMLHTTP.3.0",
		"MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.5.0",
		"MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.7.0"],

	oCreateXHR: function()
	{
		if(k64.bXHRSupport)
			return new XMLHttpRequest;
		else if(k64.bActiveXSupport)
		{
			var iI = k64.aMSXML.length - 1;

			for(; iI >= 0; iI--)
			{
				try
				{
					return new ActiveXObject(k64.aMSXML[iI]);
				}
				catch(oError) { }
			}
			throw new Error("L'objet XHR n'a pas été créé.");
		}
	},

	fnGetXHR: function(sUrl)
	{
		var oXHR = k64.oCreateXHR();

		oXHR.open('get', sUrl, false);
		oXHR.send(null);

		if(oXHR.status && /200|304/.test(oXHR.status))
			return k64.oSetData(oXHR.responseText);

		return false;
	},

	oSetData: function(sData)
	{
		return document.body.innerHTML = sData;
	},

	fnConnect: function(oElem, sEvType, fn, bCapture)
	{
		return document.addEventListener ?
			oElem.addEventListener(sEvType, fn, bCapture):
			oElem.attachEvent ?
				oElem.attachEvent('on' + sEvType, fn):
				false;
	},

	oId: function(sId)
	{
		if(document.getElementById(sId))
			return document.getElementById(sId);

		return false;
	},

	aTag: function(oEl, sTag)
	{
		if(oEl && sTag && oEl.getElementsByTagName(sTag))
			return oEl.getElementsByTagName(sTag);

		return false;
	},

	bCancelClick: function(e)
	{
		if(e && e.stopPropagation && e.preventDefault)
		{
			e.stopPropagation();
			e.preventDefault();
		}
		else if(e && window.event)
		{
			window.event.cancelBubble = true;
			window.event.returnValue = false;
		}

		return false;
	},

	sSubmit: function(e)
	{
		k64.bCancelClick(e);

		var sName = k64.oId('annee').name,
				sValue = k64.oId('annee').value;

		if(sValue != '2002' && sValue != '2004' && sValue != '2006')
		{
			alert('Tu t\'es planté d\'année ! :s\nRecommence ! ^^');
			return;
		}

		var sUrl = 'ajax.php5?';
		sUrl += encodeURIComponent(sName);
		sUrl += '=';
		sUrl += encodeURIComponent(sValue);
		sUrl += '&Ajax=true';

		return k64.fnGetXHR(sUrl);
	},

	oInit: function()
	{
		var oBody = document.body,
		    oForm = k64.aTag(oBody, 'form')[0];

		return k64.fnConnect(oForm, 'submit', k64.sSubmit, false);
	}
};

k64.fnConnect(window, 'load', k64.oInit, false);

})();



ajax.php5
<?php

final class Ajax {

	final public function noCache()
	{
		header('Pragma: no-cache');
		header('Expires: 0');
		header('Last-Modified: ' . gmdate("D, d M Y H:i:s") . ' GMT');
		header('Cache-Control: no-cache, must-revalidate');
		header('Content-type: text/plain');
	}

	final public function init()
	{
		header('Content-type: text/html; charset=utf-8');
		ob_start('ob_gzhandler');
	}

	final public function gauffre()
	{
		echo "\t\t<p>Tu t'es planté et c'est bien dommage ! [langue]</p>\n";
	}

	final public function getBook($param)
	{
		$oDom = new DOMDocument;
		$oDom->load('ajax.xml');
		$livres = $oDom->getElementsByTagName('livre');
		foreach($livres as $livre)
		{
			if($livre->getElementsByTagName('annee')->item(0)->firstChild->nodeValue === $param)
			{
				$titre = $livre->getElementsByTagName('titre')->item(0)->firstChild->nodeValue;
				$auteur = $livre->getElementsByTagName('auteur')->item(0)->firstChild->nodeValue;

				echo "\t\t", '<p>Le livre ', $titre, ', écrit par ', $auteur, ', est sorti en ', $param, '.</p>', "\n";
			}
		}
	}

}

$oAjax = new Ajax;

if(!isset($_GET['annee']))
	$oAjax->init();

if(!empty($_GET['Ajax']) && $_GET['Ajax'] === 'true' && !empty($_GET['annee']))
{
	$annee = htmlspecialchars($_GET['annee']);
	$oAjax->noCache();
	$oAjax->getBook($annee);
}
else
{

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<title>Exemple</title>
	</head>

	<body>

<?php

	if(!isset($_GET['Ajax']) && !empty($_GET['annee']) &&
	$_GET['annee'] != '2002' && $_GET['annee'] != '2004' && $_GET['annee'] != '2006')
	{
		$oAjax->gauffre();
	}
	else if(!isset($_GET['Ajax']) && !empty($_GET['annee']))
	{
		$annee = htmlspecialchars($_GET['annee']);
		$oAjax->getBook($annee);
	}
	else
		$oAjax->getBook('2002');
}

if(!isset($_GET['annee']))
{

?>

	</body>
</html>

<?php

}

?>


Et voilà ! En visuel, ça nous donne ceci. Smiley langue

Concernant le JS, je fais une requête synchrone et non asynchrone parce qu'en dessous d'1ko de données, ça ne vaut pas le coup de passer en asynchrone.

Je te laisse décortiquer le code. Smiley cligne
Super petit exemple.

Bien évidement j'ai plein de question mais je vais d'abord travailler ça avant de les poser.

Bien sur la fonction

oSetData: function(sData){
return document.body.innerHTML = sData;
},


Serat completement changé pour faire quelque chose de plus propre qui me permettra d'établir des styles a chaque partie (titre, description).

Je poste un exemple bientôt.
Modérateur
a écrit :
Serat completement changé pour faire quelque chose de plus propre qui me permettra d'établir des styles a chaque partie (titre, description).
Ben non. Smiley biggrin D'une, Ce n'est pas sale ! Smiley grouik mais c'est aussi bien plus efficace comme ça.

Tu vas voir en consultant le code que XHR ne fait qu'appeler et recevoir les données. La mise en forme du message (je parle du code xhtml et pas de css) est effectuée via php ; c'est la même fonction que celle qui me sert à créer le paragraphe sur la page ajax.php5 (getBook). J'ai juste changé le css sur la page appelante pour bien différencier les pages.

En vitesse de traitement, php est bien plus rapide mais aussi plus sûr que js donc c'est mieux de passer par là... sans compter que ça me permet de ne pas duppliquer une même fonctionnalité dans le php et dans le js.

En revanche, je mets un petit bémol. Smiley cligne Franchement, cet exemple, ça sert rarement. Ici, on peut perturber l'utilisateur car s'il clique sur précédent, il ne revient pas forcémment sur le formulaire mais peut-être sur le site qu'il a consulté avant. Faut bien peser le pour et le contre et choisir la bonne technique. Si tu souhaites conserver l'historique, mieux vaut passer par l'iframe cachée (mais ça aussi, ça ne fonctionne pas partout).

L'Ajax est donc à consommer avec modération. Smiley saouls
Modifié par koala64 (18 Apr 2007 - 22:12)
Salut Koala et bonne journée!
Aprés avoir fait des tests, j'ai fini par comprendre pourquoi tu préféres la solution innerHTML, en effet, reconstituer une balise liste, des liens, des id etc avec le DOM, c'est amusant, mais ça devient vite super lourd et effectivement beaucoup plus lent que le innerHTML.

Si le flux original et traité préalablement par php on évite les risques des probléme et on peut trés bien produire un fichier avec les bonnes balises.

En fait au début je ne voulais pas faire ça pour garder un fichier xml trés propre mais en fait ça sert pas a grand chose.

J'ai fait un test de mes expériences ici :
lecteur de flux xml Ajax/php accesible. Il faut cliquer sur les titres a gauche pour obtenir les titres et la description dans la boite de droite, (la description étant dans un infobulle sympa mais plus ou moins accessible)

J'ai encore un peu du mal à coder comme tu le fais avec des objets, donc c'est un peu plus "a l'ancienne" mais ça à l'air de bien marcher. Bien sur il faudrait essayé avec différentes configs, mais bon l'avantage que ça marche quand même sans js c'est qu'on est sur d'un résultat correct.

Dans le test présenté, ça n'a pas beaucoup d'intéret il faut imaginer la même chose au milieu d'un portail avec plein d'autre infos, des images et tout.

Il y a encore beaucoup a améliorer pour faire de l'Ajax accéssible et propre mais c'est quand même trés sympa!
Modifié par matmat (19 Apr 2007 - 06:42)
Modérateur
Salut, Smiley smile

matmat a écrit :
Il y a encore beaucoup a améliorer pour faire de l'Ajax accéssible et propre mais c'est quand même trés sympa!
oui et non...

A partir du moment où les gens comprendront qu'Ajax peut même améliorer l'accessibilité s'il est bien employé, je pense qu'on aura fait un grand pas (/me suis doux rêveur... c'est pas demain la veille Smiley lol ). Il y a des choses à faire et d'autres à ne pas faire. Le soucis, c'est qu'on dispose d'une foule de mauvais exemples et que ça ne va qu'en empirant pour l'instant. La prise de conscience n'est pas encore arrivée. Smiley ohwell

Dans ton exemple, si on désactive tout (css/js), on a l'ensemble des textes et si on clique sur l'un des titres, ça fonctionne bien donc il n'y a rien à redire, c'est accessible. Smiley smile

Lorsqu'on active css, un premier problème se présente. Les descriptions disparaissent ; ça ne devrait pas être le cas. Donc, déjà, tu pourrais ôter le #links_menu dd{display:none} et planquer les dd que lorsque js est actif. Ainsi, l'accessibilité serait maintenue.

Lorsqu'on réactive js, le principe des infos-bulles n'est pas fondamentalement mauvais mais ici, la navigation clavier n'est pas prévue. Il peut être intéressant de la réintégrer en donnant la possibilité de faire apparaitre les descriptions.

Concernant la partie Ajax, ça dépend de ce que tu cherches. Au milieu d'un portail, où tu mets uniquement une des boites à jour, ce module peut être considéré comme une application faisant partie intégrante de la page donc l'historique n'a pas à être conservé (ou alors, tu peux le proposer en option mais ça ne semble pas perturbant de passer à la page précédente plutôt que de faire une rétro-action sur les choix de l'utilisateur). C'est un peu comme un calendrier intégré à la page où on clique sur le mois suivant. Si tu veux par exemple consulter le mois d'octobre 2008, tu vas cliquer plusieurs fois sur le bouton pour passer au mois suivant (ce qui semble normal). En revanche, si tu veux revenir sur la page précédente et que tu vois défiler tous les mois que tu as passé dans le sens inverse au clic du bouton précédent, ça devient vite lourd et ce n'est pas ce que tu souhaitais.

Donc, faut bien faire son choix quant à la technique dont tu vas te servir, ce qui n'est pas forcémment des plus évidents, et bien entendu faut toujours prévoir l'alternative lorsque js est inactif (en amont, ce qui permet de s'appuyer dessus)
Modifié par koala64 (19 Apr 2007 - 09:53)
Salut,

Je répond un peu tard mais je n'ai pas pu avancer sur ça ses dernier temps
Pour les infobulles, je n'aurais aucun soucis a le faire comme tu le dis c'est vrai que c'est la solution.

Pour la navigation clavier, il faut absolument que je m'y mette car je ne connais pas du tout le sujet Smiley confused , je vais me renseigner je pense que je suis au bon endroit Smiley biggrin , j'ai des post à lire.

Concernant la navigation, effectivement faire un historique des éléments visualisés peut-être interressant. J'ai vu récement plusieurs moteurs de recherche pour des voyages avec le choix de dates et effectivement il y a des choses plus ou moins fonctionnel.

Je vais essayé de l'améliorer, je pense que c'est un bon exercice, je vous tiendrais au courant. Smiley biggrin
Bon j'ai fait une petite amélioration de ma fonction XMLHttpRequest, l'idée est la suivante:

Essayer de trouver un moyen d'écrire cette fonction de tel maniére que l'on puisse s'en servir simplement pour de multiples usages que ce soit en GET ou POST.

Par exemple :

ajaxRequest("admin.php?action=login", sendLogin ,login);

ou on envoie la fonction, les variables ou null pour la methode GET, et enfin la fonction de traitement ou rien en cas de POST sans réponse.

ça à l'air tout bête, mais je n'ai pas trouver ce genre de fonction en dehors des fameuses libraires dont on parle tant...

J'ai essayé d'abord de renvoyer la reponse avec return, pour pouvoir faire comme ça : data = ajaxRequest("admin.php?action=login", sendLogin);
Mais je n'ai pas reussi...

Donc voilà comment j'ai fait finalement, en envoyant la fonction de traitement des données en paramétres, si vous avez d'autres idée pour l'ameliorer ou si vous connaisez des fonctions existantes plus efficaces et polyvalentes n'hesitez pas.


function ajaxRequest(url, variables, action){
  
  var objXhr = false;

  if (window.XMLHttpRequest){objXhr = new XMLHttpRequest();}
   
  else if (window.ActiveXObject) {
    var ieXHR = new Array(
    "Msxml2.XMLHTTP.7.0","Msxml2.XMLHTTP.6.0",
    "Msxml2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0",
    "MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP");
	  var success = false;
    for (var I=0;I<ieXHR.length && !success;I++){
      try{objXhr = new ActiveXObject(ieXHR[I]);success = true;}
      catch (ex){}
    }
  } 
    
  if(objXhr) {
    
    if(variables==null){objXhr.open("GET",url,true);}

    if(variables!=null){	 
      objXhr.open("POST",url,true);
      objXhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');	
    }
    
    if(action){
          objXhr.onreadystatechange = function () {
	       if (objXhr.readyState == 4) {
		    if (objXhr.status == 200) {
                        action(objXhr);
		    }else{alert('failed connection')}
		}
	  }
    }
    objXhr.send(variables);
}
}



le alert('failed connection'), est un peu brutal, mais je pense que c'est important, je me suis aperçu dans plusieur cas cela peu poser un probléme si l'utilisateur n'est pas averti d'un probléme de connection.

En effet quand on fait des requetes reguliéres on s'aperçoit que les serveurs et les connections n'ont pas un fiabilité a 100% et qu' il suffit d'une courte interuption pour faire tout échouer.

Il est préférable de faire un setTimeout pour ressayer avant de balancer le alert, mais c'est une version de test.

Je suis surement loin de prevoir tout les cas de requetes, mais jusque là j'ai pu tout faire avec.

Ceci dit je triche un peu, je ne sais pas si c'est un bonne chose d'envoyer une seule variable, quite à la redécouper aprés, ce que j'aimerais rajouter, c'est la possibilté d'envoyer plusieurs variables dans un tableau, par exemple pour actualiser des données a l'aide d'un formulaire à plusieurs champs.

ajaxRequest("article_modif.php?id=4", {form:titre,date,auteur,texte}, formArticle);


Mais ça ce serat pour le prochain épisode, pour l'instant j'envoie tout dans une variable...
Modifié par matmat (22 May 2007 - 04:28)
Hello,

Désolé, je dévie un peu du sujet, mais quelqu'un sait-il de quelle partie du DOM vient la méthode load de document utilisée dans ce sujet et dans le code de Thanh ? J'ai bien l'impression qu'elle n'est définie nulle part.
koala64 a écrit :
Ben c'est à dire que load est une méthode de DOMDocument en DOM... donc... Smiley rolleyes (?)

Euh... Ben donne-moi un lien vers la définition IDL de cette méthode sur le site du W3C et on en reparle. Smiley langue

A priori, ça serait dans "DOM Load and Save", mais ça n'y est pas.
koala64 a écrit :
http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-LSParser Smiley lol

LsParser n'a rien à voir avec document.

<edit>On est d'accord. Smiley ravi
Modifié par Julien Royer (22 May 2007 - 10:28)
La réponse est chez Mozilla :
Le gros monstre rouge a écrit :
document.load() appartient à une ancienne version du module DOM Level 3 Load & Save du W3C.

Modifié par Julien Royer (22 May 2007 - 15:28)
a écrit :

mmh... pas trop le temps de regarder là mais as-tu consulté le code de Thanh ?


J'avais regardé attentivement son code, effectivement c'est interréssant, mais c'est pas vraiment la même idée, moi je voudrais juste trouver un code polyvalent qui recupére uniquement les données du xml brutes, ensuite le traitement c'est autre chose, parce que j'ai à chaque fois des besoins différents. C'est pour ça que je n'ai pas besoin de toute les classes, createXMLObject, setXMLObject, sendAndLoad etc..

Ensuite une autre chose, il me semble sauf grosse erreur de ma part, si il y a des données en dehors de l'url, ce n'est pas la peine de préciser POST ou GET, c'est automatiquement POST, et je ne vois pas trop l'interet de le transformer en get, on peut trés bien ecrire correctement l'url dés la requete, c'est plus simple et plus clair.
c'est pour cela que je suis pas trop convaincu par sa classe sendAndLoad.

Par contre je prend note de la méthode string pour l'envoie des données.
Modifié par matmat (22 May 2007 - 19:07)
Pages :