src/pyams_content/component/paragraph/zmi/container.py
changeset 140 67bad9f880ee
parent 32 66baddd786d5
child 169 483b0f16e9a6
--- a/src/pyams_content/component/paragraph/zmi/container.py	Mon Sep 11 14:53:15 2017 +0200
+++ b/src/pyams_content/component/paragraph/zmi/container.py	Mon Sep 11 14:54:30 2017 +0200
@@ -9,6 +9,7 @@
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
 #
+from pyams_content.component.association.zmi import AssociationsContainerView
 
 __docformat__ = 'restructuredtext'
 
@@ -18,9 +19,9 @@
 
 # import interfaces
 from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
-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.association.interfaces import IAssociationContainer
+from pyams_content.component.extfile.interfaces import IExtFileContainerTarget, IExtFile
+from pyams_content.component.links.interfaces import ILinkContainerTarget, IBaseLink
 from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, IBaseParagraph
 from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphTitleToolbar
 from pyams_form.interfaces.form import IFormSecurityContext
@@ -38,7 +39,7 @@
 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, JsActionColumn
+from pyams_skin.table import BaseTable, I18nColumn, TrashColumn, JsActionColumn, SorterColumn, ImageColumn
 from pyams_skin.viewlet.menu import MenuItem
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
@@ -131,21 +132,9 @@
 
 @adapter_config(name='sorter', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
                 provides=IColumn)
