Merge pull request #206 from nephila/feature/menu_modifier
Fix selecting current menu item according to menu layout
This commit is contained in:
commit
8c35763150
4 changed files with 113 additions and 15 deletions
|
@ -11,6 +11,7 @@ History
|
||||||
* Use all_languages_column to admin
|
* Use all_languages_column to admin
|
||||||
* Add publish button
|
* Add publish button
|
||||||
* Fix issues in migrations. Thanks @skirsdeda
|
* Fix issues in migrations. Thanks @skirsdeda
|
||||||
|
* Fix selecting current menu item according to menu layout
|
||||||
|
|
||||||
0.6.3 (2015-12-22)
|
0.6.3 (2015-12-22)
|
||||||
++++++++++++++++++
|
++++++++++++++++++
|
||||||
|
|
|
@ -1,21 +1,34 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
|
from cms.apphook_pool import apphook_pool
|
||||||
from cms.menu_bases import CMSAttachMenu
|
from cms.menu_bases import CMSAttachMenu
|
||||||
|
from django.core.urlresolvers import resolve
|
||||||
from django.db.models.signals import post_delete, post_save
|
from django.db.models.signals import post_delete, post_save
|
||||||
from django.utils.translation import get_language_from_request, ugettext_lazy as _
|
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 menus.menu_pool import menu_pool
|
||||||
|
|
||||||
from .cms_appconfig import BlogConfig
|
from .cms_appconfig import BlogConfig
|
||||||
from .models import BlogCategory, Post
|
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):
|
class BlogCategoryMenu(CMSAttachMenu):
|
||||||
|
"""
|
||||||
|
Main menu class
|
||||||
|
|
||||||
|
Handles all types of blog menu
|
||||||
|
"""
|
||||||
name = _('Blog menu')
|
name = _('Blog menu')
|
||||||
|
|
||||||
def get_nodes(self, request):
|
def get_nodes(self, request):
|
||||||
|
"""
|
||||||
|
Generates the nodelist
|
||||||
|
|
||||||
|
:param request:
|
||||||
|
:return: list of nodes
|
||||||
|
"""
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
language = get_language_from_request(request, check_path=True)
|
language = get_language_from_request(request, check_path=True)
|
||||||
|
@ -40,9 +53,12 @@ class BlogCategoryMenu(CMSAttachMenu):
|
||||||
node = NavigationNode(
|
node = NavigationNode(
|
||||||
category.name,
|
category.name,
|
||||||
category.get_absolute_url(),
|
category.get_absolute_url(),
|
||||||
'%s-%s' % (category.__class__.__name__, category.pk),
|
'{0}-{1}'.format(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.parent.id
|
||||||
|
) if category.parent else None
|
||||||
|
)
|
||||||
)
|
)
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
|
|
||||||
|
@ -57,10 +73,10 @@ class BlogCategoryMenu(CMSAttachMenu):
|
||||||
if categories_menu:
|
if categories_menu:
|
||||||
category = post.categories.first()
|
category = post.categories.first()
|
||||||
if category:
|
if category:
|
||||||
parent = '%s-%s' % (category.__class__.__name__, category.pk)
|
parent = '{0}-{1}'.format(category.__class__.__name__, category.pk)
|
||||||
post_id = '%s-%s' % (post.__class__.__name__, post.pk),
|
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
||||||
else:
|
else:
|
||||||
post_id = '%s-%s' % (post.__class__.__name__, post.pk),
|
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
||||||
if post_id:
|
if post_id:
|
||||||
node = NavigationNode(
|
node = NavigationNode(
|
||||||
post.get_title(),
|
post.get_title(),
|
||||||
|
@ -75,7 +91,54 @@ class BlogCategoryMenu(CMSAttachMenu):
|
||||||
menu_pool.register_menu(BlogCategoryMenu)
|
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):
|
def clear_menu_cache(**kwargs):
|
||||||
|
"""
|
||||||
|
Empty menu cache when saving categories
|
||||||
|
"""
|
||||||
menu_pool.clear(all=True)
|
menu_pool.clear(all=True)
|
||||||
|
|
||||||
post_save.connect(clear_menu_cache, sender=BlogCategory)
|
post_save.connect(clear_menu_cache, sender=BlogCategory)
|
||||||
|
|
|
@ -29,6 +29,7 @@ class MenuTest(BaseTest):
|
||||||
self.cats.append(cat)
|
self.cats.append(cat)
|
||||||
|
|
||||||
activate('en')
|
activate('en')
|
||||||
|
menu_pool.clear(all=True)
|
||||||
menu_pool.discover_menus()
|
menu_pool.discover_menus()
|
||||||
# All cms menu modifiers should be removed from menu_pool.modifiers
|
# All cms menu modifiers should be removed from menu_pool.modifiers
|
||||||
# so that they do not interfere with our menu nodes
|
# 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()),
|
(PostDetailView, 'slug', posts[0], posts[0].categories.first()),
|
||||||
(CategoryEntriesView, 'category', self.cats[2], self.cats[2])
|
(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:
|
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 smart_override('en'):
|
||||||
with switch_language(obj, '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 = view_cls()
|
||||||
view_obj.request = request
|
view_obj.request = request
|
||||||
view_obj.namespace, view_obj.config = get_app_instance(request)
|
view_obj.namespace, view_obj.config = get_app_instance(request)
|
||||||
view_obj.app_config = self.app_config_1
|
view_obj.app_config = self.app_config_1
|
||||||
view_obj.kwargs = {kwarg: obj.slug}
|
view_obj.kwargs = {kwarg: obj.slug}
|
||||||
view_obj.get(request)
|
view_obj.get(request)
|
||||||
|
view_obj.get_context_data()
|
||||||
# check if selected menu node points to cat
|
# check if selected menu node points to cat
|
||||||
nodes = menu_pool.get_nodes(request)
|
nodes = menu_pool.get_nodes(request)
|
||||||
found = False
|
found = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.selected:
|
if node.selected:
|
||||||
self.assertEqual(node.url, obj.get_absolute_url())
|
found.append(node.get_absolute_url())
|
||||||
found = True
|
self.assertTrue(obj.get_absolute_url() in found)
|
||||||
break
|
|
||||||
self.assertTrue(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()
|
||||||
|
|
|
@ -91,7 +91,7 @@ class AdminTest(BaseTest):
|
||||||
for fieldname in BlogConfigForm.base_fields:
|
for fieldname in BlogConfigForm.base_fields:
|
||||||
self.assertContains(response, 'id="id_config-%s"' % fieldname)
|
self.assertContains(response, 'id="id_config-%s"' % fieldname)
|
||||||
self.assertContains(response, '<input id="id_config-og_app_id" maxlength="200" name="config-og_app_id" type="text" />')
|
self.assertContains(response, '<input id="id_config-og_app_id" maxlength="200" name="config-og_app_id" type="text" />')
|
||||||
self.assertContains(response, '<input class="vTextField" id="id_namespace" maxlength="100" name="namespace" type="text" value="sample_app" />')
|
self.assertContains(response, 'sample_app')
|
||||||
|
|
||||||
def test_admin_category_views(self):
|
def test_admin_category_views(self):
|
||||||
post_admin = admin.site._registry[BlogCategory]
|
post_admin = admin.site._registry[BlogCategory]
|
||||||
|
|
Loading…
Reference in a new issue