1 from django import template
2 from django.conf import settings
3 from django.utils.safestring import mark_safe
4 from philo.contrib.shipherd.models import Navigation
5 from philo.models import Node
6 from django.utils.translation import ugettext as _
9 register = template.Library()
12 class LazyNavigationRecurser(object):
13 def __init__(self, template_nodes, items, context, request):
14 self.template_nodes = template_nodes
16 self.context = context
17 self.request = request
21 context = self.context
22 request = self.request
27 if 'navloop' in context:
28 parentloop = context['navloop']
33 depth = items[0].get_level()
34 len_items = len(items)
36 loop_dict = context['navloop'] = {
37 'parentloop': parentloop,
44 for i, item in enumerate(items):
45 # First set context variables.
46 loop_dict['counter0'] = i
47 loop_dict['counter'] = i + 1
48 loop_dict['revcounter'] = len_items - i
49 loop_dict['revcounter0'] = len_items - i - 1
50 loop_dict['first'] = (i == 0)
51 loop_dict['last'] = (i == len_items - 1)
53 # Set on loop_dict and context for backwards-compatibility.
54 # Eventually only allow access through the loop_dict.
55 loop_dict['active'] = context['active'] = item.is_active(request)
56 loop_dict['active_descendants'] = context['active_descendants'] = item.has_active_descendants(request)
58 # Set these directly in the context for easy access.
59 context['item'] = item
60 context['children'] = self.__class__(self.template_nodes, item.get_children(), context, request)
62 # Then render the nodelist bit by bit.
63 for node in self.template_nodes:
64 bits.append(node.render(context))
69 class RecurseNavigationNode(template.Node):
70 def __init__(self, template_nodes, instance_var, key):
71 self.template_nodes = template_nodes
72 self.instance_var = instance_var
75 def render(self, context):
77 request = context['request']
81 instance = self.instance_var.resolve(context)
84 items = instance.navigation[self.key]
86 return settings.TEMPLATE_STRING_IF_INVALID
88 return LazyNavigationRecurser(self.template_nodes, items, context, request)()
92 def recursenavigation(parser, token):
94 The recursenavigation templatetag takes two arguments:
95 - the node for which the navigation should be found
96 - the navigation's key.
98 It will then recursively loop over each item in the navigation and render the template
99 chunk within the block. recursenavigation sets the following variables in the context:
101 ============================== ================================================
103 ============================== ================================================
104 ``navloop.depth`` The current depth of the loop (1 is the top level)
105 ``navloop.depth0`` The current depth of the loop (0 is the top level)
106 ``navloop.counter`` The current iteration of the current level(1-indexed)
107 ``navloop.counter0`` The current iteration of the current level(0-indexed)
108 ``navloop.first`` True if this is the first time through the current level
109 ``navloop.last`` True if this is the last time through the current level
110 ``navloop.parentloop`` This is the loop one level "above" the current one
111 ============================== ================================================
112 ``item`` The current item in the loop (a NavigationItem instance)
113 ``children`` If accessed, performs the next level of recursion.
114 ``navloop.active`` True if the item is active for this request
115 ``navloop.active_descendants`` True if the item has active descendants for this request
116 ============================== ================================================
120 {% recursenavigation node main %}
121 <li{% if navloop.active %} class='active'{% endif %}>
122 {{ navloop.item.text }}
123 {% if item.get_children %}
129 {% endrecursenavigation %}
132 bits = token.contents.split()
134 raise template.TemplateSyntaxError(_('%s tag requires two arguments: a node and a navigation section name') % bits[0])
136 instance_var = parser.compile_filter(bits[1])
139 template_nodes = parser.parse(('recurse', 'endrecursenavigation',))
141 token = parser.next_token()
142 if token.contents == 'recurse':
143 template_nodes.append(RecurseNavigationMarker())
144 template_nodes.extend(parser.parse(('endrecursenavigation')))
145 parser.delete_first_token()
147 return RecurseNavigationNode(template_nodes, instance_var, key)
151 def has_navigation(node, key=None):
153 nav = node.navigation
155 if key in nav and bool(node.navigation[key]):
157 elif key not in node.navigation:
159 return bool(node.navigation)
165 def navigation_host(node, key):
167 return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node
169 if settings.TEMPLATE_DEBUG: