Ticket #5865: cycle.diff

File cycle.diff, 6.7 KB (added by munhitsu, 7 years ago)

v2

  • django/template/defaulttags.py

     
    3939
    4040class CycleNode(Node):
    4141    def __init__(self, cyclevars, variable_name=None):
    42         self.cycle_iter = itertools_cycle(cyclevars)
     42        self.cycle_iter = None
    4343        self.variable_name = variable_name
     44        self.cyclevars = cyclevars
     45        self.resolve = None
     46        self.collection = None
    4447
     48    def render_init(self,context):
     49        if len(self.cyclevars) == 1:
     50        #startning from syntax check
     51            if not context.has_key(self.cyclevars[0]):
     52                raise TemplateSyntaxError("Named cycle '%s' does not exist" % self.cyclevars[0])
     53        try:
     54            i = iter(Variable(self.cyclevars[0]).resolve(context))
     55            isiterable = True
     56        except TypeError:
     57            isiterable = False
     58        except NameError:
     59            isiterable = False
     60        if len(self.cyclevars) == 1 and context.has_key(self.cyclevars[0]) and isiterable:
     61            #the {% cycle colors %} case
     62            self.resolve = False
     63            self.collection = Variable(self.cyclevars[0]).resolve(context)
     64            self.cycle_iter = itertools_cycle(self.collection)
     65        else:
     66            self.resolve = True
     67            self.collection = self.cyclevars
     68            self.cycle_iter = itertools_cycle(self.collection)
     69        context['cycle'] = {
     70            # cycle internals
     71            'collection': self.collection,
     72            'name':self.variable_name,
     73            'value':None,
     74        }
     75       
     76    def __repr__(self):
     77        return "<Cycle Node: cycle_iter %s, variable_name %s, cyclevars %s, resolve %s, collection %s>" % \
     78            (self.cycle_iter, self.variable_name, self.cyclevars, self.resolve, self.collection)
     79   
    4580    def render(self, context):
    46         value = self.cycle_iter.next()
    47         value = Variable(value).resolve(context)
     81        if self.collection == None:
     82            #first execution of render, so finally we will know the context
     83            self.render_init(context)
     84        #all is initiated
     85        if self.resolve:
     86            value = self.cycle_iter.next()
     87            try:
     88                value = Variable(value).resolve(context)
     89            except NameError:
     90                pass
     91        else:
     92            value = self.cycle_iter.next()
     93
    4894        if self.variable_name:
    4995            context[self.variable_name] = value
    50         return value
     96        context['cycle'] = {
     97            # cycle internals
     98            'collection': self.collection,
     99            'name':self.variable_name,
     100            'value':value,
     101        }
     102        return value       
    51103
    52104class DebugNode(Node):
    53105    def render(self, context):
     
    456508
    457509    You can use any number of values, seperated by spaces. Commas can also
    458510    be used to separate values; if a comma is used, the cycle values are
    459     interpreted as literal strings.
     511    interpreted as literal strings.
     512   
     513    Additionally when you pass a single value, the cycle tag resolves it from
     514    context and than iterates over context value::
     515
     516        {'colors': ['red', 'blue', 'green']}
     517
     518        {% for row in mydata %}
     519        <tr class="{% cycle colors %}">...</tr>
     520        {% endfor %}
    460521    """
    461522
    462523    # Note: This returns the exact same node on each {% cycle name %} call;
     
    480541        args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]
    481542
    482543    if len(args) == 2:
    483         # {% cycle foo %} case.
     544        #two cases:
     545        # {% cycle foo %}
     546        # {% cycle foos %} where foos are an iterable type defined in context
    484547        name = args[1]
    485548        if not hasattr(parser, '_namedCycleNodes'):
    486             raise TemplateSyntaxError("No named cycles in template."
    487                                       " '%s' is not defined" % name)
    488         if not name in parser._namedCycleNodes:
    489             raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
    490         return parser._namedCycleNodes[name]
     549            #if not a table than we will throw an exception at rendering
     550            parser._namedCycleNodes = {}
     551            node = CycleNode(args[1:2])
     552            parser._namedCycleNodes[name] = node
     553        else:
     554            if not name in parser._namedCycleNodes:
     555                raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
     556            node = parser._namedCycleNodes[name]
     557        return node
    491558
    492     if len(args) > 4 and args[-2] == 'as':
     559    if len(args) >= 4 and args[-2] == 'as':
    493560        name = args[-1]
    494561        node = CycleNode(args[1:-2], name)
    495562        if not hasattr(parser, '_namedCycleNodes'):
  • tests/regressiontests/templates/tests.py

     
    394394            'cycle13': ("{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}", {'test': range(5)}, 'a0,b1,a2,b3,a4,'),
    395395            'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'),
    396396            'cycle13': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'),
     397            # List format
     398            'cycle20': ("{% cycle colors %}", {'colors': 'r'}, 'r'),
     399            'cycle21': ("{% cycle colors %}{% cycle colors %}", {'colors': ['r', 'g', 'b']}, 'rg'),
     400#            'cycle22': ("{% cycle colors %}{% cycle colors %}", {'colors': {'r': 1, 'g': 2}}, 'rg'), not reliable test
     401            'cycle23': ("{% cycle colors %}{% cycle colors %}{% cycle colors %}", {'colors': ['r', 'g', 'b']}, 'rgb'),
     402            'cycle24': ("{% cycle colors %}{% cycle colors %}{% cycle colors %}{% cycle colors %}", {'colors': ['r', 'g', 'b']}, 'rgbr'),
     403            'cycle25': ("{% cycle colors as color %}{% cycle color %}", {'colors': ['r', 'g', 'b']}, 'rg'),
     404            'cycle26': ("{% cycle colors as color %}{% cycle color %}{% cycle color %}", {'colors': ['r', 'g', 'b']}, 'rgb'),
     405            'cycle27': ("{% cycle colors as color %}{% cycle color %}{% cycle color %}{% cycle color %}", {'colors': ['r', 'g', 'b']}, 'rgbr'),
     406            'cycle28': ("{% for i in test %}{% cycle colors %}{{ cycle.value }}{{ i }},{% endfor %}", {'test': range(5),'colors': ['r', 'g', 'b']}, 'rr0,gg1,bb2,rr3,gg4,'),
     407            'cycle29': ("{% for i in test %}{% cycle colors %}{% cycle colors %}{{ i }},{% endfor %}", {'test': range(5),'colors': ['r', 'g', 'b']}, 'rg0,br1,gb2,rg3,br4,'),
    397408
    398409            ### EXCEPTIONS ############################################################
    399410
Back to Top