Ticket #5908: t5908.diff
File t5908.diff, 7.9 KB (added by , 12 years ago) |
---|
-
django/template/defaulttags.py
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 04e7a37..b6e0ecc 100644
a b class CycleNode(Node): 66 66 self.silent = silent 67 67 self.escape = escape # only while the "future" version exists 68 68 69 def reset(self, context): 70 context.render_context[self] = itertools_cycle(self.cyclevars) 71 69 72 def render(self, context): 70 73 if self not in context.render_context: 71 74 # First time the node is rendered in template … … class CycleNode(Node): 80 83 value = mark_safe(value) 81 84 return render_value_in_context(value, context) 82 85 86 class ResetCycleNode(Node): 87 def __init__(self, node): 88 self.node = node 89 def render(self, context): 90 self.node.reset(context) 91 return '' 92 83 93 class DebugNode(Node): 84 94 def render(self, context): 85 95 from pprint import pformat … … def cycle(parser, token, escape=False): 578 588 # Ugly hack warning: This stuffs the named template dict into parser so 579 589 # that names are only unique within each template (as opposed to using 580 590 # a global variable, which would make cycle names have to be unique across 581 # *all* templates. 591 # *all* templates. Also keeps last node in the parser. 582 592 583 593 args = token.split_contents() 584 594 … … def cycle(parser, token, escape=False): 623 633 else: 624 634 values = [parser.compile_filter(arg) for arg in args[1:]] 625 635 node = CycleNode(values, escape=escape) 636 parser._lastCycleNode = node 626 637 return node 627 638 628 639 @register.tag 640 def resetcycle(parser, token): 641 """ 642 Resets a cycle tag. 643 644 If an argument is given, resets the last rendered cycle tag whose name 645 matches the argument, else resets last rendered unnamed cycle tag. 646 647 """ 648 args = token.split_contents() 649 650 if len(args) > 2: 651 raise TemplateSyntaxError("%r tag accepts at most one argument." 652 % args[0]) 653 if len(args) == 2: 654 name = args[1] 655 try: 656 return ResetCycleNode(parser._namedCycleNodes[name]) 657 except AttributeError: 658 raise TemplateSyntaxError("No named cycles in template. " 659 "%r is not defined" % name) 660 except KeyError: 661 raise TemplateSyntaxError("Named cycle %r does not exist" % name) 662 try: 663 return ResetCycleNode(parser._lastCycleNode) 664 except AttributeError: 665 raise TemplateSyntaxError("No cycles in template.") 666 667 @register.tag 629 668 def csrf_token(parser, token): 630 669 return CsrfTokenNode() 631 670 -
docs/ref/templates/builtins.txt
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 287fd4f..0df17af 100644
a b Note that currently the variables included in the cycle will not be escaped. 151 151 Any HTML or Javascript code contained in the printed variable will be rendered 152 152 as-is, which could potentially lead to security issues. 153 153 154 You can use the `resetcycle`_ tag to reset a ``{% cycle %}`` tag to restart 155 from its first value when it's next encountered. 156 154 157 For backwards compatibility, the ``{% cycle %}`` tag supports the much inferior 155 158 old syntax from previous Django versions. You shouldn't use this in any new 156 159 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 893 896 ``{{ country.grouper }}`` will now display the value fields from the 894 897 ``choices`` set rather than the keys. 895 898 899 .. templatetag:: resetcycle 900 901 resetcycle 902 ^^^^^^^^^^ 903 904 Resets a previous `cycle`_ so that it restarts from its first item at its next 905 invocation. Without arguments, ``{% resetcycle %}`` will reset the last 906 ``{% cycle %}`` defined in the template. 907 908 Example usage:: 909 910 {% for coach in coach_list %} 911 <h1>{{ coach.name }}</h1> 912 {% for athlete in coach.athlete_set.all %} 913 <p class="{% cycle 'odd' 'even' %}">{{ athlete.name }}</p> 914 {% endfor %} 915 {% resetcycle %} 916 {% endfor %} 917 918 The athlete list for every coach starts with ``class="odd"``. Without the 919 ``{% resetcycle %}`` tag, the first athlete of a coach might be rendered with 920 ``class="even"`` if the last athlete of the previous coach had ``class="odd"``. 921 922 You can also reset named cycle tags:: 923 924 {% for item in list %} 925 <p class="{% cycle 'odd' 'evn' as stripe %} {% cycle 'majr' 'minr' 'minr' 'minr' 'minr' as tick %}"> 926 {{ item.data }} 927 </p> 928 {% ifchanged item.category %} 929 <h1>{{ item.category }}</h1> 930 {% if not forloop.first %}{% resetcycle tick %}{% endif %} 931 {% endifchanged %} 932 {% endfor %} 933 934 In this example we have both the alternating odd/even rows and a "major" row 935 every fifth row. Only the five-row cycle is reset when a category changes. 936 896 937 .. templatetag:: spaceless 897 938 898 939 spaceless -
docs/releases/1.6.txt
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index 9888925..01b6a36 100644
a b Minor features 231 231 `PIL`_ is pending deprecation (support to be removed in Django 1.8). 232 232 To upgrade, you should **first** uninstall PIL, **then** install Pillow. 233 233 234 * Added a :ttag:`resetcycle` template tag which allows the user to reset the 235 sequence of the :ttag:`cycle` template tag. 236 234 237 .. _`Pillow`: https://pypi.python.org/pypi/Pillow 235 238 .. _`PIL`: https://pypi.python.org/pypi/PIL 236 239 -
tests/template_tests/tests.py
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index 2aeaee9..0d90394 100644
a b class Templates(TestCase): 819 819 'cycle27': ('{% load cycle from future %}{% autoescape off %}{% cycle a b as ab %}{% cycle ab %}{% endautoescape %}', {'a': '<', 'b': '>'}, '<>'), 820 820 'cycle28': ('{% load cycle from future %}{% cycle a|safe b as ab %}{% cycle ab %}', {'a': '<', 'b': '>'}, '<>'), 821 821 822 ### RESETCYCLE TAG ######################################################## 823 'resetcycle01': ("{% resetcycle %}", {}, template.TemplateSyntaxError), 824 'resetcycle02': ("{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 825 'resetcycle04': ("{% cycle 'a' 'b' 'c' %}{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 826 'resetcycle05': ("{% cycle 'a' 'b' 'c' as abc %}{% resetcycle undefinedcycle %}", {}, template.TemplateSyntaxError), 827 'resetcycle06': ("{% for i in test %}{% cycle 'a' 'b' %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'aaaaa'), 828 'resetcycle07': ("{% cycle 'a' 'b' 'c' as abc %}{% for i in test %}{% cycle abc %}{% cycle '-' '+' %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'ab-c-a-b-c-'), 829 '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-'), 830 'resetcycle09': ("{% for i in outer %}{% for j in inner %}{% cycle 'a' 'b' %}{% endfor %}{% resetcycle %}{% endfor %}", {'outer': range(2), 'inner': range(3)}, 'abaaba'), 831 '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'), 832 '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'), 833 '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'), 834 822 835 ### EXCEPTIONS ############################################################ 823 836 824 837 # Raise exception for invalid template name