# HG changeset patch # User Damien Correia # Date 1528473438 -7200 # Node ID 82165875e66b8c07aa1ffabc6c0d658be451a185 # Parent 8eb1b401003a22926a31593ce0f86be656e26a70 Updated forms doc diff -r 8eb1b401003a -r 82165875e66b src/source/appextend.rst --- a/src/source/appextend.rst Tue Jun 05 17:14:19 2018 +0200 +++ b/src/source/appextend.rst Fri Jun 08 17:57:18 2018 +0200 @@ -7,8 +7,10 @@ .. toctree:: :maxdepth: 1 + howto-adapter + howto-form + howto-paragraph howto-portlet howto-renderer - howto-paragraph howto-skin diff -r 8eb1b401003a -r 82165875e66b src/source/howto-form.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/source/howto-form.rst Fri Jun 08 17:57:18 2018 +0200 @@ -0,0 +1,103 @@ +.. _formhowto: + + +How to create a form to a component +=================================== + + +When creating a new object to the zodb, the construction of the form can't be based on an object passed context. +To build the form we use a default factory that is attached to the container of the element. + + +1) Container factory +-------------------- + +Declaration of the **factory** of `ContactPhoneParagraph` + +.. code-block:: python + + @utility_config(name=CONTACT_PHONE_PARAGRAPH_TYPE, provides=IParagraphFactory) + class ContactPhoneParagraphFactory(BaseParagraphFactory): + """Contact paragraph factory""" + + name = _("Contact Phone card") + content_type = ContactPhoneParagraph + secondary_menu = True + + + +For example :py:class:`IParagraphContainerTarget`, it's a marker interface for paragraph containers. +We could use this interface as context to declare a new pagelet. + + +.. code-block:: python + + from pyams_form.form import ajax_config + + + @pagelet_config(name='add-contact-phone-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) + @ajax_config(name='add-contact-phone-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer, + base=BaseParagraphAJAXAddForm) + class ContactPhoneParagraphAddForm(AdminDialogAddForm): + """Contact paragraph add form""" + + legend = _("Add new phone contact card") + dialog_class = 'modal-large' + icon_css_class = 'fa fa-fw fa-phone' + edit_permission = MANAGE_CONTENT_PERMISSION + + #Retrieve fields from the interface of the component + fields = field.Fields(IContactPhoneParagraph).omit('__parent__', '__name__', 'visible') + + + def create(self, data): + """Create one instance of the component""" + return ContactPhoneParagraph() + + def add(self, object): + """Add the new component to the container that implement the interface `IParagraphContainer` """ + IParagraphContainer(self.context).append(object) + +The associate form field are generated automatically based on this interface attributes + +:py:method:`@ajax_config()` allows the form is working with ajax requests by providing `json` content. + + + +2) Edit form +------------ + +.. code-block:: python + + @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) + permission=MANAGE_CONTENT_PERMISSION) + @ajax_config(name='inner-properties.json', context=IContactPhoneParagraph, layer=IPyAMSLayer, + base=BaseParagraphAJAXEditForm) + @implementer(IInnerForm) + class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm): + """Contact paragraph inner edit form""" + + legend = None + + @property + def buttons(self): + if self.mode == INPUT_MODE: + return button.Buttons(IParagraphEditFormButtons) + else: + return button.Buttons() + + def get_ajax_output(self, changes): + output = super(ContactParagraphInnerAJAXEditForm, self).get_ajax_output(changes) + updated = changes.get(IBaseParagraph, ()) + if 'title' in updated: + output.setdefault('events', []).append(get_json_paragraph_refresh_event(self.context, self.request)) + updated = changes.get(IContactParagraph, ()) + if ('photo' in updated) or ('renderer' in updated): + # we have to commit transaction to be able to handle blobs... + if 'photo' in updated: + ITransactionManager(self.context).get().commit() + output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request, + ContactParagraphInnerEditForm)) + return output + diff -r 8eb1b401003a -r 82165875e66b src/source/howto-paragraph.rst --- a/src/source/howto-paragraph.rst Tue Jun 05 17:14:19 2018 +0200 +++ b/src/source/howto-paragraph.rst Fri Jun 08 17:57:18 2018 +0200 @@ -106,18 +106,35 @@ 1) Paragraph factory -------------------- -To create a new element inside the zodb, we need a container to this element. PyAMS provide +To create a new element instance inside the zodb, we need a container to this object. 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* +Declaration of the **factory** of `ContactPhoneParagraph` .. code-block:: python + @utility_config(name=CONTACT_PHONE_PARAGRAPH_TYPE, provides=IParagraphFactory) + class ContactPhoneParagraphFactory(BaseParagraphFactory): + """Contact paragraph factory""" + + name = _("Contact Phone card") + content_type = ContactPhoneParagraph + secondary_menu = True + + +Definition of a form to create a new ContactPhone instance + +.. code-block:: python + + from pyams_form.form import ajax_config + + @pagelet_config(name='add-contact-phone-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) + @ajax_config(name='add-contact-phone-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer, + base=BaseParagraphAJAXAddForm) class ContactPhoneParagraphAddForm(AdminDialogAddForm): """Contact phone paragraph add form""" @@ -126,7 +143,6 @@ icon_css_class = 'fa fa-fw fa-phone' fields = field.Fields(IContactPhoneParagraph).omit('__parent__', '__name__', 'visible') - ajax_handler = 'add-contact-phone-paragraph.json' #(*) edit_permission = MANAGE_CONTENT_PERMISSION def create(self, data): @@ -136,18 +152,7 @@ IParagraphContainer(self.context).append(object) -- *JSON* - -.. code-block:: python - - #(*) - @view_config(name='add-contact-phone-1paragraph.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) - class ContactPhoneParagraphAJAXAddForm(BaseParagraphAJAXAddForm, ContactPhoneParagraphAddForm): - """Contact phone paragraph add form, JSON renderer""" - - -2) Append the paragraph addform button in the menu +2) Create 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 @@ -166,18 +171,20 @@ -3) Create Edit form -------------------- +3) Create Edit inner form +------------------------- .. code-block:: python @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) + permission=MANAGE_CONTENT_PERMISSION) + @ajax_config(name='inner-properties.json', context=IContactPhoneParagraph, layer=IPyAMSLayer, + base=BaseParagraphAJAXEditForm) @implementer(IInnerForm) class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm): """Contact paragraph inner edit form""" legend = None - ajax_handler = 'inner-properties.json' @property def buttons(self): @@ -186,15 +193,6 @@ else: return button.Buttons() - - -.. code-block:: python - - @view_config(name='inner-properties.json', context=IContactPhoneParagraph, request_type=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) - class ContactPhoneParagraphInnerAJAXEditForm(BaseParagraphAJAXEditForm, ContactParagraphInnerEditForm): - """Contact paragraph inner edit form, JSON renderer""" - def get_ajax_output(self, changes): output = super(ContactParagraphInnerAJAXEditForm, self).get_ajax_output(changes) updated = changes.get(IBaseParagraph, ()) @@ -216,10 +214,10 @@ This form is used inside modals popup -- *HTML* - .. code-block:: python + @ajax_config(name='properties.json', context=IContactPhoneParagraph, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) @pagelet_config(name='properties.html', context=IContactParagraph, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) class ContactPhoneParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm): @@ -233,22 +231,95 @@ fields = field.Fields(IContactParagraph).omit('__parent__', '__name__', 'visible') fields['renderer'].widgetFactory = RendererFieldWidget - ajax_handler = 'properties.json' edit_permission = MANAGE_CONTENT_PERMISSION -- *JSON* - -.. code-block:: python - - @view_config(name='properties.json', context=IContactPhoneParagraph, request_type=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) - class ContactPhoneParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, ContactParagraphPropertiesEditForm): - """Contact phone paragraph properties edit form, JSON renderer""" - - .. note:: Select the new content block types in ZMI to make it available in tools .. image:: _static/select_paragraph.png + + +How to associate links or Illustrations to a Paragraph ? +======================================================== + +Adding the following marker interface, we add new behavior to the Paragraph `ContactPhoneParagraph` . + + +1) Inner form +------------- + +.. code-block:: python + + @adapter_config(context=(IContactPhoneParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) + @implementer(IInnerForm, IPropertiesEditForm, IAssociationParentForm) + class ContactPhoneParagraphInnerEditForm(ContactPhoneParagraphPropertiesEditForm): + """Contact paragraph inner edit form""" + + legend = None + ajax_handler = 'inner-properties.json' + + +Marker interfaces: + +:py:class:`IPropertiesEditForm` + +:py:class:`IAssociationParentForm` + + +.. image:: _static/associations_form.png + + + +2) Inside a dedicated menu +-------------------------- + +.. image:: _static/select_links_n_attachment.png + + +.. code-block:: python + + @implementer(IContactPhoneParagraph, IIllustrationTarget,ILinkContainerTarget,IExtFileContainerTarget)) + @factory_config(provided=IContactPhoneParagraph) + class ContactPhoneParagraph(BaseParagraph): + """Contact paragraph""" + ... + + +Marker interfaces: + + +--------------------------------+ + |:py:class:`IIllustrationTarget` | + +===================+============+ + | | | + +-------------------+------------+ + + +---------------------------------+ + |:py:class:`ILinkContainerTarget` | + +==============+==================+ + | | Add internal link| + | +------------------+ + | | Add external link| + | +------------------+ + | | Add mailto link | + +--------------+------------------+ + + +------------------------------------+ + |:py:class:`IExtFileContainerTarget` | + +================+===================+ + | | Add external file | + | +-------------------+ + | | Add image | + | +-------------------+ + | | Add video | + | +-------------------+ + | | Add audio file | + +----------------+-------------------+ + + +ZMI overview: +.. image:: _static/select_add_links.png + + + diff -r 8eb1b401003a -r 82165875e66b src/source/howto-skin.rst --- a/src/source/howto-skin.rst Tue Jun 05 17:14:19 2018 +0200 +++ b/src/source/howto-skin.rst Fri Jun 08 17:57:18 2018 +0200 @@ -28,7 +28,7 @@ ) -Resource can include other resource already defined in pyams_default_theme +:py:class:`Resource` can include others resources already defined with *depends* attribute, here `pyams_default_theme`. 2) Create a new Layer to your skin