--- a/src/pyams_content/component/extfile/zmi/container.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/extfile/zmi/container.py Mon Jan 18 16:08:07 2016 +0100
@@ -251,3 +251,13 @@
permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
class ExtFileLinksContainerAJAXEditForm(AJAXEditForm, ExtFileLinksContainerLinksEditForm):
"""External file links container edit form, JSON renderer"""
+
+ def get_ajax_output(self, changes):
+ if 'files' in changes.get(IExtFileLinksContainer, ()):
+ return {'status': 'success',
+ 'event': 'PyAMS_content.changed_item',
+ 'event_options': {'object_type': 'extfiles_container',
+ 'object_name': self.context.__name__,
+ 'nb_files': len(IExtFileLinksContainer(self.context).files or ())}}
+ else:
+ return super(ExtFileLinksContainerAJAXEditForm, self).get_ajax_output(changes)
--- a/src/pyams_content/component/gallery/zmi/__init__.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/gallery/zmi/__init__.py Mon Jan 18 16:08:07 2016 +0100
@@ -59,7 +59,7 @@
@pagelet_config(name='add-gallery.html', context=IGalleryContainerTarget, layer=IPyAMSLayer,
- permission='pyams.ManageContent')
+ permission=MANAGE_CONTENT_PERMISSION)
class GalleryAddForm(AdminDialogAddForm):
"""Gallery add form"""
--- a/src/pyams_content/component/gallery/zmi/container.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/gallery/zmi/container.py Mon Jan 18 16:08:07 2016 +0100
@@ -114,6 +114,20 @@
return super(GalleryContainerTable, self).render()
+@adapter_config(name='manage', context=(IGalleryContainerTarget, IPyAMSLayer, GalleryContainerTable), provides=IColumn)
+class GalleryContainerManageColumn(ActionColumn):
+ """Gallery container manage column"""
+
+ icon_class = 'fa fa-fw fa-camera'
+ icon_hint = _("Display gallery contents")
+
+ url = 'contents.html'
+ target = None
+ modal_target = True
+
+ weight = 5
+
+
@adapter_config(name='name', context=(IGalleryContainerTarget, IPyAMSLayer, GalleryContainerTable), provides=IColumn)
class GalleryContainerNameColumn(I18nColumn, WfModifiedContentColumnMixin, GetAttrColumn):
"""Galleries container name column"""
@@ -138,20 +152,6 @@
return len(obj)
-@adapter_config(name='manage', context=(IGalleryContainerTarget, IPyAMSLayer, GalleryContainerTable), provides=IColumn)
-class GalleryContainerManageColumn(ActionColumn):
- """Gallery container manage column"""
-
- icon_class = 'fa fa-fw fa-camera'
- icon_hint = _("Display gallery contents")
-
- url = 'contents.html'
- target = None
- modal_target = True
-
- weight = 30
-
-
@adapter_config(name='trash', context=(IGalleryContainerTarget, IPyAMSLayer, GalleryContainerTable), provides=IColumn)
class GalleryContainerTrashColumn(ProtectedFormObjectMixin, TrashColumn):
"""Galleries container trash column"""
@@ -196,3 +196,13 @@
permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
class GalleryLinksContainerAJAXEditForm(AJAXEditForm, GalleryLinksContainerLinksEditForm):
"""Galleries links container edit form, JSON renderer"""
+
+ def get_ajax_output(self, changes):
+ if 'galleries' in changes.get(IGalleryLinksContainer, ()):
+ return {'status': 'success',
+ 'event': 'PyAMS_content.changed_item',
+ 'event_options': {'object_type': 'galleries_container',
+ 'object_name': self.context.__name__,
+ 'nb_galleries': len(IGalleryLinksContainer(self.context).galleries or ())}}
+ else:
+ return super(GalleryLinksContainerAJAXEditForm, self).get_ajax_output(changes)
--- a/src/pyams_content/component/links/zmi/container.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/links/zmi/container.py Mon Jan 18 16:08:07 2016 +0100
@@ -209,3 +209,13 @@
permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
class LinkLinksContainerAJAXEditForm(AJAXEditForm, LinkLinksContainerLinksEditForm):
"""Links links container edit form, JSON renderer"""
+
+ def get_ajax_output(self, changes):
+ if 'links' in changes.get(ILinkLinksContainer, ()):
+ return {'status': 'success',
+ 'event': 'PyAMS_content.changed_item',
+ 'event_options': {'object_type': 'links_container',
+ 'object_name': self.context.__name__,
+ 'nb_links': len(ILinkLinksContainer(self.context).links or ())}}
+ else:
+ return super(LinkLinksContainerAJAXEditForm, self).get_ajax_output(changes)
--- a/src/pyams_content/component/paragraph/__init__.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/__init__.py Mon Jan 18 16:08:07 2016 +0100
@@ -37,6 +37,7 @@
class BaseParagraph(Persistent, Contained):
"""Base paragraph persistent class"""
+ visible = FieldProperty(IBaseParagraph['visible'])
title = FieldProperty(IBaseParagraph['title'])
--- a/src/pyams_content/component/paragraph/interfaces/__init__.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/__init__.py Mon Jan 18 16:08:07 2016 +0100
@@ -25,7 +25,7 @@
from pyams_i18n.schema import I18nTextLineField, I18nHTMLField
from zope.container.constraints import containers, contains
from zope.interface import Interface, Attribute
-from zope.schema import Choice
+from zope.schema import Bool, Choice
from pyams_content import _
@@ -38,6 +38,11 @@
containers('.IParagraphContainer')
+ visible = Bool(title=_("Visible?"),
+ description=_("Is this paragraph visible in front-office?"),
+ required=True,
+ default=True)
+
title = I18nTextLineField(title=_("Title"),
description=_("Paragraph title"),
required=False)
--- a/src/pyams_content/component/paragraph/zmi/__init__.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/zmi/__init__.py Mon Jan 18 16:08:07 2016 +0100
@@ -16,5 +16,27 @@
# import standard library
# import interfaces
+from pyams_content.component.paragraph.interfaces import IBaseParagraph
+from pyams_i18n.interfaces import II18n
# import packages
+from pyams_form.form import AJAXEditForm
+
+
+class BaseParagraphAJAXEditForm(AJAXEditForm):
+ """Base paragraph AJAX edit form"""
+
+ def get_ajax_output(self, changes):
+ updated = changes.get(IBaseParagraph, ())
+ if ('title' in updated) or ('visible' in updated):
+ return {'status': 'success',
+ 'event': 'PyAMS_content.changed_item',
+ 'event_options': {'object_type': 'paragraph',
+ 'object_name': self.context.__name__,
+ 'title': II18n(self.context).query_attribute('title', request=self.request),
+ 'visible': self.context.visible}}
+ if 'title' in changes.get(IBaseParagraph, ()):
+ return {'status': 'reload',
+ 'location': '#paragraphs.html'}
+ else:
+ return super(BaseParagraphAJAXEditForm, self).get_ajax_output(changes)
--- a/src/pyams_content/component/paragraph/zmi/container.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/zmi/container.py Mon Jan 18 16:08:07 2016 +0100
@@ -9,6 +9,7 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
+from pyams_form.interfaces.form import IFormSecurityContext
__docformat__ = 'restructuredtext'
@@ -18,10 +19,11 @@
# import interfaces
from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
-from pyams_content.component.extfile.interfaces import IExtFileLinksContainerTarget
-from pyams_content.component.gallery.interfaces import IGalleryLinksContainerTarget
-from pyams_content.component.links.interfaces import ILinkLinksContainerTarget
-from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer
+from pyams_content.component.extfile.interfaces import IExtFileLinksContainerTarget, IExtFileLinksContainer
+from pyams_content.component.gallery.interfaces import IGalleryLinksContainerTarget, IGalleryLinksContainer
+from pyams_content.component.links.interfaces import ILinkLinksContainerTarget, ILinkLinksContainer
+from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, IBaseParagraph
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
from pyams_i18n.interfaces import II18n
from pyams_skin.interfaces import IInnerPage, IPageHeader
from pyams_skin.layer import IPyAMSLayer
@@ -35,11 +37,12 @@
from pyams_form.security import ProtectedFormObjectMixin
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.page import DefaultPageHeaderAdapter
-from pyams_skin.table import BaseTable, I18nColumn, TrashColumn, ActionColumn
+from pyams_skin.table import BaseTable, I18nColumn, TrashColumn, ActionColumn, JsActionColumn
from pyams_skin.viewlet.menu import MenuItem
from pyams_template.template import template_config
-from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextAdapter
from pyams_utils.url import absolute_url
+from pyramid.exceptions import NotFound
from pyramid.view import view_config
from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.view import AdminView
@@ -64,7 +67,8 @@
# Paragraphs container view
#
-@pagelet_config(name='paragraphs.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION)
+@pagelet_config(name='paragraphs.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ permission=VIEW_SYSTEM_PERMISSION)
@template_config(template='templates/container.pt', layer=IPyAMSLayer)
@implementer(IInnerPage)
class ParagraphContainerView(AdminView):
@@ -103,10 +107,12 @@
@property
def data_attributes(self):
attributes = super(ParagraphContainerTable, self).data_attributes
- del attributes['tr']['data-ams-url']
- del attributes['tr']['data-toggle']
attributes['table'] = {'id': self.id,
+ 'data-ams-plugins': 'pyams_content',
+ 'data-ams-plugin-pyams_content-src':
+ '/--static--/pyams_content/js/pyams_content{MyAMS.devext}.js',
'data-ams-location': absolute_url(IParagraphContainer(self.context), self.request),
+ 'data-ams-tablednd-drag-handle': 'td.sorter',
'data-ams-tablednd-drop-target': 'set-paragraphs-order.json'}
return attributes
@@ -121,19 +127,58 @@
return super(ParagraphContainerTable, self).render()
-@adapter_config(name='properties', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
+@adapter_config(name='sorter', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
provides=IColumn)
-class ParagraphContainerPropertiesColumn(ActionColumn):
- """Paragraphs container properties column"""
+class ParagraphContainerSorterColumn(ProtectedFormObjectMixin, ActionColumn):
+ """Paragraphs container sorter column"""
+
+ cssClasses = {'th': 'action',
+ 'td': 'action sorter'}
+
+ icon_class = 'fa fa-fw fa-sort'
+ icon_hint = _("Click and drag to sort paragraphs...")
+
+ url = '#'
+ weight = 1
- icon_class = 'fa fa-fw fa-edit'
- icon_hint = _("Paragraph properties")
+ def get_url(self, item):
+ return '#'
+
- url = 'properties.html'
- modal_target = True
+@adapter_config(name='show-hide', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
+ provides=IColumn)
+class ParagraphContainerShowHideColumn(ProtectedFormObjectMixin, JsActionColumn):
+ """Paragraphs container visibility switcher column"""
+
+ cssClasses = {'th': 'action',
+ 'td': 'action switcher'}
+
+ icon_class = 'fa fa-fw fa-eye'
+ icon_hint = _("Switch paragraph visibility")
+
+ url = 'PyAMS_content.paragraphs.switchVisibility'
weight = 5
+ def get_icon(self, item):
+ if item.visible:
+ icon_class = 'fa fa-fw fa-eye'
+ else:
+ icon_class = 'fa fa-fw fa-eye-slash text-danger'
+ return '<i class="{icon_class}"></i>'.format(icon_class=icon_class)
+
+ def renderCell(self, item):
+ if self.permission and not self.request.has_permission(self.permission, context=item):
+ return self.get_icon(item)
+ else:
+ return super(ParagraphContainerShowHideColumn, self).renderCell(item)
+
+
+@adapter_config(context=ParagraphContainerShowHideColumn, provides=IFormSecurityContext)
+def ShowHideColumnSecurityContextFactory(column):
+ """Show/hide column security context factory"""
+ return column.table.context
+
@adapter_config(name='files', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
provides=IColumn)
@@ -143,6 +188,8 @@
icon_class = 'fa fa-fw fa-file-text-o'
icon_hint = _("External files")
+ cssClasses = {'td': 'action extfiles nowrap'}
+
url = 'extfile-links.html'
modal_target = True
@@ -151,7 +198,14 @@
def renderCell(self, item):
if not IExtFileLinksContainerTarget.providedBy(item):
return ''
- return super(ParagraphContainerExtFileLinksColumn, self).renderCell(item)
+ action = '{action} <span class="count">{{count}}</span>'.format(
+ action=super(ParagraphContainerExtFileLinksColumn, self).renderCell(item))
+ length = len(IExtFileLinksContainer(item).files or ())
+ if length:
+ action = action.format(count='({0})'.format(length))
+ else:
+ action = action.format(count='')
+ return action
@adapter_config(name='links', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
@@ -162,6 +216,8 @@
icon_class = 'fa fa-fw fa-link'
icon_hint = _("Useful links")
+ cssClasses = {'td': 'action links nowrap'}
+
url = 'link-links.html'
modal_target = True
@@ -170,7 +226,14 @@
def renderCell(self, item):
if not ILinkLinksContainerTarget.providedBy(item):
return ''
- return super(ParagraphContainerLinkLinksColumn, self).renderCell(item)
+ action = '{action} <span class="count">{{count}}</span>'.format(
+ action=super(ParagraphContainerLinkLinksColumn, self).renderCell(item))
+ length = len(ILinkLinksContainer(item).links or ())
+ if length:
+ action = action.format(count='({0})'.format(length))
+ else:
+ action = action.format(count='')
+ return action
@adapter_config(name='gallery', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
@@ -181,6 +244,8 @@
icon_class = 'fa fa-fw fa-picture-o'
icon_hint = _("Images galleries")
+ cssClasses = {'td': 'action galleries nowrap'}
+
url = 'gallery-links.html'
modal_target = True
@@ -189,7 +254,14 @@
def renderCell(self, item):
if not IGalleryLinksContainerTarget.providedBy(item):
return ''
- return super(ParagraphContainerGalleryLinksColumn, self).renderCell(item)
+ action = '{action} <span class="count">{{count}}</span>'.format(
+ action=super(ParagraphContainerGalleryLinksColumn, self).renderCell(item))
+ length = len(IGalleryLinksContainer(item).galleries or ())
+ if length:
+ action = action.format(count='({0})'.format(length))
+ else:
+ action = action.format(count='')
+ return action
@adapter_config(name='name', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
@@ -201,6 +273,25 @@
weight = 50
+ def renderHeadCell(self):
+ return '<span class="small hint" title="{title}" data-ams-hint-gravity="e"' \
+ ' data-ams-stop-propagation="true"' \
+ ' data-ams-click-handler="PyAMS_content.paragraphs.switchAllEditors">' \
+ ' <i class="fa fa-plus-square-o"></i>' \
+ '</span> '.format(
+ title=self.request.localizer.translate(_("Click to open/close all paragraphs editors"))) + \
+ super(ParagraphContainerTitleColumn, self).renderHeadCell()
+
+ def renderCell(self, item):
+ return '<div><span class="small hint" title="{title}" data-ams-hint-gravity="e"' \
+ ' data-ams-stop-propagation="true" ' \
+ ' data-ams-click-handler="PyAMS_content.paragraphs.switchEditor">' \
+ ' <i class="fa fa-plus-square-o"></i>' \
+ '</span> '.format(
+ title=self.request.localizer.translate(_("Click to open/close paragraph editor"))) + \
+ '<span class="title">{0}</span>'.format(super(ParagraphContainerTitleColumn, self).renderCell(item)) + \
+ '</div><div class="inner-table-form editor margin-x-10 margin-bottom-0"></div>'
+
def getValue(self, obj):
return II18n(obj).query_attribute('title', request=self.request) or '--'
@@ -237,3 +328,50 @@
order = list(map(str, json.loads(request.params.get('names'))))
container.updateOrder(order)
return {'status': 'success'}
+
+
+@view_config(name='set-paragraph-visibility.json', context=IParagraphContainer, request_type=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+def set_paragraph_visibility(request):
+ """Set paragraph visibility"""
+ container = IParagraphContainer(request.context)
+ paragraph = container.get(str(request.params.get('object_name')))
+ if paragraph is None:
+ raise NotFound()
+ paragraph = IBaseParagraph(paragraph)
+ paragraph.visible = not paragraph.visible
+ return {'visible': paragraph.visible}
+
+
+@view_config(name='get-paragraph-editor.json', context=IParagraphContainer, request_type=IPyAMSLayer,
+ permission=VIEW_SYSTEM_PERMISSION, renderer='json', xhr=True)
+def get_paragraph_editor(request):
+ """Get paragraph editor"""
+ container = IParagraphContainer(request.context)
+ paragraph = container.get(str(request.params.get('object_name')))
+ if paragraph is None:
+ raise NotFound()
+ registry = request.registry
+ editor = registry.queryMultiAdapter((paragraph, request), IParagraphInnerEditor)
+ if editor is None:
+ editor = registry.queryAdapter(paragraph, IParagraphInnerEditor)
+ if editor is not None:
+ editor.update()
+ return editor.render()
+
+
+@view_config(name='get-paragraphs-editors.json', context=IParagraphContainer, request_type=IPyAMSLayer,
+ permission=VIEW_SYSTEM_PERMISSION, renderer='json', xhr=True)
+def get_paragraphs_editors(request):
+ """Get all paragraphs inner editors"""
+ container = IParagraphContainer(request.context)
+ registry = request.registry
+ result = {}
+ for key, paragraph in container.items():
+ editor = registry.queryMultiAdapter((paragraph, request), IParagraphInnerEditor)
+ if editor is None:
+ editor = registry.queryAdapter(paragraph, IParagraphInnerEditor)
+ if editor is not None:
+ editor.update()
+ result[key] = editor.render()
+ return result
--- a/src/pyams_content/component/paragraph/zmi/html.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/zmi/html.py Mon Jan 18 16:08:07 2016 +0100
@@ -9,8 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
-from pyams_template.template import template_config, ViewTemplate, get_view_template
__docformat__ = 'restructuredtext'
@@ -19,25 +17,32 @@
# import interfaces
from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IHTMLParagraph, \
- IParagraphContainer, IBaseParagraph, IParagraphSummary
+ IParagraphContainer, IParagraphSummary
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
from pyams_content.shared.common.interfaces import IWfSharedContent
+from pyams_form.interfaces.form import IInnerForm, IEditFormButtons
from pyams_i18n.interfaces import II18n
from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
from pyams_skin.layer import IPyAMSLayer
+from z3c.form.interfaces import INPUT_MODE
# import packages
from pyams_content.component.paragraph.html import HTMLParagraph
+from pyams_content.component.paragraph.zmi import BaseParagraphAJAXEditForm
from pyams_content.component.paragraph.zmi.container import ParagraphContainerView
-from pyams_form.form import AJAXAddForm, AJAXEditForm
+from pyams_form.form import AJAXAddForm
from pyams_form.security import ProtectedFormObjectMixin
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.viewlet.toolbar import ToolbarMenuItem
+from pyams_template.template import template_config, get_view_template
from pyams_utils.adapter import adapter_config, ContextRequestAdapter
from pyams_utils.traversing import get_parent
-from pyams_viewlet.viewlet import viewlet_config, ContentProvider
+from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
from pyramid.view import view_config
-from z3c.form import field
+from z3c.form import field, button
+from zope.interface import implementer
from pyams_content import _
@@ -111,25 +116,38 @@
fields = field.Fields(IHTMLParagraph).omit('__parent__', '__name__')
ajax_handler = 'properties.json'
- edit_permission = 'pyams.ManageContent'
+ edit_permission = MANAGE_CONTENT_PERMISSION
def updateWidgets(self, prefix=None):
super(HTMLParagraphPropertiesEditForm, self).updateWidgets(prefix)
+ for lang in self.widgets['body'].langs:
+ widget = self.widgets['body'].widgets[lang]
+ widget.id = '{id}_{name}'.format(id=widget.id, name=self.context.__name__)
self.widgets['body'].label_css_class = 'textarea'
+@adapter_config(context=(IHTMLParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+@implementer(IInnerForm)
+class HTMLParagraphInnerEditForm(HTMLParagraphPropertiesEditForm):
+ """HTML paragraph inner edit form"""
+
+ legend = None
+ main_group_legend = _("HTML paragraph properties")
+ main_group_class = 'inner'
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IEditFormButtons)
+ else:
+ return button.Buttons()
+
+
@view_config(name='properties.json', context=IHTMLParagraph, request_type=IPyAMSLayer,
permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-class HTMLParagraphPropertiesAJAXEditForm(AJAXEditForm, HTMLParagraphPropertiesEditForm):
+class HTMLParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, HTMLParagraphPropertiesEditForm):
"""HTML paragraph properties edit form, JSON renderer"""
- def get_ajax_output(self, changes):
- if 'title' in changes.get(IBaseParagraph, ()):
- return {'status': 'reload',
- 'location': '#paragraphs.html'}
- else:
- return super(HTMLParagraphPropertiesAJAXEditForm, self).get_ajax_output(changes)
-
#
# HTML paragraph summary
--- a/src/pyams_content/component/paragraph/zmi/illustration.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/zmi/illustration.py Mon Jan 18 16:08:07 2016 +0100
@@ -9,25 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyramid.view import view_config
-from pyams_content.component.paragraph.illustration import Illustration
-from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IIllustrationParagraph, \
- IParagraphContainer, IBaseParagraph, IParagraphSummary, IIllustrationRenderer
-from pyams_content.component.paragraph.zmi.container import ParagraphContainerView
-from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
-from pyams_content.shared.common.interfaces import IWfSharedContent
-from pyams_form.form import AJAXAddForm, AJAXEditForm
-from pyams_form.security import ProtectedFormObjectMixin
-from pyams_i18n.interfaces import II18n
-from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
-from pyams_skin.layer import IPyAMSLayer
-from pyams_skin.viewlet.toolbar import ToolbarMenuItem
-from pyams_template.template import template_config, get_view_template
-from pyams_utils.adapter import ContextRequestAdapter, adapter_config
-from pyams_utils.traversing import get_parent
-from pyams_viewlet.viewlet import viewlet_config
-from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
__docformat__ = 'restructuredtext'
@@ -35,9 +16,33 @@
# import standard library
# import interfaces
+from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IIllustrationParagraph, \
+ IParagraphContainer, IParagraphSummary, IIllustrationRenderer
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+from pyams_content.shared.common.interfaces import IWfSharedContent
+from pyams_form.interfaces.form import IInnerForm, IEditFormButtons
+from pyams_i18n.interfaces import II18n
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
+from pyams_skin.layer import IPyAMSLayer
+from z3c.form.interfaces import INPUT_MODE
# import packages
-from z3c.form import field
+from pyams_content.component.paragraph.illustration import Illustration
+from pyams_content.component.paragraph.zmi import BaseParagraphAJAXEditForm
+from pyams_content.component.paragraph.zmi.container import ParagraphContainerView
+from pyams_form.form import AJAXAddForm
+from pyams_form.security import ProtectedFormObjectMixin
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.viewlet.toolbar import ToolbarMenuItem
+from pyams_template.template import template_config, get_view_template
+from pyams_utils.adapter import ContextRequestAdapter, adapter_config
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
+from pyramid.view import view_config
+from z3c.form import field, button
+from zope.interface import implementer
from pyams_content import _
@@ -106,18 +111,28 @@
edit_permission = MANAGE_CONTENT_PERMISSION
+@adapter_config(context=(IIllustrationParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+@implementer(IInnerForm)
+class IllustrationInnerEditForm(IllustrationPropertiesEditForm):
+ """Illustration inner edit form"""
+
+ legend = None
+ main_group_legend = _("Illustration properties")
+ main_group_class = 'inner'
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IEditFormButtons)
+ else:
+ return button.Buttons()
+
+
@view_config(name='properties.json', context=IIllustrationParagraph, request_type=IPyAMSLayer,
permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-class IllustrationPropertiesAJAXEditForm(AJAXEditForm, IllustrationPropertiesEditForm):
+class IllustrationPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, IllustrationPropertiesEditForm):
"""HTML paragraph properties edit form, JSON renderer"""
- def get_ajax_output(self, changes):
- if 'title' in changes.get(IBaseParagraph, ()):
- return {'status': 'reload',
- 'location': '#paragraphs.html'}
- else:
- return super(IllustrationPropertiesAJAXEditForm, self).get_ajax_output(changes)
-
#
# Illustration summary
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/zmi/interfaces.py Mon Jan 18 16:08:07 2016 +0100
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2008-2015 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.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_form.interfaces.form import IInnerForm
+
+# import packages
+
+
+class IParagraphInnerEditor(IInnerForm):
+ """Paragraph inner editor form interface"""
--- a/src/pyams_content/component/paragraph/zmi/summary.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/paragraph/zmi/summary.py Mon Jan 18 16:08:07 2016 +0100
@@ -9,18 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \
- IParagraphSummary
-from pyams_content.shared.common.interfaces.zmi import IInnerSummaryView
-from pyams_content.shared.common.zmi.summary import SharedContentSummaryForm
-from pyams_form.form import InnerDisplayForm
-from pyams_form.interfaces.form import IInnerTabForm
-from pyams_i18n.interfaces import II18nManager
-from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.layer import IPyAMSLayer
-from pyams_template.template import template_config
-from pyams_utils.adapter import adapter_config
-from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
__docformat__ = 'restructuredtext'
@@ -28,8 +16,20 @@
# import standard library
# import interfaces
+from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \
+ IParagraphSummary
+from pyams_content.shared.common.interfaces.zmi import IInnerSummaryView
+from pyams_form.interfaces.form import IInnerTabForm
+from pyams_i18n.interfaces import II18nManager
+from pyams_skin.layer import IPyAMSLayer
# import packages
+from pyams_content.shared.common.zmi.summary import SharedContentSummaryForm
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
+from pyams_zmi.form import InnerAdminDisplayForm
from z3c.form import field
from zope.interface import implementer, Interface
@@ -39,7 +39,7 @@
@adapter_config(name='paragraphs-summary',
context=(IParagraphContainerTarget, IPyAMSLayer, SharedContentSummaryForm),
provides=IInnerTabForm)
-class ParagraphsContainerSummary(InnerDisplayForm):
+class ParagraphsContainerSummary(InnerAdminDisplayForm):
"""Paragraphs container summary"""
weight = 20
--- a/src/pyams_content/component/theme/interfaces/__init__.py Thu Oct 15 15:42:01 2015 +0200
+++ b/src/pyams_content/component/theme/interfaces/__init__.py Mon Jan 18 16:08:07 2016 +0100
@@ -46,3 +46,14 @@
class IThemesTarget(Interface):
"""Themes target interface"""
+
+
+PORTLET_SETTINGS_THEMES_KEY = 'pyams_content.themes.settings'
+
+
+class IPortletThemesSettings(Interface):
+ """Interface for portlet settings managing themes"""
+
+
+class IPortletThemesSettingsTarget(Interface):
+ """Marker interface for portlet settings managing themes"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/theme/portlet.py Mon Jan 18 16:08:07 2016 +0100
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2008-2015 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.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.theme.interfaces import IPortletThemesSettings, IPortletThemesSettingsTarget, \
+ PORTLET_SETTINGS_THEMES_KEY
+from zope.annotation.interfaces import IAnnotations
+from zope.traversing.interfaces import ITraversable
+
+# import packages
+from persistent import Persistent
+from pyams_utils.adapter import adapter_config, ContextAdapter
+from zope.container.contained import Contained
+from zope.interface import implementer
+from zope.location import locate
+
+
+@implementer(IPortletThemesSettings)
+class PortletThemesSettings(Persistent, Contained):
+ """Portlet themes settings"""
+
+
+@adapter_config(context=IPortletThemesSettingsTarget, provides=IPortletThemesSettings)
+def PortletThemesSettingsFactory(context):
+ """Portlet themes settings adapter"""
+ annotations = IAnnotations(context)
+ settings = annotations.get(PORTLET_SETTINGS_THEMES_KEY)
+ if settings is None:
+ settings = annotations[PORTLET_SETTINGS_THEMES_KEY] = PortletThemesSettings()
+ locate(settings, context, '++themes++')
+ return settings
+
+
+@adapter_config(name='themes', context=IPortletThemesSettingsTarget, provides=ITraversable)
+class ThemesPortletsSettingsTraverser(ContextAdapter):
+ """++themes++ portlet settings adapter"""
+
+ def traverse(self, name, furtherpath=None):
+ return IPortletThemesSettings(self.context)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/theme/zmi/portlet.py Mon Jan 18 16:08:07 2016 +0100
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2008-2015 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.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.theme.interfaces import IPortletThemesSettingsTarget
+from pyams_form.interfaces.form import IInnerTabForm
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_portal.zmi.portlet import PortletSettingsEditor
+from pyams_utils.adapter import adapter_config
+from pyams_zmi.form import InnerAdminEditForm
+from z3c.form import field
+from zope.interface import Interface
+
+from pyams_content import _
+
+
+@adapter_config(name='themes', context=(IPortletThemesSettingsTarget, IPyAMSLayer, PortletSettingsEditor),
+ provides=IInnerTabForm)
+class PortletSettingsThemesEditor(InnerAdminEditForm):
+ """Portlet settings for themes"""
+
+ id = 'themes_form'
+ tab_label = _("Themes")
+ legend = None
+
+ fields = field.Fields(Interface)
+
+ weight = 50