4 =========================== |
4 =========================== |
5 |
5 |
6 Understading layers and skins |
6 Understading layers and skins |
7 ----------------------------- |
7 ----------------------------- |
8 |
8 |
|
9 |
|
10 .. _skinhowto: |
|
11 |
9 Creating a new skin |
12 Creating a new skin |
10 --------------------- |
13 ------------------- |
11 |
14 |
12 Adding resources |
15 A Skin is a tagging interface for associating media, javascript and CSS resources to a **renderer** |
13 ---------------- |
16 |
|
17 |
|
18 1) Create a new Layer to your skin |
|
19 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
20 |
|
21 Build a new interface inherit from `ICustomLayer` |
|
22 |
|
23 .. code-block:: python |
|
24 |
|
25 class ICustomLayer(ICustomLayer): |
|
26 """skin layer""" |
|
27 |
|
28 Define an utility providing ISkin with the custom label and the layer interface |
|
29 |
|
30 .. code-block:: python |
|
31 |
|
32 @utility_config(name='Custom skin', provides=ISkin) |
|
33 class CustomSkin(object): |
|
34 """custom root skin""" |
|
35 |
|
36 label = _("Custom: skin") |
|
37 layer = ICustomLayer |
|
38 |
|
39 |
|
40 2) Declare the layer adapter |
|
41 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
42 |
|
43 .. code-block:: python |
|
44 |
|
45 @adapter_config(context=(Interface, ICustomLayer, Interface), provides=IResources) |
|
46 class CustomSkinResourcesAdapter(ContextRequestViewAdapter): |
|
47 """Custom skin resources adapter""" |
|
48 |
|
49 def get_resources(self): |
|
50 mycms.need() |
|
51 |
|
52 |
|
53 We have defined a Multiadapter with context=(context, request, view). |
|
54 |
|
55 .. note:: |
|
56 |
|
57 In the ZMI website you can now change the default graphical theme by you custom skin |
|
58 |
|
59 .. image:: ../_static/select_skin.png |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 Adding resources library |
|
65 ------------------------ |
|
66 |
|
67 |
|
68 .. code-block:: python |
|
69 |
|
70 from fanstatic import Library, Resource |
|
71 from pyams_default_theme import pyams_default_theme |
|
72 |
|
73 #Library(name, folder_path) |
|
74 library = Library('mycms', 'resources') |
|
75 |
|
76 #Resource(library, path_to_static) |
|
77 mycms_css = Resource(library, 'css/mystyle.css',) |
|
78 |
|
79 |
|
80 mycms_js = Resource(library, 'js/pyams-default.js', |
|
81 depends=(pyams_default_theme, ) |
|
82 bottom=True |
|
83 ) |
|
84 |
|
85 |
|
86 :py:class:`Resource` can include others resources already defined with *depends* attribute, here `pyams_default_theme`. |
|
87 |
14 |
88 |
15 Overriding templates |
89 Overriding templates |
16 --------------------- |
90 -------------------- |
|
91 |
|
92 The simplest is to create a new class that inherits from the existing **Renderer** and modify this template. |
|
93 After that all you have to define a new adapter name and a new label. |
|
94 |
|
95 |
|
96 .. code-block:: python |
|
97 :linenos: |
|
98 |
|
99 # New custom contact paragraph renderer |
|
100 |
|
101 @adapter_config(name='custom', context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer) |
|
102 @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer) |
|
103 class ContactParagraphCustomRenderer(ContactParagraphDefaultRenderer): |
|
104 """Context paragraph custom renderer""" |
|
105 |
|
106 label = _("Custom contact renderer") |
|
107 #settings_interface = IContactParagraphDefaultRendererSettings |
|
108 |
|
109 |
|
110 In this example, we have defined an adapter named 'custom' with :py:class:`IContactParagraph`, |
|
111 :py:class:`IPyAMSLayer` as context and provides :py:class:`ISharedContentRenderer` interface. |
|
112 |
|
113 Using ``@template_config()`` decorator, the renderer will be displayed in html container according to the template |
|
114 `templates/contact-custom.pt` |
|
115 |
|
116 The new renderer inherit of :py:class:`ContactParagraphDefaultRenderer`, have a new **label** (line 8) |
|
117 and this associated **settings_interface** is not modify(line 9) |
|
118 |
|
119 .. tip:: |
|
120 |
|
121 You can override the template of a renderer easily with the function :py:func:`pyams_template.template.override_template` |
|
122 It's takes the context and the new template path as params. |
|
123 |
|
124 |
17 |
125 |
18 Creating custom renderer |
126 Creating custom renderer |
19 ------------------------ |
127 ------------------------ |
|
128 |
|
129 We can define a new settings for the renderer, to do that we start by creating an interface: |
|
130 |
|
131 |
|
132 a) Create setting interface for the renderer |
|
133 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
134 |
|
135 .. code-block:: python |
|
136 |
|
137 class IPhotoRendererSettings(Interface): |
|
138 """Custom renderer settings interface""" |
|
139 |
|
140 |
|
141 display_photo = Bool(title=_("Show photo?"), |
|
142 description=_("Display contact photo"), |
|
143 required=True, |
|
144 default=True) |
|
145 |
|
146 can_display_photo = Attribute("Check if photo can be displayed") |
|
147 |
|
148 |
|
149 We have created an interface with two attributes *display_photo* and *can_display_photo* |
|
150 Then we create an implemantation of the interface |
|
151 |
|
152 .. code-block:: python |
|
153 |
|
154 @implementer(IPhotoRendererSettings) |
|
155 class PhotoRendererSettings(Persistent, Location): |
|
156 """Custom renderer settings""" |
|
157 |
|
158 display_photo = FieldProperty(IPhotoRendererSettings['display_photo']) |
|
159 |
|
160 @property |
|
161 def can_display_photo(self): |
|
162 contact = IContactParagraph(self.__parent__) |
|
163 if not contact.photo: |
|
164 return False |
|
165 return self.display_photo |
|
166 |
|
167 |
|
168 |
|
169 b) Create an adapter for the render setting interface |
|
170 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
171 |
|
172 With :py:func:`@adapter_config()` we declare a new adapter that applies to a context and provide the interface of |
|
173 renderer settings |
|
174 |
|
175 .. code-block:: python |
|
176 |
|
177 PHOTO_RENDERER_SETTINGS_KEY = 'pyams_content.contact.renderer:photo' |
|
178 |
|
179 @adapter_config(context=IContactParagraph, provides=IPhotoRendererSettings) |
|
180 def custom_renderer_settings_factory(context): |
|
181 """Contact paragraph default renderer settings factory""" |
|
182 return get_annotation_adapter(context, PHOTO_RENDERER_SETTINGS_KEY, |
|
183 CustomRendererSettings) |
|
184 |
|
185 |
|
186 In this example the settings interface adapter is defined with `IContactParagraph` as context |
|
187 and provide `IPhotoRendererSettings`. |
|
188 |
|
189 |
|
190 |
|
191 c) Create an adapter for the render interface |
|
192 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
193 |
|
194 .. code-block:: python |
|
195 |
|
196 @adapter_config(context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer) |
|
197 @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer) |
|
198 class PhotoRenderer(BaseContentRenderer): |
|
199 """Context paragraph custom renderer""" |
|
200 |
|
201 label = _("Custom contact renderer") |
|
202 settings_interface = IPhotoRendererSettings |
|
203 |
|
204 |
|
205 Add settings interface to the renderer `settings_interface = IPhotoRendererSettings` |
|
206 |
|
207 .. tip:: |
|
208 When a setting_interface is associated to a renderer, you can access to `settings` attributes through the template |
|
209 |