X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/0d560fdc9e0351ebe039dcc9d9d14b6b560ba00c..2b21f17548ca9c2b1be8c3047ad86370c95fcb9e:/contrib/shipherd/templatetags/shipherd.py diff --git a/contrib/shipherd/templatetags/shipherd.py b/contrib/shipherd/templatetags/shipherd.py index fec700b..af7f05f 100644 --- a/contrib/shipherd/templatetags/shipherd.py +++ b/contrib/shipherd/templatetags/shipherd.py @@ -2,29 +2,73 @@ from django import template from django.conf import settings from django.utils.safestring import mark_safe from philo.contrib.shipherd.models import Navigation -from mptt.templatetags.mptt_tags import RecurseTreeNode, cache_tree_children +from philo.models import Node +from django.utils.translation import ugettext as _ register = template.Library() -class RecurseNavigationNode(RecurseTreeNode): - def __init__(self, template_nodes, instance_var): +class RecurseNavigationMarker(object): + pass + + +class RecurseNavigationNode(template.Node): + def __init__(self, template_nodes, instance_var, key): self.template_nodes = template_nodes self.instance_var = instance_var + self.key = key - def _render_node(self, context, node, request): - bits = [] + def _render_items(self, items, context, request): + if not items: + return '' + + if 'navloop' in context: + parentloop = context['navloop'] + else: + parentloop = {} context.push() - for child in node.get_children(): - context['node'] = child - bits.append(self._render_node(context, child, request)) - context['node'] = node - context['children'] = mark_safe(u''.join(bits)) - context['active'] = node.is_active(request) - rendered = self.template_nodes.render(context) + + 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) + + # Set on loop_dict and context for backwards-compatibility. + # Eventually only allow access through the loop_dict. + loop_dict['item'] = context['item'] = item + loop_dict['active'] = context['active'] = item.is_active(request) + loop_dict['active_descendants'] = context['active_descendants'] = item.has_active_descendants(request) + + # Then render the nodelist bit by bit. + for node in self.template_nodes: + if isinstance(node, RecurseNavigationMarker): + # Then recurse! + children = items.get_children() + bits.append(self._render_items(children, context, request)) + elif isinstance(node, template.VariableNode) and node.filter_expression.var.lookups == (u'children',): + # Then recurse! This is here for backwards-compatibility only. + children = items.get_children() + bits.append(self._render_items(children, context, request)) + else: + bits.append(node.render(context)) context.pop() - return rendered + return ''.join(bits) def render(self, context): try: @@ -33,27 +77,34 @@ class RecurseNavigationNode(RecurseTreeNode): return '' instance = self.instance_var.resolve(context) - roots = cache_tree_children(Navigation.objects.closest_navigation(instance)) - bits = [self._render_node(context, node, request) for node in roots] - return ''.join(bits) + + try: + items = instance.navigation[self.key] + except: + return settings.TEMPLATE_STRING_IF_INVALID + + return self._render_items(items, context, request) @register.tag def recursenavigation(parser, token): """ - Based on django-mptt's recursetree templatetag. In addition to {{ node }} and {{ children }}, - sets {{ active }} in the context. + 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. - Note that the tag takes one variable, navigation, which is a Navigation instance. + Note that the tag takes two variables: a Node instance and the key of the navigation to + be recursed. Usage: """ bits = token.contents.split() - if len(bits) != 2: - raise template.TemplateSyntaxError(_('%s tag requires an instance') % bits[0]) + if len(bits) != 3: + raise template.TemplateSyntaxError(_('%s tag requires two arguments: a node and a navigation section name') % bits[0]) - instance_var = template.Variable(bits[1]) + instance_var = parser.compile_filter(bits[1]) + key = bits[2] - template_nodes = parser.parse(('endrecursenavigation',)) - parser.delete_first_token() + template_nodes = parser.parse(('recurse', 'endrecursenavigation',)) - return RecurseNavigationNode(template_nodes, instance_var) \ No newline at end of file + token = parser.next_token() + if token.contents == 'recurse': + template_nodes.append(RecurseNavigationMarker()) + template_nodes.extend(parser.parse(('endrecursenavigation'))) + parser.delete_first_token() + + return RecurseNavigationNode(template_nodes, instance_var, key) + + +@register.filter +def has_navigation(node, key=None): + try: + nav = node.navigation + if key is not None: + if key in nav and bool(node.navigation[key]): + return True + elif key not in node.navigation: + return False + return bool(node.navigation) + except: + return False + + +@register.filter +def navigation_host(node, key): + try: + return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node + except: + if settings.TEMPLATE_DEBUG: + raise + return node \ No newline at end of file