--- a/src/pyams_file/zmi/image.py Mon Sep 11 13:28:59 2017 +0200
+++ b/src/pyams_file/zmi/image.py Mon Sep 11 13:30:46 2017 +0200
@@ -14,9 +14,13 @@
# import standard library
+import random
+import sys
+from collections import OrderedDict
# import interfaces
-from pyams_file.interfaces import IImage, IThumbnail, IResponsiveImage, IImageWidget, IFileModifierForm
+from pyams_file.interfaces import IImage, IThumbnail, IResponsiveImage, IImageWidget, IFileModifierForm, IThumbnailer, \
+ IFileInfo, IThumbnailForm
from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager, IFormHelp
from pyams_skin.interfaces.viewlet import IContextActions
from pyams_skin.layer import IPyAMSLayer
@@ -26,12 +30,14 @@
# import packages
from pyams_file.image import ThumbnailGeometry
from pyams_file.zmi import FileModifierAction
-from pyams_form.form import AJAXEditForm
+from pyams_form.form import AJAXEditForm, DialogDisplayForm
from pyams_form.help import FormHelp
from pyams_form.schema import CloseButton
from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.viewlet.toolbar import ToolbarActionItem
from pyams_template.template import template_config
from pyams_utils.adapter import adapter_config
+from pyams_utils.url import absolute_url
from pyams_viewlet.viewlet import viewlet_config, Viewlet
from pyams_zmi.form import AdminDialogEditForm
from pyramid.view import view_config
@@ -44,11 +50,494 @@
#
+# Image crop
+#
+
+@viewlet_config(name='image.crop.action', context=IImage, layer=IPyAMSLayer, view=IImageWidget,
+ manager=IContextActions, weight=21)
+class ImageCropAction(FileModifierAction):
+ """Image crop action"""
+
+ label = _("Crop image...")
+ label_css_class = 'fa fa-fw-md fa-crop'
+
+ url = 'crop.html'
+ modal_target = True
+
+
+class ICropFormButtons(Interface):
+ """Image crop form buttons"""
+
+ close = CloseButton(name='close', title=_("Close"))
+ crop = button.Button(name='crop', title=_("Crop"))
+
+
+@pagelet_config(name='crop.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
+@implementer(IFileModifierForm)
+class ImageCropForm(AdminDialogEditForm):
+ """Image crop form"""
+
+ legend = _("Crop image")
+ icon_css_class = 'fa fa-fw fa-crop'
+ dialog_class = 'modal-large'
+
+ fields = field.Fields(Interface)
+ buttons = button.Buttons(ICropFormButtons)
+ ajax_handler = 'crop.json'
+ edit_permission = None
+
+ @property
+ def title(self):
+ return self.context.title or self.context.filename
+
+ def updateActions(self):
+ super(ImageCropForm, self).updateActions()
+ if 'crop' in self.actions:
+ self.actions['crop'].addClass('btn-primary')
+
+
+@view_config(name='crop.json', context=IImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ImageCropAJAXForm(AJAXEditForm, ImageCropForm):
+ """Image crop form, AJAX renderer"""
+
+ def update_content(self, content, data):
+ image_size = self.context.get_image_size()
+ x1 = int(self.request.params.get('selection.x1', 0))
+ y1 = int(self.request.params.get('selection.y1', 0))
+ x2 = int(self.request.params.get('selection.x2', image_size[0]))
+ y2 = int(self.request.params.get('selection.y2', image_size[1]))
+ self.context.crop(x1, y1, x2, y2)
+
+ def get_ajax_output(self, changes):
+ return {'status': 'reload',
+ 'smallbox': self.request.localizer.translate(self.successMessage),
+ 'smallbox_status': 'success'}
+
+
+@viewlet_config(name='crop.widgets-prefix', context=IImage, layer=IAdminLayer, view=ImageCropForm,
+ manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/image-crop.pt')
+class ImageCropViewletsPrefix(Viewlet):
+ """Image crop viewlets prefix"""
+
+
+@adapter_config(context=(IImage, IAdminLayer, ImageCropForm), provides=IFormHelp)
+class ImageCropFormHelpAdapter(FormHelp):
+ """Image crop form help adapter"""
+
+ message = _("""You can use this form to crop an image.
+
+**WARNING**: cropping an image will reset all selected thumbnails and adaptive images!!""")
+ message_format = 'rest'
+
+
+#
+# Image square thumbnail selection
+#
+
+@adapter_config(context=(IImage, IAdminLayer, IThumbnailForm), provides=IFormHelp)
+class ThumbnailFormHelpAdapter(FormHelp):
+ """Thumbnail form help adapter"""
+
+ message = _("""You can use this form to make a selection on an image.""")
+ message_format = 'rest'
+
+
+class IThumbnailFormButtons(Interface):
+ """Image crop form buttons"""
+
+ close = CloseButton(name='close', title=_("Close"))
+ crop = button.Button(name='crop', title=_("Select thumbnail"))
+
+
+@viewlet_config(name='image.thumb.square.action', context=IImage, layer=IPyAMSLayer, view=IImageWidget,
+ manager=IContextActions, weight=60)
+class ImageSquareThumbnailAction(FileModifierAction):
+ """Square thumbnail image selection"""
+
+ _label = _("Select square thumbnail...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++square:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-instagram'
+
+ url = 'square-thumbnail.html'
+ modal_target = True
+
+
+@pagelet_config(name='square-thumbnail.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
+@implementer(IThumbnailForm)
+class ImageSquareThumbnailEditForm(AdminDialogEditForm):
+ """Image square thumbnail edit form"""
+
+ legend = _("Select square thumbnail")
+ icon_css_class = 'fa fa-fw fa-instagram'
+ dialog_class = 'modal-large'
+
+ fields = field.Fields(Interface)
+ buttons = button.Buttons(IThumbnailFormButtons)
+ ajax_handler = 'square-thumbnail.json'
+ edit_permission = None
+
+ @property
+ def title(self):
+ return self.context.title or self.context.filename
+
+ def updateActions(self):
+ super(ImageSquareThumbnailEditForm, self).updateActions()
+ if 'crop' in self.actions:
+ self.actions['crop'].addClass('btn-primary')
+
+
+@view_config(name='square-thumbnail.json', context=IImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ImageSquareThumbnailAJAXEditForm(AJAXEditForm, ImageSquareThumbnailEditForm):
+ """Image square thumbnail edit form, AJAX renderer"""
+
+ def update_content(self, content, data):
+ geometry = ThumbnailGeometry()
+ geometry.x1 = int(self.request.params.get('selection.x1'))
+ geometry.y1 = int(self.request.params.get('selection.y1'))
+ geometry.x2 = int(self.request.params.get('selection.x2'))
+ geometry.y2 = int(self.request.params.get('selection.y2'))
+ IThumbnail(self.context).set_geometry('square', geometry)
+
+ def get_ajax_output(self, changes):
+ return {'status': 'success',
+ 'smallbox': self.request.localizer.translate(self.successMessage),
+ 'smallbox_status': 'success'}
+
+
+@viewlet_config(name='square-thumbnail.widgets-prefix', context=IImage, layer=IAdminLayer,
+ view=ImageSquareThumbnailEditForm, manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/image-square-thumbnail.pt')
+class ImageSquareThumbnailViewletsPrefix(Viewlet):
+ """Image square thumbnail viewlets prefix"""
+
+
+@adapter_config(context=(IImage, IAdminLayer, ImageSquareThumbnailEditForm), provides=IFormHelp)
+class ImageSquareThumbnailEditFormHelpAdapter(FormHelp):
+ """Square image thumbnail edit form help adapter"""
+
+ message = _("""You can use this form to select a square thumbnail of this image.
+
+**WARNING**: cropping or resizing an image will reset all selected thumbnails and adaptive images!!""")
+ message_format = 'rest'
+
+
+#
+# Image panoramic thumbnail selection
+#
+
+@viewlet_config(name='image.thumb.pano.action', context=IImage, layer=IAdminLayer, view=IImageWidget,
+ manager=IContextActions, weight=65)
+class ImagePanoThumbnailAction(FileModifierAction):
+ """Panoramic thumbnail image selection"""
+
+ _label = _("Select panoramic thumbnail...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++pano:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-youtube-play'
+
+ url = 'pano-thumbnail.html'
+ modal_target = True
+
+
+@pagelet_config(name='pano-thumbnail.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
+@implementer(IThumbnailForm)
+class ImagePanoThumbnailEditForm(AdminDialogEditForm):
+ """Image panoramic thumbnail edit form"""
+
+ legend = _("Select panoramic thumbnail")
+ icon_css_class = 'fa fa-fw fa-youtube-play'
+ dialog_class = 'modal-large'
+
+ fields = field.Fields(Interface)
+ buttons = button.Buttons(IThumbnailFormButtons)
+ ajax_handler = 'pano-thumbnail.json'
+ edit_permission = None
+
+ @property
+ def title(self):
+ return self.context.title or self.context.filename
+
+ def updateActions(self):
+ super(ImagePanoThumbnailEditForm, self).updateActions()
+ if 'crop' in self.actions:
+ self.actions['crop'].addClass('btn-primary')
+
+
+@view_config(name='pano-thumbnail.json', context=IImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ImagePanoThumbnailAJAXEditForm(AJAXEditForm, ImagePanoThumbnailEditForm):
+ """Image panoramic thumbnail edit form, AJAX renderer"""
+
+ def update_content(self, content, data):
+ geometry = ThumbnailGeometry()
+ geometry.x1 = int(self.request.params.get('selection.x1'))
+ geometry.y1 = int(self.request.params.get('selection.y1'))
+ geometry.x2 = int(self.request.params.get('selection.x2'))
+ geometry.y2 = int(self.request.params.get('selection.y2'))
+ IThumbnail(self.context).set_geometry('pano', geometry)
+
+ def get_ajax_output(self, changes):
+ return {'status': 'success',
+ 'smallbox': self.request.localizer.translate(self.successMessage),
+ 'smallbox_status': 'success'}
+
+
+@viewlet_config(name='pano-thumbnail.widgets-prefix', context=IImage, layer=IAdminLayer,
+ view=ImagePanoThumbnailEditForm, manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/image-pano-thumbnail.pt')
+class ImagePanoThumbnailViewletsPrefix(Viewlet):
+ """Image panoramic thumbnail viewlets prefix"""
+
+
+@adapter_config(context=(IImage, IAdminLayer, ImagePanoThumbnailEditForm), provides=IFormHelp)
+class ImagePanoThumbnailEditFormHelpAdapter(FormHelp):
+ """Panoramic image thumbnail edit form help adapter"""
+
+ message = _("""You can use this form to select a panoramic thumbnail of this image.
+
+**WARNING**: cropping or resizing an image will reset all selected thumbnails and adaptive images!!""")
+ message_format = 'rest'
+
+
+#
+# Image responsive selections
+#
+
+class IResponsiveImageSelectionFormButtons(Interface):
+ """Responsive image selection form buttons"""
+
+ close = CloseButton(name='close', title=_("Close"))
+ select = button.Button(name='select', title=_("Select thumbnail"))
+
+
+@implementer(IThumbnailForm)
+class ResponsiveImageSelectionForm(AdminDialogEditForm):
+ """Base responsive image selection edit form"""
+
+ dialog_class = 'modal-large'
+
+ fields = field.Fields(Interface)
+ buttons = button.Buttons(IResponsiveImageSelectionFormButtons)
+ edit_permission = None
+
+ @property
+ def title(self):
+ return self.context.title or self.context.filename
+
+ def updateActions(self):
+ super(ResponsiveImageSelectionForm, self).updateActions()
+ if 'select' in self.actions:
+ self.actions['select'].addClass('btn-primary')
+
+
+class ResponsiveImageSelectionAJAXForm(AJAXEditForm):
+ """Base responsive image selection edit form, JSON renderer"""
+
+ def update_content(self, content, data):
+ geometry = ThumbnailGeometry()
+ geometry.x1 = int(self.request.params.get('selection.x1'))
+ geometry.y1 = int(self.request.params.get('selection.y1'))
+ geometry.x2 = int(self.request.params.get('selection.x2'))
+ geometry.y2 = int(self.request.params.get('selection.y2'))
+ IThumbnail(self.context).set_geometry(self.selection_size, geometry)
+
+ def get_ajax_output(self, changes):
+ return {'status': 'success',
+ 'smallbox': self.request.localizer.translate(self.successMessage),
+ 'smallbox_status': 'success'}
+
+
+@viewlet_config(name='responsive-image.selection.widgets-prefix', context=IResponsiveImage, layer=IAdminLayer,
+ view=ResponsiveImageSelectionForm, manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/image-selection.pt')
+class ResponsiveImageSelectionViewletsPrefix(Viewlet):
+ """Responsive image selection viewlets prefix"""
+
+
+#
+# Extra-small devices selection
+#
+
+@viewlet_config(name='responsive-image.selection.xs.action', context=IResponsiveImage, layer=IAdminLayer,
+ view=IImageWidget, manager=IContextActions, weight=41)
+class ResponsiveImageXsSelectionAction(FileModifierAction):
+ """Responsive image XS selection"""
+
+ _label = _("Select responsive XS image...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++xs:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-mobile'
+
+ url = 'selection-xs.html'
+ modal_target = True
+
+
+@pagelet_config(name='selection-xs.html', context=IResponsiveImage, layer=IPyAMSLayer,
+ permission=VIEW_PERMISSION)
+class ResponsiveImageXsSelectionForm(ResponsiveImageSelectionForm):
+ """Responsive image XS selection edit form"""
+
+ legend = _("Select image for extra-small (XS) devices")
+ icon_css_class = 'fa fa-fw fa-mobile'
+
+ selection_size = 'xs'
+ ajax_handler = 'selection-xs.json'
+
+
+@view_config(name='selection-xs.json', context=IResponsiveImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ResponsiveImageXsSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageXsSelectionForm):
+ """Responsive image XS selection edit form, JSON renderer"""
+
+
+#
+# Small devices selection
+#
+
+@viewlet_config(name='responsive-image.selection.sm.action', context=IResponsiveImage, layer=IAdminLayer,
+ view=IImageWidget, manager=IContextActions, weight=42)
+class ResponsiveImageSmSelectionAction(FileModifierAction):
+ """Responsive image SM selection"""
+
+ _label = _("Select responsive SM image...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++sm:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-tablet'
+
+ url = 'selection-sm.html'
+ modal_target = True
+
+
+@pagelet_config(name='selection-sm.html', context=IResponsiveImage, layer=IPyAMSLayer,
+ permission=VIEW_PERMISSION)
+class ResponsiveImageSmSelectionForm(ResponsiveImageSelectionForm):
+ """Responsive image SM selection edit form"""
+
+ legend = _("Select image for small (SM) devices")
+ icon_css_class = 'fa fa-fw fa-tablet'
+
+ selection_size = 'sm'
+ ajax_handler = 'selection-sm.json'
+
+
+@view_config(name='selection-sm.json', context=IResponsiveImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ResponsiveImageSmSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageSmSelectionForm):
+ """Responsive image SM selection edit form, JSON renderer"""
+
+
+#
+# Medium devices selection
+#
+
+@viewlet_config(name='responsive-image.selection.md.action', context=IResponsiveImage, layer=IAdminLayer,
+ view=IImageWidget, manager=IContextActions, weight=43)
+class ResponsiveImageMdSelectionAction(FileModifierAction):
+ """Responsive image MD selection"""
+
+ _label = _("Select responsive MD image...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++md:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-desktop'
+
+ url = 'selection-md.html'
+ modal_target = True
+
+
+@pagelet_config(name='selection-md.html', context=IResponsiveImage, layer=IPyAMSLayer,
+ permission=VIEW_PERMISSION)
+class ResponsiveImageMdSelectionForm(ResponsiveImageSelectionForm):
+ """Responsive image MD selection edit form"""
+
+ legend = _("Select image for medium (MD) devices")
+ icon_css_class = 'fa fa-fw fa-desktop'
+
+ selection_size = 'md'
+ ajax_handler = 'selection-md.json'
+
+
+@view_config(name='selection-md.json', context=IResponsiveImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ResponsiveImageMdSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageMdSelectionForm):
+ """Responsive image MD selection edit form, JSON renderer"""
+
+
+#
+# Large devices selection
+#
+
+@viewlet_config(name='responsive-image.selection.lg.action', context=IResponsiveImage, layer=IAdminLayer,
+ view=IImageWidget, manager=IContextActions, weight=44)
+class ResponsiveImageLgSelectionAction(FileModifierAction):
+ """Responsive image LG selection"""
+
+ _label = _("Select responsive LG image...")
+
+ @property
+ def label(self):
+ return '<div>{label}</div><div class="padding-y-5"><img src="{url}/++thumb++lg:200x128.jpeg?_=" ' \
+ '/></div>'.format(label=self.request.localizer.translate(self._label),
+ url=absolute_url(self.context, self.request))
+
+ label_css_class = 'fa fa-fw-md fa-television'
+
+ url = 'selection-lg.html'
+ modal_target = True
+
+
+@pagelet_config(name='selection-lg.html', context=IResponsiveImage, layer=IPyAMSLayer,
+ permission=VIEW_PERMISSION)
+class ResponsiveImageLgSelectionForm(ResponsiveImageSelectionForm):
+ """Responsive image LG selection edit form"""
+
+ legend = _("Select image for large (LG) devices")
+ icon_css_class = 'fa fa-fw fa-television'
+
+ selection_size = 'lg'
+ ajax_handler = 'selection-lg.json'
+
+
+@view_config(name='selection-lg.json', context=IResponsiveImage, request_type=IPyAMSLayer,
+ permission=VIEW_PERMISSION, renderer='json', xhr=True)
+class ResponsiveImageLgSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageLgSelectionForm):
+ """Responsive image LG selection edit form, JSON renderer"""
+
+
+#
# Image resize
#
@viewlet_config(name='image.resize.action', context=IImage, layer=IPyAMSLayer, view=IImageWidget,
- manager=IContextActions, weight=20)
+ manager=IContextActions, weight=80)
class ImageResizeAction(FileModifierAction):
"""Image resize action"""
@@ -146,413 +635,55 @@
#
-# Image crop
+# See all thumbnails!!
#
-@viewlet_config(name='image.crop.action', context=IImage, layer=IPyAMSLayer, view=IImageWidget,
- manager=IContextActions, weight=21)
-class ImageCropAction(FileModifierAction):
- """Image crop action"""
+@viewlet_config(name='display-all-thumbnails.action', context=IImage, layer=IAdminLayer,
+ view=IImageWidget, manager=IContextActions, weight=90)
+class ImageThumbnailsDisplayAction(ToolbarActionItem):
+ """Image thumbnails display action"""
- label = _("Crop image...")
- label_css_class = 'fa fa-fw-md fa-crop'
+ label = _("Display all thumbnails")
+ label_css_class = 'fa fa-fw fa-th-large text-primary'
+ hint_gravity = 'nw'
- url = 'crop.html'
+ url = 'display-all-thumbnails.html'
modal_target = True
-class ICropFormButtons(Interface):
- """Image crop form buttons"""
-
- close = CloseButton(name='close', title=_("Close"))
- crop = button.Button(name='crop', title=_("Crop"))
-
-
-@pagelet_config(name='crop.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
-@implementer(IFileModifierForm)
-class ImageCropForm(AdminDialogEditForm):
- """Image crop form"""
-
- legend = _("Crop image")
- icon_css_class = 'fa fa-fw fa-crop'
- dialog_class = 'modal-large'
-
- fields = field.Fields(Interface)
- buttons = button.Buttons(ICropFormButtons)
- ajax_handler = 'crop.json'
- edit_permission = None
-
- @property
- def title(self):
- return self.context.title or self.context.filename
-
- def updateActions(self):
- super(ImageCropForm, self).updateActions()
- if 'crop' in self.actions:
- self.actions['crop'].addClass('btn-primary')
-
-
-@view_config(name='crop.json', context=IImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ImageCropAJAXForm(AJAXEditForm, ImageCropForm):
- """Image crop form, AJAX renderer"""
-
- def update_content(self, content, data):
- image_size = self.context.get_image_size()
- x1 = int(self.request.params.get('selection.x1', 0))
- y1 = int(self.request.params.get('selection.y1', 0))
- x2 = int(self.request.params.get('selection.x2', image_size[0]))
- y2 = int(self.request.params.get('selection.y2', image_size[1]))
- self.context.crop(x1, y1, x2, y2)
-
- def get_ajax_output(self, changes):
- return {'status': 'reload',
- 'smallbox': self.request.localizer.translate(self.successMessage),
- 'smallbox_status': 'success'}
-
-
-@viewlet_config(name='crop.widgets-prefix', context=IImage, layer=IAdminLayer, view=ImageCropForm,
- manager=IWidgetsPrefixViewletsManager)
-@template_config(template='templates/image-crop.pt')
-class ImageCropViewletsPrefix(Viewlet):
- """Image crop viewlets prefix"""
-
-
-@adapter_config(context=(IImage, IAdminLayer, ImageCropForm), provides=IFormHelp)
-class ImageCropFormHelpAdapter(FormHelp):
- """Image crop form help adapter"""
-
- message = _("""You can use this form to crop an image.
-
-**WARNING**: cropping an image will reset all selected thumbnails and adaptive images!!""")
- message_format = 'rest'
-
-
-#
-# Image square thumbnail selection
-#
-
-class IThumbnailFormButtons(Interface):
- """Image crop form buttons"""
-
- close = CloseButton(name='close', title=_("Close"))
- crop = button.Button(name='crop', title=_("Select thumbnail"))
-
-
-@viewlet_config(name='image.thumb.square.action', context=IImage, layer=IPyAMSLayer, view=IImageWidget,
- manager=IContextActions, weight=31)
-class ImageSquareThumbnailAction(FileModifierAction):
- """Square thumbnail image selection"""
-
- label = _("Select square thumbnail...")
- label_css_class = 'fa fa-fw-md fa-instagram'
-
- url = 'square-thumbnail.html'
- modal_target = True
-
-
-@pagelet_config(name='square-thumbnail.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
-@implementer(IFileModifierForm)
-class ImageSquareThumbnailEditForm(AdminDialogEditForm):
- """Image square thumbnail edit form"""
-
- legend = _("Select square thumbnail")
- icon_css_class = 'fa fa-fw fa-instagram'
- dialog_class = 'modal-large'
-
- fields = field.Fields(Interface)
- buttons = button.Buttons(IThumbnailFormButtons)
- ajax_handler = 'square-thumbnail.json'
- edit_permission = None
-
- @property
- def title(self):
- return self.context.title or self.context.filename
-
- def updateActions(self):
- super(ImageSquareThumbnailEditForm, self).updateActions()
- if 'crop' in self.actions:
- self.actions['crop'].addClass('btn-primary')
-
-
-@view_config(name='square-thumbnail.json', context=IImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ImageSquareThumbnailAJAXEditForm(AJAXEditForm, ImageSquareThumbnailEditForm):
- """Image square thumbnail edit form, AJAX renderer"""
-
- def update_content(self, content, data):
- geometry = ThumbnailGeometry()
- geometry.x1 = int(self.request.params.get('selection.x1'))
- geometry.y1 = int(self.request.params.get('selection.y1'))
- geometry.x2 = int(self.request.params.get('selection.x2'))
- geometry.y2 = int(self.request.params.get('selection.y2'))
- IThumbnail(self.context).set_geometry('square', geometry)
-
- def get_ajax_output(self, changes):
- return {'status': 'success',
- 'smallbox': self.request.localizer.translate(self.successMessage),
- 'smallbox_status': 'success'}
-
-
-@viewlet_config(name='square-thumbnail.widgets-prefix', context=IImage, layer=IAdminLayer,
- view=ImageSquareThumbnailEditForm, manager=IWidgetsPrefixViewletsManager)
-@template_config(template='templates/image-square-thumbnail.pt')
-class ImageSquareThumbnailViewletsPrefix(Viewlet):
- """Image square thumbnail viewlets prefix"""
-
-
-#
-# Image panoramic thumbnail selection
-#
-
-@viewlet_config(name='image.thumb.pano.action', context=IImage, layer=IAdminLayer, view=IImageWidget,
- manager=IContextActions, weight=32)
-class ImagePanoThumbnailAction(FileModifierAction):
- """Panoramic thumbnail image selection"""
-
- label = _("Select panoramic thumbnail...")
- label_css_class = 'fa fa-fw-md fa-youtube-play'
-
- url = 'pano-thumbnail.html'
- modal_target = True
-
-
-@pagelet_config(name='pano-thumbnail.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
-@implementer(IFileModifierForm)
-class ImagePanoThumbnailEditForm(AdminDialogEditForm):
- """Image panoramic thumbnail edit form"""
-
- legend = _("Select panoramic thumbnail")
- icon_css_class = 'fa fa-fw fa-youtube-play'
- dialog_class = 'modal-large'
-
- fields = field.Fields(Interface)
- buttons = button.Buttons(IThumbnailFormButtons)
- ajax_handler = 'pano-thumbnail.json'
- edit_permission = None
+@pagelet_config(name='display-all-thumbnails.html', context=IImage, layer=IPyAMSLayer, permission=VIEW_PERMISSION)
+class ImageThumbnailsDisplayForm(DialogDisplayForm):
+ """Image thumbnails display form"""
@property
def title(self):
- return self.context.title or self.context.filename
-
- def updateActions(self):
- super(ImagePanoThumbnailEditForm, self).updateActions()
- if 'crop' in self.actions:
- self.actions['crop'].addClass('btn-primary')
-
-
-@view_config(name='pano-thumbnail.json', context=IImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ImagePanoThumbnailAJAXEditForm(AJAXEditForm, ImagePanoThumbnailEditForm):
- """Image panoramic thumbnail edit form, AJAX renderer"""
-
- def update_content(self, content, data):
- geometry = ThumbnailGeometry()
- geometry.x1 = int(self.request.params.get('selection.x1'))
- geometry.y1 = int(self.request.params.get('selection.y1'))
- geometry.x2 = int(self.request.params.get('selection.x2'))
- geometry.y2 = int(self.request.params.get('selection.y2'))
- IThumbnail(self.context).set_geometry('pano', geometry)
+ info = IFileInfo(self.context)
+ return info.title or info.filename
- def get_ajax_output(self, changes):
- return {'status': 'success',
- 'smallbox': self.request.localizer.translate(self.successMessage),
- 'smallbox_status': 'success'}
-
-
-@viewlet_config(name='pano-thumbnail.widgets-prefix', context=IImage, layer=IAdminLayer,
- view=ImagePanoThumbnailEditForm, manager=IWidgetsPrefixViewletsManager)
-@template_config(template='templates/image-pano-thumbnail.pt')
-class ImagePanoThumbnailViewletsPrefix(Viewlet):
- """Image panoramic thumbnail viewlets prefix"""
-
-
-#
-# Image responsive selections
-#
-
-class IResponsiveImageSelectionFormButtons(Interface):
- """Responsive image selection form buttons"""
-
- close = CloseButton(name='close', title=_("Close"))
- select = button.Button(name='select', title=_("Select image"))
-
-
-@implementer(IFileModifierForm)
-class ResponsiveImageSelectionForm(AdminDialogEditForm):
- """Base responsive image selection edit form"""
-
+ legend = _("Display all image thumbnails")
+ icon_css_class = 'fa fa-fw fa-th-large'
dialog_class = 'modal-large'
fields = field.Fields(Interface)
- buttons = button.Buttons(IResponsiveImageSelectionFormButtons)
- edit_permission = None
-
- @property
- def title(self):
- return self.context.title or self.context.filename
-
- def updateActions(self):
- super(ResponsiveImageSelectionForm, self).updateActions()
- if 'select' in self.actions:
- self.actions['select'].addClass('btn-primary')
-
-
-class ResponsiveImageSelectionAJAXForm(AJAXEditForm):
- """Base responsive image selection edit form, JSON renderer"""
-
- def update_content(self, content, data):
- geometry = ThumbnailGeometry()
- geometry.x1 = int(self.request.params.get('selection.x1'))
- geometry.y1 = int(self.request.params.get('selection.y1'))
- geometry.x2 = int(self.request.params.get('selection.x2'))
- geometry.y2 = int(self.request.params.get('selection.y2'))
- IThumbnail(self.context).set_geometry(self.selection_size, geometry)
-
- def get_ajax_output(self, changes):
- return {'status': 'success',
- 'smallbox': self.request.localizer.translate(self.successMessage),
- 'smallbox_status': 'success'}
-
-
-@viewlet_config(name='responsive-image.selection.widgets-prefix', context=IResponsiveImage, layer=IAdminLayer,
- view=ResponsiveImageSelectionForm, manager=IWidgetsPrefixViewletsManager)
-@template_config(template='templates/image-selection.pt')
-class ResponsiveImageSelectionViewletsPrefix(Viewlet):
- """Responsive image selection viewlets prefix"""
-
-
-#
-# Extra-small devices selection
-#
-
-@viewlet_config(name='responsive-image.selection.xs.action', context=IResponsiveImage, layer=IAdminLayer,
- view=IImageWidget, manager=IContextActions, weight=41)
-class ResponsiveImageXsSelectionAction(FileModifierAction):
- """Responsive image XS selection"""
-
- label = _("Select responsive XS image...")
- label_css_class = 'fa fa-fw-md fa-mobile'
-
- url = 'selection-xs.html'
- modal_target = True
-
-
-@pagelet_config(name='selection-xs.html', context=IResponsiveImage, layer=IPyAMSLayer,
- permission=VIEW_PERMISSION)
-class ResponsiveImageXsSelectionForm(ResponsiveImageSelectionForm):
- """Responsive image XS selection edit form"""
-
- legend = _("Select image for extra-small (XS) devices")
- icon_css_class = 'fa fa-fw fa-mobile'
-
- selection_size = 'xs'
- ajax_handler = 'selection-xs.json'
-
-
-@view_config(name='selection-xs.json', context=IResponsiveImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ResponsiveImageXsSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageXsSelectionForm):
- """Responsive image XS selection edit form, JSON renderer"""
-#
-# Small devices selection
-#
-
-@viewlet_config(name='responsive-image.selection.sm.action', context=IResponsiveImage, layer=IAdminLayer,
- view=IImageWidget, manager=IContextActions, weight=42)
-class ResponsiveImageSmSelectionAction(FileModifierAction):
- """Responsive image SM selection"""
-
- label = _("Select responsive SM image...")
- label_css_class = 'fa fa-fw-md fa-tablet'
-
- url = 'selection-sm.html'
- modal_target = True
-
-
-@pagelet_config(name='selection-sm.html', context=IResponsiveImage, layer=IPyAMSLayer,
- permission=VIEW_PERMISSION)
-class ResponsiveImageSmSelectionForm(ResponsiveImageSelectionForm):
- """Responsive image SM selection edit form"""
-
- legend = _("Select image for small (SM) devices")
- icon_css_class = 'fa fa-fw fa-tablet'
+@viewlet_config(name='image-thumbnails', context=IImage, layer=IPyAMSLayer,
+ view=ImageThumbnailsDisplayForm, manager=IWidgetsPrefixViewletsManager)
+@template_config(template='templates/image-thumbnails.pt')
+class ImageThumbnailsViewletsPrefix(Viewlet):
+ """Image thumbnails viewlets prefix"""
- selection_size = 'sm'
- ajax_handler = 'selection-sm.json'
-
-
-@view_config(name='selection-sm.json', context=IResponsiveImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ResponsiveImageSmSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageSmSelectionForm):
- """Responsive image SM selection edit form, JSON renderer"""
-
-
-#
-# Medium devices selection
-#
-
-@viewlet_config(name='responsive-image.selection.md.action', context=IResponsiveImage, layer=IAdminLayer,
- view=IImageWidget, manager=IContextActions, weight=43)
-class ResponsiveImageMdSelectionAction(FileModifierAction):
- """Responsive image MD selection"""
-
- label = _("Select responsive MD image...")
- label_css_class = 'fa fa-fw-md fa-desktop'
-
- url = 'selection-md.html'
- modal_target = True
-
+ @property
+ def random(self):
+ return random.randint(0, sys.maxsize)
-@pagelet_config(name='selection-md.html', context=IResponsiveImage, layer=IPyAMSLayer,
- permission=VIEW_PERMISSION)
-class ResponsiveImageMdSelectionForm(ResponsiveImageSelectionForm):
- """Responsive image MD selection edit form"""
-
- legend = _("Select image for medium (MD) devices")
- icon_css_class = 'fa fa-fw fa-desktop'
-
- selection_size = 'md'
- ajax_handler = 'selection-md.json'
-
-
-@view_config(name='selection-md.json', context=IResponsiveImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ResponsiveImageMdSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageMdSelectionForm):
- """Responsive image MD selection edit form, JSON renderer"""
-
-
-#
-# Large devices selection
-#
-
-@viewlet_config(name='responsive-image.selection.lg.action', context=IResponsiveImage, layer=IAdminLayer,
- view=IImageWidget, manager=IContextActions, weight=44)
-class ResponsiveImageLgSelectionAction(FileModifierAction):
- """Responsive image LG selection"""
-
- label = _("Select responsive LG image...")
- label_css_class = 'fa fa-fw-md fa-television'
-
- url = 'selection-lg.html'
- modal_target = True
-
-
-@pagelet_config(name='selection-lg.html', context=IResponsiveImage, layer=IPyAMSLayer,
- permission=VIEW_PERMISSION)
-class ResponsiveImageLgSelectionForm(ResponsiveImageSelectionForm):
- """Responsive image LG selection edit form"""
-
- legend = _("Select image for large (LG) devices")
- icon_css_class = 'fa fa-fw fa-television'
-
- selection_size = 'lg'
- ajax_handler = 'selection-lg.json'
-
-
-@view_config(name='selection-lg.json', context=IResponsiveImage, request_type=IPyAMSLayer,
- permission=VIEW_PERMISSION, renderer='json', xhr=True)
-class ResponsiveImageLgSelectionAJAXEditForm(ResponsiveImageSelectionAJAXForm, ResponsiveImageLgSelectionForm):
- """Responsive image LG selection edit form, JSON renderer"""
+ def get_thumbnails(self):
+ registry = self.request.registry
+ translate = self.request.localizer.translate
+ thumbnailers = OrderedDict()
+ adapters = sorted(registry.getAdapters((self.context, ), IThumbnailer),
+ key=lambda x: x[1].weight)
+ for name, adapter in adapters:
+ thumbnailers.setdefault(translate(adapter.section), []).append({'name': name,
+ 'label': translate(adapter.label)})
+ return thumbnailers