From 7e97489633c1a3bdf7776cb31e023ccfc5e5fa97 Mon Sep 17 00:00:00 2001 From: Shaheed Haque Date: Mon, 9 Oct 2023 20:48:01 +0100 Subject: [PATCH 1/4] WIP Jinja support. --- src/reactpy_django/templatetags/jinja.py | 67 ++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/reactpy_django/templatetags/jinja.py diff --git a/src/reactpy_django/templatetags/jinja.py b/src/reactpy_django/templatetags/jinja.py new file mode 100644 index 00000000..a851a4d9 --- /dev/null +++ b/src/reactpy_django/templatetags/jinja.py @@ -0,0 +1,67 @@ +# Copyright © 2023 Innovatie Ltd. All rights reserved. +""" +Jinja support. +""" +import typing as t + +from django.template import RequestContext, loader +from jinja2 import pass_context +from jinja2.ext import Extension +from jinja2.runtime import Context, Undefined + +from .reactpy import component as djt_component +from .. import config + + +class ReactPyExtension(Extension): + """ + Jinja has more expressive power than core Django's templates, and can + directly handle expansions such as: + + {{ component(*args, **kwargs) }} + """ + DJT_TEMPLATE = 'reactpy/component.html' + # + # 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._jinja_component + + @pass_context + def _jinja_component(self, __context: Context, dotted_path: str, *args: t.Any, host: str | None = None, + prerender: str = str(config.REACTPY_PRERENDER), **kwargs: t.Any) -> t.Union[t.Any, Undefined]: + """ + 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: + class: The HTML class to apply to the top-level component div. + key: Force the component's root node to use a specific key value. \ + Using key within a template tag is effectively useless. + host: The host to use for the ReactPy connections. If set to `None`, \ + the host will be automatically configured. \ + Example values include: `localhost:8000`, `example.com`, `example.com/subdir` + prerender: Configures whether to pre-render this component, which \ + enables SEO compatibility and reduces perceived latency. + **kwargs: The keyword arguments to provide to the component. + + Returns: + Whatever the components returns. + """ + djt_context = RequestContext(__context.parent['request'], autoescape=__context.eval_ctx.autoescape) + context = djt_component(djt_context, dotted_path, *args, host=host, prerender=prerender, **kwargs) + # + # TODO: can this be usefully cached? + # + result = loader.render_to_string(self.DJT_TEMPLATE, context, __context.parent['request']) + return result From d43263965787005e9569abf989f0fb9e04fd5765 Mon Sep 17 00:00:00 2001 From: Shaheed Haque Date: Thu, 12 Oct 2023 18:39:33 +0100 Subject: [PATCH 2/4] Address second pass review comments. --- src/reactpy_django/templatetags/jinja.py | 29 +++++++----------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/reactpy_django/templatetags/jinja.py b/src/reactpy_django/templatetags/jinja.py index a851a4d9..7f620e78 100644 --- a/src/reactpy_django/templatetags/jinja.py +++ b/src/reactpy_django/templatetags/jinja.py @@ -2,15 +2,12 @@ """ Jinja support. """ -import typing as t - from django.template import RequestContext, loader from jinja2 import pass_context from jinja2.ext import Extension -from jinja2.runtime import Context, Undefined - -from .reactpy import component as djt_component -from .. import config +from jinja2.runtime import Context +from reactpy_django import config +from reactpy_django.templatetags.reactpy import component class ReactPyExtension(Extension): @@ -31,11 +28,10 @@ def __init__(self, environment): # # All we need is to add global "component" to the environment. # - environment.globals["component"] = self._jinja_component + environment.globals["component"] = self.template_tag @pass_context - def _jinja_component(self, __context: Context, dotted_path: str, *args: t.Any, host: str | None = None, - prerender: str = str(config.REACTPY_PRERENDER), **kwargs: t.Any) -> t.Union[t.Any, Undefined]: + 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. @@ -45,23 +41,14 @@ def _jinja_component(self, __context: Context, dotted_path: str, *args: t.Any, h *args: The positional arguments to provide to the component. Keyword Args: - class: The HTML class to apply to the top-level component div. - key: Force the component's root node to use a specific key value. \ - Using key within a template tag is effectively useless. - host: The host to use for the ReactPy connections. If set to `None`, \ - the host will be automatically configured. \ - Example values include: `localhost:8000`, `example.com`, `example.com/subdir` - prerender: Configures whether to pre-render this component, which \ - enables SEO compatibility and reduces perceived latency. **kwargs: The keyword arguments to provide to the component. Returns: Whatever the components returns. """ - djt_context = RequestContext(__context.parent['request'], autoescape=__context.eval_ctx.autoescape) - context = djt_component(djt_context, dotted_path, *args, host=host, prerender=prerender, **kwargs) + 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? # - result = loader.render_to_string(self.DJT_TEMPLATE, context, __context.parent['request']) - return result + return loader.render_to_string(self.DJT_TEMPLATE, template_context, jinja_context.parent['request']) From d888b4dd5e7d7e0a22645a6dfe682de3c35303a0 Mon Sep 17 00:00:00 2001 From: Shaheed Haque Date: Sun, 26 Nov 2023 20:12:36 +0000 Subject: [PATCH 3/4] Address lastoutstadnngcomment, and run black. --- src/reactpy_django/templatetags/jinja.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/reactpy_django/templatetags/jinja.py b/src/reactpy_django/templatetags/jinja.py index 7f620e78..2f194a72 100644 --- a/src/reactpy_django/templatetags/jinja.py +++ b/src/reactpy_django/templatetags/jinja.py @@ -9,6 +9,11 @@ from reactpy_django import config from reactpy_django.templatetags.reactpy import component +# +# Point to our non-Django analogue. +# +DJT_TEMPLATE = "reactpy/component.html" + class ReactPyExtension(Extension): """ @@ -17,7 +22,7 @@ class ReactPyExtension(Extension): {{ component(*args, **kwargs) }} """ - DJT_TEMPLATE = 'reactpy/component.html' + # # Therefore, there is no new tag to parse(). # @@ -31,7 +36,9 @@ def __init__(self, environment): environment.globals["component"] = self.template_tag @pass_context - def template_tag(self, jinja_context: Context, dotted_path: str, *args, **kwargs) -> str: + 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. @@ -46,9 +53,14 @@ def template_tag(self, jinja_context: Context, dotted_path: str, *args, **kwargs Returns: Whatever the components returns. """ - django_context = RequestContext(jinja_context.parent['request'], autoescape=jinja_context.eval_ctx.autoescape) + 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(self.DJT_TEMPLATE, template_context, jinja_context.parent['request']) + return loader.render_to_string( + DJT_TEMPLATE, template_context, jinja_context.parent["request"] + ) From 3f56d4e4b5597899f69ef67dc246ff1c10baece4 Mon Sep 17 00:00:00 2001 From: Shaheed Haque Date: Tue, 28 Nov 2023 17:23:30 +0000 Subject: [PATCH 4/4] Address copyright, and use of constant to locate template. --- src/reactpy_django/templatetags/jinja.py | 11 ++--------- src/reactpy_django/templatetags/reactpy.py | 3 ++- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/reactpy_django/templatetags/jinja.py b/src/reactpy_django/templatetags/jinja.py index 2f194a72..38b14b76 100644 --- a/src/reactpy_django/templatetags/jinja.py +++ b/src/reactpy_django/templatetags/jinja.py @@ -1,4 +1,3 @@ -# Copyright © 2023 Innovatie Ltd. All rights reserved. """ Jinja support. """ @@ -6,13 +5,7 @@ from jinja2 import pass_context from jinja2.ext import Extension from jinja2.runtime import Context -from reactpy_django import config -from reactpy_django.templatetags.reactpy import component - -# -# Point to our non-Django analogue. -# -DJT_TEMPLATE = "reactpy/component.html" +from reactpy_django.templatetags.reactpy import COMPONENT_TEMPLATE, component class ReactPyExtension(Extension): @@ -62,5 +55,5 @@ def template_tag( # TODO: can this be usefully cached? # return loader.render_to_string( - DJT_TEMPLATE, template_context, jinja_context.parent["request"] + 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, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy