|
1 .. _rendererhowto: |
|
2 |
|
3 |
|
4 How to create a Renderer? |
|
5 ========================= |
|
6 |
|
7 |
|
8 **Renderer** are the layout of the utility data content. A renderer combine un context, a skin and |
|
9 a template to produce the front office html |
|
10 |
|
11 To create new renderer you can override an already exist renderer or create a new one from scratch. Steps below |
|
12 we will create a renderer for a `IContact` paragraph |
|
13 |
|
14 |
|
15 1. Override a Renderer |
|
16 ---------------------- |
|
17 |
|
18 The simplest is to create a new class that inherits from the existing **Renderer** and modify this template. |
|
19 After that all you have to define a new adapter name and a new label. |
|
20 |
|
21 |
|
22 .. code-block:: python |
|
23 :linenos: |
|
24 |
|
25 # New custom contact paragraph renderer |
|
26 |
|
27 @adapter_config(name='custom', context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer) |
|
28 @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer) |
|
29 class ContactParagraphCustomRenderer(ContactParagraphDefaultRenderer): |
|
30 """Context paragraph custom renderer""" |
|
31 |
|
32 label = _("Custom contact renderer") |
|
33 #settings_interface = IContactParagraphDefaultRendererSettings |
|
34 |
|
35 |
|
36 In this example, we have defined an adapter named 'custom' with :py:class:`IContactParagraph`, |
|
37 :py:class:`IPyAMSLayer` as context and provides :py:class:`ISharedContentRenderer` interface. |
|
38 |
|
39 Using ``@template_config()`` decorator, the renderer will be displayed in html container according to the template |
|
40 `templates/contact-custom.pt` |
|
41 |
|
42 The new renderer inherit of :py:class:`ContactParagraphDefaultRenderer`, have a new **label** (line 8) |
|
43 and this associated **settings_interface** is not modify(line 9) |
|
44 |
|
45 .. tip:: |
|
46 |
|
47 You can override the template of a renderer easily with the function :py:func:`pyams_template.template.override_template` |
|
48 It's takes the context and the new template path as params. |
|
49 |
|
50 |
|
51 |
|
52 2. Create a new Renderer from scratch |
|
53 ------------------------------------- |
|
54 |
|
55 We can define a new settings for the renderer, to do that we start by creating an interface: |
|
56 |
|
57 |
|
58 a) Create setting interface for the renderer |
|
59 """""""""""""""""""""""""""""""""""""""""""" |
|
60 |
|
61 .. code-block:: python |
|
62 |
|
63 class IPhotoRendererSettings(Interface): |
|
64 """Custom renderer settings interface""" |
|
65 |
|
66 |
|
67 display_photo = Bool(title=_("Show photo?"), |
|
68 description=_("Display contact photo"), |
|
69 required=True, |
|
70 default=True) |
|
71 |
|
72 can_display_photo = Attribute("Check if photo can be displayed") |
|
73 |
|
74 |
|
75 We have created an interface with two attributes *display_photo* and *can_display_photo* |
|
76 Then we create an implemantation of the interface |
|
77 |
|
78 .. code-block:: python |
|
79 |
|
80 @implementer(IPhotoRendererSettings) |
|
81 class PhotoRendererSettings(Persistent, Location): |
|
82 """Custom renderer settings""" |
|
83 |
|
84 display_photo = FieldProperty(IPhotoRendererSettings['display_photo']) |
|
85 |
|
86 @property |
|
87 def can_display_photo(self): |
|
88 contact = IContactParagraph(self.__parent__) |
|
89 if not contact.photo: |
|
90 return False |
|
91 return self.display_photo |
|
92 |
|
93 |
|
94 |
|
95 b) Create an adapter for the render setting interface |
|
96 """"""""""""""""""""""""""""""""""""""""""""""""""""" |
|
97 |
|
98 With :py:func:`@adapter_config()` we declare a new adapter that applies to a context and provide the interface of |
|
99 renderer settings |
|
100 |
|
101 .. code-block:: python |
|
102 |
|
103 PHOTO_RENDERER_SETTINGS_KEY = 'pyams_content.contact.renderer:photo' |
|
104 |
|
105 @adapter_config(context=IContactParagraph, provides=IPhotoRendererSettings) |
|
106 def custom_renderer_settings_factory(context): |
|
107 """Contact paragraph default renderer settings factory""" |
|
108 return get_annotation_adapter(context, PHOTO_RENDERER_SETTINGS_KEY, |
|
109 CustomRendererSettings) |
|
110 |
|
111 |
|
112 In this example the settings interface adapter is defined with `IContactParagraph` as context |
|
113 and provide `IPhotoRendererSettings`. |
|
114 |
|
115 |
|
116 |
|
117 c) Create an adapter for the render interface |
|
118 """"""""""""""""""""""""""""""""""""""""""""" |
|
119 |
|
120 .. code-block:: python |
|
121 |
|
122 @adapter_config(context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer) |
|
123 @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer) |
|
124 class PhotoRenderer(BaseContentRenderer): |
|
125 """Context paragraph custom renderer""" |
|
126 |
|
127 label = _("Custom contact renderer") |
|
128 settings_interface = IPhotoRendererSettings |
|
129 |
|
130 |
|
131 Add settings interface to the renderer `settings_interface = IPhotoRendererSettings` |
|
132 |
|
133 .. tip:: |
|
134 When a setting_interface is associated to a renderer, you can access to `settings` attributes through the template |
|
135 |