|
| 1 | +"""A copy of the IfChanged standard node, updated with |
| 2 | +SmileyChris's patch in http://code.djangoproject.com/ticket/4534 |
| 3 | +and with the context push removed.""" |
| 4 | + |
| 5 | + |
| 6 | +from django.template import Node, NodeList, resolve_variable |
| 7 | +from django.template import VariableDoesNotExist |
| 8 | +from django.template import Library |
| 9 | +from django.conf import settings |
| 10 | +import sys |
| 11 | + |
| 12 | +register = Library() |
| 13 | + |
| 14 | +class MyIfChangedNode(Node): |
| 15 | + def __init__(self, nodelist_true, nodelist_false, *varlist): |
| 16 | + self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false |
| 17 | + self._last_seen = None |
| 18 | + self._varlist = varlist |
| 19 | + |
| 20 | + def render(self, context): |
| 21 | + if context.has_key('forloop') and context['forloop']['first']: |
| 22 | + self._last_seen = None |
| 23 | + try: |
| 24 | + if self._varlist: |
| 25 | + # Consider multiple parameters. |
| 26 | + # This automatically behaves like a OR evaluation of the multiple variables. |
| 27 | + compare_to = [resolve_variable(var, context) for var in self._varlist] |
| 28 | + else: |
| 29 | + compare_to = self.nodelist_true.render(context) |
| 30 | + except VariableDoesNotExist: |
| 31 | + compare_to = None |
| 32 | + |
| 33 | + if compare_to != self._last_seen: |
| 34 | + firstloop = (self._last_seen == None) |
| 35 | + self._last_seen = compare_to |
| 36 | + #context.push() |
| 37 | + #context['ifchanged'] = {'firstloop': firstloop} |
| 38 | + content = self.nodelist_true.render(context) |
| 39 | + #context.pop() |
| 40 | + return content |
| 41 | + else: |
| 42 | + if self.nodelist_false: |
| 43 | + return self.nodelist_false.render(context) |
| 44 | + else: |
| 45 | + return '' |
| 46 | + |
| 47 | +#@register.tag |
| 48 | +def myifchanged(parser, token): |
| 49 | + """ |
| 50 | + Check if a value has changed from the last iteration of a loop. |
| 51 | +
|
| 52 | + The 'myifchanged' block tag is used within a loop. It has two possible uses. |
| 53 | +
|
| 54 | + 1. Checks its own rendered contents against its previous state and only |
| 55 | + displays the content if it has changed. For example, this displays a list of |
| 56 | + days, only displaying the month if it changes:: |
| 57 | +
|
| 58 | + <h1>Archive for {{ year }}</h1> |
| 59 | +
|
| 60 | + {% for date in days %} |
| 61 | + {% myifchanged %}<h3>{{ date|date:"F" }}</h3>{% endmyifchanged %} |
| 62 | + <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a> |
| 63 | + {% endfor %} |
| 64 | +
|
| 65 | + 2. If given a variable, check whether that variable has changed. For example, the |
| 66 | + following shows the date every time it changes, but only shows the hour if both |
| 67 | + the hour and the date have changed:: |
| 68 | +
|
| 69 | + {% for date in days %} |
| 70 | + {% myifchanged date.date %} {{ date.date }} {% endmyifchanged %} |
| 71 | + {% myifchanged date.hour date.date %} |
| 72 | + {{ date.hour }} |
| 73 | + {% endmyifchanged %} |
| 74 | + {% endfor %} |
| 75 | + """ |
| 76 | + bits = token.contents.split() |
| 77 | + nodelist_true = parser.parse(('else', 'endmyifchanged')) |
| 78 | + token = parser.next_token() |
| 79 | + if token.contents == 'else': |
| 80 | + nodelist_false = parser.parse(('endmyifchanged',)) |
| 81 | + parser.delete_first_token() |
| 82 | + else: |
| 83 | + nodelist_false = NodeList() |
| 84 | + return MyIfChangedNode(nodelist_true, nodelist_false, *bits[1:]) |
| 85 | +myifchanged = register.tag(myifchanged) |
0 commit comments