Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #208 -- Modernized the syntax of the cycle tag to allow for spa…

…ces 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
  • Loading branch information...
commit 09145d2e5f1445d59d0c121394b78ec5ed196056 1 parent a2ce766
@freakboy3742 freakboy3742 authored
Showing with 63 additions and 48 deletions.
  1. +1 −1  django/contrib/admin/templates/admin/change_list_results.html
  2. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_day.html
  3. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_homepage.html
  4. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_main.html
  5. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_month.html
  6. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_year.html
  7. +1 −1  django/contrib/databrowse/templates/databrowse/choice_detail.html
  8. +1 −1  django/contrib/databrowse/templates/databrowse/choice_list.html
  9. +1 −1  django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
  10. +1 −1  django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
  11. +1 −1  django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
  12. +1 −1  django/contrib/databrowse/templates/databrowse/homepage.html
  13. +1 −1  django/contrib/databrowse/templates/databrowse/model_detail.html
  14. +2 −2 django/contrib/databrowse/templates/databrowse/object_detail.html
  15. +22 −26 django/template/defaulttags.py
  16. +18 −7 docs/templates.txt
  17. +8 −0 tests/regressiontests/templates/tests.py
View
2  django/contrib/admin/templates/admin/change_list_results.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/calendar_day.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/calendar_homepage.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/calendar_main.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/calendar_month.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/calendar_year.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/choice_detail.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/choice_list.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/homepage.html
@@ -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
2  django/contrib/databrowse/templates/databrowse/model_detail.html
@@ -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
4 django/contrib/databrowse/templates/databrowse/object_detail.html
@@ -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
48 django/template/defaulttags.py
@@ -30,6 +30,7 @@ def __init__(self, cyclevars, variable_name=None):
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
25 docs/templates.txt
@@ -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
8 tests/regressiontests/templates/tests.py
@@ -306,6 +306,14 @@ def test_templates(self):
'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 ############################################################

0 comments on commit 09145d2

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