Raccourcis : Contenu - rubriques - sous rubriques
EN FR

Pour générer du xhtml/html, vous indiquez l'alias "html" ou "basichtml" à la méthode getResponse(). Vous récupérez alors respectivement une instance de l'objet jResponseHtml ou jResponseBasicHtml. Voici un exemple :


   $rep = $this->getResponse('html');

HTML5 ou HTML4

jResponseHtml génère un entête HTML5 plutôt que HTML4. Vous pourriez vouloir avoir du HTML4/XHTML1. Pour cela, vous devez utiliser la classe jResponseHtml4.

Aussi, si vous avez une classe de réponse personnalisée (ce qui est le cas par défaut dans les nouvelles applications), vous devez hériter de la classe jResponseHtml4 plutôt que jResponseHtml :


require_once (JELIX_LIB_CORE_PATH.'response/jResponseHtml4.class.php');

class myHtmlResponse extends jResponseHtml4 {

}

Note: jResponseHtml4 hérite de jResponseHtml, donc dans la suite du manuel, toutes les fonctionnalités décrites pour jResponseHtml sont valables pour jResponseHtml4, sauf mention contraire.

XHTML ou HTML

Les classes jResponseHtml et jResponseHtml4 ont un mode XHTML. D'ailleurs, jResponseHtml4 génère du XHTML par défaut.

La méthode setXhtmlOutput() de ces deux classes permettent de basculer en mode XHTML ou HTML :


// jResponseHtml
$rep->setXhtmlOutput(true);  // Réponse au format XHTML 5
$rep->setXhtmlOutput(false); // Réponse au format HTML 5 (par défaut)

// jResponseHtml4
$rep->setXhtmlOutput(true);  // Réponse au format XHTML 1.0 (par défaut)
$rep->setXhtmlOutput(false); // Réponse au format HTML 4

// connaitre le mode :
$outputXhtml = $this->isXhtml();

Avec jResponseHtml et jResponseHtml4, vous pouvez aussi changer le doctype, en surchargeant la méthode outputDoctype(), qui doit faire un echo du doctype souhaité.

Le mode XHTML est utilisable également avec jResponseBasicHtml. Mais cela n'influencera que les entêtes HTTP, pas le contenu de la page web. Il faut que le template utilisé indique lui-même le DOCTYPE etc.

Renvoyer le contenu d'une page statique

jResponseBasicHtml permet de renvoyer simplement une page HTML complète stockée dans un fichier. Ce fichier doit être un simple fichier PHP, cela ne doit pas être un template pour jTpl. Il doit contenir tout le code HTML de la page, et trois instructions qui affichent les variables suivantes :

  • $HEADTOP : après la balise d'ouverture <head>
  • $HEADBOTTOM : avant la balise de fin </head>
  • $BODYTOP : aprés la balise d'ouverture <body>
  • $BODYBOTTOM : avant la balise de fin </body>

Ces variables contiennent du code HTML qui a été indiqué lors des appels des méthodes addHeadContent() et addContent() de l'objet jResponseBasicHtml. Elles ont pu être appelée par des contrôleurs, des classes techniques, des plugins. C'est pourquoi il faut indiquer ces variables.

Il y a une quatrième variable, $BASEPATH qui contient le chemin de base de l'application, ce qui peut être utile pour vos feuilles de styles et autres ressources statiques.

Voici un exemple de fichier statique :


<!DOCTYPE html>
<html lang="en_US">
  <head>
     <?php echo $HEADTOP; ?>
     <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
      <title>Hello From Jelix !</title>
      <link type="text/css" href="<?php echo $BASEPATH; ?>mystyles.css" rel="stylesheet" />
      <?php echo $HEADBOTTOM; ?>
  </head>
  <body>
      <?php echo $BODYTOP; ?>
     <h1>Hello YOU !</h1>
     <p>This is a sample html page generated by Jelix</p>
      <?php echo $BODYBOTTOM; ?>
  </body>
</html>

