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 RecurseNavigationMarker(object):
16 class RecurseNavigationNode(template.Node):
17 def __init__(self, template_nodes, instance_var, key):
18 self.template_nodes = template_nodes
19 self.instance_var = instance_var
22 def _render_items(self, items, context, request):
26 if 'navloop' in context:
27 parentloop = context['navloop']
32 depth = items[0].get_level()
33 len_items = len(items)
35 loop_dict = context['navloop'] = {
36 'parentloop': parentloop,
43 for i, item in enumerate(items):
44 # First set context variables.
45 loop_dict['counter0'] = i
46 loop_dict['counter'] = i + 1
47 loop_dict['revcounter'] = len_items - i
48 loop_dict['revcounter0'] = len_items - i - 1
49 loop_dict['first'] = (i == 0)
50 loop_dict['last'] = (i == len_items - 1)
52 # Set on loop_dict and context for backwards-compatibility.
53 # Eventually only allow access through the loop_dict.
54 loop_dict['item'] = context['item'] = item
55 loop_dict['active'] = context['active'] = item.is_active(request)
56 loop_dict['active_descendants'] = context['active_descendants'] = item.has_active_descendants(request)
58 # Then render the nodelist bit by bit.
59 for node in self.template_nodes:
60 if isinstance(node, RecurseNavigationMarker):
62 children = items.get_children()
63 bits.append(self._render_items(children, context, request))
64 elif isinstance(node, template.VariableNode) and node.filter_expression.var.lookups == (u'children',):
65 # Then recurse! This is here for backwards-compatibility only.
66 children = items.get_children()
67 bits.append(self._render_items(children, context, request))
69 bits.append(node.render(context))
73 def render(self, context):
75 request = context['request']
79 instance = self.instance_var.resolve(context)
82 items = instance.navigation[self.key]
84 return settings.TEMPLATE_STRING_IF_INVALID
86 return self._render_items(items, context, request)
90 def recursenavigation(parser, token):
92 Based on django-mptt's recursetree templatetag. In addition to {{ item }} and {{ children }},
93 sets {{ active }}, {{ active_descendants }}, {{ navloop.counter }}, {{ navloop.counter0 }},
94 {{ navloop.revcounter }}, {{ navloop.revcounter0 }}, {{ navloop.first }}, {{ navloop.last }},
95 and {{ navloop.parentloop }} in the context.
97 Note that the tag takes two variables: a Node instance and the key of the navigation to
102 {% recursenavigation node main %}
103 <li{% if active %} class='active'{% endif %}>
105 {% if item.get_children %}
111 {% endrecursenavigation %}
114 bits = token.contents.split()
116 raise template.TemplateSyntaxError(_('%s tag requires two arguments: a node and a navigation section name') % bits[0])
118 instance_var = parser.compile_filter(bits[1])
121 template_nodes = parser.parse(('recurse', 'endrecursenavigation',))
123 token = parser.next_token()
124 if token.contents == 'recurse':
125 template_nodes.append(RecurseNavigationMarker())
126 template_nodes.extend(parser.parse(('endrecursenavigation')))
127 parser.delete_first_token()
129 return RecurseNavigationNode(template_nodes, instance_var, key)
133 def has_navigation(node, key=None):
135 nav = node.navigation
137 if key in nav and bool(node.navigation[key]):
139 elif key not in node.navigation:
141 return bool(node.navigation)
147 def navigation_host(node, key):
149 return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node
151 if settings.TEMPLATE_DEBUG: