menus.templatetags.menu_tags: 231 total statements, 0.0% covered

Generated: Wed 2013-03-13 10:33 CET

Source file: /media/Envs/Envs/filer-gallery/lib/python2.7/site-packages/menus/templatetags/menu_tags.py

Stats: 0 executed, 220 missed, 11 excluded, 152 ignored

  1. # -*- coding: utf-8 -*-
  2. from classytags.arguments import IntegerArgument, Argument, StringArgument
  3. from classytags.core import Options
  4. from classytags.helpers import InclusionTag
  5. from django import template
  6. from django.conf import settings
  7. from django.contrib.sites.models import Site
  8. from django.core.cache import cache
  9. from django.core.urlresolvers import reverse
  10. from django.utils.translation import activate, get_language, ugettext
  11. from menus.menu_pool import menu_pool
  12. import urllib
  13. register = template.Library()
  14. class NOT_PROVIDED: pass
  15. def cut_after(node, levels, removed):
  16. """
  17. given a tree of nodes cuts after N levels
  18. """
  19. if levels == 0:
  20. removed.extend(node.children)
  21. node.children = []
  22. else:
  23. removed_local = []
  24. for child in node.children:
  25. if child.visible:
  26. cut_after(child, levels - 1, removed)
  27. else:
  28. removed_local.append(child)
  29. for removed_child in removed_local:
  30. node.children.remove(removed_child)
  31. removed.extend(removed_local)
  32. def remove(node, removed):
  33. removed.append(node)
  34. if node.parent:
  35. if node in node.parent.children:
  36. node.parent.children.remove(node)
  37. def cut_levels(nodes, from_level, to_level, extra_inactive, extra_active):
  38. """
  39. cutting nodes away from menus
  40. """
  41. final = []
  42. removed = []
  43. selected = None
  44. for node in nodes:
  45. if not hasattr(node, 'level'):
  46. # remove and ignore nodes that don't have level information
  47. remove(node, removed)
  48. continue
  49. if node.level == from_level:
  50. # turn nodes that are on from_level into root nodes
  51. final.append(node)
  52. node.parent = None
  53. if not node.ancestor and not node.selected and not node.descendant:
  54. # cut inactive nodes to extra_inactive, but not of descendants of
  55. # the selected node
  56. cut_after(node, extra_inactive, removed)
  57. if node.level > to_level and node.parent:
  58. # remove nodes that are too deep, but not nodes that are on
  59. # from_level (local root nodes)
  60. remove(node, removed)
  61. if node.selected:
  62. selected = node
  63. if not node.visible:
  64. remove(node, removed)
  65. if selected:
  66. cut_after(selected, extra_active, removed)
  67. if removed:
  68. for node in removed:
  69. if node in final:
  70. final.remove(node)
  71. return final
  72. def flatten(nodes):
  73. flat = []
  74. for node in nodes:
  75. flat.append(node)
  76. flat.extend(flatten(node.children))
  77. return flat
  78. class ShowMenu(InclusionTag):
  79. """
  80. render a nested list of all children of the pages
  81. - from_level: starting level
  82. - to_level: max level
  83. - extra_inactive: how many levels should be rendered of the not active tree?
  84. - extra_active: how deep should the children of the active node be rendered?
  85. - namespace: the namespace of the menu. if empty will use all namespaces
  86. - root_id: the id of the root node
  87. - template: template used to render the menu
  88. """
  89. name = 'show_menu'
  90. template = 'menu/dummy.html'
  91. options = Options(
  92. IntegerArgument('from_level', default=0, required=False),
  93. IntegerArgument('to_level', default=100, required=False),
  94. IntegerArgument('extra_inactive', default=0, required=False),
  95. IntegerArgument('extra_active', default=1000, required=False),
  96. StringArgument('template', default='menu/menu.html', required=False),
  97. StringArgument('namespace', default=None, required=False),
  98. StringArgument('root_id', default=None, required=False),
  99. Argument('next_page', default=None, required=False),
  100. )
  101. def get_context(self, context, from_level, to_level, extra_inactive,
  102. extra_active, template, namespace, root_id, next_page):
  103. try:
  104. # If there's an exception (500), default context_processors may not be called.
  105. request = context['request']
  106. except KeyError:
  107. return {'template': 'menu/empty.html'}
  108. if next_page:
  109. children = next_page.children
  110. else:
  111. #new menu... get all the data so we can save a lot of queries
  112. nodes = menu_pool.get_nodes(request, namespace, root_id)
  113. if root_id: # find the root id and cut the nodes
  114. id_nodes = menu_pool.get_nodes_by_attribute(nodes, "reverse_id", root_id)
  115. if id_nodes:
  116. node = id_nodes[0]
  117. nodes = node.children
  118. for remove_parent in nodes:
  119. remove_parent.parent = None
  120. from_level += node.level + 1
  121. to_level += node.level + 1
  122. nodes = flatten(nodes)
  123. else:
  124. nodes = []
  125. children = cut_levels(nodes, from_level, to_level, extra_inactive, extra_active)
  126. children = menu_pool.apply_modifiers(children, request, namespace, root_id, post_cut=True)
  127. try:
  128. context.update({'children':children,
  129. 'template':template,
  130. 'from_level':from_level,
  131. 'to_level':to_level,
  132. 'extra_inactive':extra_inactive,
  133. 'extra_active':extra_active,
  134. 'namespace':namespace})
  135. except:
  136. context = {"template":template}
  137. return context
  138. register.tag(ShowMenu)
  139. class ShowMenuBelowId(ShowMenu):
  140. name = 'show_menu_below_id'
  141. options = Options(
  142. Argument('root_id', default=None, required=False),
  143. IntegerArgument('from_level', default=0, required=False),
  144. IntegerArgument('to_level', default=100, required=False),
  145. IntegerArgument('extra_inactive', default=0, required=False),
  146. IntegerArgument('extra_active', default=1000, required=False),
  147. Argument('template', default='menu/menu.html', required=False),
  148. Argument('namespace', default=None, required=False),
  149. Argument('next_page', default=None, required=False),
  150. )
  151. register.tag(ShowMenuBelowId)
  152. class ShowSubMenu(InclusionTag):
  153. """
  154. show the sub menu of the current nav-node.
  155. - levels: how many levels deep
  156. - template: template used to render the navigation
  157. """
  158. name = 'show_sub_menu'
  159. template = 'menu/dummy.html'
  160. options = Options(
  161. IntegerArgument('levels', default=100, required=False),
  162. Argument('template', default='menu/sub_menu.html', required=False),
  163. )
  164. def get_context(self, context, levels, template):
  165. try:
  166. # If there's an exception (500), default context_processors may not be called.
  167. request = context['request']
  168. except KeyError:
  169. return {'template': 'menu/empty.html'}
  170. nodes = menu_pool.get_nodes(request)
  171. children = []
  172. for node in nodes:
  173. if node.selected:
  174. cut_after(node, levels, [])
  175. children = node.children
  176. for child in children:
  177. child.parent = None
  178. children = menu_pool.apply_modifiers(children, request, post_cut=True)
  179. context.update({
  180. 'children':children,
  181. 'template':template,
  182. 'from_level':0,
  183. 'to_level':0,
  184. 'extra_inactive':0,
  185. 'extra_active':0
  186. })
  187. return context
  188. register.tag(ShowSubMenu)
  189. class ShowBreadcrumb(InclusionTag):
  190. """
  191. Shows the breadcrumb from the node that has the same url as the current request
  192. - start level: after which level should the breadcrumb start? 0=home
  193. - template: template used to render the breadcrumb
  194. """
  195. name = 'show_breadcrumb'
  196. template = 'menu/dummy.html'
  197. options = Options(
  198. Argument('start_level', default=0, required=False),
  199. Argument('template', default='menu/breadcrumb.html', required=False),
  200. Argument('only_visible', default=True, required=False),
  201. )
  202. def get_context(self, context, start_level, template, only_visible):
  203. try:
  204. # If there's an exception (500), default context_processors may not be called.
  205. request = context['request']
  206. except KeyError:
  207. return {'template': 'cms/content.html'}
  208. if not (isinstance(start_level, int) or start_level.isdigit()):
  209. only_visible = template
  210. template = start_level
  211. start_level = 0
  212. try:
  213. only_visible = bool(int(only_visible))
  214. except:
  215. only_visible = bool(only_visible)
  216. ancestors = []
  217. nodes = menu_pool.get_nodes(request, breadcrumb=True)
  218. selected = None
  219. home = None
  220. for node in nodes:
  221. if node.selected:
  222. selected = node
  223. if node.get_absolute_url() == urllib.unquote(reverse("pages-root")):
  224. home = node
  225. if selected and selected != home:
  226. node = selected
  227. while node:
  228. if node.visible or not only_visible:
  229. ancestors.append(node)
  230. node = node.parent
  231. if not ancestors or (ancestors and ancestors[-1] != home) and home:
  232. ancestors.append(home)
  233. ancestors.reverse()
  234. if len(ancestors) >= start_level:
  235. ancestors = ancestors[start_level:]
  236. else:
  237. ancestors = []
  238. context.update({'ancestors':ancestors,
  239. 'template': template})
  240. return context
  241. register.tag(ShowBreadcrumb)
  242. def _raw_language_marker(language, lang_code):
  243. return language
  244. def _native_language_marker(language, lang_code):
  245. activate(lang_code)
  246. return unicode(ugettext(language))
  247. def _current_language_marker(language, lang_code):
  248. return unicode(ugettext(language))
  249. def _short_language_marker(language, lang_code):
  250. return lang_code
  251. MARKERS = {
  252. 'raw': _raw_language_marker,
  253. 'native': _native_language_marker,
  254. 'current': _current_language_marker,
  255. 'short': _short_language_marker,
  256. }
  257. class LanguageChooser(InclusionTag):
  258. """
  259. Displays a language chooser
  260. - template: template used to render the language chooser
  261. """
  262. name = 'language_chooser'
  263. template = 'menu/dummy.html'
  264. options = Options(
  265. Argument('template', default=NOT_PROVIDED, required=False),
  266. Argument('i18n_mode', default='raw', required=False),
  267. )
  268. def get_context(self, context, template, i18n_mode):
  269. if template in MARKERS:
  270. _tmp = template
  271. if i18n_mode not in MARKERS:
  272. template = i18n_mode
  273. else:
  274. template = NOT_PROVIDED
  275. i18n_mode = _tmp
  276. if template is NOT_PROVIDED:
  277. template = "menu/language_chooser.html"
  278. if not i18n_mode in MARKERS:
  279. i18n_mode = 'raw'
  280. if 'request' not in context:
  281. # If there's an exception (500), default context_processors may not be called.
  282. return {'template': 'cms/content.html'}
  283. marker = MARKERS[i18n_mode]
  284. cms_languages = dict(settings.CMS_LANGUAGES)
  285. current_lang = get_language()
  286. site = Site.objects.get_current()
  287. site_languages = settings.CMS_SITE_LANGUAGES.get(site.pk, cms_languages.keys())
  288. cache_key = '%s-language-chooser-%s-%s-%s' % (settings.CMS_CACHE_PREFIX, site.pk, current_lang, i18n_mode)
  289. languages = cache.get(cache_key, [])
  290. if not languages:
  291. for lang in settings.CMS_FRONTEND_LANGUAGES:
  292. if lang in cms_languages and lang in site_languages:
  293. languages.append((lang, marker(cms_languages[lang], lang)))
  294. if current_lang != get_language():
  295. activate(current_lang)
  296. cache.set(cache_key, languages)
  297. lang = get_language()
  298. context.update({
  299. 'languages':languages,
  300. 'current_language':lang,
  301. 'template':template,
  302. })
  303. return context
  304. register.tag(LanguageChooser)
  305. class PageLanguageUrl(InclusionTag):
  306. """
  307. Displays the url of the current page in the defined language.
  308. You can set a language_changer function with the set_language_changer function in the utils.py if there is no page.
  309. This is needed if you have slugs in more than one language.
  310. """
  311. name = 'page_language_url'
  312. template = 'cms/content.html'
  313. options = Options(
  314. Argument('lang'),
  315. )
  316. def get_context(self, context, lang):
  317. try:
  318. # If there's an exception (500), default context_processors may not be called.
  319. request = context['request']
  320. except KeyError:
  321. return {'template': 'cms/content.html'}
  322. if hasattr(request, "_language_changer"):
  323. try:
  324. setattr(request._language_changer, 'request', request)
  325. except AttributeError:
  326. pass
  327. url = "/%s" % lang + request._language_changer(lang)
  328. else:
  329. page = request.current_page
  330. if page == "dummy":
  331. return {'content': ''}
  332. try:
  333. url = page.get_absolute_url(language=lang, fallback=False)
  334. url = "/" + lang + url
  335. except:
  336. # no localized path/slug
  337. if settings.CMS_HIDE_UNTRANSLATED:
  338. # redirect to root url if CMS_HIDE_UNTRANSLATED
  339. url = '/' + lang + '/'
  340. else:
  341. # If untranslated pages are shown, this will not redirect
  342. # at all.
  343. url = ''
  344. return {'content':url}
  345. register.tag(PageLanguageUrl)