قالب‌ها

فینچ از پکیج Dart به نام Jinja به‌عنوان موتور قالب خود استفاده می‌کند. فایل‌های قالب در دایرکتوری‌ای که توسط FinchConfigs.widgetsPath پیکربندی شده قرار دارند و از پسوندی که در FinchConfigs.widgetsType تنظیم شده استفاده می‌کنند (پیش‌فرض: j2.html).

رندر کردن یک قالب

rq.renderView(path: '...') را با مسیری نسبت به widgetsPath، بدون پسوند فایل، فراخوانی کنید:

// Loads: widgetsPath/pages/home.j2.html
return rq.renderView(path: 'pages/home');

پیش از فراخوانی renderView، با استفاده از rq.addParam() یا rq.addParams() داده را به قالب پاس دهید:

rq.addParams({
  'title': 'My Page',
  'user': user.toJson(),
  'items': items.map((i) => i.toJson()).toList(),
});
return rq.renderView(path: 'pages/home');

نحو قالب

فینچ از نحو استاندارد Jinja2 استفاده می‌کند. جداکننده‌ها در FinchConfigs قابل‌تنظیم هستند اما به‌صورت پیش‌فرض به این شکل‌اند:

نحو هدف
{{ expression }} خروجی گرفتن از یک متغیر یا عبارت
{% tag %} جریان کنترل: if، for، block، include و غیره
{# comment #} نظر (رندر نمی‌شود)

متغیرها

{{ title }}
{{ user.name }}
{{ user['email'] }}

جریان کنترل

{% if user %}
  <p>Hello, {{ user.name }}</p>
{% else %}
  <p>Please log in.</p>
{% endif %}

{% for item in items %}
  <li>{{ item.title }}</li>
{% endfor %}

گنجاندن (Include)

{% include 'partials/header.j2.html' %}

وارث‌سازی / بلوک‌ها

{# layout.j2.html #}
<!DOCTYPE html>
<html>
<head><title>{% block title %}{% endblock %}</title></head>
<body>
  {% block content %}{% endblock %}
</body>
</html>
{# pages/home.j2.html #}
{% extends 'layout.j2.html' %}

{% block title %}Home{% endblock %}

{% block content %}
  <h1>{{ title }}</h1>
{% endblock %}

استفاده از قالب‌های بسته‌بندی‌شده (Map)

برای باینری‌های کامپایل‌شده، قالب‌ها را نمی‌توان در زمان اجرا از روی دیسک خواند. از jinjaMapTemplate در FinchConfigs برای بسته‌بندی قالب‌ها به‌صورت یک Map<String, String> استفاده کنید:

// Generated by: finch build or finch runner
final mapTemplates = {
  'pages/home.j2.html': '<h1>{{ title }}</h1>',
  // ...
};

FinchConfigs configs = FinchConfigs(
  jinjaMapTemplate: mapTemplates,
  widgetsType: 'j2.html',
);

واچر finch serve این map را به‌صورت خودکار هنگام تغییر فایل‌های قالب، دوباره تولید می‌کند.

توابع سفارشی قالب (localEvents)

توابع سراسری‌ای اضافه کنید که از هر قالبی قابل‌فراخوانی باشند:

// In app.dart
Request.localEvents.addAll({
  'currentYear': () => DateTime.now().year,
  'formatDate': (String iso) => iso.substring(0, 10),
});

در قالب (از پیشوند $l. برای local eventها استفاده کنید):

<footer>© {{ $l.currentYear() }}</footer>
<span>{{ $l.formatDate(post.createdAt) }}</span>

فیلترهای سفارشی (localLayoutFilters)

فیلترهای Jinja اضافه کنید:

Request.addLocalLayoutFilters({
  'upper': (value) => value.toString().toUpperCase(),
  'excerpt': (value) {
    var s = value.toString();
    return s.length > 100 ? '${s.substring(0, 100)}…' : s;
  },
});

در قالب:

{{ post.title | upper }}
{{ post.body | excerpt }}

متغیرهای داخلی قالب فینچ

این متغیرها به‌صورت خودکار در هر قالبی در دسترس‌اند:

{{ isLocalDebug }}        — true in development mode
{{ data }}                — all addParam() data
{{ session }}             — current session map
{{ $rq }}                 — the Request object

برای فهرست کامل کمک‌کننده‌های $e.* و $t() به Template Events مراجعه کنید.

مثال کامل

<!DOCTYPE html>
<html lang="{{ $e.ln }}" dir="{{ $t('dir') }}">
<head>
  <meta charset="UTF-8">
  <title>{{ $t(title) }}</title>
  {{ assets.css() }}
</head>
<body>
  <nav>
    {% if user %}
      <a href="/logout">{{ user.name }}</a>
    {% else %}
      <a href="/login">Login</a>
    {% endif %}
  </nav>

  <main>
    {% block content %}{% endblock %}
  </main>

  {{ assets.js() }}
</body>
</html>