src/source/developer_guide/howto-paragraph.rst
branchdoc-dc
changeset 109 31b3d00edb8a
equal deleted inserted replaced
108:1de74ac0628f 109:31b3d00edb8a
       
     1 .. _paragraphhowto:
       
     2 
       
     3 
       
     4 How to create a Paragraph type?
       
     5 ===============================
       
     6 
       
     7 Paragraphs or Blocks are components that contain elements/fields and provide one or many renderer methods to compose
       
     8 the front office website
       
     9 
       
    10 
       
    11 Create a Paragraph
       
    12 """"""""""""""""""
       
    13 
       
    14 In this example we will create a contact paragraph to display at the user, who to contact.
       
    15 
       
    16 1) Interface
       
    17 ------------
       
    18 
       
    19 At first we create a new paragraph interface.
       
    20 
       
    21 .. code-block:: python
       
    22 
       
    23     CONTACT_PHONE_PARAGRAPH_TYPE = 'PhoneContact'
       
    24     CONTACT_PHONE_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.contact.phone.renderers'
       
    25 
       
    26 
       
    27     class IContactPhoneParagraph(IBaseParagraph):
       
    28     """Contact with phone number paragraph interface"""
       
    29 
       
    30     name = TextLine(title=_("Contact identity"),
       
    31                     description=_("Name of the contact"),
       
    32                     required=True)
       
    33 
       
    34     photo = ImageField(title=_("Photo"),
       
    35                        description=_("Use 'browse' button to select contact picture"),
       
    36                        required=False)
       
    37 
       
    38     phone = TextLine(title=_("Phone Number"),
       
    39                      description=_("Name of the contact", required=False))
       
    40 
       
    41     renderer = Choice(title=_("Contact template"),
       
    42                       description=_("Presentation template used for this contact"),
       
    43                       vocabulary=CONTACT_PHONE_PARAGRAPH_RENDERERS,
       
    44                       default='default')
       
    45 
       
    46 
       
    47 
       
    48 
       
    49 2) Implement the interface
       
    50 --------------------------
       
    51 
       
    52 An implementation of the interface
       
    53 
       
    54 .. code-block:: python
       
    55 
       
    56     @implementer(IContactPhoneParagraph)
       
    57     @factory_config(provided=IContactPhoneParagraph)
       
    58     class ContactPhoneParagraph(BaseParagraph):
       
    59         """Contact paragraph"""
       
    60 
       
    61 
       
    62         icon_class = 'fa-phone'
       
    63         icon_hint = _("Phone number card")
       
    64 
       
    65         name = FieldProperty(IContactPhoneParagraph['name'])
       
    66         _photo = FileProperty(IContactPhoneParagraph['photo'])
       
    67 
       
    68         renderer = FieldProperty(IContactParagraph['renderer'])
       
    69 
       
    70         @property
       
    71         def photo(self):
       
    72             return self._photo
       
    73 
       
    74         @photo.setter
       
    75         def photo(self, value):
       
    76             self._photo = value
       
    77             if IImage.providedBy(self._photo):
       
    78                 alsoProvides(self._photo, IResponsiveImage)
       
    79 
       
    80 
       
    81 3) Renderers Vocabulary
       
    82 -----------------------
       
    83 
       
    84 The list of rendered available for a paragraph is build automatically and is based on adapters that provide this interface
       
    85 
       
    86 .. code-block:: python
       
    87 
       
    88     @vocabulary_config(name=CONTACT_PARAGRAPH_RENDERERS)
       
    89     class ContactParagraphRendererVocabulary(RenderersVocabulary):
       
    90         """Contact Phone paragraph renderers vocabulary"""
       
    91 
       
    92         content_interface = IContactPhoneParagraph
       
    93 
       
    94 
       
    95 .. seealso::
       
    96 
       
    97     :ref:`rendererhowto`
       
    98 
       
    99 
       
   100 Paragraph in the ZMI
       
   101 """"""""""""""""""""
       
   102 
       
   103 
       
   104 To display and manage the new paragraph in the ZMI, you should create this associated forms
       
   105 
       
   106 1) Paragraph factory
       
   107 --------------------
       
   108 
       
   109 To create a new element instance inside the zodb, we need a container to this object. PyAMS provide
       
   110 `IParagraphContainerTarget`, it's the default container for all paragraphs. We could use this container interface
       
   111 as context to create a new paragraph.
       
   112 
       
   113 
       
   114 Declaration of the **factory** of `ContactPhoneParagraph`
       
   115 
       
   116 .. code-block:: python
       
   117 
       
   118     @utility_config(name=CONTACT_PHONE_PARAGRAPH_TYPE, provides=IParagraphFactory)
       
   119     class ContactPhoneParagraphFactory(BaseParagraphFactory):
       
   120         """Contact paragraph factory"""
       
   121 
       
   122         name = _("Contact Phone card")
       
   123         content_type = ContactPhoneParagraph
       
   124         secondary_menu = True
       
   125 
       
   126 
       
   127 Definition of a form to create a new ContactPhone instance
       
   128 
       
   129 .. code-block:: python
       
   130 
       
   131     from pyams_form.form import ajax_config
       
   132 
       
   133 
       
   134     @pagelet_config(name='add-contact-phone-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
       
   135                     permission=MANAGE_CONTENT_PERMISSION)
       
   136     @ajax_config(name='add-contact-phone-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
       
   137                  base=BaseParagraphAJAXAddForm)
       
   138     class ContactPhoneParagraphAddForm(AdminDialogAddForm):
       
   139         """Contact phone paragraph add form"""
       
   140 
       
   141         legend = _("Add new contact phone card")
       
   142         dialog_class = 'modal-large'
       
   143         icon_css_class = 'fa fa-fw fa-phone'
       
   144 
       
   145         fields = field.Fields(IContactPhoneParagraph).omit('__parent__', '__name__', 'visible')
       
   146         edit_permission = MANAGE_CONTENT_PERMISSION
       
   147 
       
   148          def create(self, data):
       
   149             return ContactPhoneParagraph()
       
   150 
       
   151         def add(self, object):
       
   152             IParagraphContainer(self.context).append(object)
       
   153 
       
   154 
       
   155 2) Create the Paragraph addform button in the menu
       
   156 --------------------------------------------------
       
   157 
       
   158 We have created a new form and we want add a quick access button to create a new paragraph
       
   159 
       
   160 .. code-block:: python
       
   161 
       
   162     @viewlet_config(name='add-contact-phone-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
       
   163                     layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600)
       
   164     class ContactPhoneParagraphAddMenu(BaseParagraphAddMenu):
       
   165         """Contact paragraph add menu"""
       
   166 
       
   167         label = _("Contact card...")
       
   168         label_css_class = 'fa fa-fw fa-id-card-o'
       
   169         url = 'add-contact-paragraph.html'
       
   170         paragraph_type = CONTACT_PARAGRAPH_TYPE
       
   171 
       
   172 
       
   173 
       
   174 3) Create Edit inner form
       
   175 -------------------------
       
   176 
       
   177 .. code-block:: python
       
   178 
       
   179     @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
       
   180                 permission=MANAGE_CONTENT_PERMISSION)
       
   181     @ajax_config(name='inner-properties.json', context=IContactPhoneParagraph, layer=IPyAMSLayer,
       
   182              base=BaseParagraphAJAXEditForm)
       
   183     @implementer(IInnerForm)
       
   184     class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm):
       
   185         """Contact paragraph inner edit form"""
       
   186 
       
   187         legend = None
       
   188 
       
   189         @property
       
   190         def buttons(self):
       
   191             if self.mode == INPUT_MODE:
       
   192                 return button.Buttons(IParagraphEditFormButtons)
       
   193             else:
       
   194                 return button.Buttons()
       
   195 
       
   196         def get_ajax_output(self, changes):
       
   197             output = super(ContactParagraphInnerAJAXEditForm, self).get_ajax_output(changes)
       
   198             updated = changes.get(IBaseParagraph, ())
       
   199             if 'title' in updated:
       
   200                 output.setdefault('events', []).append(get_json_paragraph_refresh_event(self.context, self.request))
       
   201             updated = changes.get(IContactParagraph, ())
       
   202             if ('photo' in updated) or ('renderer' in updated):
       
   203                 # we have to commit transaction to be able to handle blobs...
       
   204                 if 'photo' in updated:
       
   205                     ITransactionManager(self.context).get().commit()
       
   206                 output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request,
       
   207                                                                                    ContactParagraphInnerEditForm))
       
   208             return output
       
   209 
       
   210 
       
   211 4) Create an Edit modal form
       
   212 -----------------------------
       
   213 
       
   214 This form is used inside modals popup
       
   215 
       
   216 
       
   217 .. code-block:: python
       
   218 
       
   219     @ajax_config(name='properties.json', context=IContactPhoneParagraph, request_type=IPyAMSLayer,
       
   220                      permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
       
   221     @pagelet_config(name='properties.html', context=IContactParagraph, layer=IPyAMSLayer,
       
   222                     permission=MANAGE_CONTENT_PERMISSION)
       
   223     class ContactPhoneParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
       
   224         """Contact phone paragraph properties edit form"""
       
   225 
       
   226         prefix = 'contact_properties.'
       
   227 
       
   228         legend = _("Edit contact card properties")
       
   229         icon_css_class = 'fa fa-fw fa-id-card-o'
       
   230 
       
   231         fields = field.Fields(IContactParagraph).omit('__parent__', '__name__', 'visible')
       
   232         fields['renderer'].widgetFactory = RendererFieldWidget
       
   233 
       
   234         edit_permission = MANAGE_CONTENT_PERMISSION
       
   235 
       
   236 
       
   237 .. note::
       
   238 
       
   239     Select the new content block types in ZMI to make it available in tools
       
   240 
       
   241     .. image:: _static/select_paragraph.png
       
   242 
       
   243 
       
   244 How to associate links or Illustrations to a Paragraph ?
       
   245 ========================================================
       
   246 
       
   247 Adding the following marker interface, we add new behavior to the Paragraph `ContactPhoneParagraph` .
       
   248 
       
   249 
       
   250 Paragraph advanced
       
   251 """"""""""""""""""
       
   252 
       
   253 You can attach Associated files, links or illustration and manage them directly through the rubric `Links and Attachments`.
       
   254 
       
   255 .. image:: _static/select_links_n_attachment.png
       
   256 
       
   257 
       
   258 1) Paragraph with Links and Attachements
       
   259 ----------------------------------------
       
   260 
       
   261 To "activate" this features the paragrath object must to implement specific interface
       
   262 
       
   263 
       
   264 .. code-block:: python
       
   265 
       
   266     @implementer(IContactPhoneParagraph, IIllustrationTarget,ILinkContainerTarget,IExtFileContainerTarget))
       
   267     @factory_config(provided=IContactPhoneParagraph)
       
   268     class ContactPhoneParagraph(BaseParagraph):
       
   269         """Contact paragraph"""
       
   270             ...
       
   271 
       
   272 
       
   273 These interfaces will allow to link other data to the paragraph.
       
   274 
       
   275 **Marker interfaces:**
       
   276 
       
   277     +--------------------------------+
       
   278     |:py:class:`IIllustrationTarget` |
       
   279     +===================+============+
       
   280     |                   |            |
       
   281     +-------------------+------------+
       
   282 
       
   283     +---------------------------------+
       
   284     |:py:class:`ILinkContainerTarget` |
       
   285     +==============+==================+
       
   286     |              | Add internal link|
       
   287     |              +------------------+
       
   288     |              | Add external link|
       
   289     |              +------------------+
       
   290     |              | Add mailto link  |
       
   291     +--------------+------------------+
       
   292 
       
   293     +------------------------------------+
       
   294     |:py:class:`IExtFileContainerTarget` |
       
   295     +================+===================+
       
   296     |                | Add external file |
       
   297     |                +-------------------+
       
   298     |                | Add image         |
       
   299     |                +-------------------+
       
   300     |                | Add video         |
       
   301     |                +-------------------+
       
   302     |                | Add audio file    |
       
   303     +----------------+-------------------+
       
   304 
       
   305 
       
   306 **ZMI overview:**
       
   307 
       
   308 .. image:: _static/select_add_links.png
       
   309 
       
   310 
       
   311 
       
   312 2) Add link and association form
       
   313 --------------------------------
       
   314 
       
   315 You can add form to manage links and attachments directly in paragraph form to do that your form must implement
       
   316 ``IPropertiesEditForm`` and/or  ``IAssociationParentForm``
       
   317 
       
   318 
       
   319 .. code-block:: python
       
   320 
       
   321     @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
       
   322     @implementer(IInnerForm, IPropertiesEditForm, IAssociationParentForm)
       
   323     class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm):
       
   324         """Contact paragraph inner edit form"""
       
   325 
       
   326         legend = None
       
   327         ajax_handler = 'inner-properties.json'
       
   328 
       
   329 
       
   330 **Marker interfaces:**
       
   331 
       
   332 +-----------------------------------+
       
   333 |:py:class:`IPropertiesEditForm`    |
       
   334 +=========+=========================+
       
   335 |         | Add Illustration form   |
       
   336 +---------+-------------------------+
       
   337 
       
   338 +-----------------------------------+
       
   339 |:py:class:`IAssociationParentForm` |
       
   340 +===========+=======================+
       
   341 |           | Add Association form  |
       
   342 +-----------+-----------------------+
       
   343 
       
   344 .. image:: _static/associations_form.png
       
   345