# HG changeset patch # User Thierry Florac # Date 1517912183 -3600 # Node ID 5dce5350983209d84f063a0d8bd6345b2b4b3586 # Parent 871c7cb35fd659a7cd7aa0a7a49c6f90a7d36514 Added raw HTML paragraph diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/__init__.py --- a/src/pyams_content/component/paragraph/__init__.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/__init__.py Tue Feb 06 11:16:23 2018 +0100 @@ -47,7 +47,12 @@ @subscriber(IObjectAddedEvent, context_selector=IParagraphContainerTarget) def handle_new_paragraphs_container(event): - """Handle new paragraphs container""" + """Handle new paragraphs container + + Subscriber to IObjectAddedEvent for objects implementing IParagraphContainerTarget: when a + new paragraphs container is created (in version 1), automatically create new paragraphs matching + + """ container = IParagraphContainer(event.object) if len(container) > 0: return @@ -78,6 +83,15 @@ title = FieldProperty(IBaseParagraph['title']) +@implementer(IParagraphFactory) +class BaseParagraphFactory(object): + """Base paragraph factory class""" + + name = None + content_type = None + custom_menu = False + + class BaseParagraphContentChecker(BaseContentChecker): """Base paragraph content checker mixin""" diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/header.py --- a/src/pyams_content/component/paragraph/header.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/header.py Tue Feb 06 11:16:23 2018 +0100 @@ -22,7 +22,7 @@ from pyams_i18n.interfaces import II18n, II18nManager, INegotiator # import packages -from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory from pyams_utils.adapter import adapter_config from pyams_utils.registry import utility_config, get_utility from pyams_utils.text import get_text_start @@ -49,7 +49,7 @@ @utility_config(name='Header', provides=IParagraphFactory) -class HTMLParagraphFactory(object): +class HTMLParagraphFactory(BaseParagraphFactory): """HTML paragraph factory""" name = _("Header paragraph") diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/html.py --- a/src/pyams_content/component/paragraph/html.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/html.py Tue Feb 06 11:16:23 2018 +0100 @@ -22,14 +22,14 @@ from pyams_content.component.illustration.interfaces import IIllustrationTarget from pyams_content.component.links.interfaces import ILinkContainerTarget, IInternalLink, IExternalLink, IMailtoLink from pyams_content.component.paragraph.interfaces import IParagraphFactory -from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph +from pyams_content.component.paragraph.interfaces.html import IRawParagraph, IHTMLParagraph from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE from pyams_i18n.interfaces import II18n, II18nManager, INegotiator from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent # import packages from pyams_content.component.links import InternalLink, ExternalLink, MailtoLink -from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory from pyams_utils.adapter import adapter_config from pyams_utils.registry import utility_config, get_utility from pyams_utils.request import check_request @@ -46,6 +46,54 @@ # +# Raw HTML paragraph +# + +@implementer(IRawParagraph) +class RawParagraph(BaseParagraph): + """Raw HTML paragraph""" + + icon_class = 'fa-code' + icon_hint = _("Raw HTML ") + + body = FieldProperty(IRawParagraph['body']) + + +@utility_config(name='raw', provides=IParagraphFactory) +class RawParagraphFactory(BaseParagraphFactory): + """Raw paragraph factory""" + + name = _("Raw HTML paragraph") + content_type = RawParagraph + custom_menu = True + + +@adapter_config(context=IRawParagraph, provides=IContentChecker) +class RawParagraphContentChecker(BaseParagraphContentChecker): + """Raw HTML paragraph content checker""" + + 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, ) + i18n = II18n(self.context) + for lang in langs: + value = i18n.get_attribute('body', lang, request) + if not value: + field_title = translate(IRawParagraph['body'].title) + if len(langs) == 1: + output.append(translate(MISSING_VALUE).format(field=field_title)) + else: + output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang)) + return output + + +# # HTML paragraph # @@ -54,16 +102,16 @@ """HTML paragraph""" icon_class = 'fa-html5' - icon_hint = _("HTML paragraph") + icon_hint = _("Rich text") body = FieldProperty(IHTMLParagraph['body']) @utility_config(name='HTML', provides=IParagraphFactory) -class HTMLParagraphFactory(object): +class HTMLParagraphFactory(BaseParagraphFactory): """HTML paragraph factory""" - name = _("HTML paragraph") + name = _("Rich text paragraph") content_type = HTMLParagraph diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/interfaces/__init__.py --- a/src/pyams_content/component/paragraph/interfaces/__init__.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/interfaces/__init__.py Tue Feb 06 11:16:23 2018 +0100 @@ -67,6 +67,7 @@ name = Attribute("Factory name") content_type = Attribute("Factory content type") + custom_menu = Attribute("Display factory in 'custom' paragraphs menu") class IParagraphFactorySettings(Interface): diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/interfaces/html.py --- a/src/pyams_content/component/paragraph/interfaces/html.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/interfaces/html.py Tue Feb 06 11:16:23 2018 +0100 @@ -19,17 +19,30 @@ from pyams_content.component.paragraph.interfaces import IBaseParagraph # import packages -from pyams_i18n.schema import I18nHTMLField +from pyams_i18n.schema import I18nHTMLField, I18nTextField from pyams_content import _ # +# Raw HTML paragraph +# + +class IRawParagraph(IBaseParagraph): + """Raw HTML paragraph interface""" + + body = I18nTextField(title=_("Raw HTML code"), + description=_("This HTML code will be used 'as is', without any transformation. Use with " + "care!!"), + required=False) + + +# # HTML paragraph # class IHTMLParagraph(IBaseParagraph): - """HTML body paragraph""" + """Rich text paragraph interface""" body = I18nHTMLField(title=_("Body"), required=False) diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/video.py --- a/src/pyams_content/component/paragraph/video.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/video.py Tue Feb 06 11:16:23 2018 +0100 @@ -25,7 +25,7 @@ from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent # import packages -from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory from pyams_content.component.paragraph.html import check_associations from pyams_file.property import FileProperty from pyams_utils.adapter import adapter_config @@ -52,7 +52,7 @@ @utility_config(name='Video', provides=IParagraphFactory) -class VideoParagraphFactory(object): +class VideoParagraphFactory(BaseParagraphFactory): """Video paragraph factory""" name = _("Video") diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/zmi/html.py --- a/src/pyams_content/component/paragraph/zmi/html.py Tue Feb 06 11:15:55 2018 +0100 +++ b/src/pyams_content/component/paragraph/zmi/html.py Tue Feb 06 11:16:23 2018 +0100 @@ -21,10 +21,9 @@ from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationRenderer from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \ IParagraphSummary -from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph +from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph, IRawParagraph from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION -from pyams_content.shared.common.interfaces import IWfSharedContent from pyams_form.interfaces.form import IInnerForm, IEditFormButtons from pyams_i18n.interfaces import II18n from pyams_skin.interfaces.viewlet import IToolbarAddingMenu @@ -34,14 +33,13 @@ # import packages from pyams_content.component.association.zmi import AssociationsTable -from pyams_content.component.paragraph.html import HTMLParagraph +from pyams_content.component.paragraph.html import HTMLParagraph, RawParagraph from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ BaseParagraphAddMenu, BaseParagraphPropertiesEditForm from pyams_content.component.paragraph.zmi.container import ParagraphContainerTable, \ ParagraphTitleToolbarViewletManager from pyams_pagelet.pagelet import pagelet_config from pyams_template.template import template_config - from pyams_utils.adapter import adapter_config from pyams_utils.traversing import get_parent from pyams_viewlet.viewlet import viewlet_config, BaseContentProvider @@ -55,15 +53,130 @@ # -# HTML paragraph +# Raw HTML paragraph +# + +@viewlet_config(name='add-raw-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView, + layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=999) +class RawParagraphAddMenu(BaseParagraphAddMenu): + """Raw HTML paragraph add menu""" + + label = _("Add raw HTML paragraph...") + label_css_class = 'fa fa-fw fa-code' + url = 'add-raw-paragraph.html' + paragraph_type = 'raw' + + +@pagelet_config(name='add-raw-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +class RawParagraphAddForm(AdminDialogAddForm): + """Raw HTML paragraph add form""" + + legend = _("Add new raw HTML paragraph") + dialog_class = 'modal-large' + icon_css_class = 'fa fa-fw fa-code' + label_css_class = 'control-label col-md-2' + input_css_class = 'col-md-10' + + fields = field.Fields(IRawParagraph).omit('__parent__', '__name__', 'visible') + ajax_handler = 'add-raw-paragraph.json' + edit_permission = MANAGE_CONTENT_PERMISSION + + def updateWidgets(self, prefix=None): + super(RawParagraphAddForm, self).updateWidgets(prefix) + if 'body' in self.widgets: + self.widgets['body'].widget_css_class = 'textarea height-100' + + def create(self, data): + return RawParagraph() + + def add(self, object): + IParagraphContainer(self.context).append(object) + + +@view_config(name='add-raw-paragraph.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +class RawParagraphAJAXAddForm(BaseParagraphAJAXAddForm, RawParagraphAddForm): + """Raw HTML paragraph add form, JSON renderer""" + + +@pagelet_config(name='properties.html', context=IRawParagraph, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +class RawParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm): + """Raw HTML paragraph properties edit form""" + + legend = _("Edit raw HTML paragraph properties") + icon_css_class = 'fa fa-fw fa-code' + + fields = field.Fields(IRawParagraph).omit('__parent__', '__name__', 'visible') + ajax_handler = 'properties.json' + edit_permission = MANAGE_CONTENT_PERMISSION + + def updateWidgets(self, prefix=None): + super(RawParagraphPropertiesEditForm, self).updateWidgets(prefix) + if 'body' in self.widgets: + self.widgets['body'].widget_css_class = 'textarea height-100' + + +@view_config(name='properties.json', context=IRawParagraph, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +class RawParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, RawParagraphPropertiesEditForm): + """Raw HTML paragraph properties edit form, JSON renderer""" + + +@adapter_config(context=(IRawParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) +@implementer(IInnerForm) +class RawParagraphInnerEditForm(RawParagraphPropertiesEditForm): + """Raw HTML paragraph inner edit 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=IRawParagraph, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +class RawParagraphInnerAJAXEditForm(BaseParagraphAJAXEditForm, RawParagraphInnerEditForm): + """Raw HTML paragraph inner edit form, JSON renderer""" + + +# +# Raw HTML paragraph summary +# + +@adapter_config(context=(IRawParagraph, IPyAMSLayer), provides=IParagraphSummary) +@template_config(template='templates/raw-summary.pt', layer=IPyAMSLayer) +class RawParagraphSummary(BaseContentProvider): + """Raw HTML paragraph summary""" + + language = None + + def update(self): + i18n = II18n(self.context) + if self.language: + for attr in ('title', 'body'): + setattr(self, attr, i18n.get_attribute(attr, self.language, request=self.request)) + else: + for attr in ('title', 'body'): + setattr(self, attr, i18n.query_attribute(attr, request=self.request)) + + +# +# Rich text paragraph # @viewlet_config(name='add-html-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView, layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=50) class HTMLParagraphAddMenu(BaseParagraphAddMenu): - """HTML paragraph add menu""" + """Rich text paragraph add menu""" - label = _("Add HTML paragraph...") + label = _("Add rich text paragraph...") label_css_class = 'fa fa-fw fa-html5' url = 'add-html-paragraph.html' paragraph_type = 'HTML' @@ -72,9 +185,9 @@ @pagelet_config(name='add-html-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) class HTMLParagraphAddForm(AdminDialogAddForm): - """HTML paragraph add form""" + """Rich text paragraph add form""" - legend = _("Add new HTML paragraph") + legend = _("Add new rich text paragraph") dialog_class = 'modal-max' icon_css_class = 'fa fa-fw fa-html5' label_css_class = 'control-label col-md-2' @@ -99,15 +212,15 @@ @view_config(name='add-html-paragraph.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) class HTMLParagraphAJAXAddForm(BaseParagraphAJAXAddForm, HTMLParagraphAddForm): - """HTML paragraph add form, JSON renderer""" + """Rich text paragraph add form, JSON renderer""" @pagelet_config(name='properties.html', context=IHTMLParagraph, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) class HTMLParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm): - """HTML paragraph properties edit form""" + """Rich text paragraph properties edit form""" - legend = _("Edit HTML paragraph properties") + legend = _("Edit rich text paragraph properties") dialog_class = 'modal-max' icon_css_class = 'fa fa-fw fa-html5' label_css_class = 'control-label col-md-2' @@ -128,13 +241,13 @@ class IHTMLParagraphInnerEditForm(Interface): - """Marker interface for HTML paragraph inner form""" + """Marker interface for rich text paragraph inner form""" @view_config(name='properties.json', context=IHTMLParagraph, request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) class HTMLParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, HTMLParagraphPropertiesEditForm): - """HTML paragraph properties edit form, JSON renderer""" + """Rich text paragraph properties edit form, JSON renderer""" def get_ajax_output(self, changes): output = super(HTMLParagraphPropertiesAJAXEditForm, self).get_ajax_output(changes) @@ -169,7 +282,7 @@ @adapter_config(context=(IHTMLParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) @implementer(IInnerForm, IPropertiesEditForm, IAssociationsParentForm, IHTMLParagraphInnerEditForm) class HTMLParagraphInnerEditForm(HTMLParagraphPropertiesEditForm): - """HTML paragraph inner edit form""" + """Rich text paragraph inner edit form""" legend = None ajax_handler = 'inner-properties.json' @@ -185,7 +298,7 @@ @view_config(name='inner-properties.json', context=IHTMLParagraph, request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) class HTMLParagraphInnerAJAXEditForm(BaseParagraphAJAXEditForm, HTMLParagraphInnerEditForm): - """HTML paragraph inner edit form, JSON renderer""" + """Rich text paragraph inner edit form, JSON renderer""" def get_ajax_output(self, changes): output = super(HTMLParagraphInnerAJAXEditForm, self).get_ajax_output(changes) @@ -218,13 +331,13 @@ # -# HTML paragraph summary +# rich text paragraph summary # @adapter_config(context=(IHTMLParagraph, IPyAMSLayer), provides=IParagraphSummary) @template_config(template='templates/html-summary.pt', layer=IPyAMSLayer) class HTMLParagraphSummary(BaseContentProvider): - """HTML paragraph summary""" + """Rich text paragraph summary""" illustration = None illustration_renderer = None diff -r 871c7cb35fd6 -r 5dce53509832 src/pyams_content/component/paragraph/zmi/templates/raw-summary.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/paragraph/zmi/templates/raw-summary.pt Tue Feb 06 11:16:23 2018 +0100 @@ -0,0 +1,2 @@ +

title

+
body