|
from django import template |
|
from django.template.base import VariableDoesNotExist |
|
from django.template.defaulttags import IfNode |
|
from django.template.smartif import IfParser, Literal |
|
|
|
register = template.Library() |
|
|
|
# Used as a value for ifdef and ifndef tags |
|
undefined = object() |
|
|
|
class IfDefLiteral(Literal): |
|
def eval(self, context): |
|
if not self.value in context: |
|
# Can't raise an exception here because Operator catches it |
|
return undefined |
|
|
|
class IfDefParser(IfParser): |
|
def create_var(self, value): |
|
return IfDefLiteral(value) |
|
|
|
class IfDefNode(IfNode): |
|
def __init__(self, defined=True, *args, **kwargs): |
|
self.defined = defined |
|
super(IfDefNode, self).__init__(*args, **kwargs) |
|
|
|
def __repr__(self): |
|
return "<%s>" % self.__class__.__name__ |
|
|
|
def render(self, context): |
|
for condition, nodelist in self.conditions_nodelists: |
|
|
|
match = undefined |
|
if condition is not None: # if / elif clause |
|
try: |
|
match = condition.eval(context) |
|
except VariableDoesNotExist: |
|
pass |
|
|
|
if condition is None or ( # else clause, always render |
|
(self.defined and match is not undefined) or |
|
(match is undefined and not self.defined)): |
|
return nodelist.render(context) |
|
|
|
return '' |
|
|
|
def _gen_ifdef(parser, token, block_tokens, defined): |
|
# {% if ... %} |
|
bits = token.split_contents()[1:] |
|
condition = IfDefParser(bits).parse() |
|
nodelist = parser.parse(block_tokens) |
|
conditions_nodelists = [(condition, nodelist)] |
|
token = parser.next_token() |
|
|
|
# {% elif ... %} (repeatable) |
|
while token.contents.startswith(block_tokens[0]): |
|
bits = token.split_contents()[1:] |
|
condition = IfDefParser(bits).parse() |
|
nodelist = parser.parse(block_tokens) |
|
conditions_nodelists.append((condition, nodelist)) |
|
token = parser.next_token() |
|
|
|
# {% else %} (optional) |
|
if token.contents == 'else': |
|
nodelist = parser.parse(block_tokens[-1:]) |
|
conditions_nodelists.append((None, nodelist)) |
|
token = parser.next_token() |
|
|
|
# {% endif %} |
|
assert token.contents == block_tokens[-1] |
|
|
|
return IfDefNode(defined, conditions_nodelists) |
|
|
|
@register.tag |
|
def ifdef(parser, token): |
|
"""Check if variable is defined in the context |
|
|
|
Unlike the {% if %} tag, this renders the block if the variable(s) |
|
exist within the context, not only if they are truthy. That is, variables |
|
with None, 0 or [] values would also render the block. |
|
""" |
|
return _gen_ifdef(parser, token, ('elifdef', 'else', 'endifdef'), True) |
|
|
|
@register.tag |
|
def ifndef(parser, token): |
|
"""Check if variable is *not* defined in the context |
|
|
|
This is the opposite of {% ifdef %}. |
|
""" |
|
return _gen_ifdef(parser, token, ('elifndef', 'else', 'endifndef'), False) |