Brilliancy of quality
Documentation

Syntaxe pratique de Mirage Templates pour gérer la mise en page

Sapphire I.C.D.S.

Limite de la couche de modèles

Mirage est destiné à la représentation HTML et textuelle. Il permet de réorganiser des sections, modifier des cartes et des titres, ajouter des conteneurs décoratifs, gérer des classes et afficher des listes préparées et des libellés localisés. Un modèle ne doit pas exécuter de SQL, déterminer les droits, modifier les données ou remplacer la vérification de route du module. Si un champ requis n'existe pas dans le contexte d'entrée, une simple modification de la mise en page ne permet pas de le créer de manière fiable.

Les modèles publics se trouvent dans skins/<Layout>/<Skin>/<Module>/, les modèles administratifs dans adminskins/... et les modèles de modération dans moderatorskins/.... Avant toute modification, déterminez les Layout et Skin actifs. Un même nom de fichier peut apparaître dans plusieurs arborescences, et modifier une copie inactive ne changera pas la page.

Affichage échappé

La forme d'affichage principale et sûre utilise des doubles accolades :

<h1>{{ Context.Table("page").Data("title") }}</h1>
<p>{{ Context.Table("page").Data("summary") }}</p>

Le texte est échappé pour le HTML, de sorte que les caractères provenant des données ne deviennent ni des balises ni des attributs. Utilisez cette forme pour les titres, les noms, les URL dans les attributs, les libellés, les chaînes de recherche et toute valeur qu'un utilisateur a pu saisir.

L'affichage raw est indiqué par un point d'exclamation :

{{! Former.BuildHTML(Context.Table("form").Data("submit_ir")) }}

Il n'est acceptable que pour une source déjà responsable de la production d'un HTML sûr, telle qu'un élément construit par Former, une zone Echelon ou un JSON-LD préalablement sérialisé. Ne remplacez pas l'affichage ordinaire par raw afin de faire « fonctionner une balise » issue d'un champ utilisateur. Cela transforme les données en balisage actif.

Tables nommées de Context

Utilisez Context.Table pour les nouveaux modèles. Une page peut recevoir les tables meta, page, assets et des tables de modules préfixées par __. Les principaux appels sont :

  • Context.HasTable("items") : vérifier la présence d'une table ;
  • Context.Table("items").Data("title") : lire un champ de la ligne actuelle ;
  • RowCount() : obtenir le nombre de lignes ;
  • Rewind() : ramener le curseur au début ;
  • NextRow() : passer à la ligne suivante.

La syntaxe compatible Table.Data(...) demeure dans les anciens modèles à table unique, mais elle ne doit pas être mélangée sans raison avec le contexte nommé.

Conditions, valeurs et commentaires

{% if Context.Table("page").Data("status") == "published" %}
  <span class="badge badge--live">{{ Boardwords("status_published") | default("Publié") }}</span>
{% elif Context.Table("page").Data("status") == "draft" %}
  <span class="badge badge--draft">{{ Boardwords("status_draft") | default("Brouillon") }}</span>
{% else %}
  <span class="badge">{{ Boardwords("status_unknown") | default("Inconnu") }}</span>
{% endif %}

