Réalisation pratique d'une application PHP Xul

Gilles Thomassin

Ce document est plaçé sous licence LGPL


Dédicace

Ce support sans prétention est dédié à tous les pauvres développeurs, qui condamnés à une veille technologique constante, passent leur temps libre à se former et qui là encore vont prendre quelque temps pour lire ce document.

Table des matières

Préface
L'application
La page principale du site
Vue d'ensemble de l'application
Les différentes parties de l'interface utilisateur
Le code
Quelques explications sur le code
en conclusion
la partie gauche
code qui génère la partie gauche
explications sur le code

Liste des illustrations

1. Ecran principal
2. menu principal
3. menu identification
4. menu membre
5. colonne de gauche
6. colonne centrale
7. colonne de droite
8. Partie gauche
9. La recherche
10. Les news externes
11. Les news internes

Préface

Attention

Le contenu de cette page pourrait choquer le développeur débutant et le décourager dans ses initiatives. Cette page est donc réservée à un public averti.

Loin d'être une référence sur le langage XUL ou sur le langage PHP . Ce document essaie d'expliquer comment pratiquement on peut faire évoluer une applic php-html en une applic php-xul.

L'application


La page principale du site

Cette page est donc au format xul. Un script php crée le source xml décrivant l'interface de l'utilisateur. Le navigateur de la personne qui consulte le site interprète le xml reçu et dessine l'interface.

Vue d'ensemble de l'application

L'application peut ressembler à cela, tout est dynamique, il n'y a donc pas à chaque fois les mêmes éléments. Ainsi les menus et leurs contenus sont construits à partir d'une base de donnée.

Figure 1. Ecran principal

Ecran principal

Les différentes parties de l'interface utilisateur

On trouvera successivement de haut en bas et de gauche à droite les éléments suivants:

  • Une barre de menu comportant les espaces du site.

    Figure 2. menu principal

    menu principal
  • Une barre de menu dont le contenu est dynamique: elle permet tout d'abord de s'authentifier comme le montre la figure ci-dessous.

    Figure 3. menu identification

    menu identification

    Mais une fois le membre authentifié, c'est le menu des membres qui y est affiché conformément à la figure ci-dessous.

    Figure 4. menu membre

    menu membre
  • Dessous se trouve une grosse boite (hbox) contenant le reste du site composé comme ceci:
    • Une colonne de gauche (vbox) dans laquelle on trouvera un logo, des news internes, des news externes et des liens internes

      Figure 5. colonne de gauche

      colonne de gauche
    • Une colonne centrale (vbox) dont le contenu varie en fonction des choix de navigation opérés par l'utilisateur du site.

      Figure 6. colonne centrale

      colonne centrale
    • Une colonne de droite (vbox) qui permettra la saisie et l'affichage de "petits coucous" et l'affichage des dix dernières offres d'emploi de Lolix.

      Figure 7. colonne de droite

      colonne de droite

Le code

Ce code est placé dans le fichier menuXul.php que voici.

<?
//démarrage de la session php
session_start();
//s'il veut se déloguer on le délogue
if(isset($_POST["logout"]))
{
	session_destroy();	
}
header ("Content-type: application/vnd.mozilla.xul+xml; charset=iso-8859-15");
header ("title: BTS Informatique section de Gap");
echo '<' . '?xml version="1.0" encoding="iso-8859-15" ?' . '>';
echo '<' . '?xml-stylesheet href="chrome://global/skin/" type="text/css"?' . '>' . "\n";
echo ('<' . '?xml-stylesheet href="styleXul.css" type="text/css"?' . '>' . "\n");
?>
<window flex="1"
	id="wBigOne" 
	class="mainwindow"
	title="BTS informatique de Gap"
	xmlns:html="http://www.w3.org/1999/xhtml"
	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
	<script type="application/x-javascript">
		//cette fonction ouvre une nouvelle fenêtre ayant pour url ce qu'il y a dans l'attribut value du bouton activé
		function voirArticle(event) 
		{
			var url = event.target.getAttribute('value');
			if (url) 
			{
				var xx=window.open(url,"navigation");
				xx.focus();
			}
		}
		//cette fonction donne à l'url de l'iframe centrale l'url placée dans l'attribut value du bouton activé
		function loadURL(event) 
		{
			var contentFrame = document.getElementById('framePrincipale');
			var url = event.target.getAttribute('value');
			if (url) contentFrame.setAttribute('src', url);
		}
	</script>
	<vbox>
		<menubar  class="haut"  id="menuPrincipal" oncommand="loadURL(event);">
			<? include ("genMenuXul.php"); ?>
		</menubar>
		<hbox class="haut" id="hbLogin">
			<? include ("xulIdent.php");?>
		</hbox>
	</vbox>
	<hbox class="contenu" autostrech="true" flex="1" id="toutLeSite">
		<vbox width="198" id="gauche">
			<? include ("gaucheXul.php"); ?>
		</vbox>
		<splitter id="splitterGauche"/>
		<vbox class="centrale" flex="1">
			<iframe  width="396" id="framePrincipale" src="accueil.htm" flex="4" />
		</vbox>
		<splitter id="splitterDroit"/>
		<vbox width="198" id="droite">
			<? 	include ("coucouXul.php");
				include("offresLolixXul.php");
			?>
		</vbox>
	</hbox>
