X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/20db685ec49851c2870bd8cabcc97f75c5acc9cd..92e8e96c8d6814f3bd93ecd82d8da2ccb43e13c4:/contrib/shipherd/templatetags/shipherd.py diff --git a/contrib/shipherd/templatetags/shipherd.py b/contrib/shipherd/templatetags/shipherd.py index 83e98a2..b05ff0f 100644 --- a/contrib/shipherd/templatetags/shipherd.py +++ b/contrib/shipherd/templatetags/shipherd.py @@ -1,47 +1,81 @@ -from django import template +from django import template, VERSION as django_version from django.conf import settings from django.utils.safestring import mark_safe from philo.contrib.shipherd.models import Navigation from philo.models import Node -from mptt.templatetags.mptt_tags import RecurseTreeNode, cache_tree_children +from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ register = template.Library() -class RecurseNavigationNode(RecurseTreeNode): - def __init__(self, template_nodes, instance_var, key): +class LazyNavigationRecurser(object): + def __init__(self, template_nodes, items, context, request): self.template_nodes = template_nodes - self.instance_var = instance_var - self.key = key + self.items = items + self.context = context + self.request = request - def _render_node(self, context, item, request): - bits = [] + def __call__(self): + items = self.items + context = self.context + request = self.request + + if not items: + return '' + + if 'navloop' in context: + parentloop = context['navloop'] + else: + parentloop = {} context.push() - # loosely based on django.template.defaulttags.ForNode.render - children = item.get_children() - parentloop = context['navloop'] - loop_dict = context['navloop'] = {'parentloop':parentloop} - len_items = len(children) - for i, child in enumerate(children): - context['item'] = child + depth = items[0].get_level() + len_items = len(items) + + loop_dict = context['navloop'] = { + 'parentloop': parentloop, + 'depth': depth + 1, + 'depth0': depth + } + + bits = [] + + for i, item in enumerate(items): + # First set context variables. loop_dict['counter0'] = i loop_dict['counter'] = i + 1 loop_dict['revcounter'] = len_items - i loop_dict['revcounter0'] = len_items - i - 1 loop_dict['first'] = (i == 0) loop_dict['last'] = (i == len_items - 1) - bits.append(self._render_node(context, child, request)) - context['navloop'] = context['navloop']['parentloop'] - context['item'] = item - context['children'] = mark_safe(u''.join(bits)) - context['active'] = item.is_active(request) - context['active_descendants'] = item.has_active_descendants(request) - rendered = self.template_nodes.render(context) + + # Set on loop_dict and context for backwards-compatibility. + # Eventually only allow access through the loop_dict. + loop_dict['active'] = context['active'] = item.is_active(request) + loop_dict['active_descendants'] = context['active_descendants'] = item.has_active_descendants(request) + + # Set these directly in the context for easy access. + context['item'] = item + context['children'] = self.__class__(self.template_nodes, item.get_children(), context, request) + + # Django 1.2.X compatibility - a lazy recurser will not be called if accessed as a template variable. + if django_version < (1,3): + context['children'] = context['children']() + + # Then render the nodelist bit by bit. + for node in self.template_nodes: + bits.append(node.render(context)) context.pop() - return rendered + return mark_safe(''.join(bits)) + + +class RecurseNavigationNode(template.Node): + def __init__(self, template_nodes, instance_var, key_var): + self.template_nodes = template_nodes + self.instance_var = instance_var + self.key_var = key_var def render(self, context): try: @@ -50,47 +84,57 @@ class RecurseNavigationNode(RecurseTreeNode): return '' instance = self.instance_var.resolve(context) + key = self.key_var.resolve(context) + + # Fall back on old behavior if the key doesn't seem to be a variable. + if not key: + token = self.key_var.token + if token[0] not in ["'", '"'] and '.' not in token: + key = token + else: + return settings.TEMPLATE_STRING_IF_INVALID try: - items = instance.navigation[self.key] + items = instance.navigation[key] except: return settings.TEMPLATE_STRING_IF_INVALID - bits = [] - - # loosely based on django.template.defaulttags.ForNode.render - # This is a repetition of the stuff that happens above. We should eliminate that somehow. - loop_dict = context['navloop'] = {'parentloop':{}} - len_items = len(items) - for i, item in enumerate(items): - loop_dict['counter0'] = i - loop_dict['counter'] = i + 1 - loop_dict['revcounter'] = len_items - i - loop_dict['revcounter0'] = len_items - i - 1 - loop_dict['first'] = (i == 0) - loop_dict['last'] = (i == len_items - 1) - bits.append(self._render_node(context, item, request)) - - return ''.join(bits) + return LazyNavigationRecurser(self.template_nodes, items, context, request)() @register.tag def recursenavigation(parser, token): """ - Based on django-mptt's recursetree templatetag. In addition to {{ item }} and {{ children }}, - sets {{ active }}, {{ active_descendants }}, {{ navloop.counter }}, {{ navloop.counter0 }}, - {{ navloop.revcounter }}, {{ navloop.revcounter0 }}, {{ navloop.first }}, {{ navloop.last }}, - and {{ navloop.parentloop }} in the context. + The recursenavigation templatetag takes two arguments: + - the node for which the navigation should be found + - the navigation's key. + + It will then recursively loop over each item in the navigation and render the template + chunk within the block. recursenavigation sets the following variables in the context: - Note that the tag takes two variables: a Node instance and the key of the navigation to - be recursed. + ============================== ================================================ + Variable Description + ============================== ================================================ + ``navloop.depth`` The current depth of the loop (1 is the top level) + ``navloop.depth0`` The current depth of the loop (0 is the top level) + ``navloop.counter`` The current iteration of the current level(1-indexed) + ``navloop.counter0`` The current iteration of the current level(0-indexed) + ``navloop.first`` True if this is the first time through the current level + ``navloop.last`` True if this is the last time through the current level + ``navloop.parentloop`` This is the loop one level "above" the current one + ============================== ================================================ + ``item`` The current item in the loop (a NavigationItem instance) + ``children`` If accessed, performs the next level of recursion. + ``navloop.active`` True if the item is active for this request + ``navloop.active_descendants`` True if the item has active descendants for this request + ============================== ================================================ - Usage: + Example: