3 How to create a new Portlet ? |
3 How to create a new Portlet ? |
4 ----------------------------- |
4 ----------------------------- |
5 |
5 |
6 **Portlets** are pluggable user interface software components that are managed and displayed in a web portal, |
6 **Portlets** are pluggable user interface software components that are managed and displayed in a web portal, |
7 for example an enterprise portal or a web CMS. A portlet can aggregate (integrate) and personalize content from |
7 for example an enterprise portal or a web CMS. A portlet can aggregate (integrate) and personalize content from |
8 different sources within a web page. A portlet responds to requests from a web client with and generates dynamic content. |
8 different sources within a web page. A portlet responds to requests from a web client and generates dynamic content |
9 (*reference:* `Wiki portlet`_) |
9 (*reference:* `Wiki portlet`_). |
10 |
10 |
11 .. _`wiki portlet`: https://en.wikipedia.org/wiki/Portlet |
11 .. _`wiki portlet`: https://en.wikipedia.org/wiki/Portlet |
12 |
12 |
13 |
13 |
14 **Pyams Portal** provides predefined portlets that to compose and organize the structure of a website. |
14 **PyAMS Portal** provides the portal engine but only a very small set of predefined portlets that can be used to compose |
|
15 and organize the structure of a web page; additional portlets are provided by other packages, like |
|
16 :ref:`pyams_content`. |
15 |
17 |
16 1. Define a Portlet setting |
|
17 ''''''''''''''''''''''''''' |
|
18 |
18 |
19 Portlet setting interface are defined in ``interfaces.py``, you can use IPortletSettings or extend the interface |
19 1. Define portlet settings |
20 by adding an additional properties for example: |
20 '''''''''''''''''''''''''' |
|
21 |
|
22 Portlet settings interface are defined in ``interfaces.py``, you can use :py:class:`pyams_portal.interfaces.IPortletSettings` |
|
23 or extend the interface by adding additional properties for example: |
21 |
24 |
22 .. code-block:: python |
25 .. code-block:: python |
23 |
26 |
24 from zope.schema import Text |
27 from zope.schema import Text |
25 |
28 |
|
29 NEW_PORTLET_NAME = 'new.portlet' |
|
30 |
26 class INewPortletSettings(IPortletSettings): |
31 class INewPortletSettings(IPortletSettings): |
27 |
32 |
28 comment = Text(title=_("Comment"), |
33 comment = Text(title=_("Comment"), |
29 required=True, |
34 required=True) |
30 default=True) |
|
31 |
35 |
32 PortletSetting component does what IPortletSettings describes. This is usually referred to as the implementation |
36 |
33 of IPortletSettings. |
37 A :py:class:`pyams_portal.portlet.PortletSettings` persistent subclass then implements what IPortletSettings describes: |
34 |
38 |
35 .. code-block:: python |
39 .. code-block:: python |
36 |
40 |
37 @implementer(IPortletSettings) |
41 @implementer(INewPortletSettings) |
38 class ImagePortletSettings(PortletSettings): |
42 class NewPortletSettings(PortletSettings): |
39 """Image portlet settings""" |
43 """Portlet settings""" |
40 |
44 |
41 _image = FileProperty(IImagePortletSettings['image']) |
45 comment = FieldProperty(INewPortletSettings['comment']) |
42 |
|
43 @property |
|
44 def image(self): |
|
45 return self._image |
|
46 |
|
47 @image.setter |
|
48 def image(self, value): |
|
49 self._image = value |
|
50 if (value is not None) and (value is not DELETED_FILE): |
|
51 alsoProvides(self._image, IResponsiveImage) |
|
52 |
|
53 |
46 |
54 |
47 |
55 2. Create Portlet |
48 2. Create Portlet |
56 ''''''''''''''''' |
49 ''''''''''''''''' |
57 |
50 |
58 The Porltet component is a utility, it implement the IPortlet interface and it registered by the portlet_config adapter |
51 The Portlet component is a utility, which implements the :py:class:`pyams_portal.interfaces.IPortlet` interface and is |
59 |
52 registered by the :py:func:`pyams_portal.portlet.portlet_config` decorator; |
60 To register a new portlet you must specify the settings_class associated |
|
61 |
53 |
62 .. code-block:: python |
54 .. code-block:: python |
63 |
55 |
64 @portlet_config(permission=VIEW_PERMISSION) |
56 @portlet_config(permission=VIEW_PERMISSION) |
65 class ImagePortlet(Portlet): |
57 class ImagePortlet(Portlet): |
66 """Image portlet""" |
58 """Image portlet""" |
67 |
59 |
68 name = IMAGE_PORTLET_NAME |
60 name = NEW_PORTLET_NAME |
69 label = _("Image") |
61 label = _("New portlet") |
70 |
62 |
71 toolbar_image = None |
63 toolbar_image = None |
72 toolbar_css_class = 'fa fa-fw fa-2x fa-picture-o' |
64 toolbar_css_class = 'fa fa-fw fa-2x fa-picture-o' |
73 |
65 |
74 settings_class = ImagePortletSettings |
66 settings_class = NewPortletSettings |
75 |
67 |
76 |
68 |
|
69 Where: |
|
70 - **permission**: permission required to display this portlet content |
|
71 - **name**: internal name given to this portlet. This name must be unique between all portlets, so using your own |
|
72 namespace into this name is generally a good option! |
|
73 - **label**: user label given to this portlet |
|
74 - **toolbar_image**: URL of an image used to display portlet button into ZMI toolbar, if any |
|
75 - **toolbar_css_class**: CSS class used to display portlet button into ZMI toolbar, if any |
|
76 - **settings_class**: class used to store portlet settings. |
77 |
77 |
78 4. Create HTML template |
|
79 ''''''''''''''''''''''' |
|
80 |
78 |
|
79 3. Create portlet settings edit form |
|
80 '''''''''''''''''''''''''''''''''''' |
|
81 |
|
82 Portlet settings have to be updated through management interface via a :py:class:`pyams_portal.zmi.portlet.PortletSettingsEditor` |
|
83 subform: |
|
84 |
|
85 .. code-block:: python |
|
86 |
|
87 @pagelet_config(name='properties.html', context=INewPortletSettings, layer=IPyAMSLayer, |
|
88 permission=VIEW_SYSTEM_PERMISSION) |
|
89 class NewPortletSettingsEditor(PortletSettingsEditor): |
|
90 """New portlet settings editor""" |
|
91 |
|
92 settings = INewPortletSettings |
|
93 |
|
94 |
|
95 @adapter_config(name='properties.json', context=(INewPortletSettings, IPyAMSLayer), provides=IPagelet) |
|
96 class NewPortletSettingsAJAXEditor(AJAXEditForm, NewPortletSettingsEditor): |
|
97 """New portlet settings editor, JSON renderer""" |
|
98 |
|
99 |
|
100 4. Previewing portlet content |
|
101 ''''''''''''''''''''''''''''' |
|
102 |
|
103 A *previewer* is used into ZMI to display portlet content into portal template definition page: |
|
104 |
|
105 .. code-block:: python |
|
106 |
|
107 @adapter_config(context=(Interface, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletPreviewer) |
|
108 @template_config(template='my-portlet-preview.pt', layer=IPyAMSLayer) |
|
109 class NewPortletPreviewer(PortletPreviewer): |
|
110 """New portlet previewer""" |
|
111 |
|
112 |
|
113 The previewer template is a Chameleon template: |
81 |
114 |
82 .. code-block:: genshi |
115 .. code-block:: genshi |
83 |
116 |
84 <span>${view.settings.comment}</span> |
117 <tal:var define="settings view.settings"> |
|
118 <tal:if condition="settings.visible"> |
|
119 <div tal:content="settings.comment">Comment</div> |
|
120 </tal:if> |
|
121 <tal:if condition="not settings.visible"> |
|
122 <div class="text-center padding-y-5"> |
|
123 <span class="fa-stack fa-lg"> |
|
124 <i class="fa fa-eye fa-stack-1x"></i> |
|
125 <i class="fa fa-ban fa-stack-2x text-danger"></i> |
|
126 </span> |
|
127 </div> |
|
128 </tal:if> |
|
129 </tal:var> |
|
130 |
|
131 Here we check if portlet is visible or not to display a small icon when hidden; otherwise we display entered comment. |
85 |
132 |
86 |
133 |
|
134 5. Rendering portlet content |
|
135 '''''''''''''''''''''''''''' |
87 |
136 |
88 5. Renderer |
137 A *renderer* is used to display portlet content into rendered page content: |
89 ''''''''''' |
|
90 |
138 |
91 .. code-block:: python |
139 .. code-block:: python |
92 |
140 |
93 @adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, IImagePortletSettings), provides=IPortletRenderer) |
141 @adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletRenderer) |
94 @template_config(template='image.pt', layer=IPyAMSLayer) |
142 @template_config(template='my-portlet-render.pt', layer=IPyAMSLayer) |
95 class ImagePortletRenderer(PortletRenderer): |
143 class NewPortletRenderer(PortletRenderer): |
96 """Image portlet renderer""" |
144 """New portlet renderer""" |
97 |
145 |
98 label = _("Responsive image renderer") |
146 label = _("Default comment renderer") |
99 |
147 |
100 |
148 |
|
149 Each renderer template is also a Chameleon template: |
101 |
150 |
102 6. Zmi integration module |
151 .. code-block:: genshi |
103 ''''''''''''''''''''''''' |
152 |
|
153 <div class="comment" tal:content="view.settings.comment">Comment</div> |
|
154 |
|
155 |
|
156 This is the configuration of a *default* renderer defined for this portlet; you can provide several renderers for a |
|
157 given portlet by given distinct names to the adapters: |
104 |
158 |
105 .. code-block:: python |
159 .. code-block:: python |
106 |
160 |
107 @pagelet_config(name='properties.html', context=IImagePortletSettings, request_type=IPyAMSLayer, |
161 @adapter_config(name='another-renderer', |
108 permission=VIEW_SYSTEM_PERMISSION) |
162 context=(IPortalContext, IPyAMSLayer, Interface, INewPortletSettings), provides=IPortletRenderer) |
109 class ImagePortletSettingsEditor(PortletSettingsEditor): |
163 @template_config(template='my-portlet-render-2.pt', layer=IPyAMSLayer) |
110 """Image portlet settings editor""" |
164 class AnotherNewPortletRenderer(PortletRenderer): |
|
165 """Another new portlet renderer""" |
111 |
166 |
112 settings = IImagePortletSettings |
167 label = _("Another comment renderer") |
113 |
|
114 |
|
115 |
|