src/source/dev_guide/custom-skin.rst
branchdoc-dc
changeset 139 d632f8d6140b
parent 124 696f58cb5bdd
child 142 5a82a9a2ea46
--- a/src/source/dev_guide/custom-skin.rst	Thu Dec 20 17:59:43 2018 +0100
+++ b/src/source/dev_guide/custom-skin.rst	Fri Dec 21 15:20:06 2018 +0100
@@ -6,14 +6,204 @@
 Understading layers and skins
 -----------------------------
 
+
+.. _skinhowto:
+
 Creating a new skin
----------------------
+-------------------
+
+A Skin is a tagging interface for associating media, javascript and CSS resources to a **renderer**
+
+
+1) Create a new Layer to your skin
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Build a new interface inherit from `ICustomLayer`
+
+.. code-block:: python
+
+    class ICustomLayer(ICustomLayer):
+        """skin layer"""
+
+Define an utility providing ISkin with the custom label and the layer interface
+
+.. code-block:: python
+
+    @utility_config(name='Custom skin', provides=ISkin)
+    class CustomSkin(object):
+        """custom root skin"""
+
+        label = _("Custom: skin")
+        layer = ICustomLayer
+
+
+2) Declare the layer adapter
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: python
+
+    @adapter_config(context=(Interface, ICustomLayer, Interface), provides=IResources)
+    class CustomSkinResourcesAdapter(ContextRequestViewAdapter):
+    """Custom skin resources adapter"""
 
-Adding resources
-----------------
+        def get_resources(self):
+            mycms.need()
+
+
+We have defined a Multiadapter with context=(context, request, view).
+
+.. note::
+
+    In the ZMI website you can now change the default graphical theme by you custom skin
+
+    .. image:: ../_static/select_skin.png
+
+
+
+
+Adding resources library
+------------------------
+
+
+.. code-block:: python
+
+    from fanstatic import Library, Resource
+    from pyams_default_theme import pyams_default_theme
+
+    #Library(name, folder_path)
+    library = Library('mycms', 'resources')
+
+    #Resource(library, path_to_static)
+    mycms_css = Resource(library, 'css/mystyle.css',)
+
+
+    mycms_js = Resource(library, 'js/pyams-default.js',
+                        depends=(pyams_default_theme, )
+                        bottom=True
+                        )
+
+
+:py:class:`Resource` can include others resources already defined with *depends* attribute, here `pyams_default_theme`.
+
 
 Overriding templates
----------------------
+--------------------
+
+The simplest is to create a new class that inherits from the existing **Renderer**  and modify this template.
+After that all you have to define a new adapter name and a new label.
+
+
+.. code-block:: python
+    :linenos:
+
+    # New custom contact paragraph renderer
+
+    @adapter_config(name='custom', context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer)
+    @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer)
+    class ContactParagraphCustomRenderer(ContactParagraphDefaultRenderer):
+        """Context paragraph custom renderer"""
+
+        label = _("Custom contact renderer")
+        #settings_interface = IContactParagraphDefaultRendererSettings
+
+
+In this example, we have defined an adapter named 'custom' with :py:class:`IContactParagraph`,
+:py:class:`IPyAMSLayer` as context and provides :py:class:`ISharedContentRenderer` interface.
+
+Using ``@template_config()`` decorator, the renderer will be displayed in html container according to the template
+`templates/contact-custom.pt`
+
+The new renderer inherit of :py:class:`ContactParagraphDefaultRenderer`, have a new **label** (line 8)
+and this associated **settings_interface** is not modify(line 9)
+
+.. tip::
+
+    You can override the template of a renderer easily with the function :py:func:`pyams_template.template.override_template`
+    It's takes the context and the new template path as params.
+
+
 
 Creating custom renderer
 ------------------------
+
+We can define a new settings for the renderer, to do that we start by creating an interface:
+
+
+a) Create setting interface for the renderer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: python
+
+    class IPhotoRendererSettings(Interface):
+        """Custom renderer settings interface"""
+
+
+        display_photo = Bool(title=_("Show photo?"),
+                             description=_("Display contact photo"),
+                             required=True,
+                             default=True)
+
+        can_display_photo = Attribute("Check if photo can be displayed")
+
+
+We have created an interface with two attributes *display_photo* and *can_display_photo*
+Then we create an implemantation of the interface
+
+.. code-block:: python
+
+    @implementer(IPhotoRendererSettings)
+    class PhotoRendererSettings(Persistent, Location):
+        """Custom renderer settings"""
+
+        display_photo = FieldProperty(IPhotoRendererSettings['display_photo'])
+
+        @property
+        def can_display_photo(self):
+            contact = IContactParagraph(self.__parent__)
+            if not contact.photo:
+                return False
+            return self.display_photo
+
+
+
+b) Create an adapter for the render setting interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+With :py:func:`@adapter_config()` we declare a new adapter that applies to a context and provide the interface of
+ renderer settings
+
+.. code-block:: python
+
+    PHOTO_RENDERER_SETTINGS_KEY = 'pyams_content.contact.renderer:photo'
+
+    @adapter_config(context=IContactParagraph, provides=IPhotoRendererSettings)
+    def custom_renderer_settings_factory(context):
+        """Contact paragraph default renderer settings factory"""
+        return get_annotation_adapter(context, PHOTO_RENDERER_SETTINGS_KEY,
+                                      CustomRendererSettings)
+
+
+In this example the settings interface adapter is defined with `IContactParagraph` as context
+and provide `IPhotoRendererSettings`.
+
+
+
+c) Create an adapter for the render interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: python
+
+    @adapter_config(context=(IContactParagraph, IPyAMSLayer), provides=ISharedContentRenderer)
+    @template_config(template='templates/contact-custom.pt', layer=IPyAMSLayer)
+    class PhotoRenderer(BaseContentRenderer):
+        """Context paragraph custom renderer"""
+
+        label = _("Custom contact renderer")
+        settings_interface = IPhotoRendererSettings
+
+
+Add settings interface to the renderer `settings_interface = IPhotoRendererSettings`
+
+.. tip::
+    When a setting_interface is associated to a renderer, you can access to `settings` attributes through the template
+