תחביר מעשי של Mirage Templates לניהול פריסה
הגבול של שכבת התבנית
Mirage מיועד להצגת HTML וטקסט. באמצעותו אפשר לסדר מחדש מקטעים, לשנות כרטיסים וכותרות, להוסיף מכלים דקורטיביים, לנהל מחלקות ולהציג רשימות מוכנות ותוויות מתורגמות. תבנית אינה אמורה להריץ SQL, לקבוע הרשאות, לשנות נתונים או להחליף בדיקת נתיב של מודול. אם השדה הדרוש אינו קיים בהקשר הקלט, שינוי פריסה לבדו אינו יכול ליצור אותו באופן מהימן.
תבניות ציבוריות נמצאות ב-skins/<Layout>/<Skin>/<Module>/, תבניות ניהול ב-adminskins/... ותבניות מפקחים ב-moderatorskins/.... לפני השינוי קבעו אילו Layout ו-Skin פעילים. אותו שם קובץ יכול להופיע בכמה עצים, ועריכת עותק שאינו פעיל לא תשנה את הדף.
פלט עם escaping
צורת הפלט העיקרית והבטוחה היא סוגריים מסולסלים כפולים:
<h1>{{ Context.Table("page").Data("title") }}</h1>
<p>{{ Context.Table("page").Data("summary") }}</p>הטקסט עובר escaping עבור HTML, ולכן תווים מתוך הנתונים אינם הופכים לתגים או למאפיינים. השתמשו בצורה הזאת עבור כותרות, שמות, כתובות בתוך מאפיינים, תוויות, מחרוזות חיפוש וכל ערך שמשתמש עשוי להזין.
פלט גולמי מסומן בסימן קריאה:
{{! Former.BuildHTML(Context.Table("form").Data("submit_ir")) }}הוא מותר רק למקור שכבר אחראי ל-HTML בטוח, לדוגמה רכיב שנבנה ב-Former, אזור Echelon או JSON-LD שעבר סריאליזציה מראש. אל תחליפו פלט רגיל ב-raw רק כדי ש„תג יעבוד” מתוך שדה משתמש. פעולה כזאת הופכת נתונים לסימון פעיל.
טבלאות Context בעלות שם
בתבניות חדשות השתמשו ב-Context.Table. דף אחד יכול לקבל את הטבלאות meta, page, assets וטבלאות מודול בעלות הקידומת __. הקריאות העיקריות הן:
Context.HasTable("items")– בדיקה אם הטבלה קיימת;Context.Table("items").Data("title")– קריאת שדה מהשורה הנוכחית;RowCount()– קבלת מספר השורות;Rewind()– החזרת הסמן להתחלה;NextRow()– מעבר לשורה הבאה.
התחביר התואם Table.Data(...) נשאר בתבניות ישנות בעלות טבלה אחת, אך אין לערבב אותו עם הקשר בעל שם ללא סיבה.
תנאים, ערכים והערות
{% if Context.Table("page").Data("status") == "published" %}
<span class="badge badge--live">{{ Boardwords("status_published") | default("פורסם") }}</span>
{% elif Context.Table("page").Data("status") == "draft" %}
<span class="badge badge--draft">{{ Boardwords("status_draft") | default("טיוטה") }}</span>
{% else %}
<span class="badge">{{ Boardwords("status_unknown") | default("לא ידוע") }}</span>
{% endif %}דגלים מגיעים לעיתים קרובות כמחרוזות "1" ו-"0", ולכן יש להשוות אותם במפורש. עבור משתנה זמני משתמשים ב-{% set name = value %}, והערה נכתבת כ-{# הסבר #} ואינה נכללת ב-HTML.
לערך חלופי מתאימות שתי צורות:
{{ Context.Table("meta").Data("title") ?? "ללא כותרת" }}
{{ Boardwords("catalog_title") | default("קטלוג") }}ביטוי תנאי משולש נוח לערך מחלקה קצר, אך מקטעים גדולים עדיף לכתוב באמצעות if רגיל:
{{ Context.Table("page").Data("compact") == "1" ? "card--compact" : "card--wide" }}לולאה בטוחה על שורות
טבלה בעלת שם אינה הופכת אוטומטית למערך של אובייקטים. השתמשו בתבנית הסמן המלאה:
{% 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("עדיין אין דבר") }}</p>
{% endif %}הסדר הוא חובה: בדקו את השורות, הפעילו Rewind(), עברו על הטווח וקראו ל-NextRow() לפני קריאת Data(). בלולאה זמינים loop.index, loop.first, loop.last, loop.odd ו-loop.even.
לוקליזציה, טפסים ואזורים
הציגו תוויות משתמש סטטיות באמצעות Boardwords עם fallback ברור. כך נשמרת האפשרות לתרגם כאשר מעתיקים עיצוב בין עצי skin. אם שדה טופס מגיע כ-*_ir, אל תרכיבו input ידנית:
<label>{{ Boardwords("profile_name") | default("שם הפרופיל") }}</label>
{{! Former.BuildHTML(Context.Table("profile").Data("name_ir"), "class", "profile-form__input") }}Mirage מנהל את המכל, הרשת והמחלקה, ו-Former את פקד ה-HTML. גם תוכן של Echelon Zone מוצג כ-raw רק מפני שהאזור הוא יצרן מהימן של המקטע; לשדה טבלה שרירותי אין מעמד כזה.
בדיקת השינוי
- בצעו שינוי צר בתבנית הפעילה בלי להעתיק את כל ה-shell.
- בדקו דף עם נתונים, עם רשימה ריקה ועם שדות אופציונליים חסרים.
- בדקו תווים מיוחדים בטקסט ובמאפיינים.
- בדקו את כל השפות הזמינות ואת ערכי ה-fallback של Boardwords.
- בדקו desktop ו-mobile, ובטופס ניהול גם שגיאות אימות.
- ודאו ש-raw משמש רק יצרנים מהימנים של HTML.
אם התבנית דורשת הרשאות חדשות, SQL או כלל עסקי, עצרו: המשימה יצאה מגבול Mirage. הרחבה נכונה מכינה תחילה את הנתונים במודול, והתבנית נשארת שכבת תצוגה צפויה.
הרכבת דף ומקטעים דינמיים
ערכו בנפרד את ה-shell המשותף, את התפריט ואת תוכן מודול היישום. אל תעבירו את כל השלד לתבנית של כרטיס יחיד: הדבר יוצר כפילות ופוגע בהחלפת skin. למקטע שמתעדכן באמצעות מסנן, pager או לשונית, השתמשו בסביבת AJAX המקובלת עם Mirage. השאירו טקסט ציבורי קנוני שחשוב לתצוגה הראשונה ול-SEO ברינדור הדף הרגיל.
אם התבנית משתמשת ב-namespace נוסף מחבילת callback, לדוגמה עיצוב תאריך, ודאו שהחבילה קיימת ב-runtime היעד. callback כזה הוא תלות של התבנית המסוימת. ספקו fallback ברור כאשר העיצוב מאפשר זאת, ואל תנסו לחקות callback חסר באמצעות ביטויי מחרוזת מורכבים.
נוהל review בטוח
השוו את ה-HTML הסופי לפני השינוי ואחריו, ולא רק את מקור `.mirage`. בדקו איזון תגים, ייחודיות id, נגישות label, תקינות קישורים והיעדר רכיבים אינטראקטיביים מקוננים. עבור רשימות בדקו שורה אחת וכמה שורות: שגיאות סמן לעיתים אינן נראות ברשומה יחידה. בעת העברת תבנית בין עצי skin, בדקו מחדש שמות טבלאות ושדות, מפני שמודולים דומים חזותית אינם חייבים לקבל אותו הקשר.