Sintassi dei Template Facet

Sintassi dei Template Facet

Facet è il linguaggio di template usato da FaceFlow per il rendering dinamico.

Usa questa pagina come guida sintattica principale. Copre i pattern di cui gli utenti tecnici hanno effettivamente bisogno quando scrivono template di Component, template di Variable, output di elementi di lista e altri frammenti di runtime all'interno di FaceFlow.

Questa pagina è intenzionalmente dettagliata. Non è solo una guida rapida. È il documento sintattico principale per la redazione ufficiale dei template FaceFlow.

Famiglie di Sintassi

I template Facet solitamente combinano cinque famiglie di sintassi:

SintassiRuoloUso Tipico
{field}Output del campo del componenteoutput diretto da un campo del componente
{{ expr }}output di espressione escapatodati della pagina, oggetti di contesto, filtri
{{{ expr }}}output grezzocontenuti ricchi fidati e markup controllato
{{#block}}...{{/block}}controllo di flussocondizioni, loop, query di pagina, output differito
[[variable-name]]incorporamento di frammenti riutilizzabiliframmenti di template condivisi con attributi opzionali

La fonte più comune di confusione è mescolare la forma abbreviata dei campi del Component con le espressioni generali di Facet. Mantieni chiaro questo confine:

  • usa {field} quando il contratto del campo del componente proprietario supporta l'output diretto del campo o helper di campo
  • usa {{ ... }} quando si rende espressioni generali sensibili al contesto
  • usa [[variable-name]] quando la soluzione corretta è il riuso, non più logica di template

Avvio Rapido

Il modello mentale minimo utile di Facet è:

<section class="hero">
  <h1>{{ page.title }}</h1>

  {{#if summary}}
    <p>{{ summary }}</p>
  {{/if}}

  [[sales-contact-badge]]
</section>

Questo singolo esempio mostra già i tre blocchi costitutivi più importanti:

  • output di valore
  • struttura condizionale
  • composizione di frammenti riutilizzabili

Sintassi di Output

Output dei Campi del Componente

Nei template dei componenti, l'output diretto dei campi spesso usa la sintassi a parentesi graffe singole:

<h2>{title}</h2>
<p>{summary}</p>

Usa questo quando il contratto del campo del componente è semplice e orientato al campo.

Per i campi che supportano helper, la stessa famiglia si estende nella sintassi degli helper:

<img src="{heroImage.webp}" alt="{heroImage.description}">
<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>

Non presumere che ogni campo supporti il concatenamento di helper. Controlla prima la documentazione del campo proprietario.

Output di Espressioni Escapate

Usa le doppie parentesi graffe per l'output escapato normale:

<h1>{{ page.title }}</h1>
<p>{{ summary | default("No summary available.") }}</p>

Questa è la scelta predefinita per testo semplice, etichette, URL, valori scalari dinamici e tutti i casi in cui l'HTML deve essere escapato.

Output Grezzo

Usa le triple parentesi graffe quando la fonte è fidata e deve essere renderizzata come HTML:

<div class="prose">
  {{{ body }}}
</div>

Questo è appropriato per:

  • testo ricco gestito
  • frammenti HTML controllati
  • contenuti editoriali fidati

Non usare l'output grezzo per stringhe arbitrarie non fidate.

Commenti

Facet supporta commenti brevi e lunghi:

{{! short comment }}

{{!--
long comment
spanning multiple lines
--}}

I commenti non vengono mai renderizzati nell'output.

Sintassi delle Espressioni

Le espressioni sono la base dell'output dinamico del template. Permettono di accedere a proprietà annidate, chiamare trasformazioni in stile metodo, applicare filtri e usare logica condizionale inline.

Notazione a Punto

Accedi alle proprietà annidate con la notazione a punto:

{{ page.title }}
{{ page.parent.title }}
{{ page.parent.parent.name }}
{{ user.language.title }}

La notazione freccia è accettata anche nei punti in cui gli autori scrivono naturalmente l'accesso agli oggetti:

{{ page->parent->title }}
{{#if page->parent->hasChildren}}
  ...
{{/if}}
{{#each page->children as="child"}}
  ...
{{/each}}

Usa lo stile che è più chiaro all'interno del template corrente, ma mantieni coerenza all'interno di un file.

Chiamate in Stile Metodo

Alcuni oggetti espongono trasformazioni o lookup in stile metodo:

{{ page.image.width(800) }}
{{ page.image.size(600, 400) }}
{{ page.image.size(600, 400).webp.url }}

Queste sono comuni per:

  • immagini
  • collezioni
  • URL localizzati per pagina
  • helper di query sensibili alla pagina

Le chiamate in stile metodo fanno parte del modello oggetto di Facet, non sono esecuzione arbitraria di codice a runtime.

Parametri Chiave-Valore

Alcuni helper accettano parametri nominati:

{{ page.field name="summary" }}
{{ page.children selector="limit=5" }}
{{ pages.count selector="template=blog-post" }}

Usa i parametri nominati quando il contratto dell'helper li prevede esplicitamente. Questo mantiene i template leggibili ed evita di sovraccaricare gli argomenti posizionali.

Espressioni Ternarie

Facet supporta la logica ternaria per l'output:

{{ user.isLoggedin ? "Welcome back!" : "Please sign in." }}
{{ page.summary ? page.summary : "No summary provided." }}

Usa le ternarie per decisioni di output brevi. Se il branching diventa strutturale, preferisci un helper a blocchi come {{#if}}.

Catene di Filtri

Usa l'operatore pipe per trasformare i valori:

{{ page.title | upper }}
{{ page.body | striptags | truncate(200, "...") }}
{{ published | date("F j, Y") }}
{{ price | currency("$", 2) }}

I filtri si concatenano da sinistra a destra.

Stili di Argomenti dei Filtri

Facet accetta sia lo stile con parentesi sia lo stile con i due punti per gli argomenti:

{{ page.title | truncate(100, "...") }}
{{ page.title | truncate:100:... }}

Entrambe le forme sono supportate. Preferisci lo stile con parentesi nei template ufficiali perché è più chiaro e più facile da revisionare.

Helper a Blocchi

Gli helper a blocchi forniscono struttura, non solo output scalare.

Facet supporta questi tipi di blocchi core:

BloccoScopo
{{#if}}rendering condizionale
{{#each}}loop su array o collezioni esistenti
{{#pages}}interrogare un insieme di pagine
{{#page}}interrogare una pagina
{{#languages}}iterare le lingue disponibili
{{#deferred}}rendering differito compatibile con la cache

{{#if}}

Usa {{#if}} per il rendering condizionale:

{{#if summary}}
  <p>{{ summary }}</p>
{{/if}}

Con else:

{{#if user.isLoggedin}}
  <p>Hello, {{ user.name }}.</p>
{{else}}
  <p>Please sign in.</p>
{{/if}}

Con elseif:

{{#if page.template == "blog-post"}}
  <span class="badge">Blog</span>
{{elseif page.template == "case-study"}}
  <span class="badge">Case Study</span>
{{else}}
  <span class="badge">Page</span>
{{/if}}

È accettata anche la variante else if:

{{#if page.numChildren > 10}}
  <p>Many children</p>
{{else if page.numChildren > 0}}
  <p>Some children</p>
{{else}}
  <p>No children</p>
{{/if}}

Operatori di Confronto

OperatoreSignificatoEsempio
==ugualepage.template == "blog-post"
!=diversopage.status != 1
>maggiore dipage.numChildren > 5
<minore dipage.numChildren < 3
>=maggiore o ugualepage.sort >= 0
<=minore o ugualepage.sort <= 10

Operatori Logici

OperatoreSignificatoEsempio
&&ANDuser.isLoggedin && user.isSuperuser
||ORpage.template == "blog-post" || page.template == "news"
!NOT!user.isGuest

Regole di Truthiness

La truthiness in Facet segue un modello pratico orientato ai template:

ValoreTruthy?
nullfalsy
falsefalsy
""falsy
0falsy
"0"falsy
array vuoto o collezione vuotafalsy
tutto il restotruthy

Se la logica della condizione inizia a contenere regole di business invece di semplici regole di visualizzazione, torna al modello oggetto. Non nascondere un design di contenuto debole dietro blocchi if annidati.

{{#each}}

Usa {{#each}} quando la collezione esiste già nel contesto corrente:

{{#each page.children as="child"}}
  <a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}

Con la forma abbreviata this:

{{#each page.images}}
  <img src="{{ this.url }}" alt="{{ this.description }}">
{{/each}}

Con else:

{{#each page.children as="child"}}
  <div>{{ child.title }}</div>
{{else}}
  <p>No child pages found.</p>
{{/each}}

Variabili di Contesto del Loop

All'interno dei blocchi di loop, questi valori sono disponibili:

VariabileDescrizione
loop.indexindice a base zero
loop.index1indice a base uno
loop.firsttrue alla prima iterazione
loop.lasttrue all'ultima iterazione
loop.lengthconteggio totale degli elementi
loop.eventrue sugli indici pari
loop.oddtrue sugli indici dispari
@indexalias shorthand di loop.index

Esempio:

{{#each page.children as="child"}}
  <div class="{{#if loop.odd}}row-alt{{/if}}">
    <span>{{ loop.index1 }}.</span>
    {{ child.title }}
  </div>
{{/each}}

this vs alias nominati

All'interno di {{#each}}, this punta sempre all'elemento corrente.

{{#each page.children}}
  <a href="{{ this.url }}">{{ this.title }}</a>
{{/each}}

Se la leggibilità è importante, preferisci un alias esplicito:

{{#each page.children as="child"}}
  <a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}

{{#pages}}

Usa {{#pages}} quando il template deve interrogare contenuti invece di renderizzare una collezione già presente nello scope.

{{#pages selector="template=blog-post, sort=-created, limit=5" as="post"}}
  <article>
    <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
    <time>{{ post.created | date("F j, Y") }}</time>
    <p>{{ post.summary | truncate(200) }}</p>
  </article>
{{else}}
  <p>No posts found.</p>
{{/pages}}

Parametri tipici:

ParametroDescrizione
selectorstringa selector della query
asnome della variabile di loop

Usa {{#pages}} per:

  • archivi
  • pagine di elenco
  • widget di contenuti recenti
  • collezioni di navigazione
  • blocchi di contenuto guidati da query

Usa {{#each}} quando la collezione esiste già. Usa {{#pages}} quando il template deve recuperarla.

{{#page}}

Usa {{#page}} quando deve essere interrogata una sola pagina:

{{#page path="/about/"}}
  <a href="{{ page.url }}">{{ page.title }}</a>
{{/page}}

I pattern di lookup supportati includono:

{{#page id="1024"}}...{{/page}}
{{#page path="/about/"}}...{{/page}}
{{#page name="contact"}}...{{/page}}
{{#page selector="template=homepage"}}...{{/page}}

All'interno di un blocco {{#page}}, page si riferisce alla pagina interrogata per la durata di quel blocco.

{{#languages}}

Usa {{#languages}} per costruire interfacce consapevoli della lingua come i selettori di lingua:

<nav class="lang-switch">
  {{#languages as="lang"}}
    <a href="{{ lang.url }}" {{#if lang.isCurrent}}class="active"{{/if}}>
      {{ lang.title }}
    </a>
  {{/languages}}
</nav>

Con un fallback vuoto:

{{#languages as="lang"}}
  <a href="{{ lang.url }}">{{ lang.title }}</a>
{{else}}
  {{! single-language site }}
{{/languages}}

Proprietà utili delle lingue includono:

  • lang.id
  • lang.name
  • lang.title
  • lang.isDefault
  • lang.isCurrent
  • lang.url
  • lang.httpUrl
  • lang.locale

{{#deferred}}

Usa {{#deferred}} quando la pagina è pesantemente cacheable ma una parte del contenuto dipende da dati runtime per utente o che cambiano rapidamente.

{{#deferred}}
  <span>Welcome, {{ user.name }}!</span>
{{/deferred}}

Con sizing scheletro personalizzato:

{{#deferred skeleton-width="12rem" skeleton-height="2em"}}
  <div class="user-panel">
    <span>{{ user.displayName }}</span>
  </div>
{{/deferred}}

Usalo per:

  • saluti personalizzati per l'utente
  • pannelli account
  • personalizzazione sicura per la cache
  • altri contenuti che non dovrebbero essere fissati in una risposta HTML della pagina completamente cacheata

deferred dovrebbe essere usato intenzionalmente. Non avvolgere tutto il contenuto dinamico per default.

Oggetti di Contesto

Facet espone un insieme di oggetti di contesto di livello root in ogni superficie di rendering supportata.

Gli oggetti comuni includono:

  • page
  • pages
  • user
  • languages / lang
  • site
  • now
  • attr
  • loop
  • this

Nei template dei componenti, i valori dei campi del componente sono esposti anch'essi a livello root:

<h1>{{ title }}</h1>

{{#if showGallery}}
  <div class="gallery">
    {{#each images as="img"}}
      <img src="{{ img.url }}">
    {{/each}}
  </div>
{{/if}}

Il riferimento approfondito agli oggetti è documentato in:

Confine di Output delle Immagini

La sintassi delle immagini dipende da dove proviene l'oggetto immagine.

Sintassi helper del campo image del componente

<img src="{heroImage.width(1200).webp}" alt="{heroImage.description}">

Sintassi dell'oggetto immagine della pagina o della query

{{#each page.images as="img"}}
  <img src="{{ img.width(800).webp.url }}" alt="{{ img.description }}">
{{/each}}

Sintassi del loop del campo images del componente

{{#each gallery}}
  <img src="{{this.width(1200).webp}}" alt="{{this.description}}">
{{/each}}

Non mescolare queste forme a casaccio. Il campo proprietario o l'oggetto a runtime decide quale sintassi sia corretta.

Output Helper per le Mappe

I campi in stile mappa possono esporre output orientato agli helper:

{officeLocation}
{officeLocation.width(600)}
{officeLocation.height(400)}
{officeLocation.size(800,500)}

Usalo solo quando il contratto del campo lo documenta esplicitamente.

Incorporamento di Variable

Le Variable si incorporano con la sintassi a doppie parentesi quadre:

[[site-announcement]]
[[cta-badge label="New" tone="accent"]]

All'interno del template della Variable, i valori passati sono disponibili tramite attr.

Le Variable servono per frammenti riutilizzabili, non per sostituire un corretto design dell'oggetto. Se il frammento cresce fino a diventare un contratto di sezione, torna al design del componente.

Marcatori di Embed Gestiti

Form e Review vengono tipicamente renderizzati tramite marcatori di embed gestiti.

Embed a modello fisso:

<div data-form-embed="enterprise-demo-request"></div>
<div data-review-embed="customer-success-reviews"></div>

Embed basato su campo all'interno di un Component riutilizzabile:

<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>

Regola decisionale:

  • embed fisso quando il template possiede un workflow gestito stabile
  • embed basato su campo quando gli autori devono scegliere il modello gestito al momento della redazione

Linee Guida d'Uso

  • mantieni la logica del template leggibile
  • preferisci contratti di campo forti rispetto a trucchi di template complicati
  • usa {{#if}} per la struttura, non per nascondere un design di contenuto debole
  • usa {{#each}} quando la collezione esiste già
  • usa {{#pages}} quando il template deve interrogare la collezione
  • usa le Variable per piccoli frammenti riutilizzabili
  • torna al design di Component o List quando la logica del template diventa troppo complessa

Errori Comuni

Evita questi pattern:

  • usare l'output grezzo dove l'output escapato è più sicuro
  • mescolare la forma abbreviata dei campi del componente e le espressioni generiche di Facet senza capirne la differenza
  • risolvere un problema di modello di contenuto solo con condizionali
  • costruire un unico template gigante annidato invece di chiarire i confini degli oggetti
  • ripetere lo stesso frammento in più template invece di estrarre una Variable
  • usare la sintassi helper del campo su campi che non la supportano

Guida Rapida alle Decisioni

need to show one value                 -> {field} or {{ expr }}
need trusted HTML output               -> {{{ expr }}}
need to show content conditionally     -> {{#if}}
need to loop existing items            -> {{#each}}
need to query content                  -> {{#pages}} or {{#page}}
need language-aware navigation         -> {{#languages}}
need cache-safe dynamic personalization -> {{#deferred}}
need one reusable fragment             -> [[variable-name]]
need a field-specific helper output    -> {field.helper}
need a full reusable section contract  -> return to Component design

Continua