Allow any media in illustrations and galleries
authorThierry Florac <tflorac@ulthar.net>
Wed, 07 Feb 2018 11:21:14 +0100
changeset 363 86d1a240d4dc
parent 362 8fc21a7ef206
child 364 b2fc446f15d9
Allow any media in illustrations and galleries
src/pyams_content/component/gallery/__init__.py
src/pyams_content/component/gallery/file.py
src/pyams_content/component/gallery/interfaces/__init__.py
src/pyams_content/component/gallery/paragraph.py
src/pyams_content/component/gallery/zmi/__init__.py
src/pyams_content/component/gallery/zmi/file.py
src/pyams_content/component/gallery/zmi/interfaces.py
src/pyams_content/component/gallery/zmi/paragraph.py
src/pyams_content/component/gallery/zmi/templates/gallery-images.pt
src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt
src/pyams_content/component/gallery/zmi/templates/renderer-default.pt
src/pyams_content/component/illustration/interfaces/__init__.py
src/pyams_content/skin/resources/js/pyams_content.js
src/pyams_content/skin/resources/js/pyams_content.min.js
--- a/src/pyams_content/component/gallery/__init__.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/__init__.py	Wed Feb 07 11:21:14 2018 +0100
@@ -18,6 +18,7 @@
 # import interfaces
 from pyams_content.component.gallery.interfaces import IGallery, IGalleryTarget, \
     GALLERY_CONTAINER_KEY, IGalleryRenderer
+from pyams_content.component.paragraph import IBaseParagraph
 from pyams_content.features.checker.interfaces import IContentChecker
 from pyams_content.shared.common.interfaces import IWfSharedContent
 from pyams_form.interfaces.form import IFormContextPermissionChecker
@@ -71,8 +72,8 @@
             # make sure that gallery item is correctly indexed
             index_object(value)
 
-    def get_visible_images(self):
-        return [image for image in self.values() if image.visible]
+    def get_visible_medias(self):
+        return [media for media in self.values() if media.visible]
 
 
 @adapter_config(context=IGalleryTarget, provides=IGallery)
@@ -116,7 +117,12 @@
 @subscriber(IObjectAddedEvent, context_selector=IGallery)
 def handle_added_gallery(event):
     """Handle added gallery"""
-    content = get_parent(event.object, IWfSharedContent)
+    gallery = event.object
+    if IBaseParagraph.providedBy(gallery):
+        # there is another event subscriber for paragraphs,
+        # so don't trigger event twice !
+        return
+    content = get_parent(gallery, IWfSharedContent)
     if content is not None:
         get_current_registry().notify(ObjectModifiedEvent(content))
 
@@ -124,7 +130,12 @@
 @subscriber(IObjectModifiedEvent, context_selector=IGallery)
 def handle_modified_gallery(event):
     """Handle modified gallery"""
-    content = get_parent(event.object, IWfSharedContent)
+    gallery = event.object
+    if IBaseParagraph.providedBy(gallery):
+        # there is another event subscriber for paragraphs,
+        # so don't trigger event twice !
+        return
+    content = get_parent(gallery, IWfSharedContent)
     if content is not None:
         get_current_registry().notify(ObjectModifiedEvent(content))
 
@@ -132,7 +143,12 @@
 @subscriber(IObjectRemovedEvent, context_selector=IGallery)
 def handle_removed_gallery(event):
     """Handle removed gallery"""
-    content = get_parent(event.object, IWfSharedContent)
+    gallery = event.object
+    if IBaseParagraph.providedBy(gallery):
+        # there is another event subscriber for paragraphs,
+        # so don't trigger event twice !
+        return
+    content = get_parent(gallery, IWfSharedContent)
     if content is not None:
         get_current_registry().notify(ObjectModifiedEvent(content))
 
@@ -148,13 +164,13 @@
     def inner_check(self, request):
         output = []
         registry = request.registry
-        for image in IGallery(self.context).values():
-            if not image.visible:
+        for media in IGallery(self.context).values():
+            if not media.visible:
                 continue
-            for name, checker in sorted(registry.getAdapters((image, ), IContentChecker),
+            for name, checker in sorted(registry.getAdapters((media, ), IContentChecker),
                                         key=lambda x: x[1].weight):
                 output.append('- {0} : '.format(checker.label or
-                                                II18n(image).query_attribute('title', request=request)))
+                                                II18n(media).query_attribute('title', request=request)))
                 output.append(checker.get_check_output(request))
         return output
 
--- a/src/pyams_content/component/gallery/file.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/file.py	Wed Feb 07 11:21:14 2018 +0100
@@ -19,7 +19,7 @@
 from pyams_content.component.gallery.interfaces import IGalleryFile
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_content.shared.common.interfaces import IWfSharedContent
-from pyams_file.interfaces import DELETED_FILE, IResponsiveImage, IImage
+from pyams_file.interfaces import IResponsiveImage, IImage
 from pyams_form.interfaces.form import IFormContextPermissionChecker
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent
--- a/src/pyams_content/component/gallery/interfaces/__init__.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/interfaces/__init__.py	Wed Feb 07 11:21:14 2018 +0100
@@ -43,7 +43,7 @@
                               required=False)
 
     alt_title = I18nTextLineField(title=_("Accessibility title"),
-                                  description=_("Alternate title used to describe image content"),
+                                  description=_("Alternate title used to describe media content"),
                                   required=False)
 
     data = MediaField(title=_("Image or video data"),
@@ -77,8 +77,8 @@
                                       description=_("Short description of associated sound file"),
                                       required=False)
 
-    visible = Bool(title=_("Visible image?"),
-                   description=_("If 'no', this image won't be displayed in front office"),
+    visible = Bool(title=_("Visible media?"),
+                   description=_("If 'no', this media won't be displayed in front office"),
                    required=True,
                    default=True)
 
@@ -94,14 +94,15 @@
                                 description=_("Gallery description displayed by front-office template"),
                                 required=False)
 
