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