Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #13567 -- Added a 'silent' argument to the cycle tag, so that y…

…ou can declare a cycle without producing a value in the template. Thanks to anentropic for the suggestion and initial patch, and Łukasz Rekucki for the final patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14439 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit a89e02637b04b95f50087d53289e8aca8cd58007 1 parent bb062c3
Russell Keith-Magee authored November 02, 2010
35  django/template/defaulttags.py
@@ -53,13 +53,17 @@ def render(self, context):
53 53
             return u''
54 54
 
55 55
 class CycleNode(Node):
56  
-    def __init__(self, cyclevars, variable_name=None):
  56
+    def __init__(self, cyclevars, variable_name=None, silent=False):
57 57
         self.cyclevars = cyclevars
58 58
         self.variable_name = variable_name
  59
+        self.silent = silent
59 60
 
60 61
     def render(self, context):
61 62
         if self not in context.render_context:
  63
+            # First time the node is rendered in template
62 64
             context.render_context[self] = itertools_cycle(self.cyclevars)
  65
+            if self.silent:
  66
+                return ''
63 67
         cycle_iter = context.render_context[self]
64 68
         value = cycle_iter.next().resolve(context)
65 69
         if self.variable_name:
@@ -482,6 +486,17 @@ def cycle(parser, token):
482 486
     You can use any number of values, separated by spaces. Commas can also
483 487
     be used to separate values; if a comma is used, the cycle values are
484 488
     interpreted as literal strings.
  489
+
  490
+    The optional flag "silent" can be used to prevent the cycle declaration
  491
+    from returning any value::
  492
+
  493
+        {% cycle 'row1' 'row2' as rowcolors silent %}{# no value here #}
  494
+        {% for o in some_list %}
  495
+            <tr class="{% cycle rowcolors %}">{# first value will be "row1" #}
  496
+                ...
  497
+            </tr>
  498
+        {% endfor %}
  499
+
485 500
     """
486 501
 
487 502
     # Note: This returns the exact same node on each {% cycle name %} call;
@@ -513,10 +528,24 @@ def cycle(parser, token):
513 528
             raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
514 529
         return parser._namedCycleNodes[name]
515 530
 
516  
-    if len(args) > 4 and args[-2] == 'as':
  531
+    as_form = False
  532
+
  533
+    if len(args) > 4:
  534
+        # {% cycle ... as foo [silent] %} case.
  535
+        if args[-3] == "as":
  536
+            if args[-1] != "silent":
  537
+                raise TemplateSyntaxError("Only 'silent' flag is allowed after cycle's name, not '%s'." % args[-1])
  538
+            as_form = True
  539
+            silent = True
  540
+            args = args[:-1]
  541
+        elif args[-2] == "as":
  542
+            as_form = True
  543
+            silent = False
  544
+
  545
+    if as_form:
517 546
         name = args[-1]
518 547
         values = [parser.compile_filter(arg) for arg in args[1:-2]]
519  
-        node = CycleNode(values, name)
  548
+        node = CycleNode(values, name, silent=silent)
520 549
         if not hasattr(parser, '_namedCycleNodes'):
521 550
             parser._namedCycleNodes = {}
522 551
         parser._namedCycleNodes[name] = node
20  docs/ref/templates/builtins.txt
@@ -140,6 +140,26 @@ In this syntax, each value gets interpreted as a literal string, and there's no
140 140
 way to specify variable values. Or literal commas. Or spaces. Did we mention
141 141
 you shouldn't use this syntax in any new projects?
142 142
 
  143
+.. versionadded:: 1.3
  144
+
  145
+By default, when you use the ``as`` keyword with the cycle tag, the
  146
+usage of ``{% cycle %}`` that declares the cycle will itself output
  147
+the first value in the cycle. This could be a problem if you want to
  148
+use the value in a nested loop or an included template. If you want to
  149
+just declare the cycle, but not output the first value, you can add a
  150
+``silent`` keyword as the last keyword in the tag. For example::
  151
+
  152
+    {% cycle 'row1' 'row2' as rowcolors silent %}
  153
+    {% for obj in some_list %}
  154
+        <tr class="{% cycle rowcolors %}">{{ obj }}</tr>
  155
+    {% endfor %}
  156
+
  157
+This will output a list of ``<tr>`` elements with ``class``
  158
+alternating between ``row1`` and ``row2``. If the ``silent`` keyword
  159
+were to be omitted, ``row1`` would be emitted as normal text, outside
  160
+the list of ``<tr>`` elements, and the first ``<tr>`` would have a
  161
+class of ``row2``.
  162
+
143 163
 .. templatetag:: debug
144 164
 
145 165
 debug
3  tests/regressiontests/templates/tests.py
@@ -646,6 +646,9 @@ def get_template_tests(self):
646 646
             'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'),
647 647
             'cycle15': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'),
648 648
             'cycle16': ("{% cycle one|lower two as foo %}{% cycle foo %}", {'one': 'A','two': '2'}, 'a2'),
  649
+            'cycle17': ("{% cycle 'a' 'b' 'c' as abc silent %}{% cycle abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, "abca"),
  650
+            'cycle18': ("{% cycle 'a' 'b' 'c' as foo invalid_flag %}", {}, template.TemplateSyntaxError),
  651
+            'cycle19': ("{% cycle 'a' 'b' as silent %}{% cycle silent %}", {}, "ab"),
649 652
 
650 653
             ### EXCEPTIONS ############################################################
651 654
 

0 notes on commit a89e026

Please sign in to comment.
Something went wrong with that request. Please try again.