Dans votre contrôleur, vous devez indiquer où jResponseBasicHtml peut trouver ce fichier, en donnant son chemin complet dans la propriété $htmlFile. Notez que l'objet jCoordinator possède une méthode permettant de récupérer le chemin d'un module. Il est ainsi aisée de récupérer un fichier d'un module, par exemple se trouvant dans un sous-répertoire static/ du module :


   $rep = $this->getResponse('basichtml');
   $rep->htmlFile = jApp::coord()->getModulePath('unModule'). 'static/hello.php';

Générer du contenu dynamique

Pour renvoyer du contenu dynamique, il est préférable d'utiliser la classe jResponseHtml, donc de récupérer la réponse de type "html". Cette classe implémente des méthodes et propriétés supplémentaires par rapport à la réponse "basichtml", pour manipuler le contenu (X)HTML. Elle est de ce fait bien plus facilement utilisable par les divers composants (zones, templates, classes techniques, contrôleurs..) voulant agir sur la réponse.

Le source HTML d'une page est découpé en deux parties : la partie <head>, et la partie <body> :

jResponseHTML s'occupe de générer le contenu de la balise <head>, à partir des informations données au travers de ses méthodes. Par contre la génération du contenu de la partie <body> est de votre ressort, avec l'aide éventuellement d'un template. Voyons tout ça en détails.

Modification de l'entête HTML

Pour modifier le contenu de la balise <head>, vous avez plusieurs méthodes et propriétés. Vous pouvez ainsi modifier le titre du document, le "favicon", les urls des feuilles de styles et des scripts javascripts à lier au document, du CSS ou du javascript à inclure directement dans le <head>, ou encore les mots clés associés, la description de la page, et autres metas. Voyons un exemple qui montre l'ensemble de ces possibilités :


$rep->title = "Le titre de mon document";

// génère une balise <script src="/lib.js"....>
$rep->addJSLink('/lib.js');

// génère une balise <script>alert....</script> qui sera incluse dans <head>
$rep->addJSCode('alert("essai");');

// génère une balise <link>
$rep->addCSSLink('/maFeuille.css');

// génère une balise <style>
$rep->addStyle('span', 'font-weight:bold;');

// ajoute une balise meta pour la description
$rep->addMetaDescription('description');

// ajoute une balise meta pour les mots clés
$rep->addMetaKeywords('motclé motclé motclé');

// Ajoute un auteur
$resp->addMetaAuthor('Laurent');

// modifie le nom du generateur
$resp->addMetaGenerator('My Super App 1.0');

// indique le mode de compatibilité pour IE
$resp->IECompatibilityMode = 'IE=Edge'; // valeur par défaut

// spécifie le viewport
$resp->metaViewport = 'width=device-width, initial-scale=1.0';

// ajoute une balise meta
$resp->addMeta(array('name'=>'apple-touch-fullscreen', 'content'=>'yes'));

Si vous voulez injecter du contenu spécifique dans la balise <head>, vous pouvez le faire via la méthode addHeadContent()


$rep->addHeadContent('<link rel="alternate" type="application/rss+xml" title="Recent Changes" href="/feed.php" />')

Si à un moment ou à un autre, vous voulez annuler les modifications faites dans le head (par exemple, vous êtes dans une zone qui est appelée par un module tiers que vous ne voulez pas/pouvez pas modifier), vous pouvez appeler la méthode clearHtmlHeader(). Cette fonction vous permet d'effacer une partie du header de votre document html, en indiquant quoi effacer : CSSLink, Styles, JSLink, JSCode et/ou Others.


$rep->clearHtmlHeader(array('CSSLink', 'Styles'));

Cet exemple effacera les liens CSS (addCSSLink) et les balises <style> (addStyle).

Générer le contenu principal de la page HTML

jResponseHtml génère la balise <body>, mais c'est vous qui en contrôlez ses attributs et son contenu.

Pour définir les attributs de la balise <body>, vous pouvez utiliser la propriété bodyTagAttributes.


