Source code for feincms3.templatetags.feincms3

from django import template
from django.conf import settings
from django.template.base import Node, TemplateSyntaxError, kwarg_re
from django.urls import NoReverseMatch
from django.utils.html import conditional_escape, mark_safe

from feincms3.applications import reverse_app as _reverse_app
from feincms3.utils import is_first_party_link


register = template.Library()


[docs] @register.simple_tag(takes_context=True) def render_region(context, regions, region, **kwargs): """ Render a single region. See :class:`~feincms3.renderer.RegionRenderer` for additional details. Usage:: {% render_region regions "main" %} """ return regions.render(region, context, **kwargs)
class ReverseAppNode(Node): def __init__(self, namespaces, view_name, args, kwargs, asvar): self.namespaces = namespaces self.view_name = view_name self.args = args self.kwargs = kwargs self.asvar = asvar def _current_app(self, context): try: return context.request.current_app except AttributeError: try: return context.request.resolver_match.namespace except AttributeError: return None def render(self, context): args = [arg.resolve(context) for arg in self.args] kwargs = {k: v.resolve(context) for k, v in self.kwargs.items()} namespaces = self.namespaces.resolve(context) view_name = self.view_name.resolve(context) fallback = kwargs.pop("fallback", None) if not isinstance(namespaces, list | tuple): namespaces = namespaces.split(",") # Try to look up the URL. If it fails, raise NoReverseMatch unless the # {% reverse ... as var %} construct is used, in which case return # nothing. url = "" try: url = _reverse_app( namespaces, view_name, args=args, kwargs=kwargs, current_app=self._current_app(context), ) except NoReverseMatch: if fallback is not None: url = fallback elif self.asvar is None: raise if self.asvar: context[self.asvar] = url return "" else: if context.autoescape: url = conditional_escape(url) return url
[docs] @register.tag def reverse_app(parser, token): """ Reverse app URLs, preferring the active language. Usage:: {% load feincms3 %} {% reverse_app 'blog' 'detail' [args] [kw=args] [fallback='/'] %} ``namespaces`` can either be a list or a comma-separated list of namespaces. ``NoReverseMatch`` exceptions can be avoided by providing a ``fallback`` as a keyword argument or by saving the result in a variable, similar to ``{% url 'view' as url %}`` does:: {% reverse_app 'newsletter' 'subscribe-form' fallback='/newsletter/' %} Or:: {% reverse_app 'extranet' 'login' as login_url %} """ bits = token.split_contents() if len(bits) < 3: raise TemplateSyntaxError( "'reverse_app' takes at least two arguments, a namespace and" " a URL pattern name." ) namespaces = parser.compile_filter(bits[1]) viewname = parser.compile_filter(bits[2]) args = [] kwargs = {} asvar = None bits = bits[3:] if len(bits) >= 2 and bits[-2] == "as": asvar = bits[-1] bits = bits[:-2] if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise TemplateSyntaxError("Malformed arguments to reverse_app tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) return ReverseAppNode(namespaces, viewname, args, kwargs, asvar)
[docs] @register.filter def translations(iterable, languages=None): """ Return a list of dictionaries, one for each language in ``settings.LANGUAGES``. An example follows: .. code-block:: python [ {"code": "en", "name": "English", "object": <instance>}, {"code": "de", "name": "German", "object": None}, # ... ] The filter accepts anything you throw at it. "It" should be an iterable of objects having a ``language_code`` property however, or anything non-iterable (such as ``None``). The filter always returns a list of all languages in ``settings.LANGUAGES`` but the ``object`` key's value will always be ``None`` if the data is unusable. """ try: translations = {obj.language_code: obj for obj in iterable} if iterable else {} except TypeError: translations = {} return [ {"code": code, "name": name, "object": translations.get(code)} for code, name in (languages or settings.LANGUAGES) ]
@register.simple_tag def translations_from(*iterables, languages=None): t = { code: {"code": code, "name": name, "object": None} for code, name in (languages or settings.LANGUAGES) } for iterable in iterables: if iterable and not isinstance(iterable, str): for obj in iterable: t[obj.language_code]["object"] = obj return list(t.values())
[docs] @register.simple_tag def maybe_target_blank(href, *, attributes='target="_blank" rel="noopener"'): """ Return the value of ``attributes`` if the first argument isn't a first party link (as determined by :func:`~feincms3.utils.is_first_party_link`) Usage:: <a href="{{ url }}" {% maybe_target_blank url %}>...</a> """ if is_first_party_link(href): return "" return mark_safe(attributes)