diff --git a/core/src/zeit/content/article/edit/browser/configure.zcml b/core/src/zeit/content/article/edit/browser/configure.zcml index f3125cf720..2b3c7c163c 100644 --- a/core/src/zeit/content/article/edit/browser/configure.zcml +++ b/core/src/zeit/content/article/edit/browser/configure.zcml @@ -827,4 +827,47 @@ permission="zope.View" /> + + + + + + + + + + + + + + + diff --git a/core/src/zeit/content/article/edit/browser/edit.py b/core/src/zeit/content/article/edit/browser/edit.py index c98746df03..62ec5dfd08 100644 --- a/core/src/zeit/content/article/edit/browser/edit.py +++ b/core/src/zeit/content/article/edit/browser/edit.py @@ -575,3 +575,45 @@ class EditAnimation(zeit.cms.browser.manual.FormMixin, zeit.edit.browser.form.In @property def prefix(self): return 'animation.{0}'.format(self.context.__name__) + + +class EditImageRow(zeit.edit.browser.form.InlineForm): + legend = '' + form_fields = zope.formlib.form.FormFields(zeit.content.article.edit.interfaces.IImageRow).omit( + *list(zeit.edit.interfaces.IBlock) + ) + + @property + def prefix(self): + return 'image_row.{0}'.format(self.context.__name__) + + +class EditImageGrid(zeit.edit.browser.form.InlineForm): + legend = '' + omitted_fields_prefix = ['images_', 'display_mode_', 'variant_name_'] + form_fields = zope.formlib.form.FormFields( + zeit.content.article.edit.interfaces.IImageGrid + ).omit(*list(zeit.edit.interfaces.IBlock)) + _old_form_fields = form_fields + + @property + def prefix(self): + return 'image_grid.{0}'.format(self.context.__name__) + + def setUpWidgets(self, *args, **kw): + super().setUpWidgets(*args, **kw) + visible_count = 1 + for i in range(2, 4): # Start from 2 since images_1 is always visible + previous_image_field = f'images_{i - 1}' + + if getattr(self.context, previous_image_field, None): + visible_count = i + + omitted_fields = [ + f'{prefix}{j}' + for prefix in self.omitted_fields_prefix + for j in range(visible_count + 1, 4) + ] + print('Visible: ' + str(visible_count)) + + self.form_fields = self._old_form_fields.omit(*omitted_fields) diff --git a/core/src/zeit/content/article/edit/configure.zcml b/core/src/zeit/content/article/edit/configure.zcml index 53afc662a7..3d159ab4a0 100644 --- a/core/src/zeit/content/article/edit/configure.zcml +++ b/core/src/zeit/content/article/edit/configure.zcml @@ -462,6 +462,28 @@ /> + + + + + + + + + + diff --git a/core/src/zeit/content/article/edit/image_grid.py b/core/src/zeit/content/article/edit/image_grid.py new file mode 100644 index 0000000000..780dc345a0 --- /dev/null +++ b/core/src/zeit/content/article/edit/image_grid.py @@ -0,0 +1,48 @@ +import grokcore.component as grok +import lxml + +from zeit.cms.content.property import ObjectPathAttributeProperty +from zeit.cms.i18n import MessageFactory as _ +import zeit.cms.content.property +import zeit.cms.content.reference +import zeit.content.article.edit.block +import zeit.content.article.edit.interfaces + + +@grok.implementer(zeit.content.article.edit.interfaces.IImageGrid) +class ImageGrid(zeit.content.article.edit.block.Block): + type = 'image_grid' + + def __init__(self, context, xml): + # call base constructor + super(ImageGrid, self).__init__(context, xml) + for i in range(3): + if not self.xml.xpath('//group%s' % (i + 1)): + self.xml.append(lxml.etree.Element('group%s' % (i + 1))) + + show_caption = ObjectPathAttributeProperty( + '.', 'show_caption', zeit.content.article.edit.interfaces.IImageRow['show_caption'] + ) + show_source = ObjectPathAttributeProperty( + '.', 'show_source', zeit.content.article.edit.interfaces.IImageRow['show_source'] + ) + + # Images and display properties for first group + images_1 = zeit.cms.content.reference.MultiResource('.group1.image', 'image') + display_mode_1 = ObjectPathAttributeProperty('.group1', 'display_mode_1') + variant_name_1 = ObjectPathAttributeProperty('.group1', 'variant_name_1') + + # Images and display properties for second group + images_2 = zeit.cms.content.reference.MultiResource('.group2.image', 'image') + display_mode_2 = ObjectPathAttributeProperty('.group2', 'display_mode_2') + variant_name_2 = ObjectPathAttributeProperty('.group2', 'variant_name_2') + + # Images and display properties for third group + images_3 = zeit.cms.content.reference.MultiResource('.group3.image', 'image') + display_mode_3 = ObjectPathAttributeProperty('.group3', 'display_mode_3') + variant_name_3 = ObjectPathAttributeProperty('.group3', 'variant_name_3') + + +class Factory(zeit.content.article.edit.block.BlockFactory): + produces = ImageGrid + title = _('Image Grid') diff --git a/core/src/zeit/content/article/edit/image_row.py b/core/src/zeit/content/article/edit/image_row.py new file mode 100644 index 0000000000..fd5e1b1174 --- /dev/null +++ b/core/src/zeit/content/article/edit/image_row.py @@ -0,0 +1,74 @@ +import grokcore.component as grok +import lxml + +from zeit.cms.content.property import ObjectPathAttributeProperty +from zeit.cms.i18n import MessageFactory as _ +from zeit.content.article.source import LEGACY_DISPLAY_MODE_SOURCE, LEGACY_VARIANT_NAME_SOURCE +import zeit.cms.content.property +import zeit.cms.content.reference +import zeit.content.article.edit.block +import zeit.content.article.edit.interfaces + + +@grok.implementer(zeit.content.article.edit.interfaces.IImageRow) +class ImageRow(zeit.content.article.edit.block.Block): + def __init__(self, context, xml): + # call base constructor + super(ImageRow, self).__init__(context, xml) + # set xml object to default template, if it has no body + if not self.xml.xpath('//body'): + self.xml.append(lxml.etree.Element('body')) + + type = 'image_row' + + show_caption = ObjectPathAttributeProperty( + '.', 'show_caption', zeit.content.article.edit.interfaces.IImageRow['show_caption'] + ) + show_source = ObjectPathAttributeProperty( + '.', 'show_source', zeit.content.article.edit.interfaces.IImageRow['show_source'] + ) + _display_mode = zeit.cms.content.property.ObjectPathAttributeProperty('.', 'display_mode') + _variant_name = zeit.cms.content.property.ObjectPathAttributeProperty('.', 'variant_name') + images = zeit.cms.content.reference.MultiResource('.body.image', 'image') + + @property + def display_mode(self): + if self._display_mode is not None: + return self._display_mode + # backward compatibility by mapping old layout to display_mode + layout = self.xml.get('layout', None) + mapping = dict(list(LEGACY_DISPLAY_MODE_SOURCE(self))) + return mapping.get( + layout, zeit.content.article.edit.interfaces.IImage['display_mode'].default + ) + + @display_mode.setter + def display_mode(self, value): + self._display_mode = value + + @property + def variant_name(self): + if self._variant_name is not None: + return self._variant_name + # backward compatibility by mapping old layout to display_mode + layout = self.xml.get('layout', None) + mapping = dict(list(LEGACY_VARIANT_NAME_SOURCE(self))) + return mapping.get( + layout, zeit.content.article.edit.interfaces.IImage['variant_name'].default + ) + + @variant_name.setter + def variant_name(self, value): + self._variant_name = value + + # first_image = zeit.cms.content.reference.SingleResource('.image[1]', 'image') + # second_image = zeit.cms.content.reference.SingleResource('.image[2]', 'image') + # third_image = zeit.cms.content.reference.SingleResource('.image[3]', 'image') + # first_image = zeit.cms.content.reference.SingleResource('.image-1', 'image') + # second_image = zeit.cms.content.reference.SingleResource('.image-2', 'image') + # third_image = zeit.cms.content.reference.SingleResource('.image-3', 'image') + + +class Factory(zeit.content.article.edit.block.BlockFactory): + produces = ImageRow + title = _('Image Row') diff --git a/core/src/zeit/content/article/edit/interfaces.py b/core/src/zeit/content/article/edit/interfaces.py index 51685733cb..bfc751f0bb 100644 --- a/core/src/zeit/content/article/edit/interfaces.py +++ b/core/src/zeit/content/article/edit/interfaces.py @@ -653,3 +653,93 @@ class IIngredientDice(IBlock): """ pass + + +class IImageRow(IBlock): + show_caption = zope.schema.Bool(title=_('Show caption'), required=False, default=True) + show_source = zope.schema.Bool(title=_('Show source'), required=False, default=True) + images = zope.schema.Tuple( + title=_('Images'), + default=(), + max_length=3, + required=False, + value_type=zope.schema.Choice(source=zeit.content.image.interfaces.ImageGroupSource()), + ) + display_mode = zope.schema.Choice( + title=_('Display Mode'), + source=zeit.content.article.source.IMAGE_DISPLAY_MODE_SOURCE, + default='column-width', + required=False, + ) + # Currently need default for bw compat. + variant_name = zope.schema.Choice( + title=_('Variant Name'), + source=zeit.content.article.source.IMAGE_VARIANT_NAME_SOURCE, + default='wide', + required=False, + ) + + +class IImageGrid(IBlock): + show_caption = zope.schema.Bool(title=_('Show caption'), required=False, default=True) + show_source = zope.schema.Bool(title=_('Show source'), required=False, default=True) + images_1 = zope.schema.Tuple( + title=_('Images'), + default=(), + max_length=3, + required=False, + value_type=zope.schema.Choice(source=zeit.content.image.interfaces.ImageGroupSource()), + ) + display_mode_1 = zope.schema.Choice( + title=_('Display Mode'), + source=zeit.content.article.source.IMAGE_DISPLAY_MODE_SOURCE, + default='column-width', + required=False, + ) + # Currently need default for bw compat. + variant_name_1 = zope.schema.Choice( + title=_('Variant Name'), + source=zeit.content.article.source.IMAGE_VARIANT_NAME_SOURCE, + default='wide', + required=False, + ) + images_2 = zope.schema.Tuple( + title=_('Images'), + default=(), + max_length=3, + required=False, + value_type=zope.schema.Choice(source=zeit.content.image.interfaces.ImageGroupSource()), + ) + display_mode_2 = zope.schema.Choice( + title=_('Display Mode'), + source=zeit.content.article.source.IMAGE_DISPLAY_MODE_SOURCE, + default='column-width', + required=False, + ) + # Currently need default for bw compat. + variant_name_2 = zope.schema.Choice( + title=_('Variant Name'), + source=zeit.content.article.source.IMAGE_VARIANT_NAME_SOURCE, + default='wide', + required=False, + ) + images_3 = zope.schema.Tuple( + title=_('Images'), + default=(), + max_length=3, + required=False, + value_type=zope.schema.Choice(source=zeit.content.image.interfaces.ImageGroupSource()), + ) + display_mode_3 = zope.schema.Choice( + title=_('Display Mode'), + source=zeit.content.article.source.IMAGE_DISPLAY_MODE_SOURCE, + default='column-width', + required=False, + ) + # Currently need default for bw compat. + variant_name_3 = zope.schema.Choice( + title=_('Variant Name'), + source=zeit.content.article.source.IMAGE_VARIANT_NAME_SOURCE, + default='wide', + required=False, + ) diff --git a/core/src/zeit/content/article/edit/tests/modules.xml b/core/src/zeit/content/article/edit/tests/modules.xml index de62ac7594..c3dd0c206d 100644 --- a/core/src/zeit/content/article/edit/tests/modules.xml +++ b/core/src/zeit/content/article/edit/tests/modules.xml @@ -29,4 +29,6 @@ Video Ausgabe ARD Video + Bilderreihe + Bilder-Grid