-class ParagraphContainerSorterColumn(ProtectedFormObjectMixin, ActionColumn):
+class ParagraphContainerSorterColumn(ProtectedFormObjectMixin, SorterColumn):
     """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
-
-    def get_url(self, item):
-        return '#'
-
 
 @adapter_config(name='show-hide', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
                 provides=IColumn)
@@ -176,6 +165,20 @@
             return super(ParagraphContainerShowHideColumn, self).renderCell(item)
 
 
+@adapter_config(name='pictogram', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
+                provides=IColumn)
+class ParagraphContainerPictogramColumn(ImageColumn):
+    """Paragraph container pictogram column"""
+
+    weight = 6
+
+    def get_icon_class(self, item):
+        return item.icon_class
+
+    def get_icon_hint(self, item):
+        return self.request.localizer.translate(item.icon_hint)
+
+
 @adapter_config(context=ParagraphContainerShowHideColumn, provides=IFormSecurityContext)
 def ShowHideColumnSecurityContextFactory(column):
     """Show/hide column security context factory"""
@@ -190,58 +193,14 @@
     """Paragraph title toolbar viewlet manager"""
 
 
-@viewlet_config(name='files', context=IExtFileLinksContainerTarget, layer=IPyAMSLayer, view=ParagraphContainerTable,
-                manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=10)
-@template_config(template='templates/paragraph-title-icon.pt', layer=IPyAMSLayer)
-class ParagraphContainerExtFileLinksAction(Viewlet):
-    """Paragraph container external files links column"""
-
-    action_class = 'action extfiles nowrap width-40'
-    icon_class = 'fa fa-fw fa-file-text-o'
-    icon_hint = _("External files")
-
-    url = 'extfile-links.html'
-    modal_target = True
-
-    @property
-    def count(self):
-        return len(IExtFileLinksContainer(self.context).files or ())
-
-
-@viewlet_config(name='links', context=ILinkLinksContainerTarget, layer=IPyAMSLayer, view=ParagraphContainerTable,
-                manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=20)
-@template_config(template='templates/paragraph-title-icon.pt', layer=IPyAMSLayer)
-class ParagraphContainerLinkLinksAction(Viewlet):
-    """Paragraph container links links column"""
-
-    action_class = 'action links nowrap width-40'
-    icon_class = 'fa fa-fw fa-link'
-    icon_hint = _("Useful links")
-
-    url = 'link-links.html'
-    modal_target = True
-
-    @property
-    def count(self):
-        return len(ILinkLinksContainer(self.context).links or ())
-
-
-@viewlet_config(name='gallery', context=IGalleryLinksContainerTarget, layer=IPyAMSLayer, view=ParagraphContainerTable,
-                manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=30)
-@template_config(template='templates/paragraph-title-icon.pt', layer=IPyAMSLayer)
-class ParagraphContainerGalleryLinksAction(Viewlet):
-    """Paragraph container gallery links column"""
-
-    action_class = 'action galleries nowrap width-40'
-    icon_class = 'fa fa-fw fa-picture-o'
-    icon_hint = _("Images galleries")
-
-    url = 'gallery-links.html'
-    modal_target = True
-
-    @property
-    def count(self):
-        return len(IGalleryLinksContainer(self.context).galleries or ())
+def getParagraphTitleHints(item, request, table):
+    """Get paragraphs column title hints"""
+    registry = request.registry
+    provider = registry.queryMultiAdapter((item, request, table), IContentProvider,
+                                          name='pyams_paragraph.title_toolbar')
+    if provider is not None:
+        provider.update()
+        return provider.render()
 
 
 @adapter_config(name='name', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
@@ -249,7 +208,7 @@
 class ParagraphContainerTitleColumn(I18nColumn, WfModifiedContentColumnMixin, GetAttrColumn):
     """Paragraph container title column"""
 
-    _header = _("Title")
+    _header = _("Show/hide all paragraphs")
 
     weight = 50
 
@@ -258,30 +217,24 @@
                '      data-ams-stop-propagation="true"' \
                '      data-ams-click-handler="PyAMS_content.paragraphs.switchAllEditors">' \
                '    <i class="fa fa-plus-square-o"></i>' \
-               '</span> '.format(
+               '</span>&nbsp;&nbsp;&nbsp;'.format(
                     title=self.request.localizer.translate(_("Click to open/close all paragraphs editors"))) + \
                super(ParagraphContainerTitleColumn, self).renderHeadCell()
 
     def renderCell(self, item):
-        registry = self.request.registry
-        provider = registry.queryMultiAdapter((item, self.request, self.table), IContentProvider,
-                                              name='pyams_paragraph.title_toolbar')
-        if provider is not None:
-            provider.update()
-            provider = provider.render()
-        else:
-            provider = ''
+        provider = getParagraphTitleHints(item, self.request, self.table) or ''
         return '<div>{provider}<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(provider=provider,
-                                 title=self.request.localizer.translate(_("Click to open/close paragraph editor"))) + \
+               '</span>&nbsp;&nbsp;&nbsp;'.format(
+                    provider=provider,
+                    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 '--'
+        return II18n(obj).query_attribute('title', request=self.request) or ' - - - - - - - -'
 
 
 @adapter_config(name='trash', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerTable),
@@ -304,17 +257,47 @@
     """Paragraphs container header adapter"""
 
     back_url = '#properties.html'
-
     icon_class = 'fa fa-fw fa-paragraph'
 
 
-@view_config(name='set-paragraphs-order.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer,
+@viewlet_config(name='links', context=ILinkContainerTarget, layer=IPyAMSLayer, view=ParagraphContainerTable,
+                manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=10)
+@template_config(template='templates/paragraph-title-icon.pt', layer=IPyAMSLayer)
+class ParagraphContainerLinksCounter(Viewlet):
+    """Paragraph container external links count column"""
+
+    action_class = 'action links nowrap width-40'
+    icon_class = 'fa fa-fw fa-link'
+    icon_hint = _("Links")
+
+    @property
+    def count(self):
+        return len([file for file in IAssociationContainer(self.context).values()
+                    if IBaseLink.providedBy(file)])
+
+
+@viewlet_config(name='files', context=IExtFileContainerTarget, layer=IPyAMSLayer, view=ParagraphContainerTable,
+                manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=10)
+@template_config(template='templates/paragraph-title-icon.pt', layer=IPyAMSLayer)
+class ParagraphContainerExtFileCounter(Viewlet):
+    """Paragraph container external files count column"""
+
+    action_class = 'action extfiles nowrap width-40'
+    icon_class = 'fa fa-fw fa-file-text-o'
+    icon_hint = _("External files")
+
+    @property
+    def count(self):
+        return len([file for file in IAssociationContainer(self.context).values()
+                    if IExtFile.providedBy(file)])
+
+
+@view_config(name='set-paragraphs-order.json', context=IParagraphContainer, request_type=IPyAMSLayer,
              permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
 def set_paragraphs_order(request):
     """Update paragraphs order"""
-    container = IParagraphContainer(request.context)
     order = list(map(str, json.loads(request.params.get('names'))))
-    container.updateOrder(order)
+    request.context.updateOrder(order)
     return {'status': 'success'}
 
 
@@ -363,3 +346,44 @@
             editor.update()
             result[key] = editor.render()
     return result
+
+
+#
+# Paragraphs associations view
+#
+
+@viewlet_config(name='paragraphs-associations.menu', context=IParagraphContainerTarget, layer=IAdminLayer,
+                manager=IPropertiesMenu, permission=VIEW_SYSTEM_PERMISSION, weight=101)
+class ParagraphsAssociationsMenu(MenuItem):
+    """Paragraphs associations container menu"""
+
+    label = _("Associations...")
+    icon_class = 'fa-link'
+    url = '#paragraphs-associations.html'
+
+
+@pagelet_config(name='paragraphs-associations.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+                permission=VIEW_SYSTEM_PERMISSION)
+@template_config(template='templates/associations.pt', layer=IPyAMSLayer)
+@implementer(IInnerPage)
+class ParagraphsAssociationsView(AdminView):
+    """Paragraphs associations view"""
+
+    title = _("Paragraphs associations")
+
+    @reify
+    def associations(self):
+        result = []
+        for paragraph in IParagraphContainer(self.context).values():
+            associations = IAssociationContainer(paragraph, None)
+            if associations is not None:
+                view = AssociationsContainerView(paragraph, self.request)
+                view.widget_icon_class = 'fa fa-fw {0}'.format(paragraph.icon_class)
+                view.title = II18n(paragraph).query_attribute('title', request=self.request) or ' - - - - - - - -'
+                result.append(view)
+        return result
+
+    def update(self):
+        super(ParagraphsAssociationsView, self).update()
+        for association in self.associations:
+            association.update()