Fixed #208 -- Modernized the syntax of the cycle tag to allow for spaces and variables in cycle values. Thanks to SmileyChris and Chris McAvoy for their work on this.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6153 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2007-09-14 02:49:21 +00:00
parent a2ce7669d9
commit 09145d2e5f
17 changed files with 63 additions and 48 deletions

View File

@ -10,7 +10,7 @@
</thead>
<tbody>
{% for result in results %}
<tr class="{% cycle row1,row2 %}">{% for item in result %}{{ item }}{% endfor %}</tr>
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>
{% endfor %}
</tbody>
</table>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for field in field_list %}
<li class="{% cycle odd,even %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for year in date_list %}
<li class="{% cycle odd,even %}"><a href="{{ year.year }}/">{{ year.year }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ year.year }}/">{{ year.year }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for month in date_list %}
<li class="{% cycle odd,even %}"><a href="{{ month|date:"M"|lower }}/">{{ month|date:"F" }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ month|date:"M"|lower }}/">{{ month|date:"F" }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for choice in field.choices %}
<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for field in field_list %}
<li class="{% cycle odd,even %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object|iriencode }}/">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object|iriencode }}/">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -7,7 +7,7 @@
{% block content %}
{% for model in model_list %}
<div class="modelgroup {% cycle even,odd %}">
<div class="modelgroup {% cycle 'even' 'odd' %}">
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
<p>
{% for object in model.sample_objects %}

View File

@ -12,7 +12,7 @@
<ul class="objectlist">
{% for object in model.objects %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>

View File

@ -10,7 +10,7 @@
<table class="objectinfo">
{% for field in object.fields %}
<tr class="{% cycle odd,even %}">
<tr class="{% cycle 'odd' 'even' %}">
<th>{{ field.field.verbose_name|capfirst }}</th>
<td>
{% if field.urls %}
@ -29,7 +29,7 @@
{% if related_object.object_list %}
<ul class="objectlist">
{% for object in related_object.object_list %}
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
{% endfor %}
</ul>
{% else %}

View File

@ -30,6 +30,7 @@ class CycleNode(Node):
def render(self, context):
self.counter += 1
value = self.cyclevars[self.counter % self.cyclevars_len]
value = resolve_variable(value, context)
if self.variable_name:
context[self.variable_name] = value
return value
@ -403,7 +404,7 @@ def cycle(parser, token):
the loop::
{% for o in some_list %}
<tr class="{% cycle row1,row2 %}">
<tr class="{% cycle 'row1' 'row2' %}">
...
</tr>
{% endfor %}
@ -411,16 +412,17 @@ def cycle(parser, token):
Outside of a loop, give the values a unique name the first time you call
it, then use that name each sucessive time through::
<tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr>
<tr class="{% cycle 'row1' 'row2' 'row3' as rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
You can use any number of values, seperated by commas. Make sure not to
put spaces between the values -- only commas.
You can use any number of values, seperated by spaces. Commas can also
be used to separate values; if a comma is used, the cycle values are
interpreted as literal strings.
"""
# Note: This returns the exact same node on each {% cycle name %} call; that
# is, the node object returned from {% cycle a,b,c as name %} and the one
# is, the node object returned from {% cycle a b c as name %} and the one
# returned from {% cycle name %} are the exact same object. This shouldn't
# cause problems (heh), but if it does, now you know.
#
@ -429,40 +431,34 @@ def cycle(parser, token):
# a global variable, which would make cycle names have to be unique across
# *all* templates.
args = token.contents.split()
args = token.split_contents()
if len(args) < 2:
raise TemplateSyntaxError("'Cycle' statement requires at least two arguments")
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")
elif len(args) == 2 and "," in args[1]:
# {% cycle a,b,c %}
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
return CycleNode(cyclevars)
# {% cycle name %}
if ',' in args[1]:
# Backwards compatibility: {% cycle a,b %} or {% cycle a,b as foo %}
# case.
args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]
elif len(args) == 2:
if len(args) == 2:
# {% cycle foo %} case
name = args[1]
if not hasattr(parser, '_namedCycleNodes'):
raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name)
if name not in parser._namedCycleNodes:
if not name in parser._namedCycleNodes:
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes[name]
elif len(args) == 4:
# {% cycle a,b,c as name %}
if args[2] != 'as':
raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
name = args[3]
node = CycleNode(cyclevars, name)
if len(args) > 4 and args[-2] == 'as':
name = args[-1]
node = CycleNode(args[1:-2], name)
if not hasattr(parser, '_namedCycleNodes'):
parser._namedCycleNodes = {}
parser._namedCycleNodes[name] = node
return node
else:
raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
node = CycleNode(args[1:])
return node
cycle = register.tag(cycle)
def debug(parser, token):

View File

@ -366,25 +366,36 @@ Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
cycle
~~~~~
Cycle among the given strings each time this tag is encountered.
**Changed in Django development version**
Cycle among the given strings or variables each time this tag is encountered.
Within a loop, cycles among the given strings each time through the loop::
Within a loop, cycles among the given strings/variables each time through the
loop::
{% for o in some_list %}
<tr class="{% cycle row1,row2 %}">
<tr class="{% cycle 'row1' 'row2' rowvar %}">
...
</tr>
{% endfor %}
Outside of a loop, give the values a unique name the first time you call it,
then use that name each successive time through::
<tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr>
<tr class="{% cycle 'row1' 'row2' rowvar as rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
You can use any number of values, separated by commas. Make sure not to put
spaces between the values -- only commas.
You can use any number of values, separated by spaces. Values enclosed in
single (') or double quotes (") are treated as string literals, while values
without quotes are assumed to refer to context variables.
You can also separate values with commas::
{% cycle row1,row2,row3 %}
In this syntax, each value will be interpreted as literal text. The
comma-based syntax exists for backwards-compatibility, and should not be
used for new projects.
debug
~~~~~

View File

@ -306,6 +306,14 @@ class Templates(unittest.TestCase):
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),
'cycle09': ("{% for i in test %}{% cycle a,b %}{{ i }},{% endfor %}", {'test': range(5)}, 'a0,b1,a2,b3,a4,'),
# New format:
'cycle10': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}", {}, 'ab'),
'cycle11': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}", {}, 'abc'),
'cycle12': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, 'abca'),
'cycle13': ("{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}", {'test': range(5)}, 'a0,b1,a2,b3,a4,'),
'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'),
'cycle13': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'),
### EXCEPTIONS ############################################################