# HG changeset patch # User Damien Correia # Date 1528106168 -7200 # Node ID 5cf9c8a16aee5d27f846cb2a06f948e5df173416 # Parent efe71f19939cca812c6599c72d4fa855a66f17b7 Update docs diff -r efe71f19939c -r 5cf9c8a16aee src/source/_static/select_paragraph.png Binary file src/source/_static/select_paragraph.png has changed diff -r efe71f19939c -r 5cf9c8a16aee src/source/_static/select_portlet.png Binary file src/source/_static/select_portlet.png has changed diff -r efe71f19939c -r 5cf9c8a16aee src/source/_static/select_skin.png Binary file src/source/_static/select_skin.png has changed diff -r efe71f19939c -r 5cf9c8a16aee src/source/appextend.rst --- a/src/source/appextend.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/appextend.rst Mon Jun 04 11:56:08 2018 +0200 @@ -1,8 +1,8 @@ .. _appextend: -Extending PyAMS -=============== +How to extend PyAMS ? +===================== .. toctree:: :maxdepth: 1 diff -r efe71f19939c -r 5cf9c8a16aee src/source/developerguide.rst --- a/src/source/developerguide.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/developerguide.rst Mon Jun 04 11:56:08 2018 +0200 @@ -4,9 +4,6 @@ Developer's Guide ================= -PyAMS packages are developed based on ZCA - - .. toctree:: :maxdepth: 2 diff -r efe71f19939c -r 5cf9c8a16aee src/source/howto-paragraph.rst --- a/src/source/howto-paragraph.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/howto-paragraph.rst Mon Jun 04 11:56:08 2018 +0200 @@ -10,60 +10,59 @@ 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) + CONTACT_PHONE_PARAGRAPH_TYPE = 'PhoneContact' + CONTACT_PHONE_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.contact.phone.renderers' - photo = ImageField(title=_("Photo"), - description=_("Use 'browse' button to select contact picture"), - required=False) + class IContactPhoneParagraph(IBaseParagraph): + """Contact with phone number paragraph interface""" - address = Text(title=_("Address"), required=False) + 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) - contact_email = MailAddressField(title=_("Email address"), - description=_("Contact email address"), - required=False) + phone = TextLine(title=_("Phone Number"), + description=_("Name of the contact", required=False)) + + address = Text(title=_("Address"), required=False) - renderer = Choice(title=_("Contact template"), - description=_("Presentation template used for this contact"), - vocabulary=CONTACT_PARAGRAPH_RENDERERS, - default='default') + 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_PHONE_PARAGRAPH_RENDERERS, + default='default') 2) Implement the interface -"""""""""""""""""""""""""" +-------------------------- An implementation of the interface .. code-block:: python - @implementer(IContactParagraph) + @implementer(IContactPhoneParagraph) @factory_config(provided=IContactPhoneParagraph) - class ContactParagraph(RenderedContentMixin, BaseParagraph): + class ContactPhoneParagraph(BaseParagraph): """Contact paragraph""" - icon_class = 'fa-id-card-o' - icon_hint = _("Contact card") - - name = FieldProperty(IContactParagraph['name']) - _photo = FileProperty(IContactParagraph['photo']) + icon_class = 'fa-phone' + icon_hint = _("Phone number card") address = FieldProperty(IContactParagraph['address']) contact_email = FieldProperty(IContactParagraph['contact_email']) @@ -81,7 +80,7 @@ 3) renderer Vocabulary -"""""""""""""""""""""" +---------------------- The list of rendered available for a paragraph is build automatically and is based on adapters that provide this interface @@ -105,7 +104,7 @@ 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 @@ -141,9 +140,11 @@ 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): @@ -151,7 +152,7 @@ 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 @@ -167,3 +168,81 @@ url = 'add-contact-paragraph.html' paragraph_type = CONTACT_PARAGRAPH_TYPE + +3)Edit form +----------- + +- *HTML* +.. code-block:: python + + @pagelet_config(name='properties.html', context=IContactParagraph, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) + class ContactParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm): + """Contact paragraph properties edit form""" + + prefix = 'contact_properties.' + + legend = _("Edit contact card properties") + icon_css_class = 'fa fa-fw fa-id-card-o' + + fields = field.Fields(IContactParagraph).omit('__parent__', '__name__', 'visible') + fields['renderer'].widgetFactory = RendererFieldWidget + + ajax_handler = 'properties.json' + edit_permission = MANAGE_CONTENT_PERMISSION + + def updateWidgets(self, prefix=None): + super(ContactParagraphPropertiesEditForm, self).updateWidgets(prefix) + if 'address' in self.widgets: + self.widgets['address'].widget_css_class = 'textarea' + + - *JSON* + +.. code-block:: python + + @view_config(name='properties.json', context=IContactParagraph, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) + class ContactParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, ContactParagraphPropertiesEditForm): + """Contact paragraph properties edit form, JSON renderer""" + + + @adapter_config(context=(IContactParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) + @implementer(IInnerForm) + class ContactParagraphInnerEditForm(ContactParagraphPropertiesEditForm): + """Contact paragraph inner edit form""" + + legend = None + ajax_handler = 'inner-properties.json' + + @property + def buttons(self): + if self.mode == INPUT_MODE: + return button.Buttons(IParagraphEditFormButtons) + else: + return button.Buttons() + + + @view_config(name='inner-properties.json', context=IContactParagraph, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) + class ContactParagraphInnerAJAXEditForm(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, ()) + 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 + +.. note:: + + Select the new content block types in ZMI to make it available in tools + + .. image:: _static/select_paragraph.png diff -r efe71f19939c -r 5cf9c8a16aee src/source/howto-portlet.rst --- a/src/source/howto-portlet.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/howto-portlet.rst Mon Jun 04 11:56:08 2018 +0200 @@ -171,3 +171,10 @@ .. tip:: You can use an other template without create a new renderer component, with :py:func:`pyams_utils` to override the default template with you own. + + +.. note:: + + Select the new portlet in ZMI to make it available in the website template editor + + .. image:: _static/select_portlet.png diff -r efe71f19939c -r 5cf9c8a16aee src/source/howto-skin.rst --- a/src/source/howto-skin.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/howto-skin.rst Mon Jun 04 11:56:08 2018 +0200 @@ -3,3 +3,67 @@ How to create a new skin? ========================= + +A Skin is a tagging interface for associating media, javascript and CSS resources to a **renderer** + +1) Configuring resource 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 + ) + + +Resource can include other resource already defined in pyams_default_theme + + +2) 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 + + +3) Declare the layer adapter +---------------------------- + +.. code-block:: python + + @adapter_config(context=(Interface, ICustomLayer, Interface), provides=IResources) + class CustomSkinResourcesAdapter(ContextRequestViewAdapter): + """Custom skin resources adapter""" + + def get_resources(self): + mycms.need() + +.. note:: + In the ZMI website you can now change the default graphical theme by you custom skin + + .. image:: _static/select_skin.png diff -r efe71f19939c -r 5cf9c8a16aee src/source/index.rst --- a/src/source/index.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/index.rst Mon Jun 04 11:56:08 2018 +0200 @@ -20,7 +20,7 @@ :maxdepth: 2 :caption: Tutorial - User’s Guide + PyAMS CMS User’s Guide screenshots .. toctree:: diff -r efe71f19939c -r 5cf9c8a16aee src/source/zca.rst --- a/src/source/zca.rst Fri Jun 01 18:27:09 2018 +0200 +++ b/src/source/zca.rst Mon Jun 04 11:56:08 2018 +0200 @@ -3,8 +3,9 @@ Zope Component Architecture with PyAMS ++++++++++++++++++++++++++++++++++++++ -The **Zope Component Architecture** (aka **ZCA**) is used by the Pyramid framework "under the hood" to handle interfaces, -adapters and utilities. You don't **have to** use it in your own applications. But you can. +PyAMS packages are developed based on the **Zope Component Architecture** (aka **ZCA**). ZCA is used by the Pyramid framework +"under the hood" to handle interfaces, adapters and utilities. You don't **have to** use it in your own applications. +But you can. The ZCA is mainly adding elements like **interfaces**, **adapters** and **utilities** to the Python language. It allows you to write a framework or an application by using **components** which can be extended easily.