$rep->bodyTagAttributes = array('onload'=>'bodyonload()', 
                                'class'=>'maincontent');

Pour générer le contenu même de la balise body, vous avez deux choix : soit utiliser un template, soit utiliser la méthode addContent().

Générer avec un template

Pour utiliser un template, jResponseHtml propose deux propriétés :

  • bodyTpl, qui doit contenir le sélecteur du template à utiliser
  • body qui contient un objet jTpl permettant de "paramétrer" le template.

Exemple :


$rep->bodyTpl = 'myapp~main';
$rep->body->assign('person','Laurent');

Le contenu généré par le moteur de template sera intégré entre les balises <body> et </body>.

Pour en savoir plus sur l'utilisation des templates, consultez le chapitre sur les templates.

Il se peut que vous ayez besoin d'ajouter du contenu en plus de celui produit par le template. Pour cela vous utiliserez la méthode addContent(). Elle prend en paramètre une chaîne pour le contenu, et un booléen (facultatif) pour indiquer si on veut que le contenu soit ajouté avant (true) ou après (false, valeur par défaut) le contenu du template.


$rep->addContent('Mon contenu HTML après le template');
$rep->addContent('Mon contenu HTML avant le template', true);

Notez que le contenu à ajouter peut être aussi le contenu de zones


$rep->addContent(jZone::get('monmodule~uneZone'));

Générer avec un template principal et des "sous-templates"

Bien souvent, les pages d'un site ont un gabarit commun, et seules certaines zones changent (notamment le contenu principal) en fonction de l'action. Il y aura donc un template principal , défini comme on l'a vu précédemment, qui ne contiendra que le contenu commun à toutes les pages, et dans chaque action on utilisera un autre template (un "sous-template") pour générer le contenu spécifique, dont on injectera le résultat dans le template principal. Ce travail peut être fait avec un template directement, ou au moyen d'une zone.

Et pour éviter que dans chaque action on définisse à chaque fois le template principal, les élements communs (feuilles de style etc), on créera un objet réponse HTML qui héritera de jResponseHtml.

Pour savoir comment faire, lire la section sur la personnalisation de réponse commune.

Générer sans template

Si vous ne voulez pas utiliser de template pour le body, alors il faut laisser la propriété $bodyTpl à vide, et utiliser seulement la méthode addContent() :


$rep->addContent('contenu pour mon body');

Ajouter des feuilles de styles, fichiers javascript, images...

Utiliser les webassets

Plutôt que d'indiquer dans votre objet réponse, dans vos contrôleurs ou encore dans les templates, la liste des fichiers CSS et JS à utiliser (voir la section plus bas sur l'ajout de fichiers JS et CSS spécifiques), vous pouvez les lister dans la configuration en les regroupant, et ensuite indiquer dans vos réponses, contrôleurs ou templates, quels groupes d'assets vous voulez utiliser.

Cela évite de déclarer en dur à plusieurs endroits des fichiers CSS et JS, mais surtout cela permet de modifier les assets qui sont utilisés par défaut par certains composants de Jelix. Vous pouvez par exemple facilement changer la version de jQuery à utiliser, sans modifier une seule ligne de code dans les contrôleurs de module (ce qui serait délicat à faire dans des modules tiers).

