Praktyczna składnia Mirage Templates do sterowania układem
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
- Wprowadź wąską zmianę w aktywnym szablonie bez kopiowania całego shell.
- Sprawdź stronę z danymi, pustą listą i brakującymi polami opcjonalnymi.
- Przetestuj znaki specjalne w tekście i atrybutach.
- Sprawdź wszystkie dostępne języki i fallback Boardwords.
- Przetestuj desktop i mobile, a dla formularza administracyjnego także błędy walidacji.
- 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.