-    renderer = Choice(title=_("Gallery style"),
+    renderer = Choice(title=_("Gallery template"),
+                      description=_("Presentation template used for this gallery"),
                       vocabulary='PyAMS gallery renderers')
 
     def append(self, value, notify=True):
         """Append new file to gallery"""
 
-    def get_visible_images(self):
-        """Get iterator over visible images"""
+    def get_visible_medias(self):
+        """Get iterator over visible medias"""
 
 
 class IGallery(IBaseGallery):
--- a/src/pyams_content/component/gallery/paragraph.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/paragraph.py	Wed Feb 07 11:21:14 2018 +0100
@@ -37,14 +37,14 @@
     """Gallery class"""
 
     icon_class = 'fa-picture-o'
-    icon_hint = _("Images gallery")
+    icon_hint = _("Medias gallery")
 
 
 @utility_config(name='Gallery', provides=IParagraphFactory)
 class GalleryFactory(BaseParagraphFactory):
     """Gallery paragraph factory"""
 
-    name = _("Images gallery")
+    name = _("Medias gallery")
     content_type = Gallery
 
 
--- a/src/pyams_content/component/gallery/zmi/__init__.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/zmi/__init__.py	Wed Feb 07 11:21:14 2018 +0100
@@ -21,7 +21,7 @@
 
 # import interfaces
 from pyams_content.component.gallery.interfaces import IGallery, IGalleryRenderer
-from pyams_content.component.gallery.zmi.interfaces import IGalleryImageAddFields, IGalleryImagesView
+from pyams_content.component.gallery.zmi.interfaces import IGalleryMediasAddFields, IGalleryContentsView
 from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
 from pyams_file.interfaces import IFileInfo
 from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager
@@ -88,7 +88,7 @@
 #
 
 @pagelet_config(name='contents.html', context=IGallery, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION)
-@implementer(IGalleryImagesView)
+@implementer(IGalleryContentsView)
 class GalleryContentForm(AdminDialogDisplayForm):
     """Gallery contents form"""
 
@@ -99,31 +99,31 @@
     show_widget_title = True
 
 
-@viewlet_config(name='gallery-images', context=IGallery, view=IGalleryImagesView, manager=IWidgetsPrefixViewletsManager)
-@template_config(template='templates/gallery-images.pt', layer=IPyAMSLayer)
-@implementer(IGalleryImagesView)
-class GalleryImagesViewlet(Viewlet):
-    """Gallery images viewlet"""
+@viewlet_config(name='gallery-medias', context=IGallery, view=IGalleryContentsView, manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/gallery-medias.pt', layer=IPyAMSLayer)
+@implementer(IGalleryContentsView)
+class GalleryMediasViewlet(Viewlet):
+    """Gallery medias viewlet"""
 
-    def get_title(self, image):
-        return II18n(image).query_attribute('title', request=self.request)
+    def get_title(self, media):
+        return II18n(media).query_attribute('title', request=self.request)
 
 
-@view_config(name='get-gallery-images.html', context=IGallery, request_type=IPyAMSLayer,
+@view_config(name='get-gallery-medias.html', context=IGallery, request_type=IPyAMSLayer,
              permission=VIEW_SYSTEM_PERMISSION)
-@implementer(IGalleryImagesView)
-class GalleryImagesView(WfSharedContentPermissionMixin):
-    """Gallery images view"""
+@implementer(IGalleryContentsView)
+class GalleryMediasView(WfSharedContentPermissionMixin):
+    """Gallery medias view"""
 
     def __init__(self, context, request):
         self.context = context
         self.request = request
 
     def __call__(self):
-        return render_to_response('templates/gallery-images.pt', {'view': self}, request=self.request)
+        return render_to_response('templates/gallery-medias.pt', {'view': self}, request=self.request)
 
-    def get_title(self, image):
-        return II18n(image).query_attribute('title', request=self.request)
+    def get_title(self, media):
+        return II18n(media).query_attribute('title', request=self.request)
 
     def get_thumbnail_target(self, media):
         registry = self.request.registry
@@ -132,25 +132,25 @@
             return absolute_url(media, self.request, 'preview.html')
 
 
-@view_config(name='set-images-order.json', context=IGallery, request_type=IPyAMSLayer,
+@view_config(name='set-medias-order.json', context=IGallery, request_type=IPyAMSLayer,
              permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-def set_images_order(request):
-    """Set gallery images order"""
-    images_names = json.loads(request.params.get('images'))
-    request.context.updateOrder(images_names)
+def set_medias_order(request):
+    """Set gallery medias order"""
+    medias_names = json.loads(request.params.get('medias'))
+    request.context.updateOrder(medias_names)
     return {'status': 'success'}
 
 
-@view_config(name='set-image-visibility.json', context=IGallery, request_type=IPyAMSLayer,
+@view_config(name='set-media-visibility.json', context=IGallery, request_type=IPyAMSLayer,
              permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-def set_image_visibility(request):
-    """Set gallery image visibility"""
+def set_media_visibility(request):
+    """Set gallery media visibility"""
     gallery = IGallery(request.context)
-    image = gallery.get(str(request.params.get('object_name')))
-    if image is None:
+    media = gallery.get(str(request.params.get('object_name')))
+    if media is None:
         raise NotFound()
-    image.visible = not image.visible
-    return {'visible': image.visible}
+    media.visible = not media.visible
+    return {'visible': media.visible}
 
 
 #
@@ -176,17 +176,17 @@
 
 
 #
-# Gallery images downloader
+# Gallery medias downloader
 #
 
-@view_config(name='get-images.zip', context=IGallery, request_type=IPyAMSLayer,
+@view_config(name='get-medias.zip', context=IGallery, request_type=IPyAMSLayer,
              permission=VIEW_SYSTEM_PERMISSION)
-def get_images_archive(request):
-    """Get all gallery images as ZIP file"""
+def get_medias_archive(request):
+    """Get all gallery medias as ZIP file"""
     zip_data = BytesIO()
     zip_file = zipfile.ZipFile(zip_data, mode='w')
-    for image in IGallery(request.context).values():
-        zip_file.writestr(IFileInfo(image.data).filename, image.data.data)
+    for media in IGallery(request.context).values():
+        zip_file.writestr(IFileInfo(media.data).filename, media.data.data)
     zip_file.close()
     zip_data.seek(0)
     response = Response(content_type='application/zip',
--- a/src/pyams_content/component/gallery/zmi/file.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/zmi/file.py	Wed Feb 07 11:21:14 2018 +0100
@@ -9,8 +9,6 @@
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
 #
-from pyams_content.shared.common import IWfSharedContent
-from pyams_form.interfaces.form import IFormContextPermissionChecker
 
 __docformat__ = 'restructuredtext'
 
@@ -19,9 +17,10 @@
 
 # import interfaces
 from pyams_content.component.gallery.interfaces import IGallery, IGalleryFile
-from pyams_content.component.gallery.zmi.interfaces import IGalleryImageAddFields, IGalleryImagesView
+from pyams_content.component.gallery.zmi.interfaces import IGalleryMediasAddFields, IGalleryContentsView
 from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
 from pyams_file.interfaces.archive import IArchiveExtractor
+from pyams_form.interfaces.form import IFormContextPermissionChecker
 from pyams_i18n.interfaces import II18n
 from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager, IContextActions
 from pyams_skin.layer import IPyAMSLayer
@@ -31,6 +30,7 @@
 
 # import packages
 from pyams_content.component.gallery.file import GalleryFile
+from pyams_content.shared.common import IWfSharedContent
 from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin
 from pyams_file.file import get_magic_content_type
 from pyams_file.zmi.file import FilePropertiesAction
@@ -50,50 +50,50 @@
 from pyams_content import _
 
 
-@viewlet_config(name='add-image.menu', context=IGallery, view=IGalleryImagesView, manager=IWidgetTitleViewletManager)
-class GalleryImageAddMenu(WfSharedContentPermissionMixin, ToolbarAction):
-    """Gallery image add menu"""
+@viewlet_config(name='add-media.menu', context=IGallery, view=IGalleryContentsView, manager=IWidgetTitleViewletManager)
+class GalleryMediaAddMenu(WfSharedContentPermissionMixin, ToolbarAction):
+    """Gallery media add menu"""
 
-    label = _("Add image(s)")
+    label = _("Add media(s)")
 
-    url = 'add-image.html'
+    url = 'add-media.html'
     modal_target = True
     stop_propagation = True
 
 
-@pagelet_config(name='add-image.html', context=IGallery, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION)
-class GalleryImageAddForm(AdminDialogAddForm):
-    """Gallery image add form"""
+@pagelet_config(name='add-media.html', context=IGallery, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION)
+class GalleryMediaAddForm(AdminDialogAddForm):
+    """Gallery media add form"""
 
-    legend = _("Add image(s)")
+    legend = _("Add media(s)")
     icon_css_class = 'fa -fa-fw fa-picture-o'
 
-    fields = field.Fields(IGalleryImageAddFields)
-    ajax_handler = 'add-image.json'
+    fields = field.Fields(IGalleryMediasAddFields)
+    ajax_handler = 'add-media.json'
 
     def updateWidgets(self, prefix=None):
-        super(GalleryImageAddForm, self).updateWidgets(prefix)
+        super(GalleryMediaAddForm, self).updateWidgets(prefix)
         if 'author_comments' in self.widgets:
             self.widgets['author_comments'].widget_css_class = 'textarea'
 
     def create(self, data):
         medias = []
-        images = data['images_data']
-        if images and (images is not NOT_CHANGED):
+        medias_data = data['medias_data']
+        if medias_data and (medias_data is not NOT_CHANGED):
             filename = None
-            if isinstance(images, (list, tuple)):
-                filename, images = images
-            if hasattr(images, 'seek'):
-                images.seek(0)
+            if isinstance(medias_data, (list, tuple)):
+                filename, medias_data = medias_data
+            if hasattr(medias_data, 'seek'):
+                medias_data.seek(0)
             registry = self.request.registry
-            content_type = get_magic_content_type(images)
+            content_type = get_magic_content_type(medias_data)
             if isinstance(content_type, bytes):
                 content_type = content_type.decode()
-            if hasattr(images, 'seek'):
-                images.seek(0)
+            if hasattr(medias_data, 'seek'):
+                medias_data.seek(0)
             extractor = query_utility(IArchiveExtractor, name=content_type)
             if extractor is not None:
-                extractor.initialize(images)
+                extractor.initialize(medias_data)
                 for content, filename in extractor.get_contents():
                     try:
                         media = GalleryFile()
@@ -106,7 +106,7 @@
             else:
                 try:
                     media = GalleryFile()
-                    media.data = filename, images if filename else images
+                    media.data = filename, medias_data if filename else medias_data
                 except WrongType:
                     pass
                 else:
@@ -119,18 +119,18 @@
         return None
 
 
-@view_config(name='add-image.json', context=IGallery, request_type=IPyAMSLayer,
+@view_config(name='add-media.json', context=IGallery, request_type=IPyAMSLayer,
              permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-class GalleryImageAJAXAddForm(AJAXAddForm, GalleryImageAddForm):
-    """Gallery image add form, JSON renderer"""
+class GalleryMediaAJAXAddForm(AJAXAddForm, GalleryMediaAddForm):
+    """Gallery media add form, JSON renderer"""
 
     def get_ajax_output(self, changes):
         return {'status': 'reload',
-                'location': absolute_url(self.context, self.request, 'get-gallery-images.html'),
-                'target': '#gallery_images_{0}'.format(self.context.__name__)}
+                'location': absolute_url(self.context, self.request, 'get-gallery-medias.html'),
+                'target': '#gallery_medias_{0}'.format(self.context.__name__)}
 
 
-@viewlet_config(name='file.showhide.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryImagesView,
+@viewlet_config(name='file.showhide.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView,
                 manager=IContextActions, permission=VIEW_SYSTEM_PERMISSION, weight=1)
 class GalleryFileShowHideAction(WfSharedContentPermissionMixin, JsToolbarActionItem):
     """Gallery file show/hide action"""
@@ -146,7 +146,7 @@
     @property
     def label(self):
         if self.request.has_permission(self.edit_permission, context=self.context):
-            return _("Show/hide image")
+            return _("Show/hide media")
         else:
             return ''
 
@@ -159,14 +159,14 @@
 
     hint_gravity = 'nw'
 
-    url = 'PyAMS_content.galleries.switchImageVisibility'
+    url = 'PyAMS_content.galleries.switchMediaVisibility'
 
     def get_url(self):
         if self.request.has_permission(self.edit_permission, context=self.context):
             return self.url
 
 
-@viewlet_config(name='file.properties.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryImagesView,
+@viewlet_config(name='file.properties.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView,
                 manager=IContextActions, permission=VIEW_SYSTEM_PERMISSION, weight=5)
 class GalleryFilePropertiesAction(FilePropertiesAction):
     """Media properties action"""
@@ -179,7 +179,7 @@
 class GalleryFilePropertiesEditForm(AdminDialogEditForm):
     """Gallery file properties edit form"""
 
-    legend = _("Update image properties")
+    legend = _("Update media properties")
     icon_css_class = 'fa fa-fw fa-picture-o'
     dialog_class = 'modal-large'
 
@@ -223,24 +223,24 @@
                 output.setdefault('events', []).append({
                     'event': 'myams.refresh',
                     'options': {
-                        'handler': 'PyAMS_content.galleries.updateImageTitle',
-                        'image_id': 'image_{0}_{1}'.format(gallery.__name__, self.context.__name__),
+                        'handler': 'PyAMS_content.galleries.updateMediaTitle',
+                        'media_id': 'media_{0}_{1}'.format(gallery.__name__, self.context.__name__),
                         'title': II18n(self.context).query_attribute('title', request=self.request)
                     }
                 })
         return output
 
 
-@viewlet_config(name='gallery-file-remover.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryImagesView,
+@viewlet_config(name='gallery-file-remover.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView,
                 manager=IContextActions, weight=90)
 class GalleryFileRemoverAction(WfSharedContentPermissionMixin, JsToolbarActionItem):
     """Gallery file remover action"""
 
-    label = _("Remove image...")
+    label = _("Remove media...")
     label_css_class = 'fa fa-fw fa-trash'
     hint_gravity = 'nw'
 
-    url = 'PyAMS_content.galleries.removeFile'
+    url = 'PyAMS_content.galleries.removeMedia'
 
 
 @view_config(name='delete-element.json', context=IGallery, request_type=IPyAMSLayer,
@@ -256,6 +256,6 @@
     if name not in request.context:
         return {'status': 'message',
                 'messagebox': {'status': 'error',
-                               'content': translate(_("Given image name doesn't exist!"))}}
+                               'content': translate(_("Given media name doesn't exist!"))}}
     del request.context[name]
     return {'status': 'success'}
--- a/src/pyams_content/component/gallery/zmi/interfaces.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/zmi/interfaces.py	Wed Feb 07 11:21:14 2018 +0100
@@ -18,7 +18,7 @@
 # import interfaces
 
 # import packages
-from pyams_file.schema import ImageField
+from pyams_file.schema import FileField
 from pyams_i18n.schema import I18nTextField
 from zope.interface import Interface
 from zope.schema import TextLine
@@ -26,12 +26,12 @@
 from pyams_content import _
 
 
-class IGalleryImagesView(Interface):
+class IGalleryContentsView(Interface):
     """Marker interface for gallery contents view"""
 
 
-class IGalleryImageAddFields(Interface):
-    """Gallery image add fields"""
+class IGalleryMediasAddFields(Interface):
+    """Gallery medias add fields"""
 
     author = TextLine(title=_("Author"),
                       description=_("Name of document's author"),
@@ -41,6 +41,6 @@
                                     description=_("Comments relatives to author's rights management"),
                                     required=False)
 
-    images_data = ImageField(title=_("Images or videos data"),
-                             description=_("You can upload a single file or choose to upload a whole ZIP archive"),
-                             required=True)
+    medias_data = FileField(title=_("Images or videos data"),
+                            description=_("You can upload a single file or choose to upload a whole ZIP archive"),
+                            required=True)
--- a/src/pyams_content/component/gallery/zmi/paragraph.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/zmi/paragraph.py	Wed Feb 07 11:21:14 2018 +0100
@@ -19,7 +19,7 @@
 
 # import interfaces
 from pyams_content.component.gallery.interfaces import IGalleryParagraph, IBaseGallery, IGalleryRenderer
-from pyams_content.component.gallery.zmi.interfaces import IGalleryImagesView
+from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView
 from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \
     IParagraphSummary
 from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView
@@ -55,7 +55,7 @@
 class GalleryAddMenu(BaseParagraphAddMenu):
     """Gallery add menu"""
 
-    label = _("Add images gallery...")
+    label = _("Add medias gallery...")
     label_css_class = 'fa fa-fw fa-picture-o'
     url = 'add-gallery.html'
     paragraph_type = 'Gallery'
@@ -150,18 +150,18 @@
 # Gallery contents view
 #
 
-@adapter_config(name='gallery-images', context=(IGalleryParagraph, IPyAMSLayer, GalleryInnerEditForm),
+@adapter_config(name='gallery-medias', context=(IGalleryParagraph, IPyAMSLayer, GalleryInnerEditForm),
                 provides=IInnerSubForm)
-@template_config(template='templates/gallery-images.pt', layer=IPyAMSLayer)
-@implementer(IGalleryImagesView)
+@template_config(template='templates/gallery-medias.pt', layer=IPyAMSLayer)
+@implementer(IGalleryContentsView)
 class GalleryContentsView(WfSharedContentPermissionMixin, InnerAdminDisplayForm):
     """Gallery contents edit form"""
 
     fields = field.Fields(Interface)
     weight = 10
 
-    def get_title(self, image):
-        return II18n(image).query_attribute('title', request=self.request)
+    def get_title(self, media):
+        return II18n(media).query_attribute('title', request=self.request)
 
     def get_thumbnail_target(self, media):
         registry = self.request.registry
@@ -170,14 +170,14 @@
             return absolute_url(media, self.request, 'preview.html')
 
 
-@viewlet_config(name='add-image.menu', context=IGalleryParagraph, view=GalleryContentsView,
+@viewlet_config(name='add-media.menu', context=IGalleryParagraph, view=GalleryContentsView,
                 manager=IWidgetTitleViewletManager)
-class GalleryImageAddMenu(WfSharedContentPermissionMixin, ToolbarAction):
-    """Gallery image add menu"""
+class GalleryMediaAddMenu(WfSharedContentPermissionMixin, ToolbarAction):
+    """Gallery media add menu"""
 
-    label = _("Add image(s)")
+    label = _("Add media(s)")
 
-    url = 'add-image.html'
+    url = 'add-media.html'
     modal_target = True
     stop_propagation = True
 
--- a/src/pyams_content/component/gallery/zmi/templates/gallery-images.pt	Wed Feb 07 09:22:03 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-<div class="form-group" i18n:domain="pyams_content"
-	 data-ams-plugins="pyams_content"
-	 tal:attributes="data-ams-plugin-pyams_content-src extension:resource_path('pyams_content.skin:pyams_content');
-					 id string:gallery_images_${context.__name__};"
-	 data-ams-plugin-pyams_content-async="false">
-	<fieldset class="margin-top-10 padding-top-5 padding-bottom-0">
-		<legend
-			class="inner switcher margin-bottom-5 padding-right-10 no-y-padding pull-left width-auto"
-			tal:attributes="data-ams-switcher-state 'open' if context.values() else None">
-			<i18n:var translate="">Gallery images</i18n:var>
-		</legend>
-		<div class="btn-group pull-right">
-			<a class="btn btn-xs btn-primary"
-			   tal:attributes="href extension:absolute_url(context, 'get-images.zip')"
-			   i18n:translate="">Download images</a>
-		</div>
-		<div class="pull-left persistent">
-			<tal:var content="structure provider:pyams.widget_title" />
-		</div>
-		<div class="clearfix"></div>
-		<div class="sortable fancybox gallery"
-			 tal:attributes="data-ams-location extension:absolute_url(context);
-							 class '{0} fancybox gallery'.format('sortable' if request.has_permission(view.permission) else '');"
-			 data-ams-sortable-stop="PyAMS_content.galleries.setOrder"
-			 data-ams-sortable-helper="clone"
-			 data-ams-fancybox-type="image"
-			 data-ams-fancybox-loop="false"
-			 data-ams-fancybox-elements="a.fancyimg"
-			 data-ams-fancybox-after-load="PyAMS_content.galleries.afterFancyboxLoad">
-			<div tal:repeat="image context.values()"
-				 class="image margin-5 margin-bottom-10 radius-4 padding-5 pull-left text-center"
-				 style="position: relative;"
-				 tal:attributes="data-ams-element-name image.__name__">
-				<tal:var define="thumbnails extension:thumbnails(image.data);">
-					<tal:if condition="thumbnails">
-						<tal:if condition="image.data.content_type.startswith('image/')">
-							<a class="fancyimg hint" data-toggle
-							   data-ams-hint-gravity="sw"
-							   title="Zoom image" i18n:attributes="title"
-							   tal:define="target thumbnails.get_thumbnail('800x600')"
-							   tal:attributes="class 'fancyimg hint {0}'.format('not-visible' if not image.visible else '');
-											   href extension:absolute_url(target);
-											   rel string:gallery_${context.__name__};">
-								<img class="thumbnail"
-									 data-ams-hint-gravity="s"
-									 tal:define="thumbnail thumbnails.get_thumbnail('128x128');
-												 image_size thumbnail.get_image_size();
-												 margin_left 64 - image_size[0] / 2;
-												 margin_top 64 - image_size[1] / 2;
-												 title i18n:image.title;"
-									 tal:attributes="src extension:absolute_url(thumbnail);
-													 id 'image_{0}_{1}'.format(context.__name__, image.__name__);
-													 original-title title or '--';
-													 style string:margin-left: ${margin_left}px;; margin-right: ${margin_left}px;; margin-top: ${margin_top}px;; margin-bottom: ${margin_top}px;;" />
-							</a>
-						</tal:if>
-						<tal:if condition="not:image.data.content_type.startswith('image/')">
-							<a tal:define="thumbnail thumbnails.get_thumbnail('128x128');
-										   target view.get_thumbnail_target(image.data);
-										   image_size thumbnail.get_image_size();
-										   margin_left 64 - image_size[0] / 2;
-										   margin_top 64 - image_size[1] / 2;
-										   title i18n:image.title;"
-							   tal:omit-tag="not:target"
-							   tal:attributes="href target" data-toggle="modal">
-								<img class="thumbnail no-border"
-									 data-ams-hint-gravity="s"
-									 tal:attributes="src extension:absolute_url(thumbnail);
-													 id 'media_{0}_{1}'.format(context.__name__, image.__name__);
-													 original-title title or '--';
-													 style string:margin-left: ${margin_left}px;; margin-right: ${margin_left}px;; margin-top: ${margin_top}px;; margin-bottom: ${margin_top}px;;" />
-							</a>
-						</tal:if>
-					</tal:if>
-					<tal:if condition="not:thumbnails">
-						<img class="thumbnail hint" src="/--static--/pyams_skin/img/mimetypes/unknown.png"
-							 tal:attributes="title i18n:image.title"
-							 style="padding: 48px;" />
-					</tal:if>
-				</tal:var>
-				<div class="btn-group margin-top-10"
-					 tal:define="actions extension:context_actions(image);">
-					<tal:loop repeat="viewlet actions.viewlets"
-							  content="structure viewlet.render()" />
-				</div>
-				<span class="clearfix"></span>
-			</div>
-		</div>
-	</fieldset>
-</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt	Wed Feb 07 11:21:14 2018 +0100
@@ -0,0 +1,90 @@
+<div class="form-group" i18n:domain="pyams_content"
+	 data-ams-plugins="pyams_content"
+	 tal:attributes="data-ams-plugin-pyams_content-src extension:resource_path('pyams_content.skin:pyams_content');
+					 id string:gallery_medias_${context.__name__};"
+	 data-ams-plugin-pyams_content-async="false">
+	<fieldset class="margin-top-10 padding-top-5 padding-bottom-0">
+		<legend
+			class="inner switcher margin-bottom-5 padding-right-10 no-y-padding pull-left width-auto"
+			tal:attributes="data-ams-switcher-state 'open' if context.values() else None">
+			<i18n:var translate="">Gallery medias</i18n:var>
+		</legend>
+		<div class="btn-group pull-right">
+			<a class="btn btn-xs btn-primary"
+			   tal:attributes="href extension:absolute_url(context, 'get-medias.zip')"
+			   i18n:translate="">Download medias</a>
+		</div>
+		<div class="pull-left persistent">
+			<tal:var content="structure provider:pyams.widget_title" />
+		</div>
+		<div class="clearfix"></div>
+		<div class="sortable fancybox gallery"
+			 tal:attributes="data-ams-location extension:absolute_url(context);
+							 class '{0} fancybox gallery'.format('sortable' if request.has_permission(view.permission) else '');"
+			 data-ams-sortable-stop="PyAMS_content.galleries.setOrder"
+			 data-ams-sortable-helper="clone"
+			 data-ams-fancybox-type="image"
+			 data-ams-fancybox-loop="false"
+			 data-ams-fancybox-elements="a.fancyimg"
+			 data-ams-fancybox-after-load="PyAMS_content.galleries.afterFancyboxLoad">
+			<div tal:repeat="media context.values()"
+				 class="media margin-5 margin-bottom-10 radius-4 padding-5 pull-left text-center"
+				 style="position: relative;"
+				 tal:attributes="data-ams-element-name media.__name__">
+				<tal:var define="thumbnails extension:thumbnails(media.data);">
+					<tal:if condition="thumbnails">
+						<tal:if condition="media.data.content_type.startswith('image/')">
+							<a class="fancyimg hint" data-toggle
+							   data-ams-hint-gravity="sw"
+							   title="Zoom image" i18n:attributes="title"
+							   tal:define="target thumbnails.get_thumbnail('800x600')"
+							   tal:attributes="class 'fancyimg hint {0}'.format('not-visible' if not media.visible else '');
+											   href extension:absolute_url(target);
+											   rel string:gallery_${context.__name__};">
+								<img class="thumbnail"
+									 data-ams-hint-gravity="s"
+									 tal:define="thumbnail thumbnails.get_thumbnail('128x128');
+												 image_size thumbnail.get_image_size();
+												 margin_left 64 - image_size[0] / 2;
+												 margin_top 64 - image_size[1] / 2;
+												 title i18n:media.title;"
+									 tal:attributes="src extension:absolute_url(thumbnail);
+													 id 'media_{0}_{1}'.format(context.__name__, media.__name__);
+													 original-title title or '--';
+													 style string:margin-left: ${margin_left}px;; margin-right: ${margin_left}px;; margin-top: ${margin_top}px;; margin-bottom: ${margin_top}px;;" />
+							</a>
+						</tal:if>
+						<tal:if condition="not:media.data.content_type.startswith('image/')">
+							<a tal:define="thumbnail thumbnails.get_thumbnail('128x128');
+										   target view.get_thumbnail_target(media.data);
+										   image_size thumbnail.get_image_size();
+										   margin_left 64 - image_size[0] / 2;
+										   margin_top 64 - image_size[1] / 2;
+										   title i18n:media.title;"
+							   tal:omit-tag="not:target"
+							   tal:attributes="href target" data-toggle="modal">
+								<img class="thumbnail no-border"
+									 data-ams-hint-gravity="s"
+									 tal:attributes="src extension:absolute_url(thumbnail);
+													 id 'media_{0}_{1}'.format(context.__name__, media.__name__);
+													 original-title title or '--';
+													 style string:margin-left: ${margin_left}px;; margin-right: ${margin_left}px;; margin-top: ${margin_top}px;; margin-bottom: ${margin_top}px;;" />
+							</a>
+						</tal:if>
+					</tal:if>
+					<tal:if condition="not:thumbnails">
+						<img class="thumbnail hint" src="/--static--/pyams_skin/img/mimetypes/unknown.png"
+							 tal:attributes="title i18n:media.title"
+							 style="padding: 48px;" />
+					</tal:if>
+				</tal:var>
+				<div class="btn-group margin-top-10"
+					 tal:define="actions extension:context_actions(media);">
+					<tal:loop repeat="viewlet actions.viewlets"
+							  content="structure viewlet.render()" />
+				</div>
+				<span class="clearfix"></span>
+			</div>
+		</div>
+	</fieldset>
+</div>
--- a/src/pyams_content/component/gallery/zmi/templates/renderer-default.pt	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/gallery/zmi/templates/renderer-default.pt	Wed Feb 07 11:21:14 2018 +0100
@@ -1,5 +1,5 @@
 <div i18n:domain="pyams_content">
-	<tal:loop repeat="image context.values()">
+	<tal:loop repeat="image context.get_visible_medias()">
 		<picture tal:define="image_data i18n:image.data;
 							 image_url extension:absolute_url(image_data);
 							 base_width 100 / 12;
--- a/src/pyams_content/component/illustration/interfaces/__init__.py	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/component/illustration/interfaces/__init__.py	Wed Feb 07 11:21:14 2018 +0100
@@ -92,7 +92,8 @@
                         description=_("Name under which the file will be saved"),
                         required=False)
 
-    renderer = Choice(title=_("Image style"),
+    renderer = Choice(title=_("Illustration template"),
+                      description=_("Presentation template used for illustration"),
                       vocabulary='PyAMS illustration renderers')
 
     language = Choice(title=_("Language"),
--- a/src/pyams_content/skin/resources/js/pyams_content.js	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/skin/resources/js/pyams_content.js	Wed Feb 07 11:21:14 2018 +0100
@@ -61,17 +61,17 @@
 		 */
 		galleries: {
 
-			updateImageTitle: function(options) {
-				$('img[id="' + options.image_id + '"]').attr('original-title', options.title);
+			updateMediaTitle: function(options) {
+				$('img[id="' + options.media_id + '"]').attr('original-title', options.title);
 			},
 
-			switchImageVisibility: function(element) {
+			switchMediaVisibility: function(element) {
 				return function() {
 					var source = $(this);
-					var image = source.parents('.image');
-					var gallery = image.parents('.gallery');
-					MyAMS.ajax.post(gallery.data('ams-location') + '/set-image-visibility.json',
-									{object_name: image.data('ams-element-name')},
+					var media = source.parents('.media');
+					var gallery = media.parents('.gallery');
+					MyAMS.ajax.post(gallery.data('ams-location') + '/set-media-visibility.json',
+									{object_name: media.data('ams-element-name')},
 									function(result, status) {
 										if (result.visible) {
 											$('i', source).attr('class', 'fa fa-fw fa-eye');
@@ -89,9 +89,9 @@
 					return;
 				}
 				var gallery = ui.item.parents('.gallery');
-				var ids = $('.image', gallery).listattr('data-ams-element-name');
-				MyAMS.ajax.post(gallery.data('ams-location') + '/set-images-order.json',
-								{images: JSON.stringify(ids)});
+				var ids = $('.media', gallery).listattr('data-ams-element-name');
+				MyAMS.ajax.post(gallery.data('ams-location') + '/set-medias-order.json',
+								{medias: JSON.stringify(ids)});
 			},
 
 			removeFile: function(element) {
@@ -105,12 +105,12 @@
 						if (button === MyAMS.i18n.BTN_OK) {
 							var gallery = link.parents('.gallery');
 							var location = gallery.data('ams-location');
-							var image = link.parents('.image');
-							var object_name = image.data('ams-element-name');
+							var media = link.parents('.media');
+							var object_name = media.data('ams-element-name');
 							MyAMS.ajax.post(location + '/delete-element.json',
 											{object_name: object_name},
 											function(result, status) {
-												image.remove();
+												media.remove();
 											});
 						}
 					});
--- a/src/pyams_content/skin/resources/js/pyams_content.min.js	Wed Feb 07 09:22:03 2018 +0100
+++ b/src/pyams_content/skin/resources/js/pyams_content.min.js	Wed Feb 07 11:21:14 2018 +0100
@@ -1,1 +1,1 @@
-!function(a,t){"use strict";var e=t.MyAMS,s={widget:{treeview:{selectFolder:function(t,e){a(t.target).siblings('input[type="hidden"]').val(e.id)},unselectFolder:function(t,e){a(t.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(a){return a.image_list=s.TinyMCE.getImagesList,a.link_list=s.TinyMCE.getLinksList,a},getImagesList:function(t){var s=a(document.activeElement).parents("form");if(s.exists()){var i=s.attr("data-ams-form-handler")||s.attr("action"),n=i.substr(0,i.lastIndexOf("/")+1);return e.ajax.post(n+"get-images-list.json",{},t)}},getLinksList:function(t){var s=a(document.activeElement).parents("form");if(s.exists()){var i=s.attr("data-ams-form-handler")||s.attr("action"),n=i.substr(0,i.lastIndexOf("/")+1);return e.ajax.post(n+"get-links-list.json",{},t)}}},galleries:{updateImageTitle:function(t){a('img[id="'+t.image_id+'"]').attr("original-title",t.title)},switchImageVisibility:function(t){return function(){var t=a(this),s=t.parents(".image"),i=s.parents(".gallery");e.ajax.post(i.data("ams-location")+"/set-image-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?(a("i",t).attr("class","fa fa-fw fa-eye"),t.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger"),t.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(t,s){if(!s||!s.item.hasClass("already-dropped")){var i=s.item.parents(".gallery"),n=a(".image",i).listattr("data-ams-element-name");e.ajax.post(i.data("ams-location")+"/set-images-order.json",{images:JSON.stringify(n)})}},removeFile:function(t){return function(){var t=a(this);e.skin.bigBox({title:e.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+e.i18n.DELETE_WARNING,buttons:e.i18n.BTN_OK_CANCEL},function(a){if(a===e.i18n.BTN_OK){var s=t.parents(".gallery").data("ams-location"),i=t.parents(".image"),n=i.data("ams-element-name");e.ajax.post(s+"/delete-element.json",{object_name:n},function(a,t){i.remove()})}})}},afterFancyboxLoad:function(a,t){a.element.hasClass("not-visible")&&a.inner.prepend('<div class="hidden-mask"></div>')}},illustration:{addIllustration:function(){var t=a(this),e=t.parents(".btn-group").siblings("legend.switcher");a("i.fa-plus",e).click(),t.hide()}},associations:{refreshAssociations:function(a){var t=e.skin.refreshTable(a).siblings("legend");t.parents("fieldset:first").hasClass("switched")&&t.click()},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-association-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}}},paragraphs:{preReload:function(){s.paragraphs.switched=a("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){a(s.paragraphs.switched).each(function(){a("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete s.paragraphs.switched},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-paragraph-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}},refreshParagraphs:function(a){var t=e.skin.refreshTable(a).siblings("legend");t.parents("fieldset:first").hasClass("switched")&&t.click()},refreshParagraph:function(t){var e=a('table[id="paragraphs_list"]'),s=a('tr[data-ams-element-name="'+t.object_name+'"]',e);a("span.title",s).html(t.title||" - - - - - - - -")},switchEditor:function(t){var s=a(this),i=a("i.switch",s),n=s.parents("td"),r=a(".editor",n),o=s.parents("tr");if(i.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),e.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(a){r.html(a),a&&(e.initContent(r),i.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0))})}else e.skin.cleanContainer(r),r.empty(),i.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchAllEditors:function(t){var s=a(this),i=a("i",s),n=s.parents("table");i.hasClass("fa-plus-square-o")?(i.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),e.ajax.post(n.data("ams-location")+"/get-paragraphs-editors.json",{},function(t){for(var s in t)if(t.hasOwnProperty(s)){var r=a('tr[data-ams-element-name="'+s+'"]',n),o=a(".editor",r);o.is(":empty")&&(o.html(t[s]),e.initContent(o)),a(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}a("i.fa-plus-square-o",a("tbody",n)).exists()||i.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o")})):(a(".editor",n).each(function(){e.skin.cleanContainer(a(this)),a(this).empty()}),a(".fa-minus-square-o",n).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),a("tr",n).removeData("ams-disabled-handlers"))},updateToolbar:function(t){var s=a('table[id="paragraphs_list"]'),i=a('tr[data-ams-element-name="'+t.object_name+'"]',s),n=a(".title-toolbar",i);n.replaceWith(t.toolbar_tag),n=a(".title-toolbar",i),e.initContent(n)},updateMarkers:function(t){var s=a('table[id="paragraphs_list"]'),i=a('tr[data-ams-element-name="'+t.object_name+'"]',s),n=a(".title-toolbar",i),r=a("DIV.action."+t.marker_type,n);r.exists()?r.replaceWith(t.marker_tag):a(t.marker_tag).appendTo(n),t.marker_tag&&(r=a("DIV.action."+t.marker_type,n),e.initContent(r)),e.helpers.sort(n,"weight")}},themes:{initExtracts:function(t){var s=a('select[name="form.widgets.thesaurus_name:list"]',t).val(),i=a('select[name="form.widgets.extract_name:list"]',t),n=i.val();s&&e.jsonrpc.post("getExtracts",{thesaurus_name:s},{url:"/api/thesaurus/json"},function(t){i.empty(),a(t.result).each(function(){a("<option></option>").attr("value",this.id).attr("selected",this.id===n).text(this.text).appendTo(i)})}),i.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(t){var s=a(t.currentTarget).parents("form"),i=a('select[name="form.widgets.thesaurus_name:list"]',s).val();i&&e.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(t){var e=a('select[name="form.widgets.extract_name:list"]',s).data("select2");e.results.empty(),e.opts.populateResults.call(e,e.results,t.result,{term:""})})}},fields:{refreshField:function(t){var e=a('table[id="form_fields_list"]'),s=a('tr[data-ams-element-name="'+t.object_name+'"]',e);a("td:nth-child(4)",s).html(t.title)},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-form-field-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}}},imgmap:{init:function(){var t=a(this);e.ajax.check(a.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+e.devext+".js",function(){t.canvasAreaDraw({imageUrl:t.data("ams-image-url")})})},initSummary:function(){var t=a(this);e.ajax.check(a.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+e.devext+".js",function(){t.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},types:{switchSubtypes:function(t){var s=a(this),i=a("i.switch",s),n=s.parents("td"),r=a(".subtypes",n),o=s.parents("tr");if(i.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),e.ajax.post(l.data("ams-location")+"/get-subtypes-table.json",{object_name:o.data("ams-element-name")},function(a){r.html(a),a&&(e.initContent(r),i.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"))})}else e.skin.cleanContainer(r),r.empty(),i.removeClass("fa-minus-square-o").addClass("fa-plus-square-o")}},site:{switchVisibility:function(){return function(){var t=a(this),s=t.parents("tr").first();e.ajax.post(s.data("ams-location")+"/set-content-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){var i;i=e.visible?"fa-eye":"fa-eye-slash",e.published||(i+=" text-danger"),a("i",t).attr("class","fa fa-fw "+i)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(t){var i=a(".chat-body",t);i.animate({scrollTop:i[0].scrollHeight},1e3),clearInterval(s.review.timer),s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.chat),e.skin.registerCleanCallback(s.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(s.review.timer),s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.general)},updateComments:function(){var t,s=a(".badge",'nav a[href="#review-comments.html"]'),i=a(".chat-body",".widget-body");t=i.exists()?a(".message",i).length:parseInt(s.text()),e.ajax.post("get-last-review-comments.json",{count:t},function(e){i.exists()&&s.removeClass("bg-color-danger").addClass("bg-color-info"),t!==e.count&&(s.text(e.count).removeClass("hidden"),i.exists()&&(a(".messages",i).append(e.content),i.animate({scrollTop:i[0].scrollHeight},1e3)),i.exists()||s.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){a(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(t){var e=a(".chat-body",".widget-body");return{count:a(".message",e).length}},addCommentAction:function(){return function(){a('textarea[name="comment"]').focus()}},addCommentCallback:function(t){var e=a(this),s=e.parents(".widget-body");a(".messages",s).append(t.content),a('textarea[name="comment"]',e).val("");var i=a(".chat-body",s);i.animate({scrollTop:i[0].scrollHeight},1e3),a(".badge",'nav a[href="#review-comments.html"]').text(t.count).removeClass("hidden")}},profile:{switchFavorite:function(){var t=a(this),s=t.data("sequence-oid");e.ajax.post("switch-user-favorite.json",{oid:s},function(a,e){a.favorite?t.removeClass("fa-star-o").addClass("fa-star"):t.removeClass("fa-star").addClass("fa-star-o")})}}};a(".badge",'nav a[href="#review-comments.html"]').exists()&&(s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.general)),t.PyAMS_content=s}(jQuery,this);
+!function(a,t){"use strict";var e=t.MyAMS,s={widget:{treeview:{selectFolder:function(t,e){a(t.target).siblings('input[type="hidden"]').val(e.id)},unselectFolder:function(t,e){a(t.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(a){return a.image_list=s.TinyMCE.getImagesList,a.link_list=s.TinyMCE.getLinksList,a},getImagesList:function(t){var s=a(document.activeElement).parents("form");if(s.exists()){var i=s.attr("data-ams-form-handler")||s.attr("action"),n=i.substr(0,i.lastIndexOf("/")+1);return e.ajax.post(n+"get-images-list.json",{},t)}},getLinksList:function(t){var s=a(document.activeElement).parents("form");if(s.exists()){var i=s.attr("data-ams-form-handler")||s.attr("action"),n=i.substr(0,i.lastIndexOf("/")+1);return e.ajax.post(n+"get-links-list.json",{},t)}}},galleries:{updateMediaTitle:function(t){a('img[id="'+t.media_id+'"]').attr("original-title",t.title)},switchMediaVisibility:function(t){return function(){var t=a(this),s=t.parents(".media"),i=s.parents(".gallery");e.ajax.post(i.data("ams-location")+"/set-media-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?(a("i",t).attr("class","fa fa-fw fa-eye"),t.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger"),t.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(t,s){if(!s||!s.item.hasClass("already-dropped")){var i=s.item.parents(".gallery"),n=a(".media",i).listattr("data-ams-element-name");e.ajax.post(i.data("ams-location")+"/set-medias-order.json",{medias:JSON.stringify(n)})}},removeFile:function(t){return function(){var t=a(this);e.skin.bigBox({title:e.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+e.i18n.DELETE_WARNING,buttons:e.i18n.BTN_OK_CANCEL},function(a){if(a===e.i18n.BTN_OK){var s=t.parents(".gallery").data("ams-location"),i=t.parents(".media"),n=i.data("ams-element-name");e.ajax.post(s+"/delete-element.json",{object_name:n},function(a,t){i.remove()})}})}},afterFancyboxLoad:function(a,t){a.element.hasClass("not-visible")&&a.inner.prepend('<div class="hidden-mask"></div>')}},illustration:{addIllustration:function(){var t=a(this),e=t.parents(".btn-group").siblings("legend.switcher");a("i.fa-plus",e).click(),t.hide()}},associations:{refreshAssociations:function(a){var t=e.skin.refreshTable(a).siblings("legend");t.parents("fieldset:first").hasClass("switched")&&t.click()},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-association-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}}},paragraphs:{preReload:function(){s.paragraphs.switched=a("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){a(s.paragraphs.switched).each(function(){a("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete s.paragraphs.switched},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-paragraph-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}},refreshParagraphs:function(a){var t=e.skin.refreshTable(a).siblings("legend");t.parents("fieldset:first").hasClass("switched")&&t.click()},refreshParagraph:function(t){var e=a('table[id="paragraphs_list"]'),s=a('tr[data-ams-element-name="'+t.object_name+'"]',e);a("span.title",s).html(t.title||" - - - - - - - -")},switchEditor:function(t){var s=a(this),i=a("i.switch",s),n=s.parents("td"),r=a(".editor",n),o=s.parents("tr");if(i.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),e.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(a){r.html(a),a&&(e.initContent(r),i.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0))})}else e.skin.cleanContainer(r),r.empty(),i.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchAllEditors:function(t){var s=a(this),i=a("i",s),n=s.parents("table");i.hasClass("fa-plus-square-o")?(i.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),e.ajax.post(n.data("ams-location")+"/get-paragraphs-editors.json",{},function(t){for(var s in t)if(t.hasOwnProperty(s)){var r=a('tr[data-ams-element-name="'+s+'"]',n),o=a(".editor",r);o.is(":empty")&&(o.html(t[s]),e.initContent(o)),a(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}a("i.fa-plus-square-o",a("tbody",n)).exists()||i.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o")})):(a(".editor",n).each(function(){e.skin.cleanContainer(a(this)),a(this).empty()}),a(".fa-minus-square-o",n).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),a("tr",n).removeData("ams-disabled-handlers"))},updateToolbar:function(t){var s=a('table[id="paragraphs_list"]'),i=a('tr[data-ams-element-name="'+t.object_name+'"]',s),n=a(".title-toolbar",i);n.replaceWith(t.toolbar_tag),n=a(".title-toolbar",i),e.initContent(n)},updateMarkers:function(t){var s=a('table[id="paragraphs_list"]'),i=a('tr[data-ams-element-name="'+t.object_name+'"]',s),n=a(".title-toolbar",i),r=a("DIV.action."+t.marker_type,n);r.exists()?r.replaceWith(t.marker_tag):a(t.marker_tag).appendTo(n),t.marker_tag&&(r=a("DIV.action."+t.marker_type,n),e.initContent(r)),e.helpers.sort(n,"weight")}},themes:{initExtracts:function(t){var s=a('select[name="form.widgets.thesaurus_name:list"]',t).val(),i=a('select[name="form.widgets.extract_name:list"]',t),n=i.val();s&&e.jsonrpc.post("getExtracts",{thesaurus_name:s},{url:"/api/thesaurus/json"},function(t){i.empty(),a(t.result).each(function(){a("<option></option>").attr("value",this.id).attr("selected",this.id===n).text(this.text).appendTo(i)})}),i.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(t){var s=a(t.currentTarget).parents("form"),i=a('select[name="form.widgets.thesaurus_name:list"]',s).val();i&&e.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(t){var e=a('select[name="form.widgets.extract_name:list"]',s).data("select2");e.results.empty(),e.opts.populateResults.call(e,e.results,t.result,{term:""})})}},fields:{refreshField:function(t){var e=a('table[id="form_fields_list"]'),s=a('tr[data-ams-element-name="'+t.object_name+'"]',e);a("td:nth-child(4)",s).html(t.title)},switchVisibility:function(t){return function(){var t=a(this),s=t.parents("tr"),i=s.parents("table");e.ajax.post(i.data("ams-location")+"/set-form-field-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){e.visible?a("i",t).attr("class","fa fa-fw fa-eye"):a("i",t).attr("class","fa fa-fw fa-eye-slash text-danger")})}}},imgmap:{init:function(){var t=a(this);e.ajax.check(a.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+e.devext+".js",function(){t.canvasAreaDraw({imageUrl:t.data("ams-image-url")})})},initSummary:function(){var t=a(this);e.ajax.check(a.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+e.devext+".js",function(){t.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},types:{switchSubtypes:function(t){var s=a(this),i=a("i.switch",s),n=s.parents("td"),r=a(".subtypes",n),o=s.parents("tr");if(i.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),e.ajax.post(l.data("ams-location")+"/get-subtypes-table.json",{object_name:o.data("ams-element-name")},function(a){r.html(a),a&&(e.initContent(r),i.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"))})}else e.skin.cleanContainer(r),r.empty(),i.removeClass("fa-minus-square-o").addClass("fa-plus-square-o")}},site:{switchVisibility:function(){return function(){var t=a(this),s=t.parents("tr").first();e.ajax.post(s.data("ams-location")+"/set-content-visibility.json",{object_name:s.data("ams-element-name")},function(e,s){var i;i=e.visible?"fa-eye":"fa-eye-slash",e.published||(i+=" text-danger"),a("i",t).attr("class","fa fa-fw "+i)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(t){var i=a(".chat-body",t);i.animate({scrollTop:i[0].scrollHeight},1e3),clearInterval(s.review.timer),s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.chat),e.skin.registerCleanCallback(s.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(s.review.timer),s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.general)},updateComments:function(){var t,s=a(".badge",'nav a[href="#review-comments.html"]'),i=a(".chat-body",".widget-body");t=i.exists()?a(".message",i).length:parseInt(s.text()),e.ajax.post("get-last-review-comments.json",{count:t},function(e){i.exists()&&s.removeClass("bg-color-danger").addClass("bg-color-info"),t!==e.count&&(s.text(e.count).removeClass("hidden"),i.exists()&&(a(".messages",i).append(e.content),i.animate({scrollTop:i[0].scrollHeight},1e3)),i.exists()||s.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){a(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(t){var e=a(".chat-body",".widget-body");return{count:a(".message",e).length}},addCommentAction:function(){return function(){a('textarea[name="comment"]').focus()}},addCommentCallback:function(t){var e=a(this),s=e.parents(".widget-body");a(".messages",s).append(t.content),a('textarea[name="comment"]',e).val("");var i=a(".chat-body",s);i.animate({scrollTop:i[0].scrollHeight},1e3),a(".badge",'nav a[href="#review-comments.html"]').text(t.count).removeClass("hidden")}},profile:{switchFavorite:function(){var t=a(this),s=t.data("sequence-oid");e.ajax.post("switch-user-favorite.json",{oid:s},function(a,e){a.favorite?t.removeClass("fa-star-o").addClass("fa-star"):t.removeClass("fa-star").addClass("fa-star-o")})}}};a(".badge",'nav a[href="#review-comments.html"]').exists()&&(s.review.timer=setInterval(s.review.updateComments,s.review.timer_duration.general)),t.PyAMS_content=s}(jQuery,this);