Dans la section webassets_common (ou d'autres sections webassets_*, voir les collections de webassets plus bas), vous allez y définir les groupes d'assets.

Un groupe correspond en général à une liste de JS et de CSS utilisés par un composant précis. Ainsi par défaut, il existe les groupes suivants :

  jquery, jquery_ui, jforms_html, jforms_html_light, jforms_datepicker_default,
  jforms_datetimepicker_default, jforms_htmleditor_default, jforms_wikieditor_default,
  swjs

Pour déclarer les fichiers js, on utilise le nom du groupe suivit de .js. Pour les css, ça sera .css.

Par exemple, ici on définit un fichier js et un fichier css pour le groupe jforms_html_light :


jforms_html_light.js= "/jelix/js/jforms_light.js"
jforms_html_light.css= "/jelix/design/jform.css"

Si on en a plusieurs, on peut soit les indiquer séparés par une virgule, soit utiliser la notation "tableau" du format ini :


mongroupe.js= "js/foo.js, js/bar.js"

mongroupe2.js[]= "js/bla.js"
mongroupe2.js[]= "js/baz.js"

Les chemins que l'on indique pour un fichier js ou css, peuvent être de différentes formes :

  1. un chemin absolue (par rapport à la racine du site) ou une url complète.
  2. un chemin relatif (ne débutant pas par un "/"), relatif par rapport au chemin du "base path"
  3. un chemin commençant par $theme/, où $theme sera remplacé par <basepath>/themes/<themecourant>/
  4. un chemin commençant par $jelix/, où $jelix correspond au chemin vers le répertoire des assets de Jelix (valeur de jelixWWWPath)
  5. un selecteur d'une action d'un module : <module>~<controleur>:<methode>. Cette action doit donc renvoyer le contenu d'un fichier js ou css.
  6. un chemin commençant par le nom d'un module suivit par : : pour indiquer un fichier js/css contenu dans le repertoire www du module en question.

les formes 1 à 4 peuvent contenir les "variables" suivantes, $locale ou $lang qui seront respectivement remplacées par le code de la locale courante (xx_YY) ou le code de la langue courante (xx).

Exemples :


example.js[]= "/absolute/path.js"
example.js[]= related/to/basepath
example.js[]= "module:path/to/file.js, module~ctrl:meth"
example.js[]= "$theme/path/to/file.js, path/$lang/machin.js, /$locale/truc.js"

Vous pouvez aussi indiquer des attributs qui seront ajoutés sur la balise script ou link, comme les attributs defer ou media


example.js[]= "myscript.js|defer"
example.js[]= "https://popular.com/script.js.js|defer|integrity=sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K|crossorigin=anonymous"
example.js[]= "mymodule.mjs|type=module"
example.css[]= "mystyle.css|media=screen and (max-width: 600px)"
example.css[]= "otherstyles.css|rel=alternate stylesheet|title=Fancy"

Il se peut que l'utilisation d'un groupe nécessite l'utilisation d'un autre groupe. Par exemple, l'utilisation du groupe d'assets "jforms_html" nécessite l'utilisation du groupe d'assets "jquery". On peut indiquer cette dépendance dans la déclaration du groupe, afin d'éviter à le faire en PHP lorsqu'on indique au niveau de la réponse la liste des groupes à utiliser.

Pour cela il y a deux types de déclarations : require et include. Et vous indiquer la dépendance en utilisant le nom du groupe suivi du type de dépendance :


example1.js = ex1.js
example2.js = ex2.js
example2.css = ex2.css
example3.js = ex3.js
example3.css = ex3.css

example.require = example1, example2
example.include = example3
example.js = foo.js
example.css = foo.css

.require permet d'inclure les groupes en question avant de déclarer les fichiers JS et CSS du groupe, tandis que .include fait l'inclusion après. Ainsi dans l'exemple précédent, les fichiers js et css de example1 et example2 seront inclus dans la page html, suivit de foo.js, puis des fichiers js et css de example3.


<link type="text/css" href="/ex2.css" rel="stylesheet" />
<link type="text/css" href="/foo.css" rel="stylesheet" />
<link type="text/css" href="/ex3.css" rel="stylesheet" />

<script src="/ex1.js"/>
<script src="/ex2.js"/>
<script src="/foo.js"/>
<script src="/ex3.js"/>

API pour ajouter des webassets

Une fois les groupes déclarés, on peut les indiquer dans nos contrôleurs ou les objets réponses dérivant de jResponseHtml. Pour cela on appelle la méthode addAssets() de jResponseHtml avec le nom du groupe que l'on veut utiliser :


$rep = $this->getResponse('html');
$rep->addAssets('example');

On peut aussi indiquer un groupe d'assets dans un template :


{meta_html assets 'example'}

Enfin, dans le script d'installation de votre module, vous pouvez définir un groupe d'assets dans la configuration, au moyen des méthodes :

  1. $this->declareGlobalWebAssets() si vous voulez installer dans la configuration globale
  2. declareWebAssets() de l'objet du point d'entrée, pour définir le groupe d'assets au niveau de la configuration du point d'entrée.

$this->declareGlobalWebAssets(
    $nomGroupe, // nom du groupe d'assets
    array( // liste des assets
        'js'=>array('foo/bar.js', 'mymodule:baz.js'),
        'css'=> ..
        'require' => ...
        'include' => ...
    ),
    'common', // nom de la collection
    false, // true pour toujours écraser les valeurs existantes
);

Collection de webassets

Une collection regroupe plusieurs groupes d'assets dédiés à un environnement particulier, ou à un thème. Par exemple, si on débug l'application la liste des assets sera probablement différente que la liste des assets en prod, parce que les fichiers JS et CSS ne seront pas forcément concaténés ou compressés etc.

Il y a une collection "common", qui contient les groupes d'assets communs à toutes les collections. On peut redéfinir les assets et leurs groupes dans chaque collection.

Une seule collection est utilisable à la fois, et son nom est indiqué dans le paramètre useCollection dans la section webassets. Sa valeur par défaut est "common".

Chaque collection est définie dans une section webassets_<nom>. Pour la collection "common", ça sera la section webassets_common.

Ajouter des fichiers JS et CSS spécifiques

Vous avez probablement remarqué l'exemple sur l'utilisation de addJSLink() et addCSSLink(). Ces méthodes permettent de lier des feuilles de styles CSS et des fichiers javascript à votre page HTML. Même si l'utilisation des webassets est fortement recommandée, ces méthodes restent utiles pour les JS/CSS necessaires dans un contexte particulier par exemple.

addJSLink() et addCSSLink() acceptent en premier argument une URL d'un fichier Javascript ou d'un fichier CSS. Faites attention cependant à l'URL que vous indiquez. À moins que ce soit vraiment ce que vous voulez, n'utilisez pas d'URL relative (dependante donc de l'URL de la page). Car la plupart des URLs des pages de votre application étant virtuelles (ne pointant pas vers des fichiers physiques), l'URL résultante risque de ne pas être la bonne.