Les indicateurs sont souvent transmis sous forme de chaînes "1" et "0" ; comparez-les donc explicitement. Une variable temporaire s'écrit {% set name = value %}, tandis qu'un commentaire prend la forme {# explication #} et ne figure pas dans le HTML.

Deux formes permettent de fournir une valeur de repli :

{{ Context.Table("meta").Data("title") ?? "Sans titre" }}
{{ Boardwords("catalog_title") | default("Catalogue") }}

L'expression ternaire convient à une courte valeur de classe, mais il est préférable d'écrire les grands blocs avec un if ordinaire :

{{ Context.Table("page").Data("compact") == "1" ? "card--compact" : "card--wide" }}

Boucle sûre sur les lignes

Une table nommée ne se transforme pas automatiquement en tableau d'objets. Utilisez le schéma complet avec curseur :

{% if Context.Table("products").RowCount() > 0 %}
  {% set __ = Context.Table("products").Rewind() %}
  <div class="product-grid">
    {% for _ in range(0, Context.Table("products").RowCount(), 1) %}
      {% if Context.Table("products").NextRow() %}
        <article class="product-card{% if loop.even %} product-card--even{% endif %}">
          <h3>{{ Context.Table("products").Data("title") }}</h3>
          <p>{{ Context.Table("products").Data("summary") }}</p>
        </article>
      {% endif %}
    {% endfor %}
  </div>
{% else %}
  <p>{{ Boardwords("products_empty") | default("Il n'y a encore rien") }}</p>
{% endif %}

L'ordre est obligatoire : vérifier les lignes, exécuter Rewind(), parcourir l'intervalle et appeler NextRow() avant de lire Data(). La boucle donne accès à loop.index, loop.first, loop.last, loop.odd et loop.even.

Localisation, formulaires et zones

Affichez les libellés utilisateur statiques via Boardwords avec un fallback compréhensible. Ils restent ainsi traduisibles lorsque le design est copié entre plusieurs skin trees. Si un champ de formulaire arrive sous la forme *_ir, ne construisez pas l'input manuellement :

<label>{{ Boardwords("profile_name") | default("Nom du profil") }}</label>
{{! Former.BuildHTML(Context.Table("profile").Data("name_ir"), "class", "profile-form__input") }}

Mirage gère le conteneur, la grille et la classe, tandis que Former gère le contrôle HTML. Le contenu d'une Echelon Zone est lui aussi affiché en raw uniquement parce que la zone produit un fragment de confiance ; un champ de table arbitraire ne bénéficie pas de ce statut.

Vérification de la modification

  1. Apportez une modification ciblée au modèle actif sans copier l'intégralité du shell.
  2. Vérifiez la page avec des données, une liste vide et des champs facultatifs absents.
  3. Vérifiez les caractères spéciaux dans le texte et les attributs.
  4. Vérifiez toutes les langues disponibles et le fallback Boardwords.
  5. Vérifiez desktop et mobile et, pour un formulaire administratif, les erreurs de validation.
  6. Assurez-vous que raw est réservé aux producteurs de HTML de confiance.

Si le modèle requiert de nouveaux droits, du SQL ou une règle métier, arrêtez-vous : la tâche dépasse la limite de Mirage. Une extension correcte prépare d'abord les données dans le module et conserve le modèle comme couche de présentation prévisible.

Composition de la page et fragments dynamiques

Modifiez séparément le shell commun, le menu et le contenu du module applicatif. Ne transférez pas toute l'ossature dans le modèle d'une seule carte : cela crée des doublons et compromet le changement de skin. Pour un fragment mis à jour par un filtre, un pager ou un onglet, utilisez le périmètre AJAX établi avec Mirage. Conservez le texte public canonique, important pour le premier affichage et le SEO, dans le rendu normal de la page.

Si le modèle utilise un namespace supplémentaire provenant d'un paquet de callbacks, par exemple pour formater une date, assurez-vous que ce paquet est présent dans le runtime cible. Ce callback est une dépendance du modèle concerné. Prévoyez un fallback compréhensible lorsque le design le permet et n'essayez pas d'imiter un callback absent au moyen d'expressions de chaîne complexes.

Pratique d'une review sûre

Comparez le HTML final avant et après la modification, et pas seulement le fichier source .mirage. Vérifiez l'équilibre des balises, l'unicité des id, l'accessibilité des label, la validité des liens et l'absence d'éléments interactifs imbriqués. Testez une ligne puis plusieurs dans les listes : les erreurs de curseur sont souvent invisibles sur un seul enregistrement. Lors du transfert d'un modèle entre des skin trees, revérifiez les noms des tables et des champs, car des modules visuellement semblables ne reçoivent pas nécessairement le même contexte.