class RecurseNavigationNode(template.Node):
- def __init__(self, template_nodes, instance_var, key):
+ def __init__(self, template_nodes, instance_var, key_var):
self.template_nodes = template_nodes
self.instance_var = instance_var
- self.key = key
+ self.key_var = key_var
def render(self, context):
try:
return ''
instance = self.instance_var.resolve(context)
+ 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[self.key]
+ items = instance.navigation[key]
except:
return settings.TEMPLATE_STRING_IF_INVALID
@register.tag
def recursenavigation(parser, token):
"""
- The recursenavigation templatetag takes two arguments:
- - the node for which the navigation should be found
- - the navigation's key.
+ The :ttag:`recursenavigation` templatetag takes two arguments:
+
+ * the :class:`.Node` for which the :class:`.Navigation` should be found
+ * the :class:`.Navigation`'s :attr:`~.Navigation.key`.
- 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:
+ It will then recursively loop over each :class:`.NavigationItem` in the :class:`.Navigation` and render the template
+ chunk within the block. :ttag:`recursenavigation` sets the following variables in the context:
============================== ================================================
Variable Description
``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)
+
+ ``item`` The current item in the loop (a :class:`.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:
+ Example::
+
<ul>
- {% recursenavigation node main %}
- <li{% if navloop.active %} class='active'{% endif %}>
- {{ navloop.item.text }}
- {% if item.get_children %}
- <ul>
- {{ children }}
- </ul>
- {% endif %}
- </li>
- {% endrecursenavigation %}
+ {% recursenavigation node "main" %}
+ <li{% if navloop.active %} class='active'{% endif %}>
+ <a href="{{ item.get_target_url }}">{{ item.text }}</a>
+ {% if item.get_children %}
+ <ul>
+ {{ children }}
+ </ul>
+ {% endif %}
+ </li>
+ {% endrecursenavigation %}
</ul>
+
+ .. note:: {% recursenavigation %} requires that the current :class:`HttpRequest` be present in the context as ``request``. The simplest way to do this is with the `request context processor`_. Simply make sure that ``django.core.context_processors.request`` is included in your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
+
+ .. _request context processor: https://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-request
+
"""
bits = token.contents.split()
if len(bits) != 3:
raise template.TemplateSyntaxError(_('%s tag requires two arguments: a node and a navigation section name') % bits[0])
instance_var = parser.compile_filter(bits[1])
- key = bits[2]
-
- template_nodes = parser.parse(('recurse', 'endrecursenavigation',))
-
- token = parser.next_token()
- if token.contents == 'recurse':
- template_nodes.append(RecurseNavigationMarker())
- template_nodes.extend(parser.parse(('endrecursenavigation')))
- parser.delete_first_token()
+ key_var = parser.compile_filter(bits[2])
- return RecurseNavigationNode(template_nodes, instance_var, key)
+ template_nodes = parser.parse(('endrecursenavigation',))
+ token = parser.delete_first_token()
+ return RecurseNavigationNode(template_nodes, instance_var, key_var)
@register.filter
def has_navigation(node, key=None):
+ """Returns ``True`` if the node has a :class:`.Navigation` with the given key and ``False`` otherwise. If ``key`` is ``None``, returns whether the node has any :class:`.Navigation`\ s at all."""
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)
+ return bool(node.navigation[key])
except:
return False
@register.filter
def navigation_host(node, key):
+ """Returns the :class:`.Node` which hosts the :class:`.Navigation` which ``node`` has inherited for ``key``. Returns ``node`` if any exceptions are encountered."""
try:
- return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node
+ return node.navigation[key].node
except:
return node
\ No newline at end of file