Brilliancy of quality
Documentazione

Sintassi pratica di Mirage Templates per gestire il layout

Sapphire I.C.D.S.

Confine del livello template

Mirage è destinato alla rappresentazione HTML e testuale. Permette di riordinare sezioni, modificare schede e intestazioni, aggiungere contenitori decorativi, gestire classi e mostrare elenchi preparati ed etichette localizzate. Un template non deve eseguire SQL, determinare i diritti, modificare dati o sostituire il controllo della route eseguito dal modulo. Se un campo necessario non è presente nel contesto di input, non può essere creato in modo affidabile modificando solamente il layout.

I template pubblici si trovano in skins/<Layout>/<Skin>/<Module>/, quelli amministrativi in adminskins/... e quelli di moderazione in moderatorskins/.... Prima di una modifica, determinate Layout e Skin attivi. Lo stesso nome di file può comparire in più alberi e la modifica di una copia inattiva non cambierà la pagina.

Output con escape

La forma di output principale e sicura usa doppie parentesi graffe:

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

Il testo viene sottoposto a escape per HTML, quindi i caratteri provenienti dai dati non si trasformano in tag o attributi. Usate questa forma per titoli, nomi, URL negli attributi, etichette, stringhe di ricerca e qualsiasi valore che potrebbe essere stato inserito da un utente.

L'output raw è indicato da un punto esclamativo:

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

È consentito solo per una fonte già responsabile di produrre HTML sicuro, ad esempio un elemento costruito da Former, una zona Echelon o JSON-LD serializzato in precedenza. Non sostituite l'output normale con raw per far «funzionare un tag» proveniente da un campo utente. Questo trasforma i dati in markup attivo.

Tabelle con nome di Context

Per i nuovi template usate Context.Table. Una pagina può ricevere le tabelle meta, page, assets e tabelle dei moduli con prefisso __. Le chiamate principali sono:

  • Context.HasTable("items"): verifica la presenza di una tabella;
  • Context.Table("items").Data("title"): legge un campo della riga corrente;
  • RowCount(): restituisce il numero di righe;
  • Rewind(): riporta il cursore all'inizio;
  • NextRow(): passa alla riga successiva.

La sintassi compatibile Table.Data(...) resta nei vecchi template con una sola tabella, ma non deve essere mescolata senza motivo con il contesto con nome.

Condizioni, valori e commenti

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

I flag arrivano spesso come stringhe "1" e "0", quindi confrontateli esplicitamente. Per una variabile temporanea si usa {% set name = value %}, mentre un commento si scrive come {# spiegazione #} e non viene incluso nell'HTML.

Per un valore di fallback sono disponibili due forme:

{{ Context.Table("meta").Data("title") ?? "Senza titolo" }}
{{ Boardwords("catalog_title") | default("Catalogo") }}

L'espressione ternaria è comoda per un breve valore di classe, ma per i blocchi grandi è preferibile un normale if:

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

Ciclo sicuro sulle righe

Una tabella con nome non viene trasformata automaticamente in un array di oggetti. Usate lo schema completo basato sul cursore:

{% 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("Non c'è ancora nulla") }}</p>
{% endif %}

L'ordine è obbligatorio: controllare le righe, eseguire Rewind(), percorrere l'intervallo e chiamare NextRow() prima di leggere Data(). Nel ciclo sono disponibili loop.index, loop.first, loop.last, loop.odd e loop.even.

Localizzazione, moduli e zone

Mostrate le etichette statiche per l'utente tramite Boardwords con un fallback comprensibile. In questo modo restano traducibili quando si copia il design tra skin trees. Se un campo del modulo arriva come *_ir, non costruite manualmente l'input:

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

Mirage gestisce il contenitore, la griglia e la classe, mentre Former gestisce il controllo HTML. Anche il contenuto di una Echelon Zone viene mostrato come raw solo perché la zona produce un frammento affidabile; un campo arbitrario di una tabella non ha tale status.

Verifica della modifica

  1. Apportate una modifica circoscritta al template attivo, senza copiare l'intero shell.
  2. Verificate la pagina con dati, con un elenco vuoto e senza i campi facoltativi.
  3. Verificate i caratteri speciali nel testo e negli attributi.
  4. Verificate tutte le lingue disponibili e il fallback Boardwords.
  5. Verificate desktop e mobile e, per un modulo amministrativo, gli errori di convalida.
  6. Assicuratevi che raw sia usato solo per produttori di HTML affidabili.

Se il template richiede nuovi diritti, SQL o una regola di business, fermatevi: l'attività è uscita dal confine di Mirage. Un'estensione corretta prepara prima i dati nel modulo e mantiene il template come livello di presentazione prevedibile.

Composizione della pagina e frammenti dinamici

Modificate separatamente lo shell comune, il menu e il contenuto del modulo applicativo. Non spostate l'intera struttura nel template di una singola scheda: crea duplicazione e compromette il cambio di skin. Per un frammento aggiornato da un filtro, un pager o una scheda, usate il perimetro AJAX adottato con Mirage. Mantenete il testo pubblico canonico, importante per la prima visualizzazione e la SEO, nel normale rendering della pagina.

Se il template usa un namespace aggiuntivo proveniente da un pacchetto di callback, ad esempio per formattare una data, assicuratevi che il pacchetto sia presente nel runtime di destinazione. Tale callback è una dipendenza del template specifico. Prevedete un fallback comprensibile quando il design lo consente e non tentate di imitare un callback assente con espressioni di stringa complesse.

Pratica di una review sicura

Confrontate l'HTML finale prima e dopo la modifica, non solo il sorgente .mirage. Controllate il bilanciamento dei tag, l'unicità degli id, l'accessibilità dei label, la validità dei link e l'assenza di elementi interattivi annidati. Per gli elenchi, provate una riga e più righe: gli errori del cursore spesso non sono visibili con un'unica registrazione. Quando trasferite un template tra skin trees, verificate di nuovo i nomi delle tabelle e dei campi, poiché moduli visivamente simili non ricevono necessariamente lo stesso contesto.