--- a/src/pyams_portal/zmi/layout.py Tue Jul 03 15:19:50 2018 +0200
+++ b/src/pyams_portal/zmi/layout.py Tue Jul 03 15:51:19 2018 +0200
@@ -9,6 +9,8 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
+from pyams_utils.unicode import translate_string
+from pyams_utils.url import absolute_url
__docformat__ = 'restructuredtext'
@@ -23,7 +25,7 @@
IPortalTemplateContainerConfiguration, IPortalPortletsConfiguration, IPortalContext, IPortalPage, \
MANAGE_TEMPLATE_PERMISSION
from pyams_skin.interfaces import IInnerPage, IPageHeader
-from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader, IContextActions
from pyams_skin.layer import IPyAMSLayer
from pyams_zmi.interfaces.menu import IPropertiesMenu, IContentManagementMenu
from pyams_zmi.layer import IAdminLayer
@@ -33,6 +35,7 @@
# import packages
from pyams_cache.beaker import get_cache
from pyams_form.form import AJAXAddForm, AJAXEditForm, ajax_config
+from pyams_form.schema import CloseButton
from pyams_pagelet.pagelet import pagelet_config
from pyams_portal.portlet import PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME
from pyams_portal.zmi.template import PortalTemplateHeaderAdapter
@@ -40,7 +43,7 @@
from pyams_skin.viewlet.toolbar import JsToolbarMenuItem, ToolbarMenuDivider, ToolbarMenuItem
from pyams_template.template import template_config
from pyams_utils.adapter import adapter_config
-from pyams_utils.registry import query_utility
+from pyams_utils.registry import query_utility, get_utility
from pyams_utils.traversing import get_parent
from pyams_viewlet.manager import viewletmanager_config
from pyams_viewlet.viewlet import viewlet_config
@@ -50,7 +53,8 @@
from pyramid.events import subscriber
from pyramid.exceptions import NotFound
from pyramid.view import view_config
-from z3c.form import field
+from z3c.form import field, button
+from zope.copy import copy
from zope.interface import implementer, Invalid, Interface
from pyams_portal import _
@@ -547,3 +551,94 @@
config = IPortalTemplateConfiguration(request.context)
config.delete_portlet(int(request.params.get('portlet_id')))
return {'status': 'success'}
+
+
+#
+# Portal template duplication form
+#
+
+@viewlet_config(name='duplication.divider', context=IPortalTemplate, layer=IPyAMSLayer,
+ view=PortalTemplateLayoutView, manager=IContextActions, permission=MANAGE_TEMPLATE_PERMISSION, weight=99)
+class PortalTemplateDuplicationMenuDivider(ToolbarMenuDivider):
+ """Portal template duplication menu divider"""
+
+ def __new__(cls, context, request, view, manager):
+ container = get_parent(context, IPortalTemplateContainer)
+ if container is None:
+ return None
+ return ToolbarMenuDivider.__new__(cls)
+
+
+@viewlet_config(name='duplication.menu', context=IPortalTemplate, layer=IPyAMSLayer,
+ view=PortalTemplateLayoutView, manager=IContextActions, permission=MANAGE_TEMPLATE_PERMISSION, weight=100)
+class PortalTemplateDuplicationMenu(ToolbarMenuItem):
+ """Portal template duplication menu item"""
+
+ def __new__(cls, context, request, view, manager):
+ container = get_parent(context, IPortalTemplateContainer)
+ if container is None:
+ return None
+ return ToolbarMenuDivider.__new__(cls)
+
+ label = _("Duplicate template...")
+ label_css_class = 'fa fa-fw fa-files-o'
+
+ url = 'duplicate.html'
+ modal_target = True
+
+
+class IPortalTemplateDuplicationButtons(Interface):
+ """Portal template duplication form buttons"""
+
+ close = CloseButton(name='close', title=_("Cancel"))
+ duplicate = button.Button(name='duplicate', title=_("Duplicate this template"))
+
+
+@pagelet_config(name='duplicate.html', context=IPortalTemplate, layer=IPyAMSLayer,
+ permission=MANAGE_TEMPLATE_PERMISSION)
+@ajax_config(name='duplicate.json', context=IPortalTemplate, layer=IPyAMSLayer, base=AJAXAddForm)
+class PortalTemplateDuplicationForm(AdminDialogAddForm):
+ """Portal template duplicate form"""
+
+ legend = _("Duplicate template")
+ icon_css_class = 'fa fa-fw fa-files-o'
+
+ fields = field.Fields(IPortalTemplate)
+ buttons = button.Buttons(IPortalTemplateDuplicationButtons)
+
+ edit_permission = MANAGE_TEMPLATE_PERMISSION
+
+ def updateWidgets(self, prefix=None):
+ super(PortalTemplateDuplicationForm, self).updateWidgets(prefix)
+ if 'name' in self.widgets:
+ self.widgets['name'].label = _("New template name")
+
+ def updateActions(self):
+ super(PortalTemplateDuplicationForm, self).updateActions()
+ if 'duplicate' in self.actions:
+ self.actions['duplicate'].addClass('btn-primary')
+
+ def create(self, data):
+ return copy(self.context)
+
+ def add(self, template):
+ container = get_utility(IPortalTemplateContainer)
+ container[translate_string(template.name, spaces='-')] = template
+
+ def nextURL(self):
+ return absolute_url(self.request.root, self.request, 'admin#portal-templates.html')
+
+ def get_ajax_output(self, changes):
+ return {
+ 'status': 'redirect',
+ 'location': self.nextURL()
+ }
+
+
+@subscriber(IDataExtractedEvent, form_selector=PortalTemplateDuplicationForm)
+def handle_new_template_data_extraction(event):
+ """Handle new template form data extraction"""
+ container = get_utility(IPortalTemplateContainer)
+ name = translate_string(event.data.get('name'), spaces='-')
+ if name in container:
+ event.form.widgets.errors += (Invalid(_("Specified name is already used!")),)