diff --git a/kjvstudy_org/jinja_filters.py b/kjvstudy_org/jinja_filters.py index 2ca1fe0..c31d9b0 100644 --- a/kjvstudy_org/jinja_filters.py +++ b/kjvstudy_org/jinja_filters.py @@ -1,8 +1,8 @@ """ -Custom template filters for KJV Study. +Custom Jinja2 template filters for KJV Study. All filters are registered in register_filters() which should be called with -the MiniJinja environment after templates are initialized. +the Jinja2 environment after templates are initialized. Available Filters: slugify - Create URL-safe slugs from text @@ -20,7 +20,6 @@ Available Filters: import re import mistune -import minijinja from functools import lru_cache @@ -381,35 +380,17 @@ def strip_links(text): return re.sub(r']*>([^<]*)', r'\1', text) -def _safe_html(func): - """Wrap a filter function so its return value is marked as safe HTML.""" - def wrapper(*args, **kwargs): - result = func(*args, **kwargs) - if result is None: - return result - return minijinja.safe(str(result)) - return wrapper - - -def rsplit(text, sep=' ', maxsplit=-1): - """Python rsplit as a template filter, since MiniJinja lacks it.""" - if not text: - return [] - return text.rsplit(sep, maxsplit) - - def register_filters(env): - """Register all custom filters with a MiniJinja environment.""" - env.add_filter('slugify', create_slug) - env.add_filter('md', _safe_html(markdown_to_html)) - env.add_filter('mdi', _safe_html(markdown_inline)) - env.add_filter('link_names', _safe_html(link_person_names_in_text)) - env.add_filter('link_verses', _safe_html(link_verse_references_in_text)) - env.add_filter('inject_word_markers', _safe_html(inject_word_markers)) - env.add_filter('red_letter', _safe_html(red_letter)) - env.add_filter('format_lists', _safe_html(format_numbered_lists)) - env.add_filter('split_paragraphs', _safe_html(split_paragraphs)) - env.add_filter('number_format', number_format) - env.add_filter('linkify_strongs', _safe_html(linkify_strongs)) - env.add_filter('strip_links', strip_links) - env.add_filter('rsplit', rsplit) + """Register all custom filters with a Jinja2 environment.""" + env.filters['slugify'] = create_slug + env.filters['md'] = markdown_to_html + env.filters['mdi'] = markdown_inline + env.filters['link_names'] = link_person_names_in_text + env.filters['link_verses'] = link_verse_references_in_text + env.filters['inject_word_markers'] = inject_word_markers + env.filters['red_letter'] = red_letter + env.filters['format_lists'] = format_numbered_lists + env.filters['split_paragraphs'] = split_paragraphs + env.filters['number_format'] = number_format + env.filters['linkify_strongs'] = linkify_strongs + env.filters['strip_links'] = strip_links diff --git a/kjvstudy_org/minijinja_templates.py b/kjvstudy_org/minijinja_templates.py deleted file mode 100644 index dc99bcb..0000000 --- a/kjvstudy_org/minijinja_templates.py +++ /dev/null @@ -1,65 +0,0 @@ -"""MiniJinja integration for FastAPI. - -Drop-in replacement for fastapi.templating.Jinja2Templates using MiniJinja -(a fast Rust-based Jinja2-compatible template engine). -""" - -import minijinja -from markupsafe import Markup, escape as markupsafe_escape -from starlette.responses import HTMLResponse - - -def _jinja2_compatible_finalizer(value): - """Use markupsafe's escaping (same as Jinja2) instead of MiniJinja's more aggressive escaping.""" - if isinstance(value, Markup): - return value - return Markup(markupsafe_escape(str(value))) - - -class _TemplateWrapper: - """Wraps a MiniJinja environment + template name to support .render() calls.""" - - def __init__(self, env, name): - self._env = env - self._name = name - - def render(self, *args, **kwargs): - if args and isinstance(args[0], dict): - kwargs.update(args[0]) - return self._env.render_template(self._name, **kwargs) - - -class MiniJinjaTemplates: - """FastAPI-compatible template renderer backed by MiniJinja.""" - - def __init__(self, directory: str): - self.directory = directory - self.env = minijinja.Environment( - loader=minijinja.load_from_path(directory), - ) - self.env.auto_escape_callback = lambda name: name.endswith((".html", ".xml")) - self.env.finalizer = _jinja2_compatible_finalizer - self.env.reload_before_render = False - - def get_template(self, name: str): - """Return a template wrapper with a .render() method, matching Jinja2 API.""" - return _TemplateWrapper(self.env, name) - - def TemplateResponse(self, request_or_name, name_or_context=None, context=None, status_code=200, **kwargs): - """Render a template and return an HTMLResponse. - - Supports both calling conventions: - TemplateResponse(request, "name.html", {...}) # new Starlette style - TemplateResponse("name.html", {"request": req, ...}) # old Starlette style - """ - if isinstance(request_or_name, str): - # Old style: TemplateResponse("name.html", {"request": req, ...}) - name = request_or_name - ctx = dict(name_or_context) if name_or_context else {} - else: - # New style: TemplateResponse(request, "name.html", {...}) - name = name_or_context - ctx = dict(context) if context else {} - ctx["request"] = request_or_name - html = self.env.render_template(name, **ctx) - return HTMLResponse(content=html, status_code=status_code, **kwargs) diff --git a/kjvstudy_org/routes/resources.py b/kjvstudy_org/routes/resources.py index ed95409..3176c12 100644 --- a/kjvstudy_org/routes/resources.py +++ b/kjvstudy_org/routes/resources.py @@ -63,7 +63,7 @@ def init_templates(app_templates): """Initialize templates from the main app.""" global templates templates = app_templates - templates.env.add_global('resource_pdf_available', WEASYPRINT_AVAILABLE) + templates.env.globals['resource_pdf_available'] = WEASYPRINT_AVAILABLE def get_books(): diff --git a/kjvstudy_org/server.py b/kjvstudy_org/server.py index 3637773..14d71ad 100644 --- a/kjvstudy_org/server.py +++ b/kjvstudy_org/server.py @@ -12,7 +12,7 @@ from typing import List, Dict, Optional from fastapi import FastAPI, HTTPException, Request, Query, Path from fastapi.exception_handlers import http_exception_handler from fastapi.responses import HTMLResponse, Response, RedirectResponse, JSONResponse, StreamingResponse -from .minijinja_templates import MiniJinjaTemplates +from fastapi.templating import Jinja2Templates from fastapi.middleware.gzip import GZipMiddleware from fastapi.openapi.utils import get_openapi from starlette.exceptions import HTTPException as StarletteHTTPException @@ -327,14 +327,14 @@ current_dir = PathLib(__file__).parent static_dir = current_dir / "static" templates_dir = current_dir / "templates" -templates = MiniJinjaTemplates(directory=str(templates_dir)) +templates = Jinja2Templates(directory=str(templates_dir)) -# Register custom filters +# Register custom Jinja2 filters from .jinja_filters import register_filters register_filters(templates.env) # Add global template variables -templates.env.add_global('disable_analytics', os.getenv("DISABLE_ANALYTICS", "false").lower() == "true") +templates.env.globals['disable_analytics'] = os.getenv("DISABLE_ANALYTICS", "false").lower() == "true" # Cache-busting for static files using file modification time import hashlib @@ -351,7 +351,7 @@ def static_hash(filename): _static_hashes[filename] = "0" return _static_hashes[filename] -templates.env.add_function('static_hash', static_hash) +templates.env.globals['static_hash'] = static_hash # Initialize templates for route modules init_api_templates(templates) diff --git a/kjvstudy_org/templates/family_tree_generation.html b/kjvstudy_org/templates/family_tree_generation.html index 86bc240..c25ad93 100644 --- a/kjvstudy_org/templates/family_tree_generation.html +++ b/kjvstudy_org/templates/family_tree_generation.html @@ -275,15 +275,19 @@ {% endif %} -{% set ns = namespace(kekule_count=0, with_children=0, total_children=0) %} +{% set kekule_count = [] %} +{% set with_children = [] %} +{% set total_children = [] %} {% for person_id in generation_people %} {% set person = family_tree_data[person_id] %} {% if person.kekule_number is not none %} - {% set ns.kekule_count = ns.kekule_count + 1 %} + {% set _ = kekule_count.append(1) %} {% endif %} {% if person.children|length > 0 %} - {% set ns.with_children = ns.with_children + 1 %} - {% set ns.total_children = ns.total_children + person.children|length %} + {% set _ = with_children.append(1) %} + {% for c in person.children %} + {% set _ = total_children.append(1) %} + {% endfor %} {% endif %} {% endfor %} @@ -292,22 +296,22 @@ People: {{ generation_people|length }} - {% if ns.kekule_count > 0 %} + {% if kekule_count|length > 0 %}
- {% set _rp = verse.reference|rsplit(' ', 1) %}{{ verse.reference }}
+ {{ verse.reference }}
{{ verse.text }}