Ticket #5908: 5908_resetcycle.2.diff
File 5908_resetcycle.2.diff, 7.0 KB (added by , 16 years ago) |
---|
-
django/template/defaulttags.py
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index c08ecc4..ddf1783 100644
a b class CommentNode(Node): 39 39 40 40 class CycleNode(Node): 41 41 def __init__(self, cyclevars, variable_name=None): 42 self.cycle_iter = itertools_cycle(cyclevars) 42 self.cyclevars = cyclevars 43 self.reset() 43 44 self.variable_name = variable_name 44 45 46 def reset(self): 47 self.cycle_iter = itertools_cycle(self.cyclevars) 48 45 49 def render(self, context): 46 50 value = self.cycle_iter.next().resolve(context) 47 51 if self.variable_name: 48 52 context[self.variable_name] = value 49 53 return value 50 54 55 class ResetCycleNode(Node): 56 def __init__(self, node): 57 self.node = node 58 59 def render(self, context): 60 self.node.reset() 61 return '' 62 51 63 class DebugNode(Node): 52 64 def render(self, context): 53 65 from pprint import pformat … … def cycle(parser, token): 481 493 # Ugly hack warning: This stuffs the named template dict into parser so 482 494 # that names are only unique within each template (as opposed to using 483 495 # a global variable, which would make cycle names have to be unique across 484 # *all* templates .496 # *all* templates). Also keeps last unnamed node in the parser. 485 497 486 498 args = token.split_contents() 487 499 … … def cycle(parser, token): 512 524 else: 513 525 values = [parser.compile_filter(arg) for arg in args[1:]] 514 526 node = CycleNode(values) 527 parser._lastUnnamedCycleNode = node 515 528 return node 516 529 cycle = register.tag(cycle) 517 530 531 def resetcycle(parser, token): 532 """ 533 Resets a cycle tag. 534 535 If an argument is given, resets the last rendered cycle tag whose name 536 matches the argument, else resets last rendered unnamed cycle tag. 537 """ 538 args = token.split_contents() 539 540 if len(args) > 2: 541 raise TemplateSyntaxError("%r tag accepts at most one argument." 542 % args[0]) 543 if len(args) == 2: 544 name = args[1] 545 try: 546 return ResetCycleNode(parser._namedCycleNodes[name]) 547 except AttributeError: 548 raise TemplateSyntaxError("No named cycles in template. " 549 "%r is not defined" % name) 550 except KeyError: 551 raise TemplateSyntaxError("Named cycle %r does not exist" % name) 552 try: 553 return ResetCycleNode(parser._lastUnnamedCycleNode) 554 except AttributeError: 555 raise TemplateSyntaxError("No unnamed cycles in template.") 556 resetcycle = register.tag(resetcycle) 557 518 558 def debug(parser, token): 519 559 """ 520 560 Outputs a whole load of debugging information, including the current -
docs/ref/templates/builtins.txt
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 17e6e8b..0193c8d 100644
a b You can use any number of values in a ``{% cycle %}`` tag, separated by spaces. 101 101 Values enclosed in single (``'``) or double quotes (``"``) are treated as 102 102 string literals, while values without quotes are treated as template variables. 103 103 104 You can use the `resetcycle`_ tag to reset a ``{% cycle %}`` tag to restart from 105 its first value when it's next encountered. 106 104 107 For backwards compatibility, the ``{% cycle %}`` tag supports the much inferior 105 108 old syntax from previous Django versions. You shouldn't use this in any new 106 109 projects, but for the sake of the people who are still using it, here's what it … … filter, if your data is in a list of dictionaries:: 622 625 623 626 {% regroup people|dictsort:"gender" by gender as gender_list %} 624 627 628 .. templatetag:: resetcycle 629 630 resetcycle 631 ~~~~~~~~~~ 632 633 Resets a previous `cycle`_ so that it restarts from its first item when it's 634 next encountered. Without arguments, ``{% resetcycle %}`` will reset the last 635 unnamed ``{% cycle %}`` defined in the template. 636 637 Example usage:: 638 639 {% for coach in coach_list %} 640 <h1>{{ coach.name }}</h1> 641 {% for athlete in coach.athlete_set.all %} 642 <p class="{% cycle 'odd' 'even' %}">{{ athlete.name }}</p> 643 {% endfor %} 644 {% resetcycle %} 645 {% endfor %} 646 647 The athlete list for every coach starts with ``class="odd"``. Without the 648 ``{% resetcycle %}`` tag, the first athlete of a coach might be rendered with 649 ``class="even"`` if the last athlete of the previous coach had ``class="odd"``. 650 651 You can also reset named cycle tags:: 652 653 {% for item in list %} 654 <p class="{% cycle 'odd' 'evn' as stripe %} {% cycle 'majr' 'minr' 'minr' 'minr' 'minr' as tick %}"> 655 {{ item.data }} 656 </p> 657 {% ifchanged item.category %} 658 <h1>{{ item.category }}</h1> 659 {% if not forloop.first %}{% resetcycle tick %}{% endif %} 660 {% endifchanged %} 661 {% endfor %} 662 663 In this example we have both the alternating odd/even rows and a "major" row 664 every fifth row. Only the five-row cycle is reset when a category changes. 665 625 666 .. templatetag:: spaceless 626 667 627 668 spaceless -
tests/regressiontests/templates/tests.py
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index f0eee52..a4f1a26 100644
a b class Templates(unittest.TestCase): 434 434 'cycle15': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'), 435 435 'cycle16': ("{% cycle one|lower two as foo %}{% cycle foo %}", {'one': 'A','two': '2'}, 'a2'), 436 436 437 ### RESETCYCLE TAG ######################################################## 438 'resetcycle01': ("{% for i in test %}{% cycle a,b %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'aaaaa'), 439 'resetcycle02': ("{% cycle a,b,c as abc %}{% for i in test %}{% cycle abc %}{% cycle '-' '+' %}{% resetcycle %}{% endfor %}", {'test': range(5)}, 'ab-c-a-b-c-'), 440 'resetcycle03': ("{% cycle a,b,c as abc %}{% for i in test %}{% resetcycle abc %}{% cycle abc %}{% cycle '-' '+' %}{% endfor %}", {'test': range(5)}, 'aa-a+a-a+a-'), 441 'resetcycle04': ("{% for i in outer %}{% for j in inner %}{% cycle a,b %}{% endfor %}{% resetcycle %}{% endfor %}", {'outer': range(2), 'inner': range(3)}, 'abaaba'), 442 'resetcycle05': ("{% for i in outer %}{% cycle a,b %}{% for j in inner %}{% cycle X,Y %}{% endfor %}{% resetcycle %}{% endfor %}", {'outer': range(2), 'inner': range(3)}, 'aXYXbXYX'), 443 'resetcycle06': ("{% 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'), 444 'resetcycle07': ("{% 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'), 445 437 446 ### EXCEPTIONS ############################################################ 438 447 439 448 # Raise exception for invalid template name