1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

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> </thead>
<tbody> <tbody>
{% for result in results %} {% 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 %} {% endfor %}
</tbody> </tbody>
</table> </table>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in object_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for field in field_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for year in date_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in object_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for month in date_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in object_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for choice in field.choices %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in object_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for field in field_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -10,7 +10,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in object_list %} {% 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 %} {% endfor %}
</ul> </ul>

View File

@ -7,7 +7,7 @@
{% block content %} {% block content %}
{% for model in model_list %} {% 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> <h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
<p> <p>
{% for object in model.sample_objects %} {% for object in model.sample_objects %}

View File

@ -12,7 +12,7 @@
<ul class="objectlist"> <ul class="objectlist">
{% for object in model.objects %} {% 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 %} {% endfor %}
</ul> </ul>

View File

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

View File

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

View File

@ -366,25 +366,36 @@ Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
cycle 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 %} {% for o in some_list %}
<tr class="{% cycle row1,row2 %}"> <tr class="{% cycle 'row1' 'row2' rowvar %}">
... ...
</tr> </tr>
{% endfor %} {% endfor %}
Outside of a loop, give the values a unique name the first time you call it, Outside of a loop, give the values a unique name the first time you call it,
then use that name each successive time through:: 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>
<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 You can use any number of values, separated by spaces. Values enclosed in
spaces between the values -- only commas. 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 debug
~~~~~ ~~~~~

View File

@ -306,6 +306,14 @@ class Templates(unittest.TestCase):
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError), 'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, 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'), '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 ############################################################ ### EXCEPTIONS ############################################################