X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/0d560fdc9e0351ebe039dcc9d9d14b6b560ba00c..92e8e96c8d6814f3bd93ecd82d8da2ccb43e13c4:/contrib/shipherd/templatetags/shipherd.py diff --git a/contrib/shipherd/templatetags/shipherd.py b/contrib/shipherd/templatetags/shipherd.py index fec700b..b05ff0f 100644 --- a/contrib/shipherd/templatetags/shipherd.py +++ b/contrib/shipherd/templatetags/shipherd.py @@ -1,30 +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 mptt.templatetags.mptt_tags import RecurseTreeNode, cache_tree_children +from philo.models import Node +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): +class LazyNavigationRecurser(object): + def __init__(self, template_nodes, items, context, request): self.template_nodes = template_nodes - self.instance_var = instance_var + self.items = items + self.context = context + self.request = request - def _render_node(self, context, node, 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() - 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['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: @@ -33,25 +84,57 @@ 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) + 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[key] + except: + return settings.TEMPLATE_STRING_IF_INVALID + + return LazyNavigationRecurser(self.template_nodes, 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. + The recursenavigation templatetag takes two arguments: + - the node for which the navigation should be found + - the navigation's key. - Note that the tag takes one variable, navigation, which is a Navigation instance. + 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: - Usage: + ============================== ================================================ + 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 + ============================== ================================================ + + Example: """ 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_var = parser.compile_filter(bits[2]) template_nodes = parser.parse(('endrecursenavigation',)) - parser.delete_first_token() - - return RecurseNavigationNode(template_nodes, instance_var) \ No newline at end of file + token = parser.delete_first_token() + return RecurseNavigationNode(template_nodes, instance_var, key_var) + + +@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: + return node \ No newline at end of file