La création d'un site web avec un CMS implique plus de composants qu'un site composé de pages statiques en pur HTML. L'idée sous-jascente d'un CMS est que le contenu est stocké séparément de la présentation. Certains CMS stockent ces contenus dans des fichiers XML, d'autres utilisent une base de données. Chaque technique a ses avantages et ses inconvénients, mais l'idée maîtresse reste la même : "Séparer les contenus des couleurs".
Quand Typo3 génère une page, le moteur de frontend combine du contenu non formaté provenant de la source de données (la base de données) avec une maquette HTML qui défini le formatage. Dans ce processus, c'est le gabarit (l'enregistrement correspondant à la maquette) qui représente le chef d'orchestre et qui indique au moteur comment comment combiner les éléments.
Sur le schéma suivant, vous pouvez voir que le gabarit est l'élément contrôlant -le "programme"- le moteur de frontend qui va lui rechercher le contenu dans la base de données, lire la maquette statique, insérer le contenu aux emplacements réservés dans la maquette statique et, finalement, produire une jolie page web !
Dans la plupart des agences web, plusieurs personnes travaillent de concert pour produire un site web. Dans ce groupe, nous trouverons un graphiste, un développeur et un contributeur. Chacune de ces personnes a des compétences spécifiques et de ce fait interviendra à sur des parties différentes du cycle de production du site :
Dans l'illustration ci-dessus, les différentes composants d'un site web gérés par un CMS sont assignées à une personne différente de l'équipe web :
Mr. Raphaël est l'artiste du groupe. Raphaël a de fortes compétences en design et en arts graphiques. Il connaît GIMP (ou Photoshop), Quanta (ou Dreamweaver), les CSS, le HTML ... Raphaël jongle avec les films en Flash mais pas avec le PHP, le Typoscript, le SQL ... Raphaël se chargera donc de créer les maquettes statiques HTML !
Mr. Benoît est un développeur, il aime le code, les instructions de compilation, les expressions régulières, la logique, le PHP, le SQL – bientôt il adorera le Typoscript. Cependant, s'il adore son bon vieux jean comme tous les programmeurs et designers, les couleurs, la typographie, l'ergonomie et les designs "hype" sont absents de son horoscope. Par conséquent, Benoît sera en charge du Typoscript dans les gabarit.
Mr. Picouto est lui préoccupé par le contenu. C'est le gars du marketing et il est stupéfait par les merveilles que font Raphaël et Benoît pour transporter les idées du papier sur l'écran. Picouto n'est ni un programmeur, ni un designer, par contre, il a un message à faire passer. Il créera le contenu qu'il souhaite en utilisant l'interface de contribution (backend) de Typo3 sans avoir besoin d'autre compétence technique que de savoir utiliser un traitement de texte.
Nous avons donc 3 personnes possédant chacune des compétences spécifiques. Ceci nous conduit à la conclusion que la création de sites web n'est pas une promenade de santé si vous ne possédez pas les 3 compétences citées ci-dessus : Visuelle, Technique, Marketing. C'est généralement vrai dans les équipes web, plus rarement pour les individus, soyez en conscients. (Si vous n'avez pas toutes ces compétences, vous aurez vraisemblablement soit à apprendre beaucoup, soit à utiliser les maquettes standard qui sont des mises en pages fixes que vous pourrez mettre en place avec un minimum de configuration (ce qui n'est pas expliqué dans ce manuel)).
Dans ce tutoriel, je vous montrerais comment Raphaël, Benoît et Picouto devront coopérer afin de créer un site web moderne, correspondant à tous les designs possibles et facilement maintenable, où chaque participant pourra travailler librement sur son domaine réservé, en utilisant ses outils préférés. Et ce, grâce à Typo3.
Niveau, compétences et prérequis.
Webdesigner intermédiaire connaissant HTML/CSS sans être nécessairement une programmeur web.
Pour suivre cette partie du tutoriel, vous aurez besoin d'une bonne connaissance de HTML et CSS. Vous aurez également besoin d'une base de données TYPO3 fonctionnelle contenant l'arborescence que nous avons créé dans les chapitres précédents. Enfin, vous pourrez avoir besoin de connaître les concepts de programmation afin de comprendre en profondeur cette partie. Ne vous inquiétez pas, je vous indiquerais précisément quoi faire et comment, prenez le temps de comprendre les exemples et suivez précisément les instructions.
L'équipe Web a un nouveau client - Main Dish & Son – et Raphaël, l'artiste du groupe a créé une maquette du site web sous la forme d'une page HTML classique :
Cette maquette est placée dans le répertoire "fileadmin/template/main/" de l'installation Typo3 (le dummy-package).
Afin de suivre ce guide, vous devriez copier le contenu du dossier "part1/" de l'extension correspondant à ce guide dans le dossier "fileadmin/template/". Si vous n'avez pas encore importé l'extension "doc_tut_templselect" depuis le TER (Typo Extension Repository) vous devriez le faire dès maintenant !
Revenons a travail de Raphaël. La maquette statique HTML est un page HTML normale. Mais lorsque Typo3 utilisera cette maquette, l'objectif est de rendre certaines parties dynamiques, notamment le menu à gauche ainsi que la partie avec le contenu d'exemple au centre droit.
En examinant le code source de la maquette, on trouve un simple document XHTML se référant à une feuille de style et utilisant une simple table pour positionner les différents éléments dans la page :
Quelques commentaires sur cette maquette et sur les problèmes qui nous attendent :
Cette section du "header" doit être inclus dans notre page web puisqu'il fait référence à la feuille de style utilisée. Difficulté : nous devons nous assurer d'extraire cette partie et l'inclure dans la partie "header" qui est générée par le moteur de frontend !
Le menu à gauche est constitué d'un <div> par objet du menu. Chacune de ces <div> a une classe (au sens CSS) qui lui est assignée. Grâce à ce class la présentation de l'élément est contrôlé par la feuille de style. C'est une façon astucieuse de créer un menu puisque chaque élément représente un minimum de code HTML (ce qui est bon pour l'implémentation Typoscript), élément qui peut facilement être répété (cela sera nécessaire lorsque le menu sera dynamique.Difficulté : nous devons remplacer le menu d'exemple qui est ici statique par un menu dynamique, généré par Typo3.
Le content d'exemple que Raphaël a inséré dans la maquette sert juste à donner une visualisation réaliste de la maquette. Notez comment ce contenu et formaté en utilisant les balises <h1> et <p> (utilisant la classe "bodytext"). C'est une bonne approche puisque le contenu dynamique généré par Typo3 utilisera plus tard les mêmes balises et classes pour sa présentation ! (J'ai l'impression que Raphaël a quelque peu triché en se documentant sur Typo3, non ?)Difficulté : Nous devons remplacer le contenu d'exemple par une contenu généré dynamiquement.
Ce tag <br> crée un espace sous le contenu afin que le pied de page ne soit pas collé au corps de la page.
Enfin, vous noterez que les cellules du tableau qui contiennent le menu et le contenu ont été marquées avec un identifiant (id-attribute). Ceci n'est pas seulement utilisé avec les feuilles de style ! il y a une très bonne raison à l'utilisation de ces id-attribute ! Mais avant cela un peu de théorie sur les maquettes HTML :
Commençons par créer un nouveau fichier, fileadmin/template/test.html, avec ce contenu :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Untitled</title>
</head>
<body>
<!-- ###DOCUMENT_BODY### -->
<h1>
<!-- ###INSIDE_HEADER### -->
Header of the page
<!-- ###INSIDE_HEADER### -->
</h1>
<!-- ###DOCUMENT_BODY### -->
</body>
</html>
(Ce fichier peut être trouvé dans le répertoire de l'extension : "misc/test.html")
Ensuite, mettez ceci dans le champ Setup de votre gabarit :
# Template content object:
temp.mainTemplate = TEMPLATE
temp.mainTemplate {template = FILE
template.file = fileadmin/template/test.html
}
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.10 < temp.mainTemplate
Ceci créera un cObject de type "TEMPLATE" à la position "page.10". La propriété "template" de ce cObject TEMPLATE est défini comme étant un autre cObject de type "FILE". Ce cObject lit le fichier créé précédemment, "fileadmin/template/test.html". Les propriétés des cObject TEMPLATE peuvent être trouvées ici.
Si vous enregistrer les changements dans le champ Setup et visualiser la page en frontend vous verrez ceci :
En examinant les sources de la page, on constate que le cObject TEMPLATE se content de lire le fichier et le renvoie directement :
Maintenant examinons la principale fonctionnalité du cObject TEMPLATE. Il ne se contente pas de lire le fichier HTML mais nous permet d'en extraire des parties (subparts) et de les remplacer par un contenu dynamique !
Une subpart est définie comme le contenu compris entre deux marqueurs similaires entourés de ### et contenus dans un commentaire HTML (bien que cette dernière condition soit optionnelle). Le fichier "test.html" a donc deux subpart, la sous-partie "DOCUMENT_BODY" et la sous-partie "INSIDE_HEADER". Comme vous le constatez, les marqueurs de sous-parties sont encapsulées dans des commentaires HTML afin qu'il ne soient pas visibles.
Essayons maintenant de changer le champ Setup du gabarit en ceci :
# Template content object:
temp.mainTemplate = TEMPLATE
temp.mainTemplate {template = FILE
template.file = fileadmin/template/test.html
workOnSubpart = DOCUMENT_BODY
subparts.INSIDE_HEADER = TEXT
subparts.INSIDE_HEADER.value = HELLO WORLD!
}
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.10 < temp.mainTemplate
Rechargez la page et le code source devrait ressembler à ceci :
Les changement appliqués au cObjet TEMPLATE ont produit les choses suivantes :
Tout d'abord, le cObject TEMPLATE a reçu l'instruction de ne travailler QUE sur la sous-partie "###DOCUMENT_BODY###" – ainsi, le header et le tag body sont retirés (ils seraient redondants dans la page).
Dans un deuxième temps, la sous-partie délimitée par "###INSIDE_HEADER###" a été remplacée avec le contenu généré par le cObject TEXT défini dans la propriété "subparts.INSIDE_HEADER".
Suite à cet exemple simpliste, nous devons maintenant simplement pointer vers la maquette de Raphaël, fileadmin/template/main/template_1.html, insérer des marqueurs de sous-partie similaires et enfin remplacer le menu et le contenu d'exemple par un menu dynamique et le vrai contenu de la page.
Le plus simple serait d'éditer la maquette de Raphaël. Cependant, d'après mon expérience, vous ne pouvez faire confiance aux éditeurs HTML pour qu'il n'enlèvent pas ou ne réarrangent pas les commentaires HTML lorsque Raphaël retouchera la maquette par la suite. Il est parfaitement possible que Raphaël effectue quelques changements avec Dreamweaver et que les marqueurs de sous-partie soient retirés de manière silencieuse par le logiciel, la maquette cesserait immédiatement de fonctionner ! De plus, les chemins pointant vers la feuille de style et les images à l'intérieur de la maquette utilisent des chemins relatifs à l'emplacement de cette maquette ([domain]/fileadmin/template/main/), or le moteur de frontend affiche la page en utilisant le chemin [domain]/. Tous les chemins utilisés devront donc être préfixés !
L'ensemble de ces problèmes impose une meilleure solution que la simple édition de la maquette. Importez et installez maintenant l'extension "Template Auto-parser".
Installer l'extension
Allez dans le module "Extension Manager", et importez l'extension depuis le dépôt en ligne (online repository) :
Trouvez l'extension "automaketemplate", cliquez sur l'icône d'import :
Un import réussi devrait vous donner ce résultat :
Utilisez "Go back", sélectionnez "Available Extensions to Install" et installez l'extension:
Après avoir pressé le bouton "Make updates" button, retournez dans le module "Template" et regardez "l'Object Browser" :
L'extension a rajouté un cObjet USER dans l'arborescence "plugin.tx_automaketemplate_pi1". Ce cObjet peut maintenant être utilisé plutôt que le cObject FILE afin de lire la maquette de Raphaël et d'y remplacer automatiquement les marqueurs et corriger les chemins relatifs.
Configurer le "Template Auto-parser"
Comme pour toutes les extensions, vous devriez consulter son manuel sur typo3.org afin de découvrir son fonctionnement et connaître les différentes possibilités de configuration. Cliquez ce lien afin d'accéder au tableau des propriétés de ce cObject..
Malheureusement nous n'y trouvons pas d'exemple de code -ce qui aurait été formidable (une simple suggestion à l'intention de l'auteur de cette extension). Nous allons donc proposer un tel exemple maintenant.
Afin de vous faire comprendre clairement ce que fait le "Template Auto-parser" je vais simplement insérer le contenu généré par le plugin comme seul contenu de la page puis je configurerais l'object PAGE "page" afin qu'il ne génère pas les headers et footers habituels.
Voici le champ Setup du gabarit :
# Configuring the Auto-Parser:
plugin.tx_automaketemplate_pi1 {# Read the template file:
content = FILE
content.file = fileadmin/template/main/template_1.html
# Here we define which elements in the HTML that
# should be wrapped in subpart-comments:
elements {BODY.all = 1
BODY.all.subpartMarker = DOCUMENT_BODY
HEAD.all = 1
HEAD.all.subpartMarker = DOCUMENT_HEADER
HEAD.rmTagSections = title
TD.all = 1
}
# Prefix all relative paths with this value:
relPathPrefix = fileadmin/template/main/
}
# Default PAGE object:
page = PAGE
page.typeNum = 0
page.config.disableAllHeaderCode=1
page.10 =< plugin.tx_automaketemplate_pi1
Enregistrez le gabarit et visualisez la page en frontend. Vous devriez voir exactement ce que le fichier fileadmin/template/main/template_1.html donne :
Et alors, vous me direz ... ? C'est déjà pas mal, mais si vous regardez le code généré, vous comprendrez pourquoi :
Comme vous le constatez, deux choses se sont produites :
Tous les blocs de la maquette ont été automatiquement inclus dans des sous-parties (1&2).
Tous les liens / références relatifs ont été préfixés par le chemin "fileadmin/template/main/" (3)
Ceci est du au fait que l'analyseur de maquette "Template Auto-parser" a été configuré de la manière suivante pour traiter ces éléments :
...
elements {BODY.all = 1
BODY.all.subpartMarker = DOCUMENT_BODY
HEAD.all = 1
HEAD.all.subpartMarker = DOCUMENT_HEADER
HEAD.rmTagSections = title
TD.all = 1
}
...
(Les "elements" sont tous les tags HTML ayant un tag de début ET un tag de fin comme par exemple le tag <td>. Les tags simples (sans tags de fin comme <img>) doivent être définis par la propriété "single" de l'analyseur de maquette)
Ainsi, la configuration des ces éléments indique que :
a) l'élément <body> doit être encapsulé dans le marqueur de sous-partie "###DOCUMENT_BODY###"
b) l'élément <head> doit être inclus dans le marqueur de sous-partie "###DOCUMENT_HEADER###". De plus, toute section <title> doit être retirée. (Nous ne voulons pas que le tag <title> de Raphaël fasse doublon avec celui généré par Typo3 ...)
c) Tous les éléments<td> doivent entourés . Comme il n'y a pas de .subpartMarker de défini, seuls les tags avec un attribut "id" ou "class" seront wrappés dans une sous-partie dont le marqueur correspondra à l'id/class. Ainsi, le tag <td id="menu_1"> verra le contenu à l'interieur de ces balises encapsulé entre des marqueurs de sous-parties "<!--###menu_1###-->...<!--###menu_1###-->".
Comment pouvons nous tirer partie de cette fonctionnalité ?
L'analyseur de maquettes permet à Raphaël de développer ses maquettes en utilisant les feuilles de styles et en utilisant avec discernement les attributs id / class. Dans le même temps, ces attributs constitueront des marqueurs permettant à Typo3 de remplacer des portions de la maquette par du contenu dynamique ! La technique est donc aisée pour Rapahël (lle designer), pose moins de difficultés à Benoît (le développeur) et rassure le comptable de Picouto puisque moins de main d'oeuvre sera nécessaire pour convertir à la main les maquettes statiques en maquettes dynamiques avec marqueurs de sous-parties.
Voici une illustration de ce que nous souhaitons obtenir :
Le fichier de la maquette est lue par l'Auto-Parser, le résultat alors passé au cObject TEMPLATE qui substitut les sous-parties et les insère au niveau du body et du header. Ceci sera obtenu grâce au TypoScript ci-dessous (champ Setup du gabarit). Ce code est assez long, mais nous prendrons le temps de l'analyser.
# Configuring the Auto-Parser for main template:
plugin.tx_automaketemplate_pi1 {# Read the template file:
content = FILE
content.file = fileadmin/template/main/template_1.html
# Here we define which elements in the HTML that
# should be wrapped in subpart-comments:
elements {BODY.all = 1
BODY.all.subpartMarker = DOCUMENT_BODY
HEAD.all = 1
HEAD.all.subpartMarker = DOCUMENT_HEADER
HEAD.rmTagSections = title
TD.all = 1
}
# Prefix all relative paths with this value:
relPathPrefix = fileadmin/template/main/
}
# Main TEMPLATE cObject for the BODY
temp.mainTemplate = TEMPLATE
temp.mainTemplate {# Feeding the content from the Auto-parser to the TEMPLATE cObject:
template =< plugin.tx_automaketemplate_pi1
# Select only the content between the <body>-tags
workOnSubpart = DOCUMENT_BODY
# Substitute the ###menu_1### subpart with some example content:
subparts.menu_1 = TEXT
subparts.menu_1.value = HELLO WORLD - MENU
# Substitute the ###content### subpart with some example content:
subparts.content = TEXT
subparts.content.value = HELLO WORLD - CONTENT
}
# Main TEMPLATE cObject for the HEAD
temp.headTemplate = TEMPLATE
temp.headTemplate {# Feeding the content from the Auto-parser to the TEMPLATE cObject:
template =< plugin.tx_automaketemplate_pi1
# Select only the content between the <head>-tags
workOnSubpart = DOCUMENT_HEADER
}
# Default PAGE object:
page = PAGE
page.typeNum = 0
# Copying the content from TEMPLATE for <body>-section:
page.10 < temp.mainTemplate
# Copying the content from TEMPLATE for <head>-section:
page.headerData.10 < temp.headTemplate
On obtient la structure suivante :
Comme vous pouvez le constater, les cObjects "temp.mainTemplate" et "temp.headTemplate" ont été copiés à leurs positions respectives dans l'arborescence des objets. Chacun d'eux font référence au cObject USER du plugin d'analyse de Template (plugin.tx_automaketemplate_pi1=USER).
Notez également que l'objet "page.headerData" est un tableau d'objets définissant le contenu de la section "head" de la page. Ceci vous montre comment insérer du contenu dans la partie <head> des pages générées par Typo3.
Résultat
Le résultat est le suivant :
Le contenu des zones menu et contenu ont été remplacées par des cObject TEXT de test !
Voici le code source :
La partie <head> sans le tag <title> tag est inséré
La partie <body> est insérée et le contenu est substitué
Les sous-parties ###header_1### et ###footer### ne sont pas substituées car elles ne sont pas définies dans le cObject TEMPLATE "temp.mainTemplate" ! Leur présence est donc parfaitement normale.
Les sous-parties ###menu_1### et ###content### sont substituées conformément à ce que nous avions défini des le cObject TEMPLATE "temp.mainTemplate".
Résumé
Typo3 extrait automatiquement de la maquette de Raphaël les parties <head> et <body>, corrige les chemins relatifs des images, liens et feuilles de style, effectue les substitutions de contenu dynamique et insère enfin les sections <head> et <body> dans la page retournée par Typo3.Le canevas est maintenant en place – nous devons simplement ajouter les contenus dynamiques que sont les menus et le contenu principal. La manière la pus efficiente d'effectuer ceci est d'utiliser les cObjects TypoScript permettant de construire des menus et des contenus.
Le menu en 2 niveaux à gauche de la maquette doit être généré dynamiquement afin de refléter fidèlement l'arborescence des pages. Bien que Raphaël ait créé une superbe maquette pour les menus avec des marqueurs pour chaque item, il n'est pas aisé d'extraire ces marqueurs et de les remplacer en utilisant l'analyseur de maquette comme nous venons de le faire. Nous allons plutôt coder intégralement le menu en Typoscript. Ceci signifie que Benoît (le développeur) doit identifier et extraire ce qui correspond à une ligne du menu dans la maquette de Raphaël. Il pourra ensuite l'utiliser dans le gabarit pour construire le générateur de menus. Ceci implique que Raphaël ne peut pas changer le schéma de base du menu sans en notifier Benoît qui devra répercuter ces changements dans le gabarit. Cependant, si Raphaël construit sa maquette intelligemment -en utilisant des CSS par exemple, il est possible d'apporter de nombreuses modifications au style du menu sans toucher au gabarit. D'une manière générale, il est préférable d'utiliser les feuilles de style pour toute la gestion des effets visuels.
Des objets du menu et leurs états
Le premier des cObject à utiliser pour générer le menu est le HMENU. Cet objet appelle les autres cObjects de menu : TMENU ou GMENU ou GMENU_LAYERS etc. pour chaque niveau de menu que nous voulons afficher (le type d'affichage du niveau dépendant du type de cObject inséré : texte, graphique, menus déroulants ...).
Pour chaque objet du menu (par exemple un TMENU ou un GMENU), vous pouvez définir des propriétés générales affectant le niveau (profondeur) du menu qu'il représente et des propriétés spécifiques en fonction du type d'objet (par exemple la hauteur et la largeur d'un objet GMENU (graphique)). Ces propriétés spécifiques sont toujours définies pour un état donné de l'objet. L'état normal (NO) doit toujours être renseigné, mais il est également possible de renseigner l'état actif de l'objet (ACT), c'est à dire la présentation de cette ligne du menu si nous nous trouvons dans la page correspondante (ou une de ses sous-pages).
Cependant, l'objet de ce tutoriel n'est pas de détailler le cObject HMENU, reportez vous au manuel TypoScript by Example pour cela.
Jetons maintenant un oeil à la maquette de Raphaël :
Comme vous le voyez, il a utilisé un tag <div> pour chaque ligne du menu, indépendamment de son niveau ou de son état. La différence entre ces lignes est faite par la valeur de l'attribut class. Ceci et particulièrement pertinent puisque cela va épargner beaucoup de travail à Benoît pour coder le menu. De plus, le design du menu est géré en dehors de Typo3, dans la feuille de style.
Notez également que Raphaël a fourni une présentation pour les menus "actifs".
L'implémentation des menus sera donc particulièrement facile. On procédera de la manière suivante :
Tout d'abord, définissez un objet temporaire au début du gabarit (avant "temp.mainTemplate") :
# Menu 1 cObject
temp.menu_1 = HMENU
# First level menu-object, textual
temp.menu_1.1 = TMENU
temp.menu_1.1 {# Normal state properties
NO.allWrap = <div class="menu1-level1-no"> | </div>
# Enable active state and set properties:
ACT = 1
ACT.allWrap = <div class="menu1-level1-act"> | </div>
}
# Second level menu-object, textual
temp.menu_1.2 = TMENU
temp.menu_1.2 {# Normal state properties
NO.allWrap = <div class="menu1-level2-no"> | </div>
# Enable active state and set properties:
ACT = 1
ACT.allWrap = <div class="menu1-level2-act"> | </div>
}
Notez les lignes en rouge qui contiennent les marqueurs HTML que Benoît a extrait de la maquette de Raphaël. Maintenant, ces marqueurs sont codés en dur dans le gabarit.
La seule chose que vous devez faire est de copier cet objet afin qu'il soit le cObjet affecté au "menu_1" de "temp.mainTemplate" :
...
# Main TEMPLATE cObject for the BODY
temp.mainTemplate = TEMPLATE
temp.mainTemplate {# Feeding the content from the Auto-parser to the TEMPLATE cObject:
template =< plugin.tx_automaketemplate_pi1
# Select only the content between the <body>-tags
workOnSubpart = DOCUMENT_BODY
# Substitute the ###menu_1### subpart with dynamic menu:
subparts.menu_1 < temp.menu_1
# Substitute the ###content### subpart with some example content:
subparts.content = TEXT
subparts.content.value = HELLO WORLD - CONTENT
...
(La ligne en rouge vous montre le changement !)
... et le résultat qui se passe d'explications:
La structure des pages (voir ci-dessous) est clairement affichée dans le menu ci-dessus !
Mais sera-t-il facile de changer le look du menu me direz vous ? Éditez la feuille de style "fileadmin/template/main/res/stylesheet.css" :
Voyez ! Cette approche du problème vous permet de déporter les principaux facteurs contrôlant l'aspect visuel - maquette HTML et feuille de style – en dehors de Typo3 afin qu'ils soient directement accessibles et modifiables par Raphaël, le designer. Benoît pour sa part n'a eu qu'une charge de travail mineure. Il a seulement paramétré le moteur de front-end afin qu'il prenne en compte le design de Raphaël – juste un peu de TypoScript dans le gabarit.
Veuillez vous référer au manuel TypoScript by Example si vous voulez plus d'informations sur les HMENUs..
La manière la plus simple de gérer les contenu de pages dans Typo3 est de créer des éléments de contenu dans la table tt_content. En fait je ne pense pas que quelqu'un procède autrement car c'est la manière la plus simple, la plus souple et la plus directe à mettre en œuvre. Cependant, cela peut être en contradiction avec vos a priori sur l'encapsulation de contenu structuré au sein des maquettes HTML.
Les éléments de contenu ont plusieurs types prédéfinis (Text, Text w/image, Bulletlist, Table, Login box, etc) et généralement une maquette statique associée à du TypoScript permettant d'effectuer le rendu de ces éléments sans que vous ne vous occupiez de rien. Comme les éléments de contenu ont un type et que chaque type a de nombreuses options, il est impossible de générer ces éléments de contenu avec un systèmes de maquette fixe pour chaque type d'éléments. Cela ne fonctionnerait pas et vous pourrez vous en rendre compte lorsque vous aurez joué un peu avec ce concept. C'est pourquoi des cObjects combinés à des fonctions PHP sont invoquées pour générer le contenu en fonction de conditions complexes.
Alors, comment faire pour créer les contenus sans utiliser de templates HTML ? En fait, en utilisant la dernière technique Typo3 de génération de contenu - l'extension "css_styled_content" – tous vos contenus seront encapsulés dans des éléments HTML. Ceci déportera alors les décisions de design vers les feuilles de style externes !
Regardons comment cela fonctionne en commençant par créer un contenu.
Un élément de contenu
Dans le module Liste, cliquez sur l'icône de la page "licence C", puis "New" et enfin dans la frame de droite, cliquez sur le lien de l'assistant de contenu (Click here for wizard).
Sélectionnez à droite : "Text with image" et tout en bas de la page la colonne "Normal" :
Après avoir saisi votre contenu et l'avoir enregistré, vous devriez obtenir quelque chose comme ceci :
Nous avons maintenant un contenu dans la page "License C":
Inclure la maquette statique
Afin d'afficher cet élément de contenu, il nous faut inclure une maquette statique qui fournira les centaines de lignes de TypoScript qui se chargeront du rendu. Ceci sera fait en éditant le gabarit.
Mais avant toute chose, il faut installer l'extension "css_styled_content":
Dans le module "extension manager" / "Available extensions" , cliquez simplement sur le bouton "Install" de CSS Styled Content et sur le bouton Accept de la page suivante.
(Attention : au moment de l'écriture de ce manuel [mars 2003] le plugin "CSS Styled Content" n'est pas totalement terminé ! Il n'effectue le rendu que des éléments Text, Text w/image, Bullet list et Table ainsi que des "Insert plugins" et éventuellement quelques autres. Désolé ! Ce plugin sera à terme LE moyen de générer le contenu mais actuellement il vous montre simplement la direction que Typo3 prendra. Bien évidemment, le mécénat permettra d'accélérer le développement et / ou de changer les priorités ...)
De retour dans le module Gabariat : cliquez sur ce lien :
Vous devriez voir apparaître dans la boîte "Include Static (from extensions)" le contenu "CSS Styled Content". Cliquez afin de l'ajouter
Cliquez dessus afin de l'ajouter, enregistrez la maquette et allez dans le Template Analyzer:
L'analyseur de gabarit (Template Analyzer) vous montre la hiérarchie des gabarit qui sont rattachés à la maquette principale (main template record). En incluant la maquette statique "CSS Styled Content", celle-ci a été insérée avant le TypoScript contenu dans le gabarit NEWSITE. Cela signifie que les objets définis dans EXT:css_styled_content/..... peuvent être copiés et utilisés dans le gabarit NEWSITE. C'est ce que nous allons faire maintenant car la maquette statique incluse contient l'objet "style.content.get" qui sélectionne tous les éléments de la colonne "Normal" pour la page courante.
Dans le gabarit on changera donc la définition de l'objet "temp.mainTemplate" de la manière suivante :
...
# Main TEMPLATE cObject for the BODY
temp.mainTemplate = TEMPLATE
temp.mainTemplate {# Feeding the content from the Auto-parser to the TEMPLATE cObject:
template =< plugin.tx_automaketemplate_pi1
# Select only the content between the <body>-tags
workOnSubpart = DOCUMENT_BODY
# Substitute the ###menu_1### subpart with dynamic menu:
subparts.menu_1 < temp.menu_1
# Substitute the ###content### subpart with some example content:
subparts.content < styles.content.get
...
Si vous rafraîchissez le frontend pour la page "Licence C" vous devriez obtenir ceci (pensez à vider les caches si cela ne fonctionne pas (en bas du menu gauche dans l'interface d'administration)) :
Dans le source HTML on trouvera ceci :
Apparemment, le titre de l'élément de contenu a été rendu avec des tags <h1>. Si vous sélectionnez d'autres "Layout" pour ce titre, .vous changerez la manière dont il est rendu (par exemple <h2> pour un Layout 2).
Chaque ligne du corps de texte est encapsulée dans des tags <p> avec une classe css "bodytext". De cette manière, nous pouvons changer la présentation de nos contenus directement depuis la feuille de style ! Notons que Raphaël a déjà prévu la chose puisque le contenu d'exemple portait déjà des tags <p class="bodytext"> ...
Chaque élément de contenu inséré portera un tag <a> dont le nom sera l'uid de l'élément. Ceci fournira des points d'ancrage qui pourront être utilisés dans les URLs pour se rendre directement à ce contenu au sein de la page
On trouve également le rendu pour les objets de menu de niveau 2 provenant du HMENU. Notez que le lien pointe automatiquement sur la bonne page et que la gestion d'événement onFocus est même prise en charge.
Et l'arbre des objets Typo ?
En copiant l'élément de contenu virtuel "styles.content.get", qu'avons nous réellement inséré dans l'arborescence des objets Typo ? Examinons cela avec l'Object Browser :
Nous remarquons deux choses intéressantes ;
Le chemin de l'objet "styles.content.get" contient un cObjet du type CONTENT. En examinant ses propriétés, on peut en déduire qu'il sélectionne des enregistrements de la table tt_content en les classant par le contenu du champ sorting. Pour plus d'informations consultez la documentation du cObject CONTENT..
Un nouveau TLO (Top Level Object) a été créé : "tt_content". Par défaut, le cObject CONTENT qui sélectionnera ses enregistrements dans la table tt_content utilisera ce TLO pour le rendu de chaque enregistrement trouvé !Comme nous pouvons le constater, le TLO "tt_content" est défini comme une cObject de type USER invoquant une fonction PHP de l'extension "css_styled_content" – c qui a l'air correct puisque c'est justement l'extension que nous venons d'installer pour prendre en charge cela ! Pour plus de détails consultez la documentation de l'extention "css_styled_content".
Pour les insatiables curieux, nous pouvons examiner la classe "tx_cssstyledcontent_pi1" et décortiquer son fonctionnement (la magie du libre !). Voici un extrait de la fonction main() :
function main($content,$conf){$this->conf = $conf;
// This value is the Content Element Type - determines WHAT kind of element to render...
$CTypeValue = (string)$this->cObj->data["CType"];
$content="";
switch($CTypeValue){case "header":
$content = $this->getHeader().$this->render_subheader();
break;
case "bullets":
$content = $this->getHeader().$this->render_bullets();
break;
case "table":
$content = $this->getHeader().$this->render_table();
break;
case "text":
$content = $this->getHeader().$this->render_text();
break;
case "image":
$content = $this->getHeader().$this->render_image();
break;
case "textpic":
$content = $this->render_textpic();
break;
...
Nous avons maintenant terminé notre site Web. Benoît et Raphaël ont achevé leur travail et Mr Picouto en a profité pour saisir tous les contenus sur l'ensemble des pages du site. Le site web initial et donc en place. Il est basé sur des fichiers en pur HTML dans le répertoire "fileadmin/template/main/" avec un menu et des contenus remplaçant dynamiquement les zones nécessaires.
Une meilleure structure de maquette
La dernière petite chose à faire est de réorganiser le gabarit. Bien que le TypoScript utilisé soit réduit au minimum, nous pouvons constater que ce gabarit devient rapidement énorme et peu pratique. La solution est de créer une série de gabarit à inclure dans le gabarit principal.
Tout d'abord, nous allons créer une nouvelle page à la racine de l'arborescence. Utilisez le type "sysFolder" (ce qui correspond à un espace de stockage) et appelez le Template Storage.
Puis créez trois gabarit comme dans la capture ci-dessous :
Ne cochez aucune case "Clear" ! Copiez simplement les définitions d'objets "temp.xxxx" depuis le gabarit "NEW SITE" dans ces nouveaux gabarit. L'ordre de ces gabarit n'a aucune importance.
L'étape suivante est d'inclure ces trois gabarit dans le gabarit principal ("NEW SITE"). Pour cela éditez le et ajoutez les trois gabarit dans la boîte Include Basis template:
Ici, l'ordre est important : la première des maquettes listée est insérée la première. Comme le gabarit "ext: Main TEMPLATE cObject" effectue des copies par exemple de l'objet "temp.menu_1" il doit être inclus en dernier.
Enregistrez le gabarit et visualisez la nouvelle structure dans l'analyseur de gabarit.
Vous voyez que le gabarit statique (EXT:css_styled_content) a été inclus en premier puis les trois gabarit de notre répertoire de stockage et enfin le gabarit principal. Pour chacun d'eux, vous pouvez cliquer sur le titre et consulter son contenu en bas de page.
Cette section du tutoriel vous a montré qu'il est possible d''intégrer une maquette d'un designer Web d'une manière souple et confortable dans Typo3 en conservant une parfaite compatibilité avec son travail originel (aucun marqueur n'a été inséré manuellement dans la maquette). De plus, ceci ne met en œuvre que des technologies familières (HTML / CSS) - pas de choses complexes comme des feuilles de styles XSLT (bien que qu'un outil de rendu XSLT puisse être développé au niveau PHP par Benoît si tel était le besoin (par exemple pour publier des documents XML provenant de Openoffice.org)).
Cependant, bien que la liberté de Raphaël, le designer, est à peu près totale, il est nécessaire qu'il comprenne les bases des contenus dynamiques et statiques.
Parties dynamiques, parties statiques
Raphaël – et vraisemblablement toute l'équipe web – doit en premier lieu bien comprendre quelles parties des pages sont statiques et quelles parties sont dynamiques. Les parties statiques sont toutes les parties que Typo3 ne touche pas. Les parties dynamiques sont elles remplacée par Typo3 avec le contenu tiré de la base de données.
Lorsque les zones dynamiques sont clairement identifiées, Raphaël doit s'assurer de deux choses :
Cette zone doit être encapsulée dans un seul élément HTML. Ce peut être un élément <div>, <span> ou <td> .
Ce élément d'encapsulation doit avoir un attribut id ou class que le plugin Template AutoParser correctement configuré pourra retrouver et encadre de marqueurs de sous-parties. Par exemple, <td id="content"> pour une cellule qui hébergera le contenu.
Cela , n'a pas d'incidence de laisser le contenu d'exemple dans la maquette puisqu'il sera remplacé par le contenu dynamique.
Simplifiez la marquage, utiliser les feuilles de style
Nous sommes en 2003 (voire plus) et il serait peut-être temps d'abandonner les tags <font>, les attributs bgcolor et de tout mettre dans des feuilles de style externes. Pour un CMS, cette technique sert bien l'objectif de mettre le maximum de choses possibles en externe et n'utiliser que le strict nécessaire de ce qui est spécifique du CMS (comme les gabarit TypoScript).
Dans cette partie du tutoriel, le meilleur exemple est sûrement le menu de niveau 2 :
<!-- Menu table cell: -->
<td id="menu_1">
<div class="menu1-level1-no"><a href="#">Menu item 1</a></div>
<div class="menu1-level1-no"><a href="#">Menu item 2</a></div>
<div class="menu1-level1-act"><a href="#">Menu item 3 (act)</a></div>
<div class="menu1-level2-no"><a href="#">Level 2 item</a></div>
<div class="menu1-level2-no"><a href="#">Level 2 item</a></div>
<div class="menu1-level2-act"><a href="#">Level 2 item (act)</a></div>
<div class="menu1-level1-no"><a href="#">Menu item 2</a></div>
</td>
Regardons juste un de ces éléments (celui en rouge). Il aurait également pu être implémenté de la manière suivante :
<!-- Menu table cell: -->
<td id="menu_1">
<!-- Menu item level 1, begin -->
<table border="0" cellpadding="0" cellspacing="0" width="95%"><tr>
<td bgcolor="#eeeeee"><font face="verdana" size="2">
<a href="#" class="menu1-items">Menu item 1</a>
</font></td>
</tr>
<tr>
<td><img src="gray_dotted_line.gif" width="180" height="1" alt=""/></td>
</tr>
</table>
<!-- Menu item level 1, end -->
...
</td>
Rappelez vous cependant que le TMENU à l'intérieur du gabarit a été défini pour entourer l'élément au moyen d'un <div> :
temp.menu_1.1 {# Normal state properties
NO.allWrap = <div class="menu1-level1-no"> | </div>
...
donc en utilisant cette implémentation, il faudra encadrer les éléments de la manière suivante :
temp.menu_1.1 {# Normal state properties
NO.allWrap ( <table border="0" cellpadding="0" cellspacing="0" width="95%"><tr>
<td bgcolor="#eeeeee"><font face="verdana" size="2">
|
</font></td>
</tr>
<tr>
<td><img src="gray_dotted_line.gif" width="180" height="1" alt=""/></td>
</tr>
</table>
)
...
Ces modifications ne seront cependant pas suffisantes. Il faudra également ajouter la classe correspondant au tag <a> avec une autre propriété de l'état NO et préfixer l'image "gray_dotted_line.gif" avec le chemin correct du fichier – quelque chose comme "fileadmin/template/main".
N'utilisez pas de classe pour les liens dynamiques !
Beaucoup de designers seraient tentés de marquer leurs éléments de menu et les autres liens en utilisant des attributs de classe pour le tag <a>, par exemple :
<!-- Menu table cell: -->
<td id="menu_1">
<div><a href="#" class="menu1-level1-no">Menu item 1</a></div>
...
</td>
Cependant cela ne sera pas le cas car le tag <a> est généré dynamiquement par Typo3. Afin de faire fonctionner le style pour le TMENUITEM, il faudra utiliser une propriété TypoScript supplémentaire :
temp.menu_1.1 {# Normal state properties
NO.allWrap = <div> |</div>
NO.ATagParams = class="menu1-level1-no"
...
Ceci complexifie les propriétés TypoScript et donne moins de flexibilité dans la feuille de style. Par exemple, si vous souhaitez contrôler l'apparence d'un lien par une feuille de style, vous devrez employer dans ce cas :
A.menu1-level1-no { color: navy; }A.menu1-level1-no:hover { color: red; }Mais vous ne pouvez pas contrôler l'encapsulation par l'élément <div> car il n'est pas identifié par un attribut class ou id. Par contre, si vous considérez que le tag <a> ne doit pas avoir d'attribut class comme indiqué précédemment, le tag <div> peut, lui porter un tel attribut. En combinant ces différentes possibilités, vous pouvez contrôler à la fois le bloc <div> ainsi que les liens qu'il contient :
DIV.menu1-level1-no { padding: 2px 2px 2px 2px; }DIV.menu1-level1-no A { color: navy; }DIV.menu1-level1-no A:hover { color: red; }Gardez vous des row/colspans!
C'est sûrement la plus grande fonctionnalité pour le contenu dynamique – l'utilisation de colspan. C'est cependant hors de question. Considérez par exemple l'implémentation suivante du menu :
<tr>
<!-- Menu table cell: -->
<td class="menu1-level1-no"><a href="#">Menu item 1</a></td>
<!-- Page Content Area table cell: -->
<td id="content" rowspan="7">
. . .
</td>
</tr>
<tr>
<td class="menu1-level1-no"><a href="#">Menu item 2</a></td>
</tr>
<tr>
<td class="menu1-level1-act"><a href="#">Menu item 3 (act)</a></td>
</tr>
<tr>
<td class="menu1-level2-no"><a href="#">Level 2 item</a></td>
</tr>
<tr>
<td class="menu1-level2-no"><a href="#">Level 2 item</a></td>
</tr>
<tr>
<td class="menu1-level2-act"><a href="#">Level 2 item (act)</a></td>
</tr>
<tr>
<td class="menu1-level1-no"><a href="#">Menu item 2</a></td>
</tr>
Ceci est impossible à implémenter. Le premier objet est une ligne avec la cellule de contenu. Les 6 autres objets du menu sont dans des lignes séparées du tableau. De plus, la cellule de contenu nécessite un rowspan=7 afin qu'elle s'étende sur toutes les lignes du menu !
C'est très nettement une mauvaise conception d'un point de vue technique :
les marqueurs du menu sont dispersés au sein du code HTML.
Il existe une dépendance entre l'attribut rowspan et le nombre de lignes du menu (qui est dynamique !).
Par conséquent, les designers devraient s'abstenir de telles constructions. Raphaël et ses confrères devraient plutôt concevoir ces marqueurs pour les éléments dynamiques afin qu'il soient facilement répétables. Voici quelques exemples :
Celui de notre maquette :
<!-- Menu table cell: -->
<td id="menu_1">
<div class="menu1-level1-no"><a href="#">Menu item 1</a></div>
<div class="menu1-level1-no"><a href="#">Menu item 2</a></div>
<div class="menu1-level1-act"><a href="#">Menu item 3 (act)</a></div>
...
</td>
Une autre construction employant des tableaux :
<!-- Menu table cell: -->
<td id="menu_1">
<table border="0" cellspacing="0" cellpadding="0">
<tr><td class="menu1-level1-no"><a href="#">Menu item 1</a></td></tr>
<tr><td class="menu1-level1-no"><a href="#">Menu item 2</a></td></tr>
<tr><td class="menu1-level1-act"><a href="#">Menu item 3 (act)</a></td></tr>
...
</table>
</td>
Ces exemples peuvent être encore plus complexes à l'image du précédent qui incluait chaque élément du menu dans un tableau. L'important n'est cependant pas la quantité de HTML impliqué, mais la nature répétitive du marqueur pour mettre en oeuvre les éléments dynamiques.
Il est important que Raphaël (et l'ensemble des designers) comprennent bien ces problèmes afin que Benoît ne passe pas des heures à tenter de faire fonctionner une maquette inadéquate – incidemment, Mr Picouto pourrait être tellement content de l'achèvement rapide du site grâce aux efforts de Raphaël et Benoît qu'il pourrait bien les inviter à déjeuner !