Merge pull request #237 from nephila/feature/move_menus
Add some compatibility for cms menu and filer
This commit is contained in:
commit
88b8e0c738
4 changed files with 163 additions and 147 deletions
145
djangocms_blog/cms_menus.py
Normal file
145
djangocms_blog/cms_menus.py
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
# -*- 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 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, 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)
|
||||||
|
|
||||||
|
categories_menu = False
|
||||||
|
posts_menu = False
|
||||||
|
config = False
|
||||||
|
if hasattr(self, 'instance') and self.instance:
|
||||||
|
config = BlogConfig.objects.get(namespace=self.instance.application_namespace)
|
||||||
|
if config and config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_CATEGORIES):
|
||||||
|
categories_menu = True
|
||||||
|
if config and config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_POSTS):
|
||||||
|
posts_menu = True
|
||||||
|
|
||||||
|
if categories_menu:
|
||||||
|
categories = BlogCategory.objects
|
||||||
|
if config:
|
||||||
|
categories = categories.namespace(self.instance.application_namespace)
|
||||||
|
categories = categories.active_translations(language).distinct()
|
||||||
|
categories = categories.order_by('parent__id', 'translations__name')
|
||||||
|
for category in categories:
|
||||||
|
node = NavigationNode(
|
||||||
|
category.name,
|
||||||
|
category.get_absolute_url(),
|
||||||
|
'{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)
|
||||||
|
|
||||||
|
if posts_menu:
|
||||||
|
posts = Post.objects
|
||||||
|
if hasattr(self, 'instance') and self.instance:
|
||||||
|
posts = posts.namespace(self.instance.application_namespace)
|
||||||
|
posts = posts.active_translations(language).distinct()
|
||||||
|
for post in posts:
|
||||||
|
post_id = None
|
||||||
|
parent = None
|
||||||
|
if categories_menu:
|
||||||
|
category = post.categories.first()
|
||||||
|
if category:
|
||||||
|
parent = '{0}-{1}'.format(category.__class__.__name__, category.pk)
|
||||||
|
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
||||||
|
else:
|
||||||
|
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
||||||
|
if post_id:
|
||||||
|
node = NavigationNode(
|
||||||
|
post.get_title(),
|
||||||
|
post.get_absolute_url(language),
|
||||||
|
post_id,
|
||||||
|
parent
|
||||||
|
)
|
||||||
|
nodes.append(node)
|
||||||
|
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
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)
|
||||||
|
post_delete.connect(clear_menu_cache, sender=BlogCategory)
|
|
@ -1,145 +1,2 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
from djangocms_blog.cms_menus import * # NOQA
|
||||||
|
|
||||||
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 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, 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)
|
|
||||||
|
|
||||||
categories_menu = False
|
|
||||||
posts_menu = False
|
|
||||||
config = False
|
|
||||||
if hasattr(self, 'instance') and self.instance:
|
|
||||||
config = BlogConfig.objects.get(namespace=self.instance.application_namespace)
|
|
||||||
if config and config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_CATEGORIES):
|
|
||||||
categories_menu = True
|
|
||||||
if config and config.menu_structure in (MENU_TYPE_COMPLETE, MENU_TYPE_POSTS):
|
|
||||||
posts_menu = True
|
|
||||||
|
|
||||||
if categories_menu:
|
|
||||||
categories = BlogCategory.objects
|
|
||||||
if config:
|
|
||||||
categories = categories.namespace(self.instance.application_namespace)
|
|
||||||
categories = categories.active_translations(language).distinct()
|
|
||||||
categories = categories.order_by('parent__id', 'translations__name')
|
|
||||||
for category in categories:
|
|
||||||
node = NavigationNode(
|
|
||||||
category.name,
|
|
||||||
category.get_absolute_url(),
|
|
||||||
'{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)
|
|
||||||
|
|
||||||
if posts_menu:
|
|
||||||
posts = Post.objects
|
|
||||||
if hasattr(self, 'instance') and self.instance:
|
|
||||||
posts = posts.namespace(self.instance.application_namespace)
|
|
||||||
posts = posts.active_translations(language).distinct()
|
|
||||||
for post in posts:
|
|
||||||
post_id = None
|
|
||||||
parent = None
|
|
||||||
if categories_menu:
|
|
||||||
category = post.categories.first()
|
|
||||||
if category:
|
|
||||||
parent = '{0}-{1}'.format(category.__class__.__name__, category.pk)
|
|
||||||
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
|
||||||
else:
|
|
||||||
post_id = '{0}-{1}'.format(post.__class__.__name__, post.pk),
|
|
||||||
if post_id:
|
|
||||||
node = NavigationNode(
|
|
||||||
post.get_title(),
|
|
||||||
post.get_absolute_url(language),
|
|
||||||
post_id,
|
|
||||||
parent
|
|
||||||
)
|
|
||||||
nodes.append(node)
|
|
||||||
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
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)
|
|
||||||
post_delete.connect(clear_menu_cache, sender=BlogCategory)
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from cmsplugin_filer_image.models import ThumbnailOption
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
@ -15,6 +14,13 @@ from parler.utils.context import smart_override
|
||||||
from djangocms_blog.cms_appconfig import BlogConfig
|
from djangocms_blog.cms_appconfig import BlogConfig
|
||||||
from djangocms_blog.models import BlogCategory, Post
|
from djangocms_blog.models import BlogCategory, Post
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from filer.models import ThumbnailOption # NOQA
|
||||||
|
except ImportError:
|
||||||
|
from cmsplugin_filer_image.models import ThumbnailOption # NOQA
|
||||||
|
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
|
12
tox.ini
12
tox.ini
|
@ -13,8 +13,6 @@ deps =
|
||||||
django18: django-mptt>=0.8
|
django18: django-mptt>=0.8
|
||||||
django19: Django>=1.9,<1.10
|
django19: Django>=1.9,<1.10
|
||||||
django19: django-mptt>=0.8
|
django19: django-mptt>=0.8
|
||||||
django19: https://github.com/divio/django-filer/archive/develop.zip
|
|
||||||
django19: https://github.com/divio/cmsplugin-filer/archive/develop.zip
|
|
||||||
cms30: https://github.com/divio/django-cms/archive/support/3.0.x.zip
|
cms30: https://github.com/divio/django-cms/archive/support/3.0.x.zip
|
||||||
cms31: https://github.com/divio/django-cms/archive/support/3.1.x.zip
|
cms31: https://github.com/divio/django-cms/archive/support/3.1.x.zip
|
||||||
cms32: https://github.com/divio/django-cms/archive/release/3.2.x.zip
|
cms32: https://github.com/divio/django-cms/archive/release/3.2.x.zip
|
||||||
|
@ -23,6 +21,16 @@ deps =
|
||||||
django-meta>=1.2
|
django-meta>=1.2
|
||||||
https://github.com/nephila/djangocms-helper/archive/develop.zip
|
https://github.com/nephila/djangocms-helper/archive/develop.zip
|
||||||
py26: unittest2
|
py26: unittest2
|
||||||
|
py26: django-filer<1.2
|
||||||
|
py26: cmsplugin-filer<1.1
|
||||||
|
py27: django-filer<1.3
|
||||||
|
py27: cmsplugin-filer<1.2
|
||||||
|
py33: django-filer<1.3
|
||||||
|
py33: cmsplugin-filer<1.2
|
||||||
|
py34: django-filer<1.3
|
||||||
|
py34: cmsplugin-filer<1.2
|
||||||
|
py35: django-filer<1.3
|
||||||
|
py35: cmsplugin-filer<1.2
|
||||||
https://github.com/aldryn/aldryn-apphooks-config/archive/master.zip
|
https://github.com/aldryn/aldryn-apphooks-config/archive/master.zip
|
||||||
https://github.com/nephila/djangocms-apphook-setup/archive/master.zip
|
https://github.com/nephila/djangocms-apphook-setup/archive/master.zip
|
||||||
-r{toxinidir}/requirements-test.txt
|
-r{toxinidir}/requirements-test.txt
|
||||||
|
|
Loading…
Reference in a new issue