Par exemple, 'css/styles.css' dans la page http://exemple.com/foo/bar/ donne http://exemple.com/foo/bar/css/styles.css, tandis que dans la page http://exemple.com/foo/bar (notez l'absence du slash final) ou http://exemple.com/foo/, cela donne http://exemple.com/foo/css/styles.css.

Si vous donnez une URL absolue (avec ou sans le nom de domaine), vous obtiendrez toujours le bon chemin. '/css/styles.css' (notez le / au début) donne toujours http://exemple.com/css/styles.css quelle que soit l'URL de la page.

Aussi il est recommandé d'indiquer une URL absolue, dont le chemin débute à la racine du site. Cependant, pour être sûr que le chemin sera bon, quelque soit le niveau de répertoire dans lequel l'application est installée sur le serveur, vous utiliserez jApp::urlBasePath() pour récupérer le début du chemin correspondant au répertoire www/, (ou jApp::urlJelixWWWPath() pour le chemin vers le répertoire de fichier js/css de Jelix). Cela est d'autant plus important si le module que vous développez peut-être utilisé par d'autres applications.

Exemple :


  $resp->addCSSLink(jApp::urlBasePath().'css/mystyles.css');

au lieu de


  $resp->addCSSLink('/css/mystyles.css');

Si vous voulez lier un fichier CSS/JS du répertoire lib/jelix-www/, vous ferez plutôt :


  $resp->addJSLink(jApp::urlJelixWWWPath().'js/tooltip.js');

Si le fichier CSS/JS se trouve dans un module, alors vous ne pouvez pas indiquer le chemin direct, les fichiers d'un module n'étant pas accessibles directement à partir d'un navigateur, en temps normal. Vous devez passer par deux méthodes spécifiques addJSLinkModule() et addCSSLinkModule().

