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 mptt.templatetags.mptt_tags import RecurseTreeNode, cache_tree_children
7 from django.utils.translation import ugettext as _
10 register = template.Library()
13 class RecurseNavigationNode(RecurseTreeNode):
14 def __init__(self, template_nodes, instance_var, key):
15 self.template_nodes = template_nodes
16 self.instance_var = instance_var
19 def _render_node(self, context, item, request):
23 # loosely based on django.template.defaulttags.ForNode.render
24 children = item.get_children()
25 parentloop = context['navloop']
26 loop_dict = context['navloop'] = {'parentloop':parentloop}
27 len_items = len(children)
28 for i, child in enumerate(children):
29 context['item'] = child
30 loop_dict['counter0'] = i
31 loop_dict['counter'] = i + 1
32 loop_dict['revcounter'] = len_items - i
33 loop_dict['revcounter0'] = len_items - i - 1
34 loop_dict['first'] = (i == 0)
35 loop_dict['last'] = (i == len_items - 1)
36 bits.append(self._render_node(context, child, request))
37 context['navloop'] = context['navloop']['parentloop']
38 context['item'] = item
39 context['children'] = mark_safe(u''.join(bits))
40 context['active'] = item.is_active(request)
41 context['active_descendants'] = item.has_active_descendants(request)
42 rendered = self.template_nodes.render(context)
46 def render(self, context):
48 request = context['request']
52 instance = self.instance_var.resolve(context)
55 items = instance.navigation[self.key]
57 return settings.TEMPLATE_STRING_IF_INVALID
61 # loosely based on django.template.defaulttags.ForNode.render
62 # This is a repetition of the stuff that happens above. We should eliminate that somehow.
63 loop_dict = context['navloop'] = {'parentloop':{}}
64 len_items = len(items)
65 for i, item in enumerate(items):
66 loop_dict['counter0'] = i
67 loop_dict['counter'] = i + 1
68 loop_dict['revcounter'] = len_items - i
69 loop_dict['revcounter0'] = len_items - i - 1
70 loop_dict['first'] = (i == 0)
71 loop_dict['last'] = (i == len_items - 1)
72 bits.append(self._render_node(context, item, request))
78 def recursenavigation(parser, token):
80 Based on django-mptt's recursetree templatetag. In addition to {{ item }} and {{ children }},
81 sets {{ active }}, {{ active_descendants }}, {{ navloop.counter }}, {{ navloop.counter0 }},
82 {{ navloop.revcounter }}, {{ navloop.revcounter0 }}, {{ navloop.first }}, {{ navloop.last }},
83 and {{ navloop.parentloop }} in the context.
85 Note that the tag takes one variable, which is a Node instance.
89 {% recursenavigation node main %}
90 <li{% if active %} class='active'{% endif %}>
92 {% if navigation.get_children %}
98 {% endrecursenavigation %}
101 bits = token.contents.split()
103 raise template.TemplateSyntaxError(_('%s tag requires two arguments: a node and a navigation section name') % bits[0])
105 instance_var = parser.compile_filter(bits[1])
108 template_nodes = parser.parse(('endrecursenavigation',))
109 parser.delete_first_token()
111 return RecurseNavigationNode(template_nodes, instance_var, key)
115 def has_navigation(node, key=None):
117 nav = node.navigation
119 if key in nav and bool(node.navigation[key]):
121 elif key not in node.navigation:
123 return bool(node.navigation)
129 def navigation_host(node, key):
131 return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node
133 if settings.TEMPLATE_DEBUG: