Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from django.core.urlresolvers import reverse
- from django.contrib.admin import site
- from django.template.loader import render_to_string
- from django.utils.safestring import mark_safe
- from cms.utils import get_page_from_url
- class NavigableMixin(object):
- """
- Adds a bunch of methods for generating navigation for objects.
- Using classmethods instead of regular methods as sometimes we need to generate the navigation
- when we don't have a current instance (i.e. to render a page outside the hierarchy)
- """
- # The following stubs are required for any class using this Mixin
- # The first 4 should already be supplied by any MPTT registered model
- # The last one just returns True/False depending on whether we have a hierarchical model or not
- # The 4 MPTT methods should never get called if this returns False so shouldn't need to be implemented
- def get_siblings(self, include_self):
- raise NotImplementedError
- def get_children(self):
- raise NotImplementedError
- def get_ancestors(self, ascending):
- raise NotImplementedError
- def is_root_node(self):
- raise NotImplementedError
- @classmethod
- def is_hierarchical(cls):
- raise NotImplemented
- @classmethod
- def _link(cls, navigable, current_navigable, extra_markup=''):
- """
- Takes a navigable node and the current navigable node being rendered
- and returns the correct element (span or a) with class="ancestor" or class="selected" for the node
- """
- if current_navigable:
- if navigable==current_navigable:
- # Current
- return '<span id="nav-%s" class="selected">%s%s</span>' % (navigable.name, extra_markup, navigable.title)
- elif cls.is_hierarchical() and navigable in current_navigable.get_active_ancestors(include_root=False):
- # Ancestor
- return '<a href="%s" id="nav-%s" class="ancestor">%s%s</a>' % (navigable.get_absolute_url(), navigable.name, extra_markup, navigable.title)
- # Anything Else
- return '<a href="%s" id="nav-%s">%s%s</a>' % (navigable.get_absolute_url(), navigable.name, extra_markup, navigable.title)
- @classmethod
- def nav_tree_ul(cls, nav_array=None, current_navigable=None, extra_markup=''): # TODO fix for sites that don't pass in extra_markup
- # Pass in a nested structure in the form [node, node, ...]
- # Node is either {'node': navigable_instance}
- # or {'node': navigable_instance, 'children': [...]}
- # where children is another list of nodes
- #
- # Returns: A set of nested <ul> and <li> tags as a string (missing the top outer <ul></li> pair)
- # <li>'s contain <a href's>
- # except the current navigable which is just a span
- # Any direct ancestor has the class 'selected'
- def ul(inner):
- return '<ul>%s</ul>\n' % inner
- def li(inner):
- return '<li>%s</li>\n' % inner
- def li_ancestor(inner):
- return '<li class="ancestor">%s</li>\n' % inner
- html = []
- for item in nav_array:
- if item.get('children', None):
- html_fragment = cls._link(item['node'], current_navigable)
- html_fragment += cls.nav_tree_ul(item['children'], current_navigable)
- html.append(li_ancestor(html_fragment))
- else:
- html_fragment = li(cls._link(item['node'], current_navigable))
- html.append(html_fragment)
- if cls.is_hierarchical() and nav_array and len(nav_array[0]['node'].get_ancestors())==1:
- # Add home page to top level even though it's really the parent
- html = [li(cls._link(nav_array[0]['node'].get_ancestors()[0], current_navigable))] + html
- # Don't return empty <ul>'s
- if html:
- return ul(''.join(html))
- else:
- return ''
- @classmethod
- def get_nav_tree(cls, current, nodes):
- """
- Gets the tree back from 'current' only opening up subtrees if they are on route to the current navigable but including all the items 'nodes' TODO better explanation!
- """
- result = []
- for node in nodes:
- subresult = {}
- subresult['node'] = node
- if not(node.is_leaf_node()) and (node in current.get_active_ancestors(include_root=True)):
- subresult['children'] = cls.get_nav_tree(current, node.get_active_children())
- result.append(subresult)
- return result
- def get_all_active_siblings(self):
- return self.get_siblings(include_self=True).filter(active=True, show_in_navigation=True)
- def get_active_children(self):
- return self.get_children().filter(active=True, show_in_navigation=True)
- def get_active_ancestors(self, include_root=False):
- ancestors = list(self.get_ancestors(ascending=False).filter(active=True, show_in_navigation=True))+[self]
- if include_root:
- return ancestors
- else:
- return ancestors[1:]
- def get_navigation_array(self, starting_level=0, top_tier_only=False):
- if type(self).is_hierarchical():
- if self.is_root_node():
- root = self
- else:
- try:
- # Set the root to the parent of the requested starting_level
- root = self.get_active_ancestors(include_root=True)[starting_level]
- except IndexError:
- # Ooops! We've asked for a starting_level deeper than the current navigable
- return None
- if not top_tier_only:
- nav_array = self.get_nav_tree(self, root.get_active_children())
- else:
- nav_array = [{'node': x} for x in root.get_active_children()] # Where is this used?
- else:
- nav_array = [{'node': x} for x in type(self).objects.filter(active=True, show_in_navigation=True)]
- return nav_array
- # Main entry point Returns the full tree or a part of it for the current navigable
- def get_navigation_ul(self, starting_level=0, top_tier_only=False):
- nav_array = self.get_navigation_array(starting_level, top_tier_only)
- return self.nav_tree_ul(nav_array, self)
- # Helper methods
- def get_subnavigation_ul(self): # Everything below the top level
- return self.get_navigation_ul(starting_level=1)
- def get_mainnavigation_ul(self): # Just the top level (and the root navigable)
- return self.get_navigation_ul(top_tier_only=True)
- def get_secondary_navigation_ul(self): # Just the second level
- return self.get_navigation_ul(starting_level=1, top_tier_only=True)
Add Comment
Please, Sign In to add comment