Ticket #5908: 5908-resetcycle.3.diff
File 5908-resetcycle.3.diff, 7.3 KB (added by , 13 years ago) |
---|
-
django/template/defaulttags.py
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 06838cf..4b1f8ce 100644
a b class CycleNode(Node): 111 111 self.variable_name = variable_name 112 112 self.silent = silent 113 113 114 def reset(self, context): 115 context.render_context[self] = itertools_cycle(self.cyclevars) 116 114 117 def render(self, context): 115 118 if self not in context.render_context: 116 119 # First time the node is rendered in template … … class CycleNode(Node): 123 126 return '' 124 127 return value 125 128 129 class ResetCycleNode(Node): 130 def __init__(self, node): 131 self.node = node 132 133 def render(self, context): 134 self.node.reset(context) 135 return '' 136 126 137 class DebugNode(Node): 127 138 def render(self, context): 128 139 from pprint import pformat … … def cycle(parser, token): 582 593 # Ugly hack warning: This stuffs the named template dict into parser so 583 594 # that names are only unique within each template (as opposed to using 584 595 # a global variable, which would make cycle names have to be unique across 585 # *all* templates. 596 # *all* templates. Also keeps last unnamed node in the parser. 586 597 587 598 args = token.split_contents() 588 599 … … def cycle(parser, token): 627 638 else: 628 639 values = [parser.compile_filter(arg) for arg in args[1:]] 629 640 node = CycleNode(values) 641 parser._lastUnnamedCycleNode = node 630 642 return node 631 643 632 644 @register.tag 645 def resetcycle(parser, token): 646 """ 647 Resets a cycle tag. 648 649 If an argument is given, resets the last rendered cycle tag whose name 650 matches the argument, else resets last rendered unnamed cycle tag. 651 652 """ 653 args = token.split_contents() 654 655 if len(args) > 2: 656 raise TemplateSyntaxError("%r tag accepts at most one argument." 657 % args[0]) 658 if len(args) == 2: 659 name = args[1] 660 try: 661 return ResetCycleNode(parser._namedCycleNodes[name]) 662 except AttributeError: 663 raise TemplateSyntaxError("No named cycles in template. " 664 "%r is not defined" % name) 665 except KeyError: 666 raise TemplateSyntaxError("Named cycle %r does not exist" % name) 667 try: 668 return ResetCycleNode(parser._lastUnnamedCycleNode) 669 except AttributeError: 670 raise TemplateSyntaxError("No unnamed cycles in template.") 671 672 @register.tag 633 673 def csrf_token(parser, token): 634 674 return CsrfTokenNode() 635 675 -
docs/ref/templates/builtins.txt
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 3638ce9..6f440e5 100644
a b explicitly:: 144 144 {% cycle var1 var2 var3 %} 145 145 {% endfilter %} 146 146 147 You can use the `resetcycle`_ tag to reset a ``{% cycle %}`` tag to restart 148 from its first value when it's next encountered. 149 147 150 For backwards compatibility, the ``{% cycle %}`` tag supports the much inferior 148 151 old syntax from previous Django versions. You shouldn't use this in any new 149 152 projects, but for the sake of the people who are still using it, here's what it … … attribute, allowing you to group on the display string rather than the 864 867 ``{{ gender.grouper }}`` will now display the value fields from the 865 868 ``choices`` set rather than the keys. 866 869 870 .. templatetag:: resetcycle 871 872 resetcycle 873 ^^^^^^^^^^ 874 875 Resets a previous `cycle`_ so that it restarts from its first item at its next 876 invocation. Without arguments, ``{% resetcycle %}`` will reset the last 877 unnamed ``{% cycle %}`` defined in the template. 878 879 Example usage:: 880 881 {% for coach in coach_list %} 882 <h1>{{ coach.name }}</h1> 883 {% for athlete in coach.athlete_set.all %} 884 <p class="{% cycle 'odd' 'even' %}">{{ athlete.name }}</p> 885 {% endfor %} 886 {% resetcycle %} 887 {% endfor %} 888 889 The athlete list for every coach starts with ``class="odd"``. Without the 890 ``{% resetcycle %}`` tag, the first athlete of a coach might be rendered with 891 ``class="even"`` if the last athlete of the previous coach had ``class="odd"``. 892 893 You can also reset named cycle tags:: 894 895 {% for item in list %} 896 <p class="{% cycle 'odd' 'evn' as stripe %} {% cycle 'majr' 'minr' 'minr' 'minr' 'minr' as tick %}"> 897 {{ item.data }} 898 </p> 899 {% ifchanged item.category %} 900 <h1>{{ item.category }}</h1> 901 {% if not forloop.first %}{% resetcycle tick %}{% endif %} 902 {% endifchanged %} 903 {% endfor %} 904 905 In this example we have both the alternating odd/even rows and a "major" row 906 every fifth row. Only the five-row cycle is reset when a category changes. 907 867 908 .. templatetag:: spaceless 868 909 869 910 spaceless -
tests/regressiontests/templates/tests.py
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index c5c65fd..9c1d2f2 100644
a b class Templates(unittest.TestCase): 750 750 'included-cycle': ('{{ abc }}', {'abc': 'xxx'}, 'xxx'), 751 751 'cycle24': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{% include 'included-cycle' %}{% endfor %}", {'values': [1,2,3,4]}, "abca"), 752 752 753 ### RESETCYCLE TAG ######################################################## 754 'resetcycle01': ("{% resetcycle %}", {}, template.TemplateSyntaxError), 755 'resetcycle02': ("{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 756 'resetcycle03': ("{% cycle 'a' 'b' 'c' as abc %}{% resetcycle %}", {}, template.TemplateSyntaxError), 757 'resetcycle04': ("{% cycle 'a' 'b' 'c' %}{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 758 'resetcycle05': ("{% cycle 'a' 'b' 'c' as abc %}{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 759 'resetcycle06': ("{% for i in test %}{% cycle 'a' 'b' %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'aaaaa'), 760 'resetcycle07': ("{% cycle 'a' 'b' 'c' as abc %}{% for i in test %}{% cycle abc %}{% cycle '-' '+' %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'ab-c-a-b-c-'), 761 'resetcycle08': ("{% cycle 'a' 'b' 'c' as abc %}{% for i in test %}{% resetcycle abc %}{% cycle abc %}{% cycle '-' '+' %}{% endfor %}", {'test': range(5)}, 'aa-a+a-a+a-'), 762 'resetcycle09': ("{% for i in outer %}{% for j in inner %}{% cycle 'a' 'b' %}{% endfor %}{% resetcycle %}{% endfor %}", {'outer': range(2), 'inner': range(3)}, 'abaaba'), 763 'resetcycle10': ("{% for i in outer %}{% cycle 'a' 'b' %}{% for j in inner %}{% cycle 'X' 'Y' %}{% endfor %}{% resetcycle %}{% endfor %}", {'outer': range(2), 'inner': range(3)}, 'aXYXbXYX'), 764 'resetcycle11': ("{% for i in test %}{% cycle 'X' 'Y' 'Z' as XYZ %}{% cycle 'a' 'b' 'c' as abc %}{% ifequal i 1 %}{% resetcycle abc %}{% endifequal %}{% endfor %}", {'test': range(5)}, 'XaYbZaXbYc'), 765 'resetcycle12': ("{% for i in test %}{% cycle 'X' 'Y' 'Z' as XYZ %}{% cycle 'a' 'b' 'c' as abc %}{% ifequal i 1 %}{% resetcycle XYZ %}{% endifequal %}{% endfor %}", {'test': range(5)}, 'XaYbXcYaZb'), 766 753 767 ### EXCEPTIONS ############################################################ 754 768 755 769 # Raise exception for invalid template name