src/source/appextend.rst
branchdoc-dc
changeset 62 dc2bd8068d7a
parent 57 e7d62e94392f
child 58 7e5e72ddeeb2
equal deleted inserted replaced
61:cfb7276fdd33 62:dc2bd8068d7a
     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