--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/__init__.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,122 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.
+#
+from pyams_i18n.interfaces import II18nManager, INegotiator, II18n
+from pyams_utils.traversing import get_parent
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+from persistent import Persistent
+
+# import interfaces
+from pyams_content.component.video.interfaces import IExternalVideo, IExternalVideoProvider, IExternalVideoSettings
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
+from zope.annotation import IAnnotations
+
+# import packages
+from pyams_content.features.checker import BaseContentChecker, VALUE_OK
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import query_utility, get_utility
+from zope.container.contained import Contained
+from zope.interface import implementer
+from zope.location import locate
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+@implementer(IExternalVideo)
+class ExternalVideo(Persistent, Contained):
+ """External video persistent class"""
+
+ description = FieldProperty(IExternalVideo['description'])
+ author = FieldProperty(IExternalVideo['author'])
+ provider_name = FieldProperty(IExternalVideo['provider_name'])
+
+ def get_provider(self):
+ return query_utility(IExternalVideoProvider, name=self.provider_name)
+
+ @property
+ def settings(self):
+ provider = self.get_provider()
+ if provider is None:
+ return None
+ return provider.settings_interface(self)
+
+
+EXTERNAL_VIDEO_SETTINGS_KEY = 'pyams_content.video::{0}'
+
+
+@adapter_config(context=IExternalVideo, provides=IExternalVideoSettings)
+def ExternalVideoSettingsFactory(context):
+ """External video settings factory"""
+ if not context.provider_name:
+ return None
+ annotations = IAnnotations(context)
+ settings_key = EXTERNAL_VIDEO_SETTINGS_KEY.format(context.provider_name.lower())
+ settings = annotations.get(settings_key)
+ if settings is None:
+ provider = context.get_provider()
+ if provider is not None:
+ settings = annotations[settings_key] = IExternalVideoSettings(provider)
+ locate(settings, context)
+ return settings
+
+
+@adapter_config(context=IExternalVideo, provides=IContentChecker)
+class ExternalVideoContentChecker(BaseContentChecker):
+ """External video content checker"""
+
+ label = _("External video")
+ weight = 50
+
+ def inner_check(self, request):
+ output = []
+ translate = request.localizer.translate
+ manager = get_parent(self.context, II18nManager)
+ if manager is not None:
+ langs = manager.get_languages()
+ else:
+ negotiator = get_utility(INegotiator)
+ langs = (negotiator.server_language, )
+ missing_value = translate(MISSING_VALUE)
+ missing_lang_value = translate(MISSING_LANG_VALUE)
+ i18n = II18n(self.context)
+ for attr in ('description', ):
+ for lang in langs:
+ value = i18n.get_attribute(attr, lang, request)
+ if not value:
+ if len(langs) == 1:
+ output.append(missing_value.format(field=translate(IExternalVideo[attr].title)))
+ else:
+ output.append(missing_lang_value.format(field=translate(IExternalVideo[attr].title),
+ lang=lang))
+ for attr in ('author', 'provider_name'):
+ value = getattr(self.context, attr)
+ if not value:
+ output.append(missing_value.format(field=translate(IExternalVideo[attr].title)))
+ settings = self.context.settings
+ if settings is None:
+ pass
+ else:
+ checker = IContentChecker(settings, None)
+ if checker is not None:
+ checker_output = checker.inner_check(request)
+ if checker_output:
+ output.append('<div class="padding-left-20">')
+ output.append('- {0} :'.format(translate(checker.label)))
+ output.append([checker.sep.join(checker_output)])
+ output.append('</div>')
+ else:
+ output.append('- {0} : {1}'.format(translate(checker.label), translate(VALUE_OK)))
+ return output
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/interfaces/__init__.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,71 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.paragraph.interfaces import IBaseParagraph
+from zope.annotation import IAttributeAnnotatable
+from zope.contentprovider.interfaces import IContentProvider
+
+# import packages
+from pyams_i18n.schema import I18nHTMLField, I18nTextField
+from zope.interface import Interface, Attribute
+from zope.schema import Choice, TextLine
+
+from pyams_content import _
+
+
+class IExternalVideoSettings(Interface):
+ """External video settings"""
+
+
+class IExternalVideoProvider(Interface):
+ """External video provider"""
+
+ settings_interface = Attribute("Video provider settings interface")
+
+
+class IExternalVideo(IAttributeAnnotatable):
+ """Base interface for external video integration"""
+
+ description = I18nTextField(title=_("Description"),
+ description=_("File description displayed by front-office template"),
+ required=False)
+
+ author = TextLine(title=_("Author"),
+ description=_("Name of document's author"),
+ required=False)
+
+ provider_name = Choice(title=_("Video provider"),
+ description=_("Name of external platform providing selected video"),
+ required=False,
+ vocabulary="PyAMS video providers")
+
+ def get_provider(self):
+ """Get external video provider utility"""
+
+ settings = Attribute("Video settings")
+
+
+class IExternalVideoParagraph(IExternalVideo, IBaseParagraph):
+ """External video paragraph"""
+
+ body = I18nHTMLField(title=_("Body"),
+ required=False)
+
+
+class IExternalVideoRenderer(IContentProvider):
+ """External video renderer"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/paragraph.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.
+#
+from pyams_utils.traversing import get_parent
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.paragraph.interfaces import IParagraphFactory
+from pyams_content.component.video.interfaces import IExternalVideoParagraph
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
+from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
+
+# import packages
+from pyams_content.component.paragraph import BaseParagraph, BaseParagraphFactory
+from pyams_content.component.video import ExternalVideo, ExternalVideoContentChecker
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import utility_config, get_utility
+from pyams_utils.request import check_request
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+@implementer(IExternalVideoParagraph)
+class ExternalVideoParagraph(ExternalVideo, BaseParagraph):
+ """External video paragraph"""
+
+ icon_class = 'fa-youtube-play'
+ icon_hint = _("External video")
+
+ body = FieldProperty(IExternalVideoParagraph['body'])
+
+
+@utility_config(name='External video', provides=IParagraphFactory)
+class ExternalVideoParagraphFactory(BaseParagraphFactory):
+ """External video paragraph factory"""
+
+ name = _("External video")
+ content_type = ExternalVideoParagraph
+
+
+@adapter_config(context=IExternalVideoParagraph, provides=IContentChecker)
+class ExternalVideoParagraphContentChecker(ExternalVideoContentChecker):
+ """External video paragraph content checker"""
+
+ @property
+ def label(self):
+ request = check_request()
+ translate = request.localizer.translate
+ return II18n(self.context).query_attribute('title', request) or \
+ '({0})'.format(translate(self.context.icon_hint).lower())
+
+ def inner_check(self, request):
+ output = super(ExternalVideoParagraphContentChecker, self).inner_check(request)
+ translate = request.localizer.translate
+ manager = get_parent(self.context, II18nManager)
+ if manager is not None:
+ langs = manager.get_languages()
+ else:
+ negotiator = get_utility(INegotiator)
+ langs = (negotiator.server_language, )
+ missing_value = translate(MISSING_VALUE)
+ missing_lang_value = translate(MISSING_LANG_VALUE)
+ i18n = II18n(self.context)
+ for attr in ('title', ):
+ for lang in langs:
+ value = i18n.get_attribute(attr, lang, request)
+ if not value:
+ if len(langs) == 1:
+ output.insert(0, missing_value.format(field=translate(IExternalVideoParagraph[attr].title)))
+ else:
+ output.insert(0, missing_lang_value.format(field=translate(IExternalVideoParagraph[attr].title),
+ lang=lang))
+ return output
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/__init__.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.video.interfaces import IExternalVideoProvider
+
+# import packages
+from pyams_utils.vocabulary import vocabulary_config
+from zope.componentvocabulary.vocabulary import UtilityVocabulary
+
+
+@vocabulary_config(name='PyAMS video providers')
+class VideoProvidersVocabulary(UtilityVocabulary):
+ """Video providers vocabulary"""
+
+ interface = IExternalVideoProvider
+ nameOnly = True
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/dailymotion.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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 re
+
+from persistent import Persistent
+
+# import interfaces
+from pyams_content.component.video.interfaces import IExternalVideo, IExternalVideoProvider, IExternalVideoSettings
+from pyams_content.component.video.provider.interfaces import IDailymotionVideoSettings
+from pyams_content.features.checker.interfaces import IContentChecker
+
+# import packages
+from pyams_content.component.video import ExternalVideoSettingsFactory
+from pyams_content.features.checker import BaseContentChecker
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import utility_config
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+DAILYMOTION_BASE_URL = re.compile('http://dai.ly/(.*)')
+
+
+@implementer(IDailymotionVideoSettings)
+class DailymotionVideoSettings(Persistent):
+ """Dailymotion video settings"""
+
+ _video_id = FieldProperty(IDailymotionVideoSettings['video_id'])
+ width = FieldProperty(IDailymotionVideoSettings['width'])
+ height = FieldProperty(IDailymotionVideoSettings['height'])
+ start_at = FieldProperty(IDailymotionVideoSettings['start_at'])
+ autoplay = FieldProperty(IDailymotionVideoSettings['autoplay'])
+ show_info = FieldProperty(IDailymotionVideoSettings['show_info'])
+ show_commands = FieldProperty(IDailymotionVideoSettings['show_commands'])
+ ui_theme = FieldProperty(IDailymotionVideoSettings['ui_theme'])
+ show_branding = FieldProperty(IDailymotionVideoSettings['show_branding'])
+ show_endscreen = FieldProperty(IDailymotionVideoSettings['show_endscreen'])
+ allow_fullscreen = FieldProperty(IDailymotionVideoSettings['allow_fullscreen'])
+ allow_sharing = FieldProperty(IDailymotionVideoSettings['allow_sharing'])
+
+ @property
+ def video_id(self):
+ return self._video_id
+
+ @video_id.setter
+ def video_id(self, value):
+ if value:
+ match = DAILYMOTION_BASE_URL.match(value)
+ if match:
+ value = match.groups()[0]
+ self._video_id = value
+
+
+@utility_config(name='Dailymotion', provides=IExternalVideoProvider)
+class DailymotionVideoProvider(object):
+ """Dailymotion video provider"""
+
+ settings_interface = IDailymotionVideoSettings
+
+
+@adapter_config(context=IExternalVideo, provides=IDailymotionVideoSettings)
+def DailymotionVideoSettingsFactory(context):
+ """Dailymotion video settings factory"""
+ if context.provider_name != 'Dailymotion':
+ return None
+ return ExternalVideoSettingsFactory(context)
+
+
+@adapter_config(context=DailymotionVideoProvider, provides=IExternalVideoSettings)
+def DailymotionVideoProviderSettingsFactory(context):
+ """Dailymotion video provider settings factory"""
+ return DailymotionVideoSettings()
+
+
+@adapter_config(context=IDailymotionVideoSettings, provides=IContentChecker)
+class DailymotionVideoSettingsContentChecker(BaseContentChecker):
+ """Dailymotion video settings content checker"""
+
+ label = _("Dailymotion settings")
+
+ def inner_check(self, request):
+ return []
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/interfaces.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,218 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.video import IExternalVideoSettings
+
+# import packages
+from pyams_utils.schema import ColorField
+from zope.schema import TextLine, Bool, Int, Choice
+
+from pyams_content import _
+
+
+class IYoutubeVideoSettings(IExternalVideoSettings):
+ """Youtube video provider settings"""
+
+ video_id = TextLine(title=_("Video ID"),
+ description=_("To get video ID, just use the 'Share' button in Youtube platform and "
+ "copy/paste the given URL here"),
+ required=True)
+
+ width = Int(title=_("Video width"),
+ description=_("Initial video frame width; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=720)
+
+ height = Int(title=_("Video height"),
+ description=_("Initial video frame height; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=405)
+
+ start_at = TextLine(title=_("Start at"),
+ description=_("Position at which to start video, in 'seconds' or 'minutes:seconds' format"),
+ required=False,
+ default='0:00')
+
+ stop_at = TextLine(title=_("Stop at"),
+ description=_("Position at which to stop video, in 'seconds' or 'minutes:seconds' format"),
+ required=False)
+
+ autoplay = Bool(title=_("Auto play?"),
+ description=_("If 'yes', video is started automatically on page load"),
+ required=True,
+ default=False)
+
+ loop = Bool(title=_("Loop playback?"),
+ description=_("If 'yes', video is played indefinitely"),
+ required=True,
+ default=False)
+
+ show_info = Bool(title=_("Show video info?"),
+ description=_("If 'no', video title and information won't be displayed"),
+ required=True,
+ default=True)
+
+ show_commands = Bool(title=_("Show commands?"),
+ description=_("Show video player commands"),
+ required=True,
+ default=True)
+
+ hide_branding = Bool(title=_("Hide branding?"),
+ description=_("If 'yes', Youtube branding won't be displayed"),
+ required=True,
+ default=False)
+
+ show_related = Bool(title=_("Show related videos?"),
+ description=_("Show related videos when video end"),
+ required=True,
+ default=True)
+
+ allow_fullscreen = Bool(title=_("Allow full screen?"),
+ description=_("If 'yes', video can be displayed in full screen"),
+ required=True,
+ default=True)
+
+ disable_keyboard = Bool(title=_("Disable keyboard?"),
+ description=_("If 'yes', video player can't be controlled via keyboard shortcuts"),
+ required=True,
+ default=False)
+
+
+class IDailymotionVideoSettings(IExternalVideoSettings):
+ """Dailymotion video provider settings"""
+
+ video_id = TextLine(title=_("Video ID"),
+ description=_("To get video ID, just use the 'Share' button in Dailymotion platform, "
+ "click on \"Copy link\" and paste the given URL here"),
+ required=True)
+
+ width = Int(title=_("Video width"),
+ description=_("Initial video frame width; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=720)
+
+ height = Int(title=_("Video height"),
+ description=_("Initial video frame height; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=405)
+
+ start_at = TextLine(title=_("Start at"),
+ description=_("Position at which to start video, in 'seconds' or 'minutes:seconds' format"),
+ required=False,
+ default='0:00')
+
+ autoplay = Bool(title=_("Auto play?"),
+ description=_("If 'yes', video is started automatically on page load"),
+ required=True,
+ default=False)
+
+ show_info = Bool(title=_("Show video info?"),
+ description=_("If 'no', video title and information won't be displayed"),
+ required=True,
+ default=True)
+
+ show_commands = Bool(title=_("Show commands?"),
+ description=_("Show video player commands"),
+ required=True,
+ default=True)
+
+ ui_theme = Choice(title=_("UI theme"),
+ description=_("Default base color theme"),
+ values=('dark', 'light'),
+ default='dark')
+
+ show_branding = Bool(title=_("Show branding?"),
+ description=_("If 'no', Dailymotion branding won't be displayed"),
+ required=True,
+ default=True)
+
+ show_endscreen = Bool(title=_("Show end screen?"),
+ description=_("Show end screen when video end"),
+ required=True,
+ default=True)
+
+ allow_fullscreen = Bool(title=_("Allow full screen?"),
+ description=_("If 'yes', video can be displayed in full screen"),
+ required=True,
+ default=True)
+
+ allow_sharing = Bool(title=_("Allow sharing?"),
+ description=_("If 'no', video sharing will be disabled"),
+ required=True,
+ default=True)
+
+
+class IVimeoVideoSettings(IExternalVideoSettings):
+ """Vimeo video provider settings"""
+
+ video_id = TextLine(title=_("Video ID"),
+ description=_("To get video ID, just use the 'Share' button in Vimeo platform, "
+ "click on \"Link\" entry and copy/paste the given URL here"),
+ required=True)
+
+ width = Int(title=_("Video width"),
+ description=_("Initial video frame width; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=720)
+
+ height = Int(title=_("Video height"),
+ description=_("Initial video frame height; mandatory for old browsers but may be overridden by "
+ "presentation skin"),
+ required=True,
+ min=200,
+ default=405)
+
+ show_title = Bool(title=_("Show title?"),
+ description=_("If 'no', video title won't be displayed"),
+ required=True,
+ default=True)
+
+ show_signature = Bool(title=_("Show signature?"),
+ description=_("If 'no', video signature won't be displayed"),
+ required=True,
+ default=True)
+
+ color = ColorField(title=_("Infos color"),
+ description=_("Color used for title and signature"),
+ required=True,
+ default='ffffff')
+
+ autoplay = Bool(title=_("Auto play?"),
+ description=_("If 'yes', video is started automatically on page load"),
+ required=True,
+ default=False)
+
+ loop = Bool(title=_("Loop playback?"),
+ description=_("If 'yes', video is played indefinitely"),
+ required=True,
+ default=False)
+
+ allow_fullscreen = Bool(title=_("Allow full screen?"),
+ description=_("If 'yes', video can be displayed in full screen"),
+ required=True,
+ default=True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/vimeo.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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 re
+
+from persistent import Persistent
+
+# import interfaces
+from pyams_content.component.video.interfaces import IExternalVideo, IExternalVideoProvider, IExternalVideoSettings
+from pyams_content.component.video.provider.interfaces import IVimeoVideoSettings
+from pyams_content.features.checker.interfaces import IContentChecker
+
+# import packages
+from pyams_content.component.video import ExternalVideoSettingsFactory
+from pyams_content.features.checker import BaseContentChecker
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import utility_config
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+VIMEO_BASE_URL = re.compile('https://vimeo.com/([0-9]+)')
+
+
+@implementer(IVimeoVideoSettings)
+class VimeoVideoSettings(Persistent):
+ """Vimeo video settings"""
+
+ _video_id = FieldProperty(IVimeoVideoSettings['video_id'])
+ width = FieldProperty(IVimeoVideoSettings['width'])
+ height = FieldProperty(IVimeoVideoSettings['height'])
+ show_title = FieldProperty(IVimeoVideoSettings['show_title'])
+ show_signature = FieldProperty(IVimeoVideoSettings['show_signature'])
+ color = FieldProperty(IVimeoVideoSettings['color'])
+ autoplay = FieldProperty(IVimeoVideoSettings['autoplay'])
+ loop = FieldProperty(IVimeoVideoSettings['loop'])
+ allow_fullscreen = FieldProperty(IVimeoVideoSettings['allow_fullscreen'])
+
+ @property
+ def video_id(self):
+ return self._video_id
+
+ @video_id.setter
+ def video_id(self, value):
+ if value:
+ match = VIMEO_BASE_URL.match(value)
+ if match:
+ value = match.groups()[0]
+ self._video_id = value
+
+
+@utility_config(name='Vimeo', provides=IExternalVideoProvider)
+class VimeoVideoProvider(object):
+ """Vimeo video provider"""
+
+ settings_interface = IVimeoVideoSettings
+
+
+@adapter_config(context=IExternalVideo, provides=IVimeoVideoSettings)
+def VimeoVideoSettingsFactory(context):
+ """Vimeo video settings factory"""
+ if context.provider_name != 'Vimeo':
+ return None
+ return ExternalVideoSettingsFactory(context)
+
+
+@adapter_config(context=VimeoVideoProvider, provides=IExternalVideoSettings)
+def VimeoVideoProviderSettingsFactory(context):
+ """Vimeo video provider settings factory"""
+ return VimeoVideoSettings()
+
+
+@adapter_config(context=IVimeoVideoSettings, provides=IContentChecker)
+class VimeoVideoSettingsContentChecker(BaseContentChecker):
+ """Vimeo video settings content checker"""
+
+ label = _("Vimeo settings")
+
+ def inner_check(self, request):
+ return []
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/youtube.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,99 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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 re
+
+from persistent import Persistent
+
+# import interfaces
+from pyams_content.component.video.interfaces import IExternalVideo, IExternalVideoProvider, IExternalVideoSettings
+from pyams_content.component.video.provider.interfaces import IYoutubeVideoSettings
+from pyams_content.features.checker.interfaces import IContentChecker
+
+# import packages
+from pyams_content.component.video import ExternalVideoSettingsFactory
+from pyams_content.features.checker import BaseContentChecker
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import utility_config
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+YOUTUBE_BASE_URL = re.compile('https://youtu.be/(.*)')
+
+
+@implementer(IYoutubeVideoSettings)
+class YoutubeVideoSettings(Persistent):
+ """Youtube video settings"""
+
+ _video_id = FieldProperty(IYoutubeVideoSettings['video_id'])
+ width = FieldProperty(IYoutubeVideoSettings['width'])
+ height = FieldProperty(IYoutubeVideoSettings['height'])
+ start_at = FieldProperty(IYoutubeVideoSettings['start_at'])
+ stop_at = FieldProperty(IYoutubeVideoSettings['stop_at'])
+ autoplay = FieldProperty(IYoutubeVideoSettings['autoplay'])
+ loop = FieldProperty(IYoutubeVideoSettings['loop'])
+ show_info = FieldProperty(IYoutubeVideoSettings['show_info'])
+ show_commands = FieldProperty(IYoutubeVideoSettings['show_commands'])
+ hide_branding = FieldProperty(IYoutubeVideoSettings['hide_branding'])
+ show_related = FieldProperty(IYoutubeVideoSettings['show_related'])
+ allow_fullscreen = FieldProperty(IYoutubeVideoSettings['allow_fullscreen'])
+ disable_keyboard = FieldProperty(IYoutubeVideoSettings['disable_keyboard'])
+
+ @property
+ def video_id(self):
+ return self._video_id
+
+ @video_id.setter
+ def video_id(self, value):
+ if value:
+ match = YOUTUBE_BASE_URL.match(value)
+ if match:
+ value = match.groups()[0]
+ self._video_id = value
+
+
+@utility_config(name='Youtube', provides=IExternalVideoProvider)
+class YoutubeVideoProvider(object):
+ """Youtube video provider"""
+
+ settings_interface = IYoutubeVideoSettings
+
+
+@adapter_config(context=IExternalVideo, provides=IYoutubeVideoSettings)
+def YoutubeVideoSettingsFactory(context):
+ """Youtube video settings factory"""
+ if context.provider_name != 'Youtube':
+ return None
+ return ExternalVideoSettingsFactory(context)
+
+
+@adapter_config(context=YoutubeVideoProvider, provides=IExternalVideoSettings)
+def YoutubeVideoProviderSettingsFactory(context):
+ """Youtubr video provider settings factory"""
+ return YoutubeVideoSettings()
+
+
+@adapter_config(context=IYoutubeVideoSettings, provides=IContentChecker)
+class YoutubeVideoSettingsContentChecker(BaseContentChecker):
+ """Youtube video settings content checker"""
+
+ label = _("Youtube settings")
+
+ def inner_check(self, request):
+ return []
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/zmi/__init__.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.video.interfaces import IExternalVideoRenderer
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_content.component.video.provider.dailymotion import DailymotionVideoSettings
+from pyams_content.component.video.provider.vimeo import VimeoVideoSettings
+from pyams_content.component.video.provider.youtube import YoutubeVideoSettings
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from pyams_viewlet.viewlet import BaseContentProvider
+from pyramid.encode import urlencode
+
+
+def time_to_seconds(value):
+ """Convert min:sec value to seconds"""
+ if value and (':' in value):
+ min, sec = value.split(':', 1)
+ return str(int(min)*60 + int(sec))
+ else:
+ return value or ''
+
+
+YOUTUBE_PARAMS = (
+ ('start_at', 'start', time_to_seconds),
+ ('stop_at', 'end', time_to_seconds),
+ ('autoplay', 'autoplay', int),
+ ('loop', 'loop', int),
+ ('show_info', 'showinfo', int),
+ ('show_commands', 'controls', int),
+ ('hide_branding', 'modestbranding', int),
+ ('show_related', 'rel', int),
+ ('allow_fullscreen', 'fs', int),
+ ('disable_keyboard', 'disablekb', int)
+)
+
+
+DAILYMOTION_PARAMS = (
+ ('start_at', 'start', time_to_seconds),
+ ('autoplay', 'autoplay', int),
+ ('show_info', 'ui-start-screen-info', int),
+ ('show_commands', 'controls', int),
+ ('ui_theme', 'ui-theme', str),
+ ('show_branding', 'ui-logo', int),
+ ('show_endscreen', 'endscreen-enable', int),
+ ('allow_sharing', 'sharing-enable', int)
+)
+
+
+VIMEO_PARAMS = (
+ ('show_title', 'title', int),
+ ('show_signature', 'byline', int),
+ ('color', 'color', str),
+ ('autoplay', 'autoplay', int),
+ ('loop', 'loop', int)
+)
+
+
+class BaseExternalVideoRenderer(BaseContentProvider):
+ """Base external video renderer"""
+
+ params = ()
+
+ def get_url_params(self):
+ settings = self.context
+ params = {}
+ for attr, param, handler in self.params:
+ params[param] = handler(getattr(settings, attr))
+ return urlencode(params)
+
+
+@adapter_config(context=(YoutubeVideoSettings, IPyAMSLayer), provides=IExternalVideoRenderer)
+@template_config(template='templates/youtube-preview.pt', layer=IPyAMSLayer)
+class YoutubeVideoRenderer(BaseExternalVideoRenderer):
+ """Youtube video renderer"""
+
+ params = YOUTUBE_PARAMS
+
+
+@adapter_config(context=(DailymotionVideoSettings, IPyAMSLayer), provides=IExternalVideoRenderer)
+@template_config(template='templates/dailymotion-preview.pt', layer=IPyAMSLayer)
+class DailymotionVideoRenderer(BaseExternalVideoRenderer):
+ """Dailymotion video renderer"""
+
+ params = DAILYMOTION_PARAMS
+
+
+@adapter_config(context=(VimeoVideoSettings, IPyAMSLayer), provides=IExternalVideoRenderer)
+@template_config(template='templates/vimeo-preview.pt', layer=IPyAMSLayer)
+class VimeoVideoRenderer(BaseExternalVideoRenderer):
+ """Vimeo video renderer"""
+
+ params = VIMEO_PARAMS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/zmi/templates/dailymotion-preview.pt Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,8 @@
+<div class="video-wrapper">
+ <iframe type="text/html" class="video" frameborder="0"
+ tal:attributes="src string:https://www.dailymotion.com/embed/video/${context.video_id}?${view.get_url_params()};
+ width context.width;
+ height context.height;
+ allowfullscreen 'true' if context.allow_fullscreen else None;
+ allow 'autoplay' if context.autoplay else None;"></iframe>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/zmi/templates/vimeo-preview.pt Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,9 @@
+<div class="video-wrapper">
+ <iframe type="text/html" class="video" frameborder="0"
+ tal:attributes="src string:https://player.vimeo.com/video/${context.video_id}?${view.get_url_params()};
+ width context.width;
+ height context.height;
+ allowfullscreen 'true' if context.allow_fullscreen else None;
+ webkitallowfullscreen 'true' if context.allow_fullscreen else None;
+ mozallowfullscreen 'true' if context.allow_fullscreen else None;"></iframe>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/provider/zmi/templates/youtube-preview.pt Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,7 @@
+<div class="video-wrapper">
+ <iframe type="text/html" class="video" frameborder="0"
+ tal:attributes="src string:https://www.youtube.com/embed/${context.video_id}?${view.get_url_params()};
+ width context.width;
+ height context.height;
+ allowfullscreen 'allowfullscreen' if context.allow_fullscreen else None;"></iframe>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/zmi/__init__.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/zmi/paragraph.py Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,292 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# 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.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, IBaseParagraph, \
+ IParagraphSummary
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphContainerView, IParagraphInnerEditor
+from pyams_content.component.video.interfaces import IExternalVideoProvider, IExternalVideoSettings, \
+ IExternalVideoParagraph, IExternalVideoRenderer
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager, IInnerForm, IEditFormButtons
+from pyams_i18n.interfaces import II18n
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces.data import IObjectData
+from z3c.form.interfaces import DISPLAY_MODE, INPUT_MODE, IDataExtractedEvent
+
+# import packages
+from pyams_content.component.paragraph.zmi import BaseParagraphAddMenu, BaseParagraphAJAXAddForm, \
+ BaseParagraphPropertiesEditForm, BaseParagraphAJAXEditForm
+from pyams_content.component.video.paragraph import ExternalVideoParagraph
+from pyams_form.group import NamedWidgetsGroup
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from pyams_utils.registry import get_utility, get_current_registry
+from pyams_utils.url import absolute_url
+from pyams_viewlet.viewlet import viewlet_config, Viewlet, BaseContentProvider
+from pyams_zmi.form import AdminDialogAddForm, InnerAdminAddForm, InnerAdminEditForm
+from pyramid.events import subscriber
+from pyramid.exceptions import NotFound
+from pyramid.response import Response
+from pyramid.view import view_config
+from z3c.form import field, button
+from zope.interface import implementer, alsoProvides, Interface, Invalid
+from zope.schema import getFieldNamesInOrder
+
+from pyams_content import _
+
+
+@viewlet_config(name='add-external-video.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
+ layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=75)
+class ExternalVideoParagraphAddMenu(BaseParagraphAddMenu):
+ """External video paragraph add menu"""
+
+ label = _("External video...")
+ label_css_class = 'fa fa-fw fa-youtube-play'
+ url = 'add-external-video.html'
+ paragraph_type = 'External video'
+
+
+@pagelet_config(name='add-external-video.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+class ExternalVideoParagraphAddForm(AdminDialogAddForm):
+ """External video paragraph add form"""
+
+ legend = _("Add new external video...")
+ dialog_class = 'modal-large'
+ icon_css_class = 'fa fa-fw fa-youtube-play'
+
+ fields = field.Fields(IExternalVideoParagraph).omit('__parent__', '__name__', 'visible')
+ ajax_handler = 'add-external-video.json'
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+ def updateWidgets(self, prefix=None):
+ super(ExternalVideoParagraphAddForm, self).updateWidgets(prefix)
+ if 'description' in self.widgets:
+ self.widgets['description'].widget_css_class = 'textarea'
+ if 'body' in self.widgets:
+ self.widgets['body'].label = ''
+ self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',),
+ bordered=False,
+ legend=_("HTML content"),
+ css_class='inner switcher padding-right-10 no-y-padding pull-left',
+ switch=True,
+ hide_if_empty=True))
+ self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets,
+ ('description', 'author', 'provider_name'),
+ bordered=False))
+ if 'provider_name' in self.widgets:
+ widget = self.widgets['provider_name']
+ widget.object_data = {
+ 'ams-change-handler': 'MyAMS.helpers.select2ChangeHelper',
+ 'ams-change-stop-propagation': 'true',
+ 'ams-select2-helper-type': 'html',
+ 'ams-select2-helper-url': absolute_url(self.context, self.request,
+ 'get-video-provider-settings-add-form.html'),
+ 'ams-select2-helper-argument': 'provider_name',
+ 'ams-select2-helper-target': '#video-settings-helper'
+ }
+ alsoProvides(widget, IObjectData)
+
+ def create(self, data):
+ return ExternalVideoParagraph()
+
+ def update_content(self, content, data):
+ changes = super(ExternalVideoParagraphAddForm, self).update_content(content, data)
+ settings = IExternalVideoSettings(content, None)
+ if settings is not None:
+ provider = content.get_provider()
+ form = InnerAdminEditForm(settings, self.request)
+ form.edit_permission = MANAGE_CONTENT_PERMISSION
+ form.fields = field.Fields(provider.settings_interface)
+ form.update()
+ settings_data, errors = form.extractData()
+ if not errors:
+ changes.update(form.update_content(settings, settings_data))
+ return changes
+
+ def add(self, object):
+ IParagraphContainer(self.context).append(object)
+
+
+@view_config(name='add-external-video.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class ExternalVideoParagraphAJAXAddForm(BaseParagraphAJAXAddForm, ExternalVideoParagraphAddForm):
+ """External video paragraph add form, JSON renderer"""
+
+
+@subscriber(IDataExtractedEvent, form_selector=ExternalVideoParagraphAddForm)
+def handle_video_paragraph_add_form_data_extraction(event):
+ """Handle provider name data extraction"""
+ data = event.data
+ if not data.get('provider_name'):
+ event.form.widgets.errors += (Invalid(_("Video provider is required")), )
+
+
+@viewlet_config(name='external-video-settings', context=Interface, layer=IPyAMSLayer,
+ view=ExternalVideoParagraphAddForm, manager=IWidgetsSuffixViewletsManager)
+@template_config(template='templates/video-settings.pt', layer=IPyAMSLayer)
+class VideoSettingsWidgetsSuffix(Viewlet):
+ """External video settings edit form widgets suffix"""
+
+
+@view_config(name='get-video-provider-settings-add-form.html', context=IParagraphContainerTarget,
+ request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, xhr=True)
+def ExternalVideoProviderSettingsAddForm(request):
+ """External video provider settings form"""
+ provider_name = request.params.get('provider_name')
+ if provider_name is None:
+ raise NotFound("No provided provider_name argument")
+ elif (not provider_name) or (provider_name == '--NOVALUE--'):
+ return Response('')
+ else:
+ provider = get_utility(IExternalVideoProvider, name=provider_name)
+ form = InnerAdminAddForm(request.context, request)
+ form.legend = request.localizer.translate(_("Video provider settings"))
+ form.label_css_class = 'control-label col-md-4'
+ form.input_css_class = 'col-md-8'
+ form.fields = field.Fields(provider.settings_interface)
+ form.update()
+ return Response(form.render())
+
+
+@pagelet_config(name='properties.html', context=IExternalVideoParagraph, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+class ExternalVideoParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
+ """External video paragraph properties edit form"""
+
+ legend = _("Edit video properties")
+ icon_css_class = 'fa fa-fw fa-youtube-play'
+
+ ajax_handler = 'properties.json'
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+ @property
+ def fields(self):
+ fields = field.Fields(IExternalVideoParagraph).omit('__parent__', '__name__', 'visible')
+ provider = self.context.get_provider()
+ if provider is not None:
+ fields += field.Fields(provider.settings_interface)
+ return fields
+
+ def updateWidgets(self, prefix=None):
+ super(ExternalVideoParagraphPropertiesEditForm, self).updateWidgets(prefix)
+ if 'description' in self.widgets:
+ self.widgets['description'].widget_css_class = 'textarea'
+ if 'body' in self.widgets:
+ self.widgets['body'].label = ''
+ self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',),
+ bordered=False,
+ fieldset_class='margin-top-10 padding-y-5',
+ legend=_("HTML content"),
+ css_class='inner switcher padding-right-10 no-y-padding pull-left',
+ switch=True,
+ hide_if_empty=True))
+ self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets,
+ ('description', 'author', 'provider_name'),
+ bordered=False))
+ if 'provider_name' in self.widgets:
+ self.widgets['provider_name'].mode = DISPLAY_MODE
+ provider = self.context.get_provider()
+ if provider is not None:
+ self.add_group(NamedWidgetsGroup(self, 'provider_group', self.widgets,
+ getFieldNamesInOrder(provider.settings_interface),
+ legend=_("Video provider settings"),
+ fieldset_class='margin-top-10 padding-y-5',
+ css_class='inner padding-right-10 no-y-padding pull-left',
+ bordered=False))
+
+
+@view_config(name='properties.json', context=IExternalVideoParagraph, request_type=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class ExternalVideoParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, ExternalVideoParagraphPropertiesEditForm):
+ """External video paragraph properties edit form, JSON renderer"""
+
+ def get_ajax_output(self, changes):
+ output = super(ExternalVideoParagraphPropertiesAJAXEditForm, self).get_ajax_output(changes)
+ if 'title' in changes.get(IBaseParagraph, ()):
+ output.setdefault('events', []).append({
+ 'event': 'myams.refresh',
+ 'options': {
+ 'handler': 'PyAMS_content.paragraphs.refreshParagraph',
+ 'object_name': self.context.__name__,
+ 'title': II18n(self.context).query_attribute('title', request=self.request),
+ 'visible': self.context.visible
+ }
+ })
+ return output
+
+
+@adapter_config(context=(IExternalVideoParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+@implementer(IInnerForm)
+class ExternalVideoParagraphInnerEditForm(ExternalVideoParagraphPropertiesEditForm):
+ """External video paragraph properties inner deit form"""
+
+ legend = None
+ ajax_handler = 'inner-properties.json'
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IEditFormButtons)
+ else:
+ return button.Buttons()
+
+
+@view_config(name='inner-properties.json', context=IExternalVideoParagraph, request_type=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class ExternalVideoParagraphInnerAJAXEditForm(BaseParagraphAJAXEditForm, ExternalVideoParagraphInnerEditForm):
+ """External video paragraph inner edit form, JSON renderer"""
+
+
+#
+# Video paragraph summary
+#
+
+@adapter_config(context=(IExternalVideoParagraph, IPyAMSLayer), provides=IParagraphSummary)
+@template_config(template='templates/video-summary.pt', layer=IPyAMSLayer)
+class ExternalVideoParagraphSummary(BaseContentProvider):
+ """External video paragraph summary"""
+
+ video_renderer = None
+
+ def __init__(self, context, request):
+ super(ExternalVideoParagraphSummary, self).__init__(context, request)
+ provider = context.get_provider()
+ if provider is not None:
+ registry = get_current_registry()
+ self.video_renderer = registry.queryMultiAdapter((context.settings, request), IExternalVideoRenderer)
+
+ def update(self):
+ i18n = II18n(self.context)
+ if self.language:
+ for attr in ('title', 'body', 'description'):
+ setattr(self, attr, i18n.get_attribute(attr, self.language, request=self.request))
+ else:
+ for attr in ('title', 'body', 'description'):
+ setattr(self, attr, i18n.query_attribute(attr, request=self.request))
+ renderer = self.video_renderer
+ if renderer is not None:
+ renderer.update()
+
+ def render_video(self):
+ renderer = self.video_renderer
+ if not renderer:
+ return ''
+ return renderer.render()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/zmi/templates/video-settings.pt Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,1 @@
+<div id="video-settings-helper"></div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/video/zmi/templates/video-summary.pt Wed Feb 21 17:18:04 2018 +0100
@@ -0,0 +1,7 @@
+<h3 tal:condition="view.title"
+ tal:content="view.title">title</h3>
+<div tal:condition="view.body"
+ tal:content="structure view.body">body</div>
+<div tal:condition="view.description"
+ tal:content="structure extension:html(view.description)">Description</div>
+<tal:var replace="structure view.render_video()" />