diff --git a/HISTORY.rst b/HISTORY.rst
index 76ae54f..6fda271 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -11,6 +11,7 @@ History
* Use all_languages_column to admin
* Add publish button
* Fix issues in migrations. Thanks @skirsdeda
+* Fix selecting current menu item according to menu layout
0.6.3 (2015-12-22)
++++++++++++++++++
diff --git a/djangocms_blog/menu.py b/djangocms_blog/menu.py
index 8d7920f..6be7aad 100644
--- a/djangocms_blog/menu.py
+++ b/djangocms_blog/menu.py
@@ -1,21 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
+from cms.apphook_pool import apphook_pool
from cms.menu_bases import CMSAttachMenu
+from django.core.urlresolvers import resolve
from django.db.models.signals import post_delete, post_save
from django.utils.translation import get_language_from_request, ugettext_lazy as _
-from menus.base import NavigationNode
+from menus.base import Modifier, NavigationNode
from menus.menu_pool import menu_pool
from .cms_appconfig import BlogConfig
from .models import BlogCategory, Post
-from .settings import MENU_TYPE_CATEGORIES, MENU_TYPE_COMPLETE, MENU_TYPE_POSTS
+from .settings import MENU_TYPE_CATEGORIES, MENU_TYPE_COMPLETE, MENU_TYPE_POSTS, get_setting
class BlogCategoryMenu(CMSAttachMenu):
+ """
+ Main menu class
+
+ Handles all types of blog menu
+ """
name = _('Blog menu')
def get_nodes(self, request):
+ """
+ Generates the nodelist
+
+ :param request:
+ :return: list of nodes
+ """
nodes = []
language = get_language_from_request(request, check_path=True)
@@ -40,9 +53,12 @@ class BlogCategoryMenu(CMSAttachMenu):
node = NavigationNode(
category.name,
category.get_absolute_url(),
- '%s-%s' % (category.__class__.__name__, category.pk),
- ('%s-%s' % (category.__class__.__name__, category.parent.id) if category.parent
- else None)
+ '{0}-{1}'.format(category.__class__.__name__, category.pk),
+ (
+ '{0}-{1}'.format(
+ category.__class__.__name__, category.parent.id
+ ) if category.parent else None
+ )
)
nodes.append(node)
@@ -57,10 +73,10 @@ class BlogCategoryMenu(CMSAttachMenu):
if categories_menu:
category = post.categories.first()
if category:
- parent = '%s-%s' % (category.__class__.__name__, category.pk)
- post_id = '%s-%s' % (post.__class__.__name__, post.pk),
+ parent = '{0}-{1}'.format(category.__class__.__name__, category.pk)
+ post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
else:
- post_id = '%s-%s' % (post.__class__.__name__, post.pk),
+ post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
if post_id:
node = NavigationNode(
post.get_title(),
@@ -75,7 +91,54 @@ class BlogCategoryMenu(CMSAttachMenu):
menu_pool.register_menu(BlogCategoryMenu)
+class BlogNavModifier(Modifier):
+ """
+ This navigation modifier makes sure that when
+ a particular blog post is viewed,
+ a corresponding category is selected in menu
+ """
+ def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
+ """
+ Actual modifier function
+ :param request: request
+ :param nodes: complete list of nodes
+ :param namespace: Menu namespace
+ :param root_id: eventual root_id
+ :param post_cut: flag for modifier stage
+ :param breadcrumb: flag for modifier stage
+ :return: nodeslist
+ """
+ app = None
+ config = None
+ if getattr(request, 'current_page', None) and request.current_page.application_urls:
+ app = apphook_pool.get_apphook(request.current_page.application_urls)
+
+ if app and app.app_config:
+ namespace = resolve(request.path).namespace
+ config = app.get_config(namespace)
+ if config and config.menu_structure != MENU_TYPE_CATEGORIES:
+ return nodes
+ if post_cut:
+ return nodes
+ current_post = getattr(request, get_setting('CURRENT_POST_IDENTIFIER'), None)
+ category = None
+ if current_post and current_post.__class__ == Post:
+ category = current_post.categories.first()
+ if not category:
+ return nodes
+
+ for node in nodes:
+ if '{0}-{1}'.format(category.__class__.__name__, category.pk) == node.id:
+ node.selected = True
+ return nodes
+
+menu_pool.register_modifier(BlogNavModifier)
+
+
def clear_menu_cache(**kwargs):
+ """
+ Empty menu cache when saving categories
+ """
menu_pool.clear(all=True)
post_save.connect(clear_menu_cache, sender=BlogCategory)
diff --git a/tests/test_menu.py b/tests/test_menu.py
index 0f9f046..8247368 100644
--- a/tests/test_menu.py
+++ b/tests/test_menu.py
@@ -29,6 +29,7 @@ class MenuTest(BaseTest):
self.cats.append(cat)
activate('en')
+ menu_pool.clear(all=True)
menu_pool.discover_menus()
# All cms menu modifiers should be removed from menu_pool.modifiers
# so that they do not interfere with our menu nodes
@@ -139,22 +140,55 @@ class MenuTest(BaseTest):
(PostDetailView, 'slug', posts[0], posts[0].categories.first()),
(CategoryEntriesView, 'category', self.cats[2], self.cats[2])
)
+ self.app_config_1.app_data.config.menu_structure = MENU_TYPE_COMPLETE
+ self.app_config_1.save()
for view_cls, kwarg, obj, cat in tests:
- request = self.get_page_request(pages[1], self.user, path=obj.get_absolute_url())
with smart_override('en'):
with switch_language(obj, 'en'):
+ request = self.get_page_request(
+ pages[1], self.user, path=obj.get_absolute_url()
+ )
+ cache.clear()
+ menu_pool.clear(all=True)
view_obj = view_cls()
view_obj.request = request
view_obj.namespace, view_obj.config = get_app_instance(request)
view_obj.app_config = self.app_config_1
view_obj.kwargs = {kwarg: obj.slug}
view_obj.get(request)
+ view_obj.get_context_data()
# check if selected menu node points to cat
nodes = menu_pool.get_nodes(request)
- found = False
+ found = []
for node in nodes:
if node.selected:
- self.assertEqual(node.url, obj.get_absolute_url())
- found = True
- break
- self.assertTrue(found)
+ found.append(node.get_absolute_url())
+ self.assertTrue(obj.get_absolute_url() in found)
+
+ self.app_config_1.app_data.config.menu_structure = MENU_TYPE_CATEGORIES
+ self.app_config_1.save()
+ for view_cls, kwarg, obj, cat in tests:
+ with smart_override('en'):
+ with switch_language(obj, 'en'):
+ request = self.get_page_request(
+ pages[1], self.user, path=obj.get_absolute_url()
+ )
+ cache.clear()
+ menu_pool.clear(all=True)
+ view_obj = view_cls()
+ view_obj.request = request
+ view_obj.namespace, view_obj.config = get_app_instance(request)
+ view_obj.app_config = self.app_config_1
+ view_obj.kwargs = {kwarg: obj.slug}
+ view_obj.get(request)
+ view_obj.get_context_data()
+ # check if selected menu node points to cat
+ nodes = menu_pool.get_nodes(request)
+ found = []
+ for node in nodes:
+ if node.selected:
+ found.append(node.get_absolute_url())
+ self.assertTrue(cat.get_absolute_url() in found)
+
+ self.app_config_1.app_data.config.menu_structure = MENU_TYPE_COMPLETE
+ self.app_config_1.save()
diff --git a/tests/test_models.py b/tests/test_models.py
index ab8977d..689e2ae 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -91,7 +91,7 @@ class AdminTest(BaseTest):
for fieldname in BlogConfigForm.base_fields:
self.assertContains(response, 'id="id_config-%s"' % fieldname)
self.assertContains(response, '')
- self.assertContains(response, '')
+ self.assertContains(response, 'sample_app')
def test_admin_category_views(self):
post_admin = admin.site._registry[BlogCategory]