</window>
				

Quelques explications sur le code

Hum ça n'a pas l'air simple !!!

Mais si, regardons cela avec un peu de recul.

On va distinguer 3 parties: du php, du xul et du javascript

le morceau de php du haut

<?
//démarrage de la session php
session_start();
//s'il veut se déloguer on le délogue
if(isset($_POST["logout"]))
{
	session_destroy();	
}
header ("Content-type: application/vnd.mozilla.xul+xml; charset=iso-8859-15");
header ("title: BTS Informatique section de Gap");
echo '<' . '?xml version="1.0" encoding="iso-8859-15" ?' . '>';
echo '<' . '?xml-stylesheet href="chrome://global/skin/" type="text/css"?' . '>' . "\n";
echo ('<' . '?xml-stylesheet href="styleXul.css" type="text/css"?' . '>' . "\n");
?>

					

Aprés avoir démarré la session, si jamais on est arrivé ici aprés envoi d'un logout, on efface la session. Dans tous les cas, c'est du xul qu'on envoie et on le fait savoir au navigateur. Difficile ensuite mais pourtant obligatoire de lui envoyer version xml et feuilles de styles internes et externes.

le javascript

On y trouve deux fonctions: l'une permet le changement de contenu de l'iframe centrale, l'autre permet l'ouverture d'une nouvelle fenêtre de navigation.

function loadURL(event) 
{
	var contentFrame = document.getElementById('framePrincipale');
	var url = event.target.getAttribute('value');
	if (url) contentFrame.setAttribute('src', url);
}
	
					

on obtient dans contentFrame une référence à l'iframe dont l'id vaut framePrincipale.

on récupère l'attribut value du bouton qui a été cliqué.

il s'agit de l'url de la page que l'on souhaite afficher dans l'iframe principale.

Enfin si cette url n'est pas vide, on redirige la frame principale vers l'url obtenue.

si donc on a cliqué sur le bouton "livre d'or", l'iframe centrale affichera la figure 6, si on a cliqué sur le menu "php" l'iframe principale sera celle de la figure 1.

La deuxième fonction permet l'ouverture d'une nouvelle fenêtre avec pour url l'url spécifiée dans le champ value du bouton sur lequel l'utilisateur a cliqué.

Elle ressemble donc beaucoup à la première fonction.

function voirArticle(event) 
{
	var url = event.target.getAttribute('value');
	if (url) 
	{
		var xx=window.open(url,"navigation");
		xx.focus();
	}
}
			
					

On récupére l'url, on ouvre notre window, on lui donne le focus (la main). Notez bien que si la fenêtre est déjà ouverte, son contenu va changer.

Le Xul

Enfin nous trouvons du xul, ensemble de balises décrivant l'interface utilisateur que nous souhaitons créer. Comme c'est trivial ;) je vous laisse le soin de le découvrir.

en conclusion

C'est tout ?, et ça affiche tout ça ?...

Peut-être avez-vous remarqué des petits morceaux de code php dans le xul. Ils correspondent à l'inclusion de scripts externes.Un découpage fonctionnel et visuel de l'aaplication a été réalisé. Chacun de ces scripts inclus sera chargé de créer et d'envoyer une partie de l'interface utilisateur.

la partie gauche

Figure 8. Partie gauche

Partie gauche

Elle est générée par le fichier gaucheXul.php dont voici le code source.

code qui génère la partie gauche