Vous devez donner deux paramètres, le nom du module et le chemin du fichier dans le répertoire www/ du module. Par exemple, si vous voulez lier le fichier

myapp/modules/mymodule/www/css/mystyles.css :


  $resp->addCSSLinkModule('mymodule', 'css/mystyles.css');

Notez que pour les méthodes addCSSLink, addJSLink, addJSLinkModule() et addCSSLinkModule() vous pouvez indiquer un paramètre supplémentaire qui doit être un tableau associatif, décrivant les attributs supplémentaires à mettre dans la balise HTML générée.


$rep->addCSSLink('maFeuille.css', 
                  array('title'=>'design bleu',
                        'rel'=>'alternate stylesheet',
                        'media'=>'all'));

Tous les exemples précédent sur la récupération des URL des fichiers CSS, fonctionnent aussi bien pour les fichiers JS, les images et autres fichiers de ressources, stockés dans le répertoire www/ d'une application, d'un module ou dans le répertoire jelix-www.

Et vous pouvez appliquer les mêmes principes dans un template :


  {* dans le www/ d'une application *}
  {meta_html css '/css/mystyles.css'}
  {meta_html css $j_basepath.'css/mystyles.css'}
  
  {* dans le jelix-www/ *}
  {meta_html js  $j_jelixwww.'js/tooltip.js'}

  {* dans le www/ d'un module *}
  {meta_htmlmodule css 'mymodule', 'css/mystyles.css'}

  {* lien vers une image mymodule/www/img/mypicture.png *}  
  <img src="{jurl 'jelix~www:getfile', array('targetmodule=>'mymodule', 'file'=>'img/mypicture.png')}" />

Voyez le chapitre sur les templates pour en savoir plus.

Autres paramètres pour les réponses html et basichtml

Comme jResponseHtml et jResponseBasicHtml sont dérivés de jReponse, vous pouvez influer sur les entêtes HTTP, comme le code "status", et bien sûr ajouter d'autres en-têtes.


 $rep->setHttpStatus  ("404", "Not Found");
 $rep->addHttpHeader  ("Date-modified", "....");

Il y a aussi une autre propriété : $xhtmlContentType. Cette propriété définit si le contenu xHTML doit être envoyé avec un en-tête HTTP Content-Type spécifique : application/xhtml+xml. Bien sûr, une vérification des capacités du navigateur à recevoir du xhtml est faite, et si le navigateur ne peut pas recevoir du xHTML, la réponse sera envoyée avec le Content-Type text/html comme pour le HTML classique.


$rep->xhtmlContentType = true ;

Activer des plugins

Les classes jResponseHtml, jResponseHtml4 et jResponseBasicHtml ont un système de plugin. Ces plugins permettent d'enrichir ou agir automatiquement sur le contenu de toutes les pages HTML du site. C'est ainsi qu'il existe par exemple un plugin pour afficher une barre de debug, ou encore un autre pour "minifier" les fichiers CSS et Javascript (disponible séparement).

Ces plugins sont des plugins de type "htmlresponse", ils doivent se trouver dans un répertoire htmlresponse/ d'un dépot de plugin. Et pour les activer, il faut indiquer les noms des plugins utilisé dans l'option plugins de la section jResponseHtml de la configuration générale. Exemple :


[jResponseHtml]
plugins = debugbar, minify

Compression des fichiers css et javascript

La concaténation et l'obfuscation des fichiers JS et CSS se fait en général avec des outils en ligne de commande comme WebPack, Grunt.. Vous indiquez alors les fichiers résultants dans les liste d'assets dans la configuration.

Mais il peut encore arriver que l'on préfère faire ces opérations à la volée. Pour cela il est proposé un module reposant sur la bibliothèque Minify, qu'il faut installer dans votre application. Il s'agit du module jMinify disponible via composer sous le nom "jelix/minify-module". Voyez sa documentation sur Github pour savoir comment l'installer et l'utiliser.