--- a/src/pyams_skin/skin.py Thu Oct 06 16:18:03 2016 +0200
+++ b/src/pyams_skin/skin.py Mon Oct 10 11:32:08 2016 +0200
@@ -22,6 +22,7 @@
# import packages
from pyams_utils.registry import utility_config
+from pyams_utils.traversing import get_parent
from pyramid.events import subscriber
from pyramid.threadlocal import get_current_request
from pyramid_zope_request import PyramidPublisherRequest
@@ -43,40 +44,48 @@
class SkinnableContent(object):
"""Skinnable content base class"""
- def get_skin(self):
- """Get current skin"""
- raise NotImplementedError("SkinnableContent subclasses must implement `get_skin` method")
+ _inherit_skin = FieldProperty(ISkinnable['inherit_skin'])
+
+ skin = FieldProperty(IUserSkinnable['skin'])
+
+ @property
+ def can_inherit_skin(self):
+ return get_parent(self, ISkinnable, allow_context=False) is not None
+
+ @property
+ def inherit_skin(self):
+ return self._inherit_skin if self.can_inherit_skin else False
+
+ @inherit_skin.setter
+ def inherit_skin(self, value):
+ if value and not self.can_inherit_skin:
+ value = False
+ self._inherit_skin = value
+
+ @property
+ def skin_parent(self):
+ if (not self._inherit_skin) and self.skin:
+ return self
+ parent = get_parent(self, ISkinnable)
+ if parent is not None:
+ return parent.skin_parent
+
+ def get_skin(self, request=None):
+ parent = self.skin_parent
+ if parent is self:
+ return self.skin
+ elif parent is not None:
+ skin = parent.skin
+ if skin is not None:
+ if request is None:
+ request = get_current_request()
+ return request.registry.queryUtility(ISkin, skin)
@implementer(IUserSkinnable)
class UserSkinnableContent(SkinnableContent):
"""User skinnable content base class"""
- skin = FieldProperty(IUserSkinnable['skin'])
-
- def get_skin(self, request=None):
- skin = self.skin
- if skin is not None:
- if request is None:
- request = get_current_request()
- return request.registry.queryUtility(ISkin, skin)
-
-
-@subscriber(IBeforeTraverseEvent, context_selector=ISkinnable)
-def handle_content_skin(event):
- """Apply skin when traversing skinnable object"""
- request = event.request
- skin = event.object.get_skin(request)
- if skin is not None:
- apply_skin(request, skin)
-
-
-@subscriber(IBeforeTraverseEvent, context_selector=ISiteRoot)
-def handle_root_skin(event):
- """Apply skin when traversing site root"""
- if not ISkinnable.providedBy(event.object):
- apply_skin(event.request, PyAMSSkin)
-
def apply_skin(request, skin):
"""Apply given skin to request"""
@@ -98,3 +107,23 @@
else:
request.registry.notify(SkinChangedEvent(request))
request.annotations['__skin__'] = skin
+
+
+@subscriber(IBeforeTraverseEvent, context_selector=ISkinnable)
+def handle_content_skin(event):
+ """Apply skin when traversing skinnable object"""
+ request = event.request
+ try:
+ skin = event.object.get_skin(request)
+ except NotImplementedError:
+ pass
+ else:
+ if skin is not None:
+ apply_skin(request, skin)
+
+
+@subscriber(IBeforeTraverseEvent, context_selector=ISiteRoot)
+def handle_root_skin(event):
+ """Apply skin when traversing site root"""
+ if not ISkinnable.providedBy(event.object):
+ apply_skin(event.request, PyAMSSkin)