# HG changeset patch # User Thierry Florac # Date 1518703709 -3600 # Node ID 2a39b333a5857b3fd27a2f62dcf12ea1d88fe052 # Parent 1ebcb03e9bffdc8679a4fd18bf6fe8ffa2baf83b Added generic content renderer feature diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/__init__.py --- a/src/pyams_content/component/gallery/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/gallery/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -16,8 +16,8 @@ # import standard library # import interfaces -from pyams_content.component.gallery.interfaces import IGallery, IGalleryTarget, \ - GALLERY_CONTAINER_KEY, IGalleryRenderer +from pyams_content.component.gallery.interfaces import IBaseGallery, IGallery, IGalleryTarget, \ + GALLERY_CONTAINER_KEY from pyams_content.component.paragraph import IBaseParagraph from pyams_content.features.checker.interfaces import IContentChecker from pyams_content.shared.common.interfaces import IWfSharedContent @@ -31,18 +31,16 @@ # import packages from pyams_catalog.utils import index_object from pyams_content.features.checker import BaseContentChecker +from pyams_content.features.renderer import RenderedContentMixin from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.container import BTreeOrderedContainer -from pyams_utils.request import check_request from pyams_utils.traversing import get_parent -from pyams_utils.vocabulary import vocabulary_config from pyramid.events import subscriber from pyramid.threadlocal import get_current_registry from zope.interface import implementer from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent from zope.location import locate from zope.schema.fieldproperty import FieldProperty -from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from pyams_content import _ @@ -52,7 +50,7 @@ # @implementer(IGallery) -class Gallery(BTreeOrderedContainer): +class Gallery(BTreeOrderedContainer, RenderedContentMixin): """Gallery persistent class""" title = FieldProperty(IGallery['title']) @@ -179,18 +177,3 @@ def GalleryTargetContentChecker(context): gallery = IGallery(context) return IContentChecker(gallery, None) - - -@vocabulary_config(name='PyAMS gallery renderers') -class GalleryRendererVocabulary(SimpleVocabulary): - """Gallery renderer utilities vocabulary""" - - def __init__(self, context=None): - request = check_request() - translate = request.localizer.translate - registry = request.registry - context = Gallery() - terms = [SimpleTerm(name, title=translate(adapter.label)) - for name, adapter in sorted(registry.getAdapters((context, request), IGalleryRenderer), - key=lambda x: x[1].weight)] - super(GalleryRendererVocabulary, self).__init__(terms) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/interfaces/__init__.py --- a/src/pyams_content/component/gallery/interfaces/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/gallery/interfaces/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -17,15 +17,15 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IBaseParagraph +from pyams_content.features.renderer.interfaces import IRenderedContent from zope.container.interfaces import IOrderedContainer -from zope.contentprovider.interfaces import IContentProvider # import packages from pyams_file.schema import MediaField, AudioField from pyams_i18n.schema import I18nTextLineField, I18nTextField from zope.annotation.interfaces import IAttributeAnnotatable from zope.container.constraints import contains, containers -from zope.interface import Interface, Attribute +from zope.interface import Interface from zope.schema import Bool, TextLine, Choice from pyams_content import _ @@ -34,11 +34,15 @@ GALLERY_CONTAINER_KEY = 'pyams_content.gallery' -class IGalleryFile(Interface): - """Gallery file marker interface""" +class IGalleryItem(Interface): + """Gallery item base interface""" containers('.IGallery') + +class IGalleryFile(IGalleryItem): + """Gallery file marker interface""" + title = I18nTextLineField(title=_("Legend"), required=False) @@ -83,7 +87,7 @@ default=True) -class IBaseGallery(IOrderedContainer, IAttributeAnnotatable): +class IBaseGallery(IOrderedContainer, IAttributeAnnotatable, IRenderedContent): """Base gallery interface""" title = I18nTextLineField(title=_("Title"), @@ -113,13 +117,7 @@ class IGallery(IBaseGallery): """Gallery interface""" - contains(IGalleryFile) - - -class IGalleryRenderer(IContentProvider): - """Gallery renderer utility interface""" - - label = Attribute("Renderer label") + contains(IGalleryItem) class IGalleryTarget(IAttributeAnnotatable): diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/renderer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/gallery/renderer.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,42 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.gallery.interfaces import IBaseGallery +from pyams_content.features.renderer.interfaces import IContentRenderer + +# import packages +from pyams_content.component.gallery import Gallery +from pyams_utils.request import check_request +from pyams_utils.vocabulary import vocabulary_config +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm + + +@vocabulary_config(name='PyAMS gallery renderers') +class GalleryRendererVocabulary(SimpleVocabulary): + """Gallery renderer utilities vocabulary""" + + def __init__(self, context=None): + request = check_request() + translate = request.localizer.translate + registry = request.registry + if not IBaseGallery.providedBy(context): + context = Gallery() + terms = [SimpleTerm(name, title=translate(adapter.label)) + for name, adapter in sorted(registry.getAdapters((context, request), IContentRenderer), + key=lambda x: x[1].weight)] + super(GalleryRendererVocabulary, self).__init__(terms) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/zmi/__init__.py --- a/src/pyams_content/component/gallery/zmi/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/gallery/zmi/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -20,8 +20,9 @@ from io import BytesIO # import interfaces -from pyams_content.component.gallery.interfaces import IGallery, IGalleryRenderer +from pyams_content.component.gallery.interfaces import IGallery from pyams_content.component.gallery.zmi.interfaces import IGalleryMediasAddFields, IGalleryContentsView +from pyams_content.features.renderer.interfaces import IContentRenderer from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION from pyams_file.interfaces import IFileInfo from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager @@ -32,10 +33,12 @@ # import packages from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin +from pyams_content.features.renderer.zmi import BaseContentRenderer +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_form.form import AJAXEditForm from pyams_pagelet.pagelet import pagelet_config -from pyams_template.template import template_config, get_view_template -from pyams_utils.adapter import adapter_config, ContextRequestAdapter +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, AdminDialogDisplayForm @@ -61,6 +64,8 @@ icon_css_class = 'fa fa-fw fa-picture-o' fields = field.Fields(IGallery).omit('__parent__', '__file__') + fields['renderer'].widgetFactory = RendererFieldWidget + ajax_handler = 'properties.json' edit_permission = MANAGE_CONTENT_PERMISSION @@ -154,28 +159,6 @@ # -# Gallery renderers -# - -class BaseGalleryRenderer(ContextRequestAdapter): - """Base gallery renderer""" - - def update(self): - pass - - render = get_view_template() - - -@adapter_config(name='default', context=(IGallery, IPyAMSLayer), provides=IGalleryRenderer) -@template_config(template='templates/renderer-default.pt', layer=IPyAMSLayer) -class DefaultGalleryRenderer(BaseGalleryRenderer): - """Default gallery renderer""" - - label = _("Default gallery renderer") - weight = 1 - - -# # Gallery medias downloader # diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/zmi/paragraph.py --- a/src/pyams_content/component/gallery/zmi/paragraph.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/gallery/zmi/paragraph.py Thu Feb 15 15:08:29 2018 +0100 @@ -15,10 +15,8 @@ # import standard library -from datetime import datetime - # import interfaces -from pyams_content.component.gallery.interfaces import IGalleryParagraph, IBaseGallery, IGalleryRenderer +from pyams_content.component.gallery.interfaces import IGalleryParagraph, IBaseGallery from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \ IParagraphSummary @@ -35,6 +33,7 @@ from pyams_content.component.gallery.paragraph import Gallery from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ BaseParagraphAddMenu, BaseParagraphPropertiesEditForm +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin from pyams_pagelet.pagelet import pagelet_config from pyams_skin.viewlet.toolbar import ToolbarAction @@ -100,6 +99,8 @@ icon_css_class = 'fa fa-fw fa-picture-o' fields = field.Fields(IGalleryParagraph).omit('__parent__', '__name__', 'visible') + fields['renderer'].widgetFactory = RendererFieldWidget + ajax_handler = 'properties.json' edit_permission = MANAGE_CONTENT_PERMISSION @@ -192,8 +193,7 @@ def __init__(self, context, request): super(GalleryParagraphSummary, self).__init__(context, request) - self.renderer = request.registry.queryMultiAdapter((context, request), IGalleryRenderer, - name=self.context.renderer) + self.renderer = self.context.get_renderer(request) language = None diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/gallery/zmi/renderer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/gallery/zmi/renderer.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.gallery import IGallery +from pyams_content.features.renderer.interfaces import IContentRenderer +from pyams_skin.layer import IPyAMSLayer + +# import packages +from pyams_content.features.renderer.zmi import BaseContentRenderer +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config + +from pyams_content import _ + + +class BaseGalleryRenderer(BaseContentRenderer): + """Base gallery renderer""" + + +@adapter_config(name='default', context=(IGallery, IPyAMSLayer), provides=IContentRenderer) +@template_config(template='templates/renderer-default.pt', layer=IPyAMSLayer) +class DefaultGalleryRenderer(BaseGalleryRenderer): + """Default gallery renderer""" + + label = _("Default gallery renderer") + weight = 1 diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/__init__.py --- a/src/pyams_content/component/illustration/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/illustration/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration.interfaces import IIllustrationRenderer, IIllustration, IIllustrationTarget, \ +from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationTarget, \ ILLUSTRATION_KEY from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE from pyams_file.interfaces import IFileInfo, IImage, IResponsiveImage @@ -29,12 +29,12 @@ # import packages from persistent import Persistent from pyams_content.features.checker import BaseContentChecker +from pyams_content.features.renderer import RenderedContentMixin from pyams_i18n.property import I18nFileProperty from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.registry import query_utility, get_utility from pyams_utils.request import check_request from pyams_utils.traversing import get_parent -from pyams_utils.vocabulary import vocabulary_config from pyramid.events import subscriber from pyramid.threadlocal import get_current_registry from zope.container.contained import Contained @@ -42,13 +42,12 @@ from zope.lifecycleevent import ObjectCreatedEvent, ObjectAddedEvent from zope.location import locate from zope.schema.fieldproperty import FieldProperty -from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from pyams_content import _ @implementer(IIllustration) -class Illustration(Persistent, Contained): +class Illustration(Persistent, Contained, RenderedContentMixin): """Illustration persistent class""" title = FieldProperty(IIllustration['title']) @@ -67,7 +66,7 @@ @data.setter def data(self, value): self._data = value - for data in self._data.values(): + for data in (self._data or {}).values(): if IImage.providedBy(data): alsoProvides(data, IResponsiveImage) @@ -181,18 +180,3 @@ illustration = IIllustration(context, None) if illustration is not None: return IContentChecker(illustration) - - -@vocabulary_config(name='PyAMS illustration renderers') -class IllustrationRendererVocabulary(SimpleVocabulary): - """Illustration renderer utilities vocabulary""" - - def __init__(self, context=None): - request = check_request() - translate = request.localizer.translate - registry = request.registry - context = Illustration() - terms = [SimpleTerm(name, title=translate(adapter.label)) - for name, adapter in sorted(registry.getAdapters((context, request), IIllustrationRenderer), - key=lambda x: x[1].weight)] - super(IllustrationRendererVocabulary, self).__init__(terms) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/interfaces/__init__.py --- a/src/pyams_content/component/illustration/interfaces/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/illustration/interfaces/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -17,12 +17,11 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IBaseParagraph +from pyams_content.features.renderer.interfaces import IRenderedContent from pyams_i18n.schema import I18nTextLineField, I18nTextField, I18nThumbnailMediaField from zope.annotation.interfaces import IAttributeAnnotatable -from zope.contentprovider.interfaces import IContentProvider # import packages -from zope.interface import Interface, Attribute from zope.schema import Choice, TextLine from pyams_content import _ @@ -35,7 +34,7 @@ ILLUSTRATION_KEY = 'pyams_content.illustration' -class IIllustration(Interface): +class IIllustration(IRenderedContent): """Illustration paragraph""" title = I18nTextLineField(title=_("Legend"), @@ -63,7 +62,8 @@ renderer = Choice(title=_("Illustration template"), description=_("Presentation template used for illustration"), - vocabulary='PyAMS illustration renderers') + vocabulary='PyAMS illustration renderers', + default='hidden') language = Choice(title=_("Language"), description=_("File's content language"), @@ -75,12 +75,6 @@ """Illustration target marker interface""" -class IIllustrationRenderer(IContentProvider): - """Illustration renderer utility interface""" - - label = Attribute("Renderer label") - - class IIllustrationParagraph(IIllustration, IBaseParagraph): """Illustration paragraph""" diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/renderer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/illustration/renderer.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.features.renderer.interfaces import IContentRenderer + +# import packages +from pyams_content.component.illustration import Illustration, IIllustration +from pyams_utils.request import check_request +from pyams_utils.vocabulary import vocabulary_config +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm + + +@vocabulary_config(name='PyAMS illustration renderers') +class IllustrationRendererVocabulary(SimpleVocabulary): + """Illustration renderer utilities vocabulary""" + + def __init__(self, context=None): + request = check_request() + translate = request.localizer.translate + registry = request.registry + if not IIllustration.providedBy(context): + context = Illustration() + terms = [SimpleTerm(name, title=translate(adapter.label)) + for name, adapter in sorted(registry.getAdapters((context, request), IContentRenderer), + key=lambda x: x[1].weight)] + super(IllustrationRendererVocabulary, self).__init__(terms) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/zmi/__init__.py --- a/src/pyams_content/component/illustration/zmi/__init__.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/illustration/zmi/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -16,10 +16,9 @@ # import standard library # import interfaces -from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationRenderer, IIllustrationTarget +from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationTarget from pyams_content.component.paragraph.zmi.interfaces import IParagraphContainerTable, IParagraphTitleToolbar from pyams_form.interfaces.form import IInnerSubForm, IWidgetsPrefixViewletsManager -from pyams_i18n.interfaces import II18n from pyams_skin.layer import IPyAMSLayer from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from pyams_utils.interfaces.data import IObjectData @@ -27,11 +26,12 @@ from transaction.interfaces import ITransactionManager # import packages +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_content.skin import pyams_content from pyams_form.security import ProtectedFormObjectMixin from pyams_skin.viewlet.toolbar import JsToolbarAction -from pyams_template.template import get_view_template, template_config -from pyams_utils.adapter import ContextRequestAdapter, adapter_config +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config from pyams_utils.fanstatic import get_resource_path from pyams_viewlet.viewlet import viewlet_config, Viewlet from pyams_zmi.form import InnerAdminEditForm @@ -42,63 +42,6 @@ # -# Illustration renderers -# - -class BaseIllustrationRenderer(ContextRequestAdapter): - """Base illustration renderer""" - - language = None - - def update(self): - i18n = II18n(self.context) - if self.language: - self.legend = i18n.get_attribute('alt_title', self.language, request=self.request) - else: - self.legend = i18n.query_attribute('alt_title', request=self.request) - - render = get_view_template() - - -@adapter_config(name='hidden', context=(IIllustration, IPyAMSLayer), provides=IIllustrationRenderer) -class HiddenIllustrationRenderer(BaseIllustrationRenderer): - """Hidden illustration renderer""" - - label = _("Hidden illustration") - weight = -999 - - def render(self): - return '' - - -@adapter_config(name='default', context=(IIllustration, IPyAMSLayer), provides=IIllustrationRenderer) -@template_config(template='templates/renderer-default.pt', layer=IPyAMSLayer) -class DefaultIllustrationRenderer(BaseIllustrationRenderer): - """Default illustration renderer""" - - label = _("Centered illustration") - weight = 1 - - -@adapter_config(name='left+zoom', context=(IIllustration, IPyAMSLayer), provides=IIllustrationRenderer) -@template_config(template='templates/renderer-left.pt', layer=IPyAMSLayer) -class LeftIllustrationWithZoomRenderer(BaseIllustrationRenderer): - """Illustrtaion renderer with small image and zoom""" - - label = _("Small illustration on the left with zoom") - weight = 2 - - -@adapter_config(name='right+zoom', context=(IIllustration, IPyAMSLayer), provides=IIllustrationRenderer) -@template_config(template='templates/renderer-right.pt', layer=IPyAMSLayer) -class RightIllustrationWithZoomRenderer(BaseIllustrationRenderer): - """Illustrtaion renderer with small image and zoom""" - - label = _("Small illustration on the right with zoom") - weight = 3 - - -# # Illustration properties inner edit form # @@ -138,6 +81,8 @@ legend_class = 'illustration switcher no-y-padding padding-right-10 pull-left width-auto' fields = field.Fields(IIllustration).omit('__parent__', '__name__') + fields['renderer'].widgetFactory = RendererFieldWidget + hide_widgets_prefix_div = True weight = 10 @@ -155,7 +100,8 @@ def get_ajax_output(self, changes): output = super(IllustrationPropertiesInnerEditForm, self).get_ajax_output(changes) - if 'data' in changes.get(IIllustration, ()): + illustration_changes = changes.get(IIllustration, ()) + if ('data' in illustration_changes) or ('renderer' in illustration_changes): # we have to commit transaction to be able to handle blobs... ITransactionManager(self.context).get().commit() form = IllustrationPropertiesInnerEditForm(self.context, self.request) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/zmi/interfaces.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/illustration/zmi/interfaces.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,32 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +# import standard library + +# import interfaces + +# import packages +from zope.interface import Interface +from zope.schema import Bool + +from pyams_content import _ + + +class IIllustrationWithZoomSettings(Interface): + """Illustration with zoom interface""" + + zoom_on_click = Bool(title=_("Zoom on click?"), + description=_("If 'yes', a click on illustration thumbnail is required to zoom"), + required=True, + default=True) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/zmi/paragraph.py --- a/src/pyams_content/component/illustration/zmi/paragraph.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/illustration/zmi/paragraph.py Thu Feb 15 15:08:29 2018 +0100 @@ -18,7 +18,7 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, \ IParagraphContainer, IParagraphSummary -from pyams_content.component.illustration.interfaces import IIllustrationRenderer, IIllustration, IIllustrationParagraph +from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationParagraph from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION from pyams_form.interfaces.form import IInnerForm, IEditFormButtons @@ -32,6 +32,7 @@ from pyams_content.component.illustration.paragraph import Illustration from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ BaseParagraphAddMenu, BaseParagraphPropertiesEditForm +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_pagelet.pagelet import pagelet_config from pyams_utils.adapter import adapter_config from pyams_viewlet.viewlet import viewlet_config, BaseContentProvider @@ -99,6 +100,8 @@ icon_css_class = 'fa fa-fw fa-file-image-o' fields = field.Fields(IIllustrationParagraph).omit('__parent__', '__name__', 'visible') + fields['renderer'].widgetFactory = RendererFieldWidget + ajax_handler = 'properties.json' edit_permission = MANAGE_CONTENT_PERMISSION @@ -191,8 +194,7 @@ def __init__(self, context, request): super(IllustrationSummary, self).__init__(context, request) - self.renderer = request.registry.queryMultiAdapter((context, request), IIllustrationRenderer, - name=self.context.renderer) + self.renderer = self.context.get_renderer() language = None diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/illustration/zmi/renderer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/illustration/zmi/renderer.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,119 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library +from persistent import Persistent + +# import interfaces +from pyams_content.component.illustration.interfaces import IIllustration +from pyams_content.component.illustration.zmi.interfaces import IIllustrationWithZoomSettings +from pyams_i18n.interfaces import II18n +from pyams_content.features.renderer.interfaces import IContentRenderer +from pyams_skin.layer import IPyAMSLayer +from zope.annotation.interfaces import IAnnotations + +# import packages +from pyams_content.features.renderer.zmi import BaseContentRenderer +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from zope.interface import implementer +from zope.location import locate, Location +from zope.schema.fieldproperty import FieldProperty + +from pyams_content import _ + + +# +# Illustration renderers +# + +class BaseIllustrationRenderer(BaseContentRenderer): + """Base illustration renderer""" + + language = None + + def update(self): + i18n = II18n(self.context) + if self.language: + self.legend = i18n.get_attribute('alt_title', self.language, request=self.request) + else: + self.legend = i18n.query_attribute('alt_title', request=self.request) + + +@adapter_config(name='hidden', context=(IIllustration, IPyAMSLayer), provides=IContentRenderer) +class HiddenIllustrationRenderer(BaseIllustrationRenderer): + """Hidden illustration renderer""" + + label = _("Hidden illustration") + weight = -999 + + def render(self): + return '' + + +@adapter_config(name='default', context=(IIllustration, IPyAMSLayer), provides=IContentRenderer) +@template_config(template='templates/renderer-default.pt', layer=IPyAMSLayer) +class DefaultIllustrationRenderer(BaseIllustrationRenderer): + """Default illustration renderer""" + + label = _("Centered illustration") + weight = 1 + + +@adapter_config(name='left+zoom', context=(IIllustration, IPyAMSLayer), provides=IContentRenderer) +@template_config(template='templates/renderer-left.pt', layer=IPyAMSLayer) +class LeftIllustrationWithZoomRenderer(BaseIllustrationRenderer): + """Illustration renderer with small image and zoom""" + + label = _("Small illustration on the left with zoom") + weight = 2 + + target_interface = IIllustrationWithZoomSettings + + +@adapter_config(name='right+zoom', context=(IIllustration, IPyAMSLayer), provides=IContentRenderer) +@template_config(template='templates/renderer-right.pt', layer=IPyAMSLayer) +class RightIllustrationWithZoomRenderer(BaseIllustrationRenderer): + """Illustration renderer with small image and zoom""" + + label = _("Small illustration on the right with zoom") + weight = 3 + + target_interface = IIllustrationWithZoomSettings + + +# +# Illustration renderer with zoom settings +# + +ILLUSTRATION_ZOOM_RENDERER_SETTINGS_KEY = 'pyams_content.illustration.renderer:zoom' + + +@implementer(IIllustrationWithZoomSettings) +class IllustrationZoomSettings(Persistent, Location): + """Illustration zoom renderer settings""" + + zoom_on_click = FieldProperty(IIllustrationWithZoomSettings['zoom_on_click']) + + +@adapter_config(context=IIllustration, provides=IIllustrationWithZoomSettings) +def IllustrationWithZoomSettingsFactory(context): + """Illustration zoom renderer settings factory""" + annotations = IAnnotations(context) + settings = annotations.get(ILLUSTRATION_ZOOM_RENDERER_SETTINGS_KEY) + if settings is None: + settings = annotations[ILLUSTRATION_ZOOM_RENDERER_SETTINGS_KEY] = IllustrationZoomSettings() + locate(settings, context) + return settings diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/component/paragraph/zmi/html.py --- a/src/pyams_content/component/paragraph/zmi/html.py Sun Feb 11 12:11:05 2018 +0100 +++ b/src/pyams_content/component/paragraph/zmi/html.py Thu Feb 15 15:08:29 2018 +0100 @@ -18,7 +18,7 @@ # import interfaces from pyams_content.component.association.interfaces import IAssociationTarget from pyams_content.component.association.zmi.interfaces import IAssociationsParentForm -from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationRenderer +from pyams_content.component.illustration.interfaces import IIllustration from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \ IParagraphSummary from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph, IRawParagraph @@ -354,9 +354,7 @@ self.illustration = IIllustration(self.context) if self.illustration.data: registry = get_current_registry() - renderer = self.illustration_renderer = registry.queryMultiAdapter((self.illustration, self.request), - IIllustrationRenderer, - name=self.illustration.renderer) + renderer = self.illustration_renderer = self.illustration.get_renderer() if renderer is not None: renderer.update() diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/features/renderer/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/renderer/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.features.renderer.interfaces import IRenderedContent, IContentRenderer, IRendererSettings + +# import packages +from pyams_utils.adapter import adapter_config +from pyams_utils.request import check_request +from zope.interface import implementer + + +@implementer(IRenderedContent) +class RenderedContentMixin(object): + """Renderer mixin interface""" + + renderer = None + + def get_renderer(self, request=None): + if request is None: + request = check_request() + return request.registry.queryMultiAdapter((self, request), IContentRenderer, name=self.renderer) + + +@adapter_config(context=IRenderedContent, provides=IContentRenderer) +def RenderedContentRendererFactory(context): + """Rendered content renderer factory""" + return context.get_renderer() + + +@adapter_config(context=IRenderedContent, provides=IRendererSettings) +def RenderedContentRendererSettingsFactory(context): + """Rendered content renderer settings factory""" + renderer = IContentRenderer(context) + if renderer.target_interface is None: + return None + return renderer.target_interface(context) diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/features/renderer/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/renderer/interfaces/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,44 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from zope.annotation import IAttributeAnnotatable +from zope.contentprovider.interfaces import IContentProvider + +# import packages +from zope.interface import Interface, Attribute + + +class IRenderedContent(IAttributeAnnotatable): + """Generic interface for any rendered content""" + + renderer = Attribute("Selected renderer name") + + def get_renderer(self, request=None): + """Get selected renderer implementation""" + + +class IContentRenderer(IContentProvider): + """Content renderer interface""" + + label = Attribute("Renderer label") + + target_interface = Attribute("Renderer target interface") + + +class IRendererSettings(Interface): + """Base renderer settings interface""" diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/features/renderer/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/renderer/zmi/__init__.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,74 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.features.renderer.interfaces import IRenderedContent, IContentRenderer, IRendererSettings +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_skin.layer import IPyAMSLayer + +# import packages +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_template.template import get_view_template +from pyams_utils.adapter import ContextRequestAdapter +from pyams_zmi.form import AdminDialogEditForm +from pyramid.view import view_config +from z3c.form import field +from zope.interface import implementer, Interface + +from pyams_content import _ + + +@implementer(IContentRenderer) +class BaseContentRenderer(ContextRequestAdapter): + """Base content renderer""" + + target_interface = None + + @property + def settings(self): + if self.target_interface is None: + return None + return IRendererSettings(self.context) + + render = get_view_template() + + +@pagelet_config(name='renderer-properties.html', context=IRenderedContent, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +class RendererPropertiesEditForm(AdminDialogEditForm): + """Renderer properties edit form""" + + legend = _("Edit renderer properties") + icon_css_class = 'fa fa-fw fa-pencil-square-o' + + @property + def fields(self): + renderer = IContentRenderer(self.context) + return field.Fields(renderer.target_interface or Interface) + + ajax_handler = 'renderer-properties.json' + edit_permission = MANAGE_CONTENT_PERMISSION + + def getContent(self): + return IRendererSettings(self.context) + + +@view_config(name='renderer-properties.json', context=IRenderedContent, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +class RendererPropertiesAJAXEditForm(AJAXEditForm, RendererPropertiesEditForm): + """Renderer properties edit form, JSON renderer""" diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/features/renderer/zmi/templates/renderer-input.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/renderer/zmi/templates/renderer-input.pt Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,43 @@ + diff -r 1ebcb03e9bff -r 2a39b333a585 src/pyams_content/features/renderer/zmi/widget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/renderer/zmi/widget.py Thu Feb 15 15:08:29 2018 +0100 @@ -0,0 +1,39 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.features.renderer.interfaces import IContentRenderer +from pyams_form.interfaces.form import IFormLayer +from z3c.form.interfaces import INPUT_MODE + +# import packages +from pyams_form.widget import Select2Widget, widgettemplate_config +from z3c.form.widget import FieldWidget + + +@widgettemplate_config(mode=INPUT_MODE, template='templates/renderer-input.pt', layer=IFormLayer) +class RendererWidget(Select2Widget): + """Illustration renderer selection widget""" + + @property + def show_renderer_properties(self): + renderer = IContentRenderer(self.context) + return (renderer is not None) and (renderer.target_interface is not None) + + +def RendererFieldWidget(field, request): + return FieldWidget(field, RendererWidget(request))