Brilliancy of quality
Dokumentacja

Praktyczna składnia Mirage Templates do sterowania układem

Sapphire I.C.D.S.

Granica warstwy szablonów

Mirage służy do prezentacji HTML i tekstu. Pozwala przestawiać sekcje, zmieniać karty i nagłówki, dodawać kontenery dekoracyjne, sterować klasami oraz wyświetlać przygotowane listy i zlokalizowane etykiety. Szablon nie powinien wykonywać SQL, ustalać uprawnień, modyfikować danych ani zastępować modułowej weryfikacji trasy. Jeżeli potrzebnego pola nie ma w kontekście wejściowym, sama zmiana układu nie utworzy go w wiarygodny sposób.

Szablony publiczne znajdują się w skins/<Layout>/<Skin>/<Module>/, administracyjne w adminskins/..., a moderatorskie w moderatorskins/.... Przed edycją ustal aktywne Layout i Skin. Ta sama nazwa pliku może występować w kilku drzewach, a zmiana nieaktywnej kopii nie wpłynie na stronę.

Wyjście z escapingiem

Podstawowa i najbezpieczniejsza forma wyjścia używa podwójnych nawiasów klamrowych:

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

Tekst jest escapowany dla HTML, dlatego znaki z danych nie stają się tagami ani atrybutami. Stosuj tę formę dla tytułów, nazw, URL w atrybutach, etykiet, tekstów wyszukiwania i każdej wartości, którą mógł wprowadzić użytkownik.

Surowe wyjście oznacza się wykrzyknikiem:

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

Używaj go wyłącznie dla źródła, które już odpowiada za bezpieczny kontrakt HTML, takiego jak kontrolka wygenerowana przez Former, strefa Echelon lub wcześniej zserializowany JSON-LD. Nie przełączaj zwykłego wyjścia na raw tylko po to, by zadziałał tag zapisany w polu użytkownika. Zamieniłoby to dane w aktywny markup.

Nazwane tabele Context

W nowych szablonach używaj Context.Table. Jedna strona może otrzymywać tabele meta, page, assets oraz tabele modułu z prefiksem __. Główne wywołania to:

  • Context.HasTable("items") sprawdza obecność tabeli;
  • Context.Table("items").Data("title") odczytuje pole bieżącego wiersza;
  • RowCount() zwraca liczbę wierszy;
  • Rewind() resetuje kursor;
  • NextRow() przechodzi do następnego wiersza.

Zgodna składnia Table.Data(...) pozostaje w starszych szablonach z jedną tabelą, lecz nie należy mieszać jej z nazwanym kontekstem bez wyraźnej przyczyny.

Warunki, wartości i komentarze

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

Flagi często przychodzą jako ciągi "1" i "0", dlatego porównuj je jawnie. Zmienną ustawia się przez {% set name = value %}. Komentarz ma postać {# komentarz #} i nie trafia do HTML.

Dla wartości zastępczych dostępne są dwie formy:

{{ Context.Table("meta").Data("title") ?? "Bez tytułu" }}
{{ Boardwords("catalog_title") | default("Katalog") }}

Wyrażenie trójargumentowe jest wygodne dla krótkiej wartości klasy; większe bloki zapisuj zwykłym if:

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

Bezpieczna pętla po wierszach

Nazwana tabela nie zmienia się automatycznie w tablicę obiektów wierszy. Używaj pełnego wzorca kursora:

{% 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("Na razie brak danych") }}</p>
{% endif %}

Kolejność jest obowiązkowa: sprawdź wiersze, wykonaj Rewind(), przejdź zakres i wywołaj NextRow() przed odczytem Data(). W pętli dostępne są loop.index, loop.first, loop.last, loop.odd i loop.even.

Lokalizacja, formularze i strefy

Statyczne etykiety użytkownika wyświetlaj przez Boardwords z czytelnym fallback. Zachowuje to możliwość tłumaczenia po skopiowaniu projektu między drzewami skin. Jeżeli pole formularza przychodzi jako *_ir, nie buduj input ręcznie:

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

Mirage steruje kontenerem, siatką i klasą, natomiast Former odpowiada za kontrolkę HTML. Treść Echelon Zone jest również wyświetlana jako raw wyłącznie dlatego, że strefa jest zaufanym producentem fragmentu; dowolne pole tabeli nie ma takiego statusu.

Weryfikacja zmiany

  1. Wprowadź wąską zmianę w aktywnym szablonie bez kopiowania całego shell.
  2. Sprawdź stronę z danymi, pustą listą i brakującymi polami opcjonalnymi.
  3. Przetestuj znaki specjalne w tekście i atrybutach.
  4. Sprawdź wszystkie dostępne języki i fallback Boardwords.
  5. Przetestuj desktop i mobile, a dla formularza administracyjnego także błędy walidacji.
  6. Upewnij się, że raw jest używany tylko dla zaufanych producentów HTML.

Jeżeli szablon wymaga nowego uprawnienia, SQL lub reguły biznesowej, zatrzymaj się: zadanie przekroczyło granicę Mirage. Prawidłowe rozszerzenie najpierw przygotowuje dane w module, a szablon pozostaje przewidywalną warstwą prezentacji.

Kompozycja strony i fragmenty dynamiczne

Wspólny shell, nawigację i treść modułu aplikacyjnego edytuj osobno. Nie przenoś całej ramy strony do szablonu karty, ponieważ tworzy to duplikację i psuje zmianę skin. Dla fragmentu odświeżanego przez filtr, Pager lub zakładkę użyj przyjętego konturu AJAX z Mirage. Kanoniczny tekst publiczny ważny dla pierwszego renderowania i SEO pozostaw w zwykłym renderze strony.

Jeśli szablon używa dodatkowego namespace pakietu callback, na przykład do formatowania daty, upewnij się, że pakiet jest obecny w docelowym runtime. Taki callback jest zależnością szablonu. Zapewnij czytelny fallback, jeśli pozwala na to projekt, i nie próbuj naśladować brakującego callback złożonymi wyrażeniami tekstowymi.

Praktyka bezpiecznego review

Porównuj wynikowy HTML przed i po zmianie, a nie tylko źródło .mirage. Sprawdź równowagę tagów, unikalność id, dostępność label, poprawność odnośników i brak zagnieżdżonych elementów interaktywnych. Testuj listy z jednym i wieloma wierszami, ponieważ błędy kursora mogą być niewidoczne przy pojedynczym rekordzie. Przy przenoszeniu szablonu między drzewami skin ponownie sprawdź nazwy tabel i pól; wizualnie podobne moduły nie muszą otrzymywać identycznego kontekstu.