src/source/howto-paragraph.rst
branchdoc-dc
changeset 73 a3a8642a31b2
parent 67 81281f49aeb4
child 75 5cf9c8a16aee
--- a/src/source/howto-paragraph.rst	Fri May 25 15:23:31 2018 +0200
+++ b/src/source/howto-paragraph.rst	Mon May 28 13:45:30 2018 +0200
@@ -3,3 +3,167 @@
 
 How to create a new paragraph type?
 ===================================
+
+Paragraphs are components or blocs that contain elements/fields and provide one or many renderer methods to compose
+the front office website
+
+In this example we will create a contact paragraph to display at the user, who to contact
+
+1) Define a paragraph Interface
+"""""""""""""""""""""""""""""""
+
+At first we create a new paragraph interface.
+
+.. code-block:: python
+
+    CONTACT_PARAGRAPH_TYPE = 'Contact'
+    CONTACT_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.contact.renderers'
+
+
+    class IContactParagraph(IBaseParagraph):
+        """Contact paragraph interface"""
+
+        name = TextLine(title=_("Contact identity"),
+                        description=_("Name of the contact"),
+                        required=True)
+
+
+        photo = ImageField(title=_("Photo"),
+                           description=_("Use 'browse' button to select contact picture"),
+                           required=False)
+
+        address = Text(title=_("Address"), required=False)
+
+        contact_email = MailAddressField(title=_("Email address"),
+                                         description=_("Contact email address"),
+                                         required=False)
+
+        renderer = Choice(title=_("Contact template"),
+                          description=_("Presentation template used for this contact"),
+                          vocabulary=CONTACT_PARAGRAPH_RENDERERS,
+                          default='default')
+
+
+
+
+2) Implement the interface
+""""""""""""""""""""""""""
+
+An implementation of the interface
+
+.. code-block:: python
+
+    @implementer(IContactParagraph)
+    @factory_config(provided=IContactPhoneParagraph)
+    class ContactParagraph(RenderedContentMixin, BaseParagraph):
+        """Contact paragraph"""
+
+
+        icon_class = 'fa-id-card-o'
+        icon_hint = _("Contact card")
+
+        name = FieldProperty(IContactParagraph['name'])
+        _photo = FileProperty(IContactParagraph['photo'])
+
+        address = FieldProperty(IContactParagraph['address'])
+        contact_email = FieldProperty(IContactParagraph['contact_email'])
+        renderer = FieldProperty(IContactParagraph['renderer'])
+
+        @property
+        def photo(self):
+            return self._photo
+
+        @photo.setter
+        def photo(self, value):
+            self._photo = value
+            if IImage.providedBy(self._photo):
+                alsoProvides(self._photo, IResponsiveImage)
+
+
+3) renderer Vocabulary
+""""""""""""""""""""""
+
+The list of rendered available for a paragraph is build automatically and is based on adapters that provide this interface
+
+.. code-block:: python
+
+    @vocabulary_config(name=CONTACT_PARAGRAPH_RENDERERS)
+    class ContactParagraphRendererVocabulary(RenderersVocabulary):
+        """Contact paragraph renderers vocabulary"""
+
+        content_interface = IContactParagraph
+
+
+.. seealso::
+
+    :ref:`rendererhowto`
+
+
+How integrate a paragraph in the ZMI?
+=====================================
+
+To display and manage the new paragraph in the ZMI, you should create this associated forms
+
+1) paragraph factory
+""""""""""""""""""""
+
+To create a new element inside the zodb, we need a container to this element. PyAMS provide
+`IParagraphContainerTarget`, it's the default container for all paragraphs. We could use this container interface
+as context to create a new paragraph.
+
+We need to create two views
+
+- *HTML*
+
+.. code-block:: python
+
+    @pagelet_config(name='add-contact-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+                    permission=MANAGE_CONTENT_PERMISSION)
+    class ContactParagraphAddForm(AdminDialogAddForm):
+        """Contact paragraph add form"""
+
+        legend = _("Add new contact card")
+        dialog_class = 'modal-large'
+        icon_css_class = 'fa fa-fw fa-id-card-o'
+
+        fields = field.Fields(IContactParagraph).omit('__parent__', '__name__', 'visible')
+        ajax_handler = 'add-contact-paragraph.json'
+        edit_permission = MANAGE_CONTENT_PERMISSION
+
+        def updateWidgets(self, prefix=None):
+            super(ContactParagraphAddForm, self).updateWidgets(prefix)
+            if 'address' in self.widgets:
+                self.widgets['address'].widget_css_class = 'textarea'
+
+        def create(self, data):
+            return ContactParagraph()
+
+        def add(self, object):
+            IParagraphContainer(self.context).append(object)
+
+- *JSON*
+
+.. code-block:: python
+    @view_config(name='add-contact-paragraph.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer,
+                 permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+    class ContactParagraphAJAXAddForm(BaseParagraphAJAXAddForm, ContactParagraphAddForm):
+        """Contact paragraph add form, JSON renderer"""
+
+
+2) Append the paragraph addform button in the menu
+""""""""""""""""""""""""""""""""""""""""""""""""""
+
+We have created a new form and we want add a quick access button to create a new paragraph
+
+.. code-block:: python
+
+    @viewlet_config(name='add-contact-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
+                    layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600)
+    class ContactParagraphAddMenu(BaseParagraphAddMenu):
+        """Contact paragraph add menu"""
+
+        label = _("Contact card...")
+        label_css_class = 'fa fa-fw fa-id-card-o'
+        url = 'add-contact-paragraph.html'
+        paragraph_type = CONTACT_PARAGRAPH_TYPE
+