8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 import logging |
13 import logging |
16 logger = logging.getLogger('PyAMS (skin)') |
|
17 |
14 |
18 from pyramid.events import subscriber |
15 from pyramid.events import subscriber |
19 from pyramid.threadlocal import get_current_request |
16 from pyramid.threadlocal import get_current_request |
20 from pyramid_zope_request import PyramidPublisherRequest |
17 from pyramid_zope_request import PyramidPublisherRequest |
21 from zope.interface import implementer, directlyProvidedBy, directlyProvides |
18 from zope.interface import Interface, directlyProvidedBy, directlyProvides, implementer |
22 from zope.schema.fieldproperty import FieldProperty |
19 from zope.schema.fieldproperty import FieldProperty |
23 from zope.traversing.interfaces import IBeforeTraverseEvent |
20 from zope.traversing.interfaces import IBeforeTraverseEvent |
24 |
21 |
25 from pyams_file.interfaces import DELETED_FILE |
22 from pyams_file.interfaces import DELETED_FILE, IFileInfo |
26 from pyams_file.property import FileProperty |
23 from pyams_file.property import FileProperty |
27 from pyams_skin.interfaces import ISkin, ISkinnable, IUserSkinnable, SkinChangedEvent |
24 from pyams_skin.interfaces import ISkin, ISkinnable, IUserSkinnable, SkinChangedEvent |
28 from pyams_skin.layer import IBaseLayer, IPyAMSLayer |
25 from pyams_skin.layer import IBaseLayer, IPyAMSLayer |
|
26 from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config |
29 from pyams_utils.interfaces.site import ISiteRoot |
27 from pyams_utils.interfaces.site import ISiteRoot |
|
28 from pyams_utils.interfaces.tales import ITALESExtension |
30 from pyams_utils.registry import utility_config |
29 from pyams_utils.registry import utility_config |
31 from pyams_utils.traversing import get_parent |
30 from pyams_utils.traversing import get_parent |
32 from pyams_utils.zodb import volatile_property |
31 from pyams_utils.zodb import volatile_property |
33 |
32 |
|
33 |
|
34 __docformat__ = 'restructuredtext' |
|
35 |
34 from pyams_skin import _ |
36 from pyams_skin import _ |
|
37 |
|
38 |
|
39 logger = logging.getLogger('PyAMS (skin)') |
35 |
40 |
36 |
41 |
37 @implementer(ISkinnable) |
42 @implementer(ISkinnable) |
38 class SkinnableContent(object): |
43 class SkinnableContent(object): |
39 """Skinnable content base class""" |
44 """Skinnable content base class""" |
40 |
45 |
41 _inherit_skin = FieldProperty(ISkinnable['inherit_skin']) |
46 _inherit_skin = FieldProperty(ISkinnable['inherit_skin']) |
42 _skin = FieldProperty(IUserSkinnable['skin']) |
47 _skin = FieldProperty(IUserSkinnable['skin']) |
43 |
48 |
|
49 _container_class = FieldProperty(ISkinnable['container_class']) |
44 _custom_stylesheet = FileProperty(ISkinnable['custom_stylesheet']) |
50 _custom_stylesheet = FileProperty(ISkinnable['custom_stylesheet']) |
45 _editor_stylesheet = FileProperty(ISkinnable['editor_stylesheet']) |
51 _editor_stylesheet = FileProperty(ISkinnable['editor_stylesheet']) |
46 _custom_script = FileProperty(ISkinnable['custom_script']) |
52 _custom_script = FileProperty(ISkinnable['custom_script']) |
47 |
53 |
48 @property |
54 @property |
87 if not self.inherit_skin: |
93 if not self.inherit_skin: |
88 self._skin = value |
94 self._skin = value |
89 del self.skin_parent |
95 del self.skin_parent |
90 |
96 |
91 @property |
97 @property |
|
98 def container_class(self): |
|
99 if not self.inherit_skin: |
|
100 return self._container_class |
|
101 else: |
|
102 return self.skin_parent.container_class |
|
103 |
|
104 @container_class.setter |
|
105 def container_class(self, value): |
|
106 if not self.inherit_skin: |
|
107 self._container_class = value |
|
108 |
|
109 @property |
92 def custom_stylesheet(self): |
110 def custom_stylesheet(self): |
93 if not self.inherit_skin: |
111 if not self.inherit_skin: |
94 return self._custom_stylesheet |
112 return self._custom_stylesheet |
95 else: |
113 else: |
96 return self.skin_parent.custom_stylesheet |
114 return self.skin_parent.custom_stylesheet |
99 def custom_stylesheet(self, value): |
117 def custom_stylesheet(self, value): |
100 if not self.inherit_skin: |
118 if not self.inherit_skin: |
101 self._custom_stylesheet = value |
119 self._custom_stylesheet = value |
102 if value and (value is not DELETED_FILE): |
120 if value and (value is not DELETED_FILE): |
103 self._custom_stylesheet.content_type = 'text/css' |
121 self._custom_stylesheet.content_type = 'text/css' |
|
122 IFileInfo(self._custom_stylesheet).filename = 'skin.css' |
104 |
123 |
105 @property |
124 @property |
106 def editor_stylesheet(self): |
125 def editor_stylesheet(self): |
107 if not self.inherit_skin: |
126 if not self.inherit_skin: |
108 return self._editor_stylesheet |
127 return self._editor_stylesheet |
113 def editor_stylesheet(self, value): |
132 def editor_stylesheet(self, value): |
114 if not self.inherit_skin: |
133 if not self.inherit_skin: |
115 self._editor_stylesheet = value |
134 self._editor_stylesheet = value |
116 if value and (value is not DELETED_FILE): |
135 if value and (value is not DELETED_FILE): |
117 self._editor_stylesheet.content_type = 'text/css' |
136 self._editor_stylesheet.content_type = 'text/css' |
|
137 IFileInfo(self._editor_stylesheet).filename = 'editor-skin.css' |
118 |
138 |
119 @property |
139 @property |
120 def custom_script(self): |
140 def custom_script(self): |
121 if not self.inherit_skin: |
141 if not self.inherit_skin: |
122 return self._custom_script |
142 return self._custom_script |
127 def custom_script(self, value): |
147 def custom_script(self, value): |
128 if not self.inherit_skin: |
148 if not self.inherit_skin: |
129 self._custom_script = value |
149 self._custom_script = value |
130 if value and (value is not DELETED_FILE): |
150 if value and (value is not DELETED_FILE): |
131 self._custom_script.content_type = 'text/javascript' |
151 self._custom_script.content_type = 'text/javascript' |
|
152 IFileInfo(self._custom_stylesheet).filename = 'skin.js' |
132 |
153 |
133 def get_skin(self, request=None): |
154 def get_skin(self, request=None): |
134 parent = self.skin_parent |
155 parent = self.skin_parent |
135 if parent is self: |
156 if parent is self: |
136 return self.skin |
157 return self.skin |
140 if request is None: |
161 if request is None: |
141 request = get_current_request() |
162 request = get_current_request() |
142 return request.registry.queryUtility(ISkin, skin) |
163 return request.registry.queryUtility(ISkin, skin) |
143 |
164 |
144 |
165 |
|
166 @adapter_config(name='container_class', |
|
167 context=(Interface, IPyAMSLayer, Interface), |
|
168 provides=ITALESExtension) |
|
169 class ContainerClassTALESExtension(ContextRequestViewAdapter): |
|
170 """Container class TALES extension""" |
|
171 |
|
172 def render(self, context=None, default=''): |
|
173 if context is None: |
|
174 context = self.context |
|
175 result = default |
|
176 skin = get_parent(context, ISkinnable) |
|
177 if skin is not None: |
|
178 result = skin.container_class or result |
|
179 return result |
|
180 |
|
181 |
145 @implementer(IUserSkinnable) |
182 @implementer(IUserSkinnable) |
146 class UserSkinnableContent(SkinnableContent): |
183 class UserSkinnableContent(SkinnableContent): |
147 """User skinnable content base class""" |
184 """User skinnable content base class""" |
148 |
185 |
149 |
186 |