--- 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
+