diff --git a/src/reactpy_django/templatetags/jinja.py b/src/reactpy_django/templatetags/jinja.py new file mode 100644 index 00000000..38b14b76 --- /dev/null +++ b/src/reactpy_django/templatetags/jinja.py @@ -0,0 +1,59 @@ +""" +Jinja support. +""" +from django.template import RequestContext, loader +from jinja2 import pass_context +from jinja2.ext import Extension +from jinja2.runtime import Context +from reactpy_django.templatetags.reactpy import COMPONENT_TEMPLATE, component + + +class ReactPyExtension(Extension): + """ + Jinja has more expressive power than core Django's templates, and can + directly handle expansions such as: + + {{ component(*args, **kwargs) }} + """ + + # + # Therefore, there is no new tag to parse(). + # + tags = {} + + def __init__(self, environment): + super().__init__(environment) + # + # All we need is to add global "component" to the environment. + # + environment.globals["component"] = self.template_tag + + @pass_context + def template_tag( + self, jinja_context: Context, dotted_path: str, *args, **kwargs + ) -> str: + """ + This method is used to embed an existing ReactPy component into your + Jinja2 template. + + Args: + dotted_path: String of the fully qualified name of a component. + *args: The positional arguments to provide to the component. + + Keyword Args: + **kwargs: The keyword arguments to provide to the component. + + Returns: + Whatever the components returns. + """ + django_context = RequestContext( + jinja_context.parent["request"], + autoescape=jinja_context.eval_ctx.autoescape, + ) + template_context = component(django_context, dotted_path, *args, **kwargs) + # + # TODO: can this be usefully cached? + # + return loader.render_to_string( + COMPONENT_TEMPLATE, template_context, jinja_context.parent["request"] + ) diff --git a/src/reactpy_django/templatetags/reactpy.py b/src/reactpy_django/templatetags/reactpy.py index 209c0ec8..97dd99f9 100644 --- a/src/reactpy_django/templatetags/reactpy.py +++ b/src/reactpy_django/templatetags/reactpy.py @@ -27,11 +27,12 @@ RESOLVED_WEB_MODULES_PATH = reverse("reactpy:web_modules", args=["/"]).strip("/") except NoReverseMatch: RESOLVED_WEB_MODULES_PATH = "" +COMPONENT_TEMPLATE = "reactpy/component.html" register = template.Library() _logger = getLogger(__name__) -@register.inclusion_tag("reactpy/component.html", takes_context=True) +@register.inclusion_tag(COMPONENT_TEMPLATE, takes_context=True) def component( context: template.RequestContext, dotted_path: str,