Guest User

Untitled

a guest
Feb 18th, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.59 KB | None | 0 0
  1. from django.core.urlresolvers import reverse
  2. from django.contrib.admin import site
  3. from django.template.loader import render_to_string
  4. from django.utils.safestring import mark_safe
  5.  
  6. from cms.utils import get_page_from_url
  7.  
  8.  
  9. class NavigableMixin(object):
  10. """
  11. Adds a bunch of methods for generating navigation for objects.
  12. Using classmethods instead of regular methods as sometimes we need to generate the navigation
  13. when we don't have a current instance (i.e. to render a page outside the hierarchy)
  14. """
  15.  
  16. # The following stubs are required for any class using this Mixin
  17. # The first 4 should already be supplied by any MPTT registered model
  18. # The last one just returns True/False depending on whether we have a hierarchical model or not
  19. # The 4 MPTT methods should never get called if this returns False so shouldn't need to be implemented
  20.  
  21. def get_siblings(self, include_self):
  22. raise NotImplementedError
  23.  
  24. def get_children(self):
  25. raise NotImplementedError
  26.  
  27. def get_ancestors(self, ascending):
  28. raise NotImplementedError
  29.  
  30. def is_root_node(self):
  31. raise NotImplementedError
  32.  
  33. @classmethod
  34. def is_hierarchical(cls):
  35. raise NotImplemented
  36.  
  37.  
  38. @classmethod
  39. def _link(cls, navigable, current_navigable, extra_markup=''):
  40. """
  41. Takes a navigable node and the current navigable node being rendered
  42. and returns the correct element (span or a) with class="ancestor" or class="selected" for the node
  43. """
  44. if current_navigable:
  45. if navigable==current_navigable:
  46. # Current
  47. return '<span id="nav-%s" class="selected">%s%s</span>' % (navigable.name, extra_markup, navigable.title)
  48. elif cls.is_hierarchical() and navigable in current_navigable.get_active_ancestors(include_root=False):
  49. # Ancestor
  50. return '<a href="%s" id="nav-%s" class="ancestor">%s%s</a>' % (navigable.get_absolute_url(), navigable.name, extra_markup, navigable.title)
  51. # Anything Else
  52. return '<a href="%s" id="nav-%s">%s%s</a>' % (navigable.get_absolute_url(), navigable.name, extra_markup, navigable.title)
  53.  
  54. @classmethod
  55. def nav_tree_ul(cls, nav_array=None, current_navigable=None, extra_markup=''): # TODO fix for sites that don't pass in extra_markup
  56.  
  57. # Pass in a nested structure in the form [node, node, ...]
  58. # Node is either {'node': navigable_instance}
  59. # or {'node': navigable_instance, 'children': [...]}
  60. # where children is another list of nodes
  61. #
  62. # Returns: A set of nested <ul> and <li> tags as a string (missing the top outer <ul></li> pair)
  63. # <li>'s contain <a href's>
  64. # except the current navigable which is just a span
  65. # Any direct ancestor has the class 'selected'
  66.  
  67. def ul(inner):
  68. return '<ul>%s</ul>\n' % inner
  69. def li(inner):
  70. return '<li>%s</li>\n' % inner
  71. def li_ancestor(inner):
  72. return '<li class="ancestor">%s</li>\n' % inner
  73.  
  74. html = []
  75. for item in nav_array:
  76. if item.get('children', None):
  77. html_fragment = cls._link(item['node'], current_navigable)
  78. html_fragment += cls.nav_tree_ul(item['children'], current_navigable)
  79. html.append(li_ancestor(html_fragment))
  80. else:
  81. html_fragment = li(cls._link(item['node'], current_navigable))
  82. html.append(html_fragment)
  83.  
  84. if cls.is_hierarchical() and nav_array and len(nav_array[0]['node'].get_ancestors())==1:
  85. # Add home page to top level even though it's really the parent
  86. html = [li(cls._link(nav_array[0]['node'].get_ancestors()[0], current_navigable))] + html
  87. # Don't return empty <ul>'s
  88. if html:
  89. return ul(''.join(html))
  90. else:
  91. return ''
  92.  
  93. @classmethod
  94. def get_nav_tree(cls, current, nodes):
  95. """
  96. 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!
  97. """
  98. result = []
  99. for node in nodes:
  100. subresult = {}
  101. subresult['node'] = node
  102. if not(node.is_leaf_node()) and (node in current.get_active_ancestors(include_root=True)):
  103. subresult['children'] = cls.get_nav_tree(current, node.get_active_children())
  104. result.append(subresult)
  105. return result
  106.  
  107. def get_all_active_siblings(self):
  108. return self.get_siblings(include_self=True).filter(active=True, show_in_navigation=True)
  109.  
  110. def get_active_children(self):
  111. return self.get_children().filter(active=True, show_in_navigation=True)
  112.  
  113. def get_active_ancestors(self, include_root=False):
  114. ancestors = list(self.get_ancestors(ascending=False).filter(active=True, show_in_navigation=True))+[self]
  115. if include_root:
  116. return ancestors
  117. else:
  118. return ancestors[1:]
  119.  
  120. def get_navigation_array(self, starting_level=0, top_tier_only=False):
  121.  
  122. if type(self).is_hierarchical():
  123. if self.is_root_node():
  124. root = self
  125. else:
  126. try:
  127. # Set the root to the parent of the requested starting_level
  128. root = self.get_active_ancestors(include_root=True)[starting_level]
  129. except IndexError:
  130. # Ooops! We've asked for a starting_level deeper than the current navigable
  131. return None
  132.  
  133. if not top_tier_only:
  134. nav_array = self.get_nav_tree(self, root.get_active_children())
  135. else:
  136. nav_array = [{'node': x} for x in root.get_active_children()] # Where is this used?
  137.  
  138. else:
  139. nav_array = [{'node': x} for x in type(self).objects.filter(active=True, show_in_navigation=True)]
  140.  
  141. return nav_array
  142.  
  143. # Main entry point Returns the full tree or a part of it for the current navigable
  144. def get_navigation_ul(self, starting_level=0, top_tier_only=False):
  145. nav_array = self.get_navigation_array(starting_level, top_tier_only)
  146. return self.nav_tree_ul(nav_array, self)
  147.  
  148.  
  149. # Helper methods
  150. def get_subnavigation_ul(self): # Everything below the top level
  151. return self.get_navigation_ul(starting_level=1)
  152.  
  153. def get_mainnavigation_ul(self): # Just the top level (and the root navigable)
  154. return self.get_navigation_ul(top_tier_only=True)
  155.  
  156. def get_secondary_navigation_ul(self): # Just the second level
  157. return self.get_navigation_ul(starting_level=1, top_tier_only=True)
Add Comment
Please, Sign In to add comment