<label class="titre" value="btsinfogap.org"/>
<image id="logoLycee" src="logolycee.png"/>
<label class="titre" value="Quoi d' neuf"/>
<script>
function valideOkRecherche()
{ 
	var vWhat=document.getElementById("what").value;
	var leBouton=document.getElementById("btSearch");
	if(vWhat)
	{
		leBouton.setAttribute("disabled","false");
	}
	else leBouton.setAttribute("disabled", "true");
}
function affResultatRecherche()
{
	var contentFrame = document.getElementById('framePrincipale');
	var vWhat=document.getElementById("what").value;
	var url = "rechercheXul.php?ChaineRec="+vWhat;
	if (vWhat) contentFrame.setAttribute('src', url);
}
</script>
<? include "newsXul.php"?>
<label class="titre" value="Rechercher"/>
<vbox id="rechercher" oncommand="affResultatRecherche()">
	<hbox>
		<image src="logos/chercher.png"/>
		<textbox onkeyup="valideOkRecherche()" width="100" flex="1"  id="what"/>
	</hbox>
	<button width="20" id="btSearch"  label="Ok" disabled="true"/>
</vbox>
<? 
	//aff des news linux fr
	include ("affNewsXul.php") ;
	affNews("http://linuxfr.org/backend/news/rss20.rss","datanews/news.rss","Quelques news");
	// affichage des liens internes
?>
<vbox id="liensInternes" oncommand="loadURL(event)">
	<label class="titre" value="Liens internes"/>
	<button id="btAccueil" value="accueil.htm" label="Accueil"/>
	<button id="btLivreDOr" value="indexlorXul.php" label="Livre d'Or"/>
	<button id="btForum" value="livredor.php" label="Forum"/>
</vbox>
				

explications sur le code

La recherche

Figure 9. La recherche

La recherche

Lorsqu'une touche est relâchée dans la zone de saisie "what", la fonction javascript valideOkRecherche() est exécutée.

Cette fonction active le bouton "ok" de la recherche si le contenu de la zone de saisie "what" n'est pas vide.

Lors du clic sur le bouton "ok", l'iframe centrale doit afficher le résultat de la recherche. On change donc l'url de l'iframe en rechercheXul.php?ChaineRec=ceQuiAEtéSaisi . On simule donc grâce à cette technique la soumission par la méthode "get" d'un formulaire contenant un input nommé "ChaineRec" et ayant pour action "rechercheXul.php".

Les news externes

Figure 10. Les news externes

Les news externes

Pour obtenir les 10 dernières news de linuxfr, je fais appel à la fonction php affNews().

Cette fonction génère 10 boutons dans une boîte verticale ayant pour titre le titre des dernières news et ayant pour value l'url où la news peut être consultée.

L'origine est un fichier rss généré par linuxfr. Afin de na pas ralentir l'application, le flux rss n'est rechargé qu'en cas de besoin. En l'occurrence, le rechargement ne s'effectuera que si le dernier chargement a été effectué il y a plus d'une heure.

Remarquez que c'est la même fonction qui permet de charger les dix dernières offres d'emploi dans la colonne de droite.

Le code:

<? 
/* statut ok */
function obtenir($source,$destination)
{
	copy($source,$destination);

}
function parseRSS($src,$cache) {
    //recherche d'un fichier xml assez récent
    $fcache=fopen($cache,"r");
    if(!($fcache))
    {
	    obtenir($src,$cache);
    }
    else
    {
	    $fstat=fstat($fcache);
	    $dateCre=$fstat["mtime"];
	    $delai=3600;
	    //si le fichier a besoin de mise à jour
	    if(time()-$dateCre>$delai)
	    obtenir($src,$cache);
    }
 
    $feed = simplexml_load_file($cache);
    for($nb=0;$nb<10;$nb++)
    {
	    $res=$feed->channel->item[$nb]; 
	    printf('<button crop="right" label="%s" value="%s"/>',
            utf8_decode(htmlspecialchars($res->title)),
            htmlspecialchars($res->link)
        );
    }
}

function affNews($source,$cache,$titre)
{
?>
<vbox oncommand="voirArticle(event)">
<label class="titre" value="<?=$titre?>"/>
<? 
 parseRSS($source,$cache); 
?>
</vbox>
<?
}
?>
						

Les news internes

Figure 11. Les news internes

Les news internes

L'affichage des news internes est délégué au fichier source newsXul.php.

Ce script va chercher dans la table "news" de la base de donnée mysql les 5 derniers enregistrements, et crée 5 labels dans une vbox.

En voici le code:

<?
$req="select dayofmonth(datenews),month(datenews),textenews from news order by datenews desc limit 5";
$result = mysql_query($req);
while ($enr = mysql_fetch_row ($result))
{
	echo "<label value=\"[".$enr[0]."/".$enr[1]."] ".$enr[2]."\"/>";
}
?>