--- 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"""
--- 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")
--- 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
--- 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):
--- 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)
--- 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")
--- 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
--- /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 @@
+<h3 tal:content="view.title">title</h3>
+<div tal:content="structure view.body">body</div>