--- a/src/pyams_portal/interfaces.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/interfaces.py Thu Aug 05 09:27:48 2021 +0200
@@ -228,9 +228,13 @@
required=True,
default=True)
+ container_css_class = TextLine(title=_("Container CSS class"),
+ description=_("CSS class applied to this slot container"),
+ required=False)
+
xs_width = Int(title=_("Extra small device width"),
- description=_("Slot width, in columns count, on extra small devices (phones...); "
- "set to 0 to hide the portlet"),
+ description=_("Slot width, in columns count, on extra small devices "
+ "(phones...); set to 0 to hide the portlet"),
required=False,
min=0,
max=12)
@@ -243,15 +247,15 @@
max=12)
md_width = Int(title=_("Medium devices width"),
- description=_("Slot width, in columns count, on medium desktop devices (>= 992 pixels); "
- "set to 0 to hide the portlet"),
+ description=_("Slot width, in columns count, on medium desktop devices "
+ "(>= 992 pixels); set to 0 to hide the portlet"),
required=False,
min=0,
max=12)
lg_width = Int(title=_("Large devices width"),
- description=_("Slot width, in columns count, on large desktop devices (>= 1200 pixels); "
- "set to 0 to hide the portlet"),
+ description=_("Slot width, in columns count, on large desktop devices "
+ "(>= 1200 pixels); set to 0 to hide the portlet"),
required=False,
min=0,
max=12)
@@ -374,6 +378,11 @@
description=_("Two registered templates can't share the same name..."),
required=True)
+ css_class = TextLine(title=_("CSS class"),
+ description=_("This CSS class can be included into main presentation "
+ "layout..."),
+ required=False)
+
class IPortalTemplateContainer(IContainer, IAttributeAnnotatable):
"""Portal template container interface"""
Binary file src/pyams_portal/locales/fr/LC_MESSAGES/pyams_portal.mo has changed
--- a/src/pyams_portal/locales/fr/LC_MESSAGES/pyams_portal.po Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/locales/fr/LC_MESSAGES/pyams_portal.po Thu Aug 05 09:27:48 2021 +0200
@@ -126,7 +126,7 @@
#: src/pyams_portal/interfaces.py:259
msgid "CSS class"
-msgstr "Class CSS"
+msgstr "Classe CSS"
#: src/pyams_portal/interfaces.py:260
msgid "CSS class applied to this slot"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_portal/skin/template.py Thu Aug 05 09:27:48 2021 +0200
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2015-2021 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+"""PyAMS_portal.skin.template module
+
+This module provides a TALES extension which allows to get current template
+configuration and CSS class.
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface
+
+from pyams_portal.interfaces import IPortalContext, IPortalPage
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
+from pyams_utils.interfaces.tales import ITALESExtension
+from pyams_utils.traversing import get_parent
+
+
+@adapter_config(name='template_container_class',
+ context=(Interface, IPyAMSLayer, Interface),
+ provides=ITALESExtension)
+class TemplateContainerClassTALESExtension(ContextRequestViewAdapter):
+ """Template class getter TALES extension"""
+
+ def render(self, context=None, default=''):
+ if context is None:
+ context = self.context
+ result = default
+ portal_context = get_parent(context, IPortalContext)
+ if portal_context is not None:
+ page = IPortalPage(portal_context, None)
+ if page is not None:
+ template = page.template
+ if template is not None:
+ result = template.css_class
+ return result
--- a/src/pyams_portal/slot.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/slot.py Thu Aug 05 09:27:48 2021 +0200
@@ -33,6 +33,7 @@
slot_name = FieldProperty(ISlotConfiguration['slot_name'])
_portlet_ids = FieldProperty(ISlotConfiguration['portlet_ids'])
visible = FieldProperty(ISlotConfiguration['visible'])
+ container_css_class = FieldProperty(ISlotConfiguration['container_css_class'])
xs_width = FieldProperty(ISlotConfiguration['xs_width'])
sm_width = FieldProperty(ISlotConfiguration['sm_width'])
md_width = FieldProperty(ISlotConfiguration['md_width'])
--- a/src/pyams_portal/template.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/template.py Thu Aug 05 09:27:48 2021 +0200
@@ -80,6 +80,7 @@
"""Portal template class"""
name = FieldProperty(IPortalTemplate['name'])
+ css_class = FieldProperty(IPortalTemplate['css_class'])
content_name = _("Portal template")
--- a/src/pyams_portal/templates/pagelet.pt Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/templates/pagelet.pt Thu Aug 05 09:27:48 2021 +0200
@@ -5,14 +5,17 @@
<div class="row" tal:repeat="row range(template_config.rows)">
<div class="slots">
<tal:loop repeat="slot_name template_config.get_slots(row)">
- <div class="slot"
- tal:define="slot_config template_config.get_slot_configuration(slot_name)"
+ <div tal:define="slot_config template_config.get_slot_configuration(slot_name)"
tal:condition="slot_config.visible"
- tal:attributes="class string:slot col ${slot_config.get_css_class()}">
- <div class="portlets">
- <div tal:repeat="portlet_id template_config.slot_config[slot_name].portlet_ids"
- class="portlet ${view.get_portlet_css_class(portlet_id)}">
- <tal:var replace="structure view.render_portlet(portlet_id)">Content</tal:var>
+ tal:omit-tag="not:slot_config.container_css_class"
+ class="${slot_config.container_css_class}">
+ <div class="slot"
+ tal:attributes="class string:slot col ${slot_config.get_css_class()}">
+ <div class="portlets">
+ <div tal:repeat="portlet_id template_config.slot_config[slot_name].portlet_ids"
+ class="portlet ${view.get_portlet_css_class(portlet_id)}">
+ <tal:var replace="structure view.render_portlet(portlet_id)">Content</tal:var>
+ </div>
</div>
</div>
</div>
--- a/src/pyams_portal/zmi/container.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/container.py Thu Aug 05 09:27:48 2021 +0200
@@ -70,7 +70,8 @@
return absolute_url(self.request.root, self.request, 'admin#portal-templates.html')
-@adapter_config(context=(IPortalTemplateContainer, IAdminLayer, ITable), provides=ITableElementEditor)
+@adapter_config(context=(IPortalTemplateContainer, IAdminLayer, ITable),
+ provides=ITableElementEditor)
class PortalTemplateContainerTableElementEditor(DefaultElementEditorAdapter):
"""Portal template container table element editor"""
@@ -83,7 +84,8 @@
return resource_url(site, self.request, 'admin#{0}'.format(self.view_name))
-@viewlet_config(name='portal-templates.menu', context=ISite, layer=IAdminLayer, manager=IControlPanelMenu,
+@viewlet_config(name='portal-templates.menu',
+ context=ISite, layer=IAdminLayer, manager=IControlPanelMenu,
permission=MANAGE_TEMPLATE_PERMISSION, weight=20)
@viewletmanager_config(name='portal-templates.menu', context=ISite, layer=IAdminLayer)
@implementer(IPortalTemplateContainerMenu)
@@ -114,10 +116,12 @@
return attributes
-@adapter_config(context=(IPortalTemplate, IAdminLayer, PortalTemplateContainerTable), provides=ITableElementEditor)
+@adapter_config(context=(IPortalTemplate, IAdminLayer, PortalTemplateContainerTable),
+ provides=ITableElementEditor)
class PortalTemplateTableElementEditor(DefaultElementEditorAdapter):
"""Portal template table element editor"""
+ view_name = 'layout.html'
modal_target = False
@property
@@ -125,14 +129,16 @@
return resource_url(self.context, self.request, 'admin#{0}'.format(self.view_name))
-@adapter_config(name='name', context=(Interface, IAdminLayer, PortalTemplateContainerTable), provides=IColumn)
+@adapter_config(name='name', context=(Interface, IAdminLayer, PortalTemplateContainerTable),
+ provides=IColumn)
class PortalTemplateContainerNameColumn(NameColumn):
"""Portal template container name column"""
attrName = 'name'
-@adapter_config(name='trash', context=(Interface, IAdminLayer, PortalTemplateContainerTable), provides=IColumn)
+@adapter_config(name='trash', context=(Interface, IAdminLayer, PortalTemplateContainerTable),
+ provides=IColumn)
class PortalTemplateContainerTrashColumn(TrashColumn):
"""Portal template container trash column"""
@@ -140,14 +146,16 @@
permission = MANAGE_TEMPLATE_PERMISSION
-@view_config(name='delete-element.json', context=IPortalTemplateContainer, request_type=IPyAMSLayer,
+@view_config(name='delete-element.json',
+ context=IPortalTemplateContainer, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def delete_portal_template(request):
"""Delete selected template"""
return delete_container_element(request, ignore_permission=True)
-@adapter_config(context=(ISite, IAdminLayer, PortalTemplateContainerTable), provides=IValues)
+@adapter_config(context=(ISite, IAdminLayer, PortalTemplateContainerTable),
+ provides=IValues)
class PortalTemplateContainerValuesAdapter(ContextRequestViewAdapter):
"""Portal template container values adapter"""
@@ -159,7 +167,8 @@
return ()
-@pagelet_config(name='portal-templates.html', context=ISite, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION)
+@pagelet_config(name='portal-templates.html',
+ context=ISite, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION)
@implementer(IInnerPage)
class PortalTemplateContainerView(AdminView, ContainerView):
"""Portal template container view"""
@@ -170,7 +179,8 @@
super(PortalTemplateContainerView, self).__init__(context, request)
-@adapter_config(context=(ISite, IAdminLayer, PortalTemplateContainerView), provides=IPageHeader)
+@adapter_config(context=(ISite, IAdminLayer, PortalTemplateContainerView),
+ provides=IPageHeader)
class PortalTemplateContainerHeaderAdapter(DefaultPageHeaderAdapter):
"""Portal template container header adapter"""
@@ -181,8 +191,10 @@
# Templates container configuration views
#
-@viewlet_config(name='templates-container-configuration.menu', context=ISite, layer=IAdminLayer,
- manager=IPortalTemplateContainerMenu, permission=MANAGE_TEMPLATE_PERMISSION, weight=1)
+@viewlet_config(name='templates-container-configuration.menu',
+ context=ISite, layer=IAdminLayer,
+ manager=IPortalTemplateContainerMenu, weight=1,
+ permission=MANAGE_TEMPLATE_PERMISSION)
class PortalTemplatesContainerPropertiesMenu(MenuItem):
"""Portal template container configuration menu"""
--- a/src/pyams_portal/zmi/layout.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/layout.py Thu Aug 05 09:27:48 2021 +0200
@@ -65,19 +65,23 @@
return _("Template management")
-@viewlet_config(name='template-properties.menu', context=IPortalTemplate, layer=IAdminLayer,
- manager=IContentManagementMenu, permission=MANAGE_TEMPLATE_PERMISSION, weight=1)
-@viewletmanager_config(name='template-properties.menu', layer=IAdminLayer, provides=IPropertiesMenu)
+@viewlet_config(name='template-layout.menu',
+ context=IPortalTemplate, layer=IAdminLayer,
+ manager=IContentManagementMenu, weight=1,
+ permission=MANAGE_TEMPLATE_PERMISSION)
+@viewletmanager_config(name='template-layout.menu',
+ layer=IAdminLayer,
+ provides=IPropertiesMenu)
@implementer(IPropertiesMenu)
class PortalTemplatePropertiesMenu(MenuItem):
"""Portal template properties menu"""
- label = _("Properties")
+ label = _("Layout")
icon_class = 'fa-edit'
- url = '#properties.html'
+ url = '#layout.html'
-@pagelet_config(name='properties.html', context=IPortalTemplate, layer=IPyAMSLayer,
+@pagelet_config(name='layout.html', context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
@template_config(template='templates/layout.pt', layer=IAdminLayer)
@implementer(IInnerPage)
@@ -92,14 +96,11 @@
page = IPortalPage(context)
if page.use_local_template:
return _("Local template configuration")
- else:
- if page.template.name == LOCAL_TEMPLATE_NAME:
- return _("Inherited local template configuration")
- else:
- translate = self.request.localizer.translate
- return translate(_("Shared template configuration ({0})")).format(page.template.name)
- else:
- return _("Template configuration")
+ if page.template.name == LOCAL_TEMPLATE_NAME:
+ return _("Inherited local template configuration")
+ translate = self.request.localizer.translate
+ return translate(_("Shared template configuration ({0})")).format(page.template.name)
+ return _("Template configuration")
def get_template(self):
return self.context
@@ -141,18 +142,16 @@
portlet = self.get_portlet(name)
if portlet is not None:
return self.request.localizer.translate(portlet.label)
- else:
- return self.request.localizer.translate(_("{{ missing portlet }}"))
+ return self.request.localizer.translate(_("{{ missing portlet }}"))
def get_portlet_preview(self, portlet_id):
settings = self.portlet_configuration.get_portlet_configuration(portlet_id).settings
- previewer = self.request.registry.queryMultiAdapter((self.get_context(), self.request, self, settings),
- IPortletPreviewer)
+ previewer = self.request.registry.queryMultiAdapter(
+ (self.get_context(), self.request, self, settings), IPortletPreviewer)
if previewer is not None:
previewer.update()
return previewer.render()
- else:
- return ''
+ return ''
#
@@ -170,7 +169,8 @@
url = 'PyAMS_portal.template.addRow'
-@view_config(name='add-template-row.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='add-template-row.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def add_template_row(request):
"""Add template raw"""
@@ -178,7 +178,8 @@
return {'row_id': config.add_row()}
-@view_config(name='set-template-row-order.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='set-template-row-order.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def set_template_row_order(request):
"""Set template rows order"""
@@ -188,7 +189,8 @@
return {'status': 'success'}
-@view_config(name='delete-template-row.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='delete-template-row.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def delete_template_row(request):
"""Delete template row"""
@@ -201,9 +203,10 @@
# Slots views
#
-@viewlet_config(name='add-template-slot.menu', context=IPortalTemplate, layer=IAdminLayer,
- view=PortalTemplateLayoutView, manager=IToolbarAddingMenu,
- permission=MANAGE_TEMPLATE_PERMISSION, weight=2)
+@viewlet_config(name='add-template-slot.menu',
+ context=IPortalTemplate, layer=IAdminLayer, view=PortalTemplateLayoutView,
+ manager=IToolbarAddingMenu, weight=2,
+ permission=MANAGE_TEMPLATE_PERMISSION)
class PortalTemplateSlotAddMenu(ToolbarMenuItem):
"""Portal template slot add menu"""
@@ -213,9 +216,11 @@
modal_target = True
-@pagelet_config(name='add-template-slot.html', context=IPortalTemplate, layer=IPyAMSLayer,
+@pagelet_config(name='add-template-slot.html',
+ context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
-@ajax_config(name='add-template-slot.json', context=IPortalTemplate, layer=IPyAMSLayer,
+@ajax_config(name='add-template-slot.json',
+ context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, base=AJAXAddForm)
class PortalTemplateSlotAddForm(AdminDialogAddForm):
"""Portal template slot add form"""
@@ -274,11 +279,12 @@
else:
if not 0 < row_id <= config.rows:
translate = event.form.request.localizer.translate
- event.form.widgets.errors += (Invalid(translate(_("Row ID must be between 1 and {0}!")).format(
- config.rows)),)
+ event.form.widgets.errors += (Invalid(translate(
+ _("Row ID must be between 1 and {0}!")).format(config.rows)),)
-@view_config(name='set-template-slot-order.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='set-template-slot-order.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def set_template_slot_order(request):
"""Set template slots order"""
@@ -290,7 +296,8 @@
return {'status': 'success'}
-@view_config(name='get-slots-width.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='get-slots-width.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def get_template_slots_width(request):
"""Get template slots width"""
@@ -298,7 +305,8 @@
return config.get_slots_width(request.params.get('device'))
-@view_config(name='set-slot-width.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='set-slot-width.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def set_template_slot_width(request):
"""Set template slot width"""
@@ -309,9 +317,11 @@
return config.get_slots_width(request.params.get('device'))
-@pagelet_config(name='slot-properties.html', context=IPortalTemplate, layer=IPyAMSLayer,
+@pagelet_config(name='slot-properties.html',
+ context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
-@ajax_config(name='slot-properties.json', context=IPortalTemplate, layer=IPyAMSLayer)
+@ajax_config(name='slot-properties.json',
+ context=IPortalTemplate, layer=IPyAMSLayer)
class PortalTemplateSlotPropertiesEditForm(AdminDialogEditForm):
"""Slot properties edit form"""
@@ -363,7 +373,8 @@
return super(self.__class__, self).get_ajax_output(changes)
-@view_config(name='delete-template-slot.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='delete-template-slot.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def delete_template_slot(request):
"""Delete template slot"""
@@ -376,16 +387,18 @@
# Portlet views
#
-@viewlet_config(name='add-template-portlet.divider', context=IPortalTemplate, layer=IAdminLayer,
- view=PortalTemplateLayoutView, manager=IToolbarAddingMenu,
- permission=MANAGE_TEMPLATE_PERMISSION, weight=10)
+@viewlet_config(name='add-template-portlet.divider',
+ context=IPortalTemplate, layer=IAdminLayer, view=PortalTemplateLayoutView,
+ manager=IToolbarAddingMenu, weight=10,
+ permission=MANAGE_TEMPLATE_PERMISSION)
class PortalTemplateAddMenuDivider(ToolbarMenuDivider):
"""Portal template menu divider"""
-@viewlet_config(name='add-template-portlet.menu', context=IPortalTemplate, layer=IAdminLayer,
- view=PortalTemplateLayoutView, manager=IToolbarAddingMenu,
- permission=MANAGE_TEMPLATE_PERMISSION, weight=20)
+@viewlet_config(name='add-template-portlet.menu',
+ context=IPortalTemplate, layer=IAdminLayer, view=PortalTemplateLayoutView,
+ manager=IToolbarAddingMenu, weight=20,
+ permission=MANAGE_TEMPLATE_PERMISSION)
class PortalTemplatePortletAddMenu(ToolbarMenuItem):
"""Portal template portlet add menu"""
@@ -395,9 +408,11 @@
modal_target = True
-@pagelet_config(name='add-template-portlet.html', context=IPortalTemplate, layer=IPyAMSLayer,
+@pagelet_config(name='add-template-portlet.html',
+ context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
-@ajax_config(name='add-template-portlet.json', context=IPortalTemplate, layer=IPyAMSLayer,
+@ajax_config(name='add-template-portlet.json',
+ context=IPortalTemplate, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, base=AJAXAddForm)
class PortalTemplatePortletAddForm(AdminDialogAddForm):
"""Portal template portlet add form"""
@@ -421,8 +436,8 @@
def get_ajax_output(self, changes):
configuration = IPortalPortletsConfiguration(self.context)
settings = configuration.get_portlet_configuration(changes['portlet_id']).settings
- previewer = self.request.registry.queryMultiAdapter((self.context, self.request, self, settings),
- IPortletPreviewer)
+ previewer = self.request.registry.queryMultiAdapter(
+ (self.context, self.request, self, settings), IPortletPreviewer)
if previewer is not None:
previewer.update()
changes['preview'] = previewer.render()
@@ -433,7 +448,8 @@
}
-@view_config(name='drag-template-portlet.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='drag-template-portlet.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def drag_template_portlet(request):
"""Drag portlet icon to slot"""
@@ -443,8 +459,8 @@
slot_name = request.params.get('slot_name')
changes = tmpl_config.add_portlet(portlet_name, slot_name)
settings = portlets_config.get_portlet_configuration(changes['portlet_id']).settings
- previewer = request.registry.queryMultiAdapter((request.context, request, request, settings),
- IPortletPreviewer)
+ previewer = request.registry.queryMultiAdapter(
+ (request.context, request, request, settings), IPortletPreviewer)
if previewer is not None:
previewer.update()
changes['preview'] = previewer.render()
@@ -456,7 +472,8 @@
}
-@view_config(name='set-template-portlet-order.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='set-template-portlet-order.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def set_template_portlet_order(request):
"""Set template portlet order"""
@@ -480,11 +497,12 @@
request = self.request
request.registry.notify(PageletCreatedEvent(self))
portlet_id = int(request.params.get('{0}widgets.portlet_id'.format(self.prefix)))
- portlet_config = IPortalPortletsConfiguration(self.context).get_portlet_configuration(portlet_id)
+ portlet_config = IPortalPortletsConfiguration(self.context) \
+ .get_portlet_configuration(portlet_id)
if portlet_config is None:
raise NotFound()
- editor = self.request.registry.queryMultiAdapter((portlet_config.editor_settings, request),
- IPagelet, name='properties.html')
+ editor = self.request.registry.queryMultiAdapter(
+ (portlet_config.editor_settings, request), IPagelet, name='properties.html')
if editor is None:
raise NotFound()
request.registry.notify(PageletCreatedEvent(editor))
@@ -503,7 +521,8 @@
request.registry.notify(PageletCreatedEvent(self))
# load portlet config
portlet_id = int(request.params.get('{0}widgets.portlet_id'.format(self.prefix)))
- portlet_config = IPortalPortletsConfiguration(self.context).get_portlet_configuration(portlet_id)
+ portlet_config = IPortalPortletsConfiguration(self.context) \
+ .get_portlet_configuration(portlet_id)
if portlet_config is None:
raise NotFound()
# check inheritance
@@ -552,7 +571,8 @@
return changes
-@view_config(name='delete-template-portlet.json', context=IPortalTemplate, request_type=IPyAMSLayer,
+@view_config(name='delete-template-portlet.json',
+ context=IPortalTemplate, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
def delete_template_portlet(request):
"""Delete template portlet"""
--- a/src/pyams_portal/zmi/page.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/page.py Thu Aug 05 09:27:48 2021 +0200
@@ -95,6 +95,11 @@
def getContent(self):
return IPortalPage(self.context)
+ @property
+ def template_css_class(self):
+ template = IPortalPage(self.context).local_template
+ return template.css_class if template is not None else ''
+
def updateWidgets(self, prefix=None):
super().updateWidgets(prefix)
shared_template = self.widgets.get('shared_template')
@@ -116,7 +121,12 @@
content.use_local_template = False
elif template_mode == TEMPLATE_LOCAL_MODE:
content.use_local_template = True
- return {IPortalPage: ('inherit_parent', 'use_local_template', 'shared_template')}
+ template = IPortalPage(self.context).local_template
+ if template is not None:
+ template.css_class = self.request.params.get('template_css_class', '')
+ return {
+ IPortalPage: ('inherit_parent', 'use_local_template', 'shared_template')
+ }
def get_ajax_output(self, changes):
output = super(self.__class__, self).get_ajax_output(changes)
@@ -137,23 +147,27 @@
form = event.form
if not form.getContent().can_inherit:
data = event.data
- if (form.request.params.get('template_mode') == TEMPLATE_SHARED_MODE) and not data.get('shared_template'):
+ if (form.request.params.get('template_mode') == TEMPLATE_SHARED_MODE) and \
+ not data.get('shared_template'):
form.widgets.errors += (Invalid(_("You must select which shared template to use!")),)
-@adapter_config(context=(Interface, IPyAMSLayer, PortalContextTemplatePropertiesEditForm), provides=IPageHeader)
+@adapter_config(context=(Interface, IPyAMSLayer, PortalContextTemplatePropertiesEditForm),
+ provides=IPageHeader)
class PortalContextPropertiesEditFormHeaderAdapter(PropertiesEditFormHeaderAdapter):
"""Portal context template properties edit form header adapter"""
icon_class = 'fa fa-fw fa-columns'
-@adapter_config(context=(IPortalContext, IAdminLayer, PortalContextTemplatePropertiesEditForm), provides=IFormHelp)
+@adapter_config(context=(IPortalContext, IAdminLayer, PortalContextTemplatePropertiesEditForm),
+ provides=IFormHelp)
class PortalContextPropertiesEditFormHelpAdapter(FormHelp):
"""Portal context properties edit form help adapter"""
message = _("If you choose a shared template, you can only adjust settings of "
- "each portlet individually but can't change portlets list or page configuration.\n"
+ "each portlet individually but can't change portlets list or page "
+ "configuration.\n"
"If you use a local template, you can define a whole custom "
"configuration but the template definition can't be reused anywhere...""")
message_format = 'text'
@@ -163,8 +177,10 @@
# Portal context template configuration
#
-@viewlet_config(name='template-config.menu', context=IPortalContext, layer=IAdminLayer,
- manager=IPortalContextTemplatePropertiesMenu, permission=MANAGE_TEMPLATE_PERMISSION, weight=50)
+@viewlet_config(name='template-config.menu',
+ context=IPortalContext, layer=IAdminLayer,
+ manager=IPortalContextTemplatePropertiesMenu, weight=50,
+ permission=MANAGE_TEMPLATE_PERMISSION)
class PortalContextTemplateConfigMenu(MenuItem):
"""Portal context template configuration menu"""
@@ -186,7 +202,8 @@
return super(PortalContextTemplateConfigMenu, self).get_url()
-@pagelet_config(name='template-config.html', context=IPortalContext, layer=IPyAMSLayer,
+@pagelet_config(name='template-config.html',
+ context=IPortalContext, layer=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
class PortalContextTemplateLayoutView(PortalTemplateLayoutView):
"""Portal context template configuration view"""
@@ -201,7 +218,8 @@
return self.request.has_permission(MANAGE_TEMPLATE_PERMISSION)
-@adapter_config(context=(IPortalContext, IAdminLayer, PortalContextTemplateLayoutView), provides=IPageHeader)
+@adapter_config(context=(IPortalContext, IAdminLayer, PortalContextTemplateLayoutView),
+ provides=IPageHeader)
class PortalContextTemplateLayoutHeaderAdapter(PortalTemplateHeaderAdapter):
"""Portal context template configuration header adapter"""
@@ -210,7 +228,8 @@
# Template management views
#
-@view_config(name='get-slots-width.json', context=IPortalContext, request_type=IPyAMSLayer,
+@view_config(name='get-slots-width.json',
+ context=IPortalContext, request_type=IPyAMSLayer,
permission=VIEW_SYSTEM_PERMISSION, renderer='json', xhr=True)
def get_template_slots_width(request):
"""Get template slots width"""
@@ -218,13 +237,15 @@
return config.get_slots_width(request.params.get('device'))
-@view_config(name='portlet-properties.html', context=IPortalContext, request_type=IPyAMSLayer,
+@view_config(name='portlet-properties.html',
+ context=IPortalContext, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION)
class PortalContextTemplatePortletEditForm(PortalTemplatePortletEditForm):
"""Portal context template portlet edit form"""
-@view_config(name='portlet-properties.json', context=IPortalContext, request_type=IPyAMSLayer,
+@view_config(name='portlet-properties.json',
+ context=IPortalContext, request_type=IPyAMSLayer,
permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True)
class PortalContextTemplatePortletAJAXEditForm(PortalTemplatePortletAJAXEditForm):
"""Portal context template portlet edit form, JSON renderer"""
--- a/src/pyams_portal/zmi/portlet.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/portlet.py Thu Aug 05 09:27:48 2021 +0200
@@ -10,25 +10,17 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
-
-# import standard library
-
from pyramid.decorator import reify
from z3c.form import field
from z3c.form.interfaces import INPUT_MODE
-from zope.interface import implementer, Interface
+from zope.interface import Interface, implementer
-# import packages
from pyams_form.form import ajax_config
from pyams_form.help import FormHelp
-# import interfaces
-from pyams_form.interfaces.form import IFormManager, IInnerTabForm, IFormHelp
+from pyams_form.interfaces.form import IFormHelp, IFormManager, IInnerTabForm
from pyams_pagelet.pagelet import pagelet_config
-from pyams_portal import _
-from pyams_portal.interfaces import IPortlet, IPortalTemplate, IPortalPage, MANAGE_TEMPLATE_PERMISSION, \
- IPortletSettings, IPortletRendererSettings, LOCAL_TEMPLATE_NAME
+from pyams_portal.interfaces import IPortalPage, IPortalTemplate, IPortlet, \
+ IPortletRendererSettings, IPortletSettings, LOCAL_TEMPLATE_NAME, MANAGE_TEMPLATE_PERMISSION
from pyams_portal.zmi.widget import PortletRendererFieldWidget
from pyams_skin.event import get_json_widget_refresh_event
from pyams_skin.layer import IPyAMSLayer
@@ -40,6 +32,11 @@
from pyams_zmi.layer import IAdminLayer
+__docformat__ = 'restructuredtext'
+
+from pyams_portal import _
+
+
@template_config(template='templates/portlet.pt', layer=IPyAMSLayer)
class PortletSettingsEditor(AdminDialogEditForm):
"""Portlet settings edit form"""
@@ -53,10 +50,11 @@
if not IPortalTemplate.providedBy(parent):
parent = IPortalPage(parent).template
if parent.name == LOCAL_TEMPLATE_NAME:
- return translate(_("Local portal template - {0}")).format(translate(self.portlet.label))
+ return translate(_("Local portal template - {0}")).format(
+ translate(self.portlet.label))
else:
- return translate(_("« {0} » portal template - {1}")).format(parent.name,
- translate(self.portlet.label))
+ return translate(_("« {0} » portal template - {1}")).format(
+ parent.name, translate(self.portlet.label))
legend = _("Edit portlet settings")
dialog_class = 'modal-large'
@@ -104,11 +102,14 @@
return None
return FormHelp.__new__(cls)
- message = _("""WARNING: Portlet properties are saved automatically when changing inherit mode!!""")
+ message = _("WARNING: Portlet properties are saved "
+ "automatically when changing inherit mode!!")
message_format = 'rest'
-@adapter_config(name='properties', context=(Interface, IPyAMSLayer, PortletSettingsEditor), provides=IInnerTabForm)
+@adapter_config(name='properties',
+ context=(Interface, IPyAMSLayer, PortletSettingsEditor),
+ provides=IInnerTabForm)
class PortletSettingsPropertiesEditor(InnerAdminEditForm):
"""Portlet settings properties editor"""
@@ -149,11 +150,13 @@
'close_form': False
})
output.setdefault('events', []).append(
- get_json_widget_refresh_event(self.context, self.request, get_form_factory, 'renderer'))
+ get_json_widget_refresh_event(self.context, self.request,
+ get_form_factory, 'renderer'))
output['smallbox'] = {
'status': 'info',
- 'message': self.request.localizer.translate(_("You changed renderer selection. Don't omit to "
- "update new renderer properties...")),
+ 'message': self.request.localizer.translate(
+ _("You changed renderer selection. "
+ "Don't omit to update new renderer properties...")),
'timeout': 5000
}
return output
@@ -198,22 +201,22 @@
if self.manager is not None:
self.manager.update()
else:
- super(PortletRendererPropertiesEditForm, self).update()
+ super().update()
def updateWidgets(self, prefix=None):
if self.manager is not None:
self.manager.updateWidgets(prefix)
else:
- super(PortletRendererPropertiesEditForm, self).updateWidgets(prefix)
+ super().updateWidgets(prefix)
def updateActions(self):
if self.manager is not None:
self.manager.updateActions()
else:
- super(PortletRendererPropertiesEditForm, self).updateActions()
+ super().updateActions()
def updateGroups(self):
if self.manager is not None:
self.manager.updateGroups()
else:
- super(PortletRendererPropertiesEditForm, self).updateGroups()
+ super().updateGroups()
--- a/src/pyams_portal/zmi/template.py Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/template.py Thu Aug 05 09:27:48 2021 +0200
@@ -33,6 +33,7 @@
from pyams_skin.page import DefaultPageHeaderAdapter
from pyams_skin.table import DefaultElementEditorAdapter
from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem
+from pyams_skin.viewlet.menu import MenuItem
from pyams_skin.viewlet.toolbar import ToolbarAction, ToolbarMenuDivider, ToolbarMenuItem
from pyams_utils.adapter import ContextRequestAdapter, adapter_config
from pyams_utils.registry import get_utility, query_utility
@@ -41,6 +42,7 @@
from pyams_utils.url import absolute_url
from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
+from pyams_zmi.interfaces.menu import IPropertiesMenu
from pyams_zmi.layer import IAdminLayer
@@ -82,9 +84,11 @@
return self.context.name
context = get_parent(self.context, IPortalContext)
if context is not None:
- adapter = self.request.registry.queryMultiAdapter((context, self.request), ITableElementName)
+ adapter = self.request.registry.queryMultiAdapter((context, self.request),
+ ITableElementName)
if adapter is not None:
- return self.request.localizer.translate(_("{0} (local template)")).format(adapter.name)
+ return self.request.localizer.translate(_("{0} (local template)")).format(
+ adapter.name)
return '--'
@@ -112,7 +116,8 @@
# check for portal context
context = get_parent(self.context, IPortalContext)
if context is not None:
- adapter = self.request.registry.queryMultiAdapter((context, self.request, self.view), IContentTitle)
+ adapter = self.request.registry.queryMultiAdapter((context, self.request, self.view),
+ IContentTitle)
if adapter is None:
adapter = IContentTitle(context, None)
if adapter is not None:
@@ -120,7 +125,7 @@
#
-# Template views
+# Template add views
#
@viewlet_config(name='add-portal-template.action', context=ISite, layer=IAdminLayer,
@@ -144,7 +149,7 @@
legend = _("Add shared template")
icon_css_class = 'fa fa-fw fa-columns'
- fields = field.Fields(IPortalTemplate)
+ fields = field.Fields(IPortalTemplate).select('name')
edit_permission = MANAGE_TEMPLATE_PERMISSION
def create(self, data):
@@ -168,58 +173,47 @@
#
-# Template renaming form
+# Template properties form
#
-@viewlet_config(name='rename.menu', context=IPortalTemplate, layer=IPyAMSLayer,
- view=PortalTemplateLayoutView, manager=IContextActions,
- permission=MANAGE_TEMPLATE_PERMISSION, weight=100)
-class PortalTemplateRenameMenu(ToolbarMenuItem):
- """Portal template rename menu item"""
+@viewlet_config(name='properties.menu',
+ context=IPortalTemplate, layer=IAdminLayer,
+ manager=IPropertiesMenu, weight=10,
+ permission=MANAGE_TEMPLATE_PERMISSION)
+class PortalTemplatePropertiesMenu(MenuItem):
+ """Portal template properties menu item"""
def __new__(cls, context, request, view, manager):
container = get_parent(context, IPortalTemplateContainer)
if container is None:
return None
- return ToolbarMenuDivider.__new__(cls)
+ return MenuItem.__new__(cls)
- label = _("Rename template...")
+ label = _("Template properties...")
label_css_class = 'fa fa-fw fa-edit'
- url = 'rename.html'
+ url = 'properties.html'
modal_target = True
-class IPortalTemplateRenameButtons(Interface):
- """Portal template rename form buttons"""
-
- close = CloseButton(name='close', title=_("Cancel"))
- rename = button.Button(name='rename', title=_("Rename template"))
-
+@pagelet_config(name='properties.html',
+ context=IPortalTemplate, layer=IPyAMSLayer,
+ permission=MANAGE_TEMPLATE_PERMISSION)
+@ajax_config(name='properties.json', context=IPortalTemplate, layer=IPyAMSLayer)
+class PortalTemplatePropertiesEditForm(AdminDialogEditForm):
+ """Portal template properties edit form"""
-@pagelet_config(name='rename.html', context=IPortalTemplate, layer=IPyAMSLayer,
- permission=MANAGE_TEMPLATE_PERMISSION)
-@ajax_config(name='rename.json', context=IPortalTemplate, layer=IPyAMSLayer)
-class PortalTemplateRenameForm(AdminDialogEditForm):
- """Portal template rename form"""
-
- legend = _("Rename template")
+ legend = _("Template properties")
icon_css_class = 'fa fa-fw fa-edit'
- fields = field.Fields(IPortalTemplate).select('name')
- buttons = button.Buttons(IPortalTemplateRenameButtons)
+ fields = field.Fields(IPortalTemplate).select('name', 'css_class')
edit_permission = MANAGE_TEMPLATE_PERMISSION
_renamed = False
- def updateActions(self):
- super(PortalTemplateRenameForm, self).updateActions()
- if 'rename' in self.actions:
- self.actions['rename'].addClass('btn-primary')
-
def update_content(self, content, data):
- changes = super(PortalTemplateRenameForm, self).update_content(content, data)
+ changes = super().update_content(content, data)
if changes:
data = data.get(self, data)
old_name = content.__name__
@@ -237,8 +231,7 @@
'status': 'redirect',
'location': absolute_url(self.getContent(), self.request, 'admin#properties.html')
}
- else:
- return super(PortalTemplateRenameForm, self).get_ajax_output(changes)
+ return super().get_ajax_output(changes)
#
--- a/src/pyams_portal/zmi/templates/template-properties.pt Fri Mar 26 16:32:52 2021 +0100
+++ b/src/pyams_portal/zmi/templates/template-properties.pt Thu Aug 05 09:27:48 2021 +0200
@@ -82,6 +82,20 @@
<i></i><span i18n:translate="">Use custom local template</span>
</label>
</div>
+ <div class="form-group">
+ <div>
+ <div class="control-label col-md-3">
+ <span i18n:translate="">Custom CSS class</span>
+ </div>
+ <div class="col-md-3">
+ <div class="input">
+ <input type="text"
+ name="template_css_class"
+ value="${view.template_css_class}" />
+ </div>
+ </div>
+ </div>
+ </div>
</fieldset>
</div>
<footer tal:condition="view.actions and (view.is_dialog or (view.mode == 'input'))">