Added HTML paragraph renderer including logo
authorThierry Florac <tflorac@ulthar.net>
Fri, 13 Nov 2020 13:23:00 +0100
changeset 529 43de10a58806
parent 528 45eb6e5705c0
child 530 094d9b11bc83
Added HTML paragraph renderer including logo
src/pyams_default_theme/component/paragraph/html.py
src/pyams_default_theme/component/paragraph/interfaces/html.py
src/pyams_default_theme/component/paragraph/templates/html-logos.pt
--- a/src/pyams_default_theme/component/paragraph/html.py	Mon Sep 28 15:50:58 2020 +0200
+++ b/src/pyams_default_theme/component/paragraph/html.py	Fri Nov 13 13:23:00 2020 +0100
@@ -11,18 +11,27 @@
 #
 
 from fanstatic import ConfigurationError
+from persistent import Persistent
+from zope.location import Location
+from zope.schema.fieldproperty import FieldProperty
 
 from pyams_content.component.illustration import IIllustration
+from pyams_content.component.links import InternalReferenceMixin
 from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph, IRawParagraph
 from pyams_content.features.renderer.interfaces import IContentRenderer
 from pyams_default_theme import library
+from pyams_default_theme.component.paragraph.interfaces.html import \
+    IHTMLParagraphWithLogosRendererSettings
 from pyams_default_theme.features.renderer import BaseContentRenderer
+from pyams_default_theme.shared.logo import DISABLED_LINK, INTERNAL_FIRST
 from pyams_skin.layer import IPyAMSLayer
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config, get_annotation_adapter
+from pyams_utils.factory import factory_config
 from pyams_utils.fanstatic import ExternalResource
 from pyams_utils.interfaces.text import IHTMLRenderer
 from pyams_utils.pygments import IPygmentsCodeConfiguration, render_source
+from pyams_utils.url import canonical_url, relative_url
 
 
 __docformat__ = 'restructuredtext'
@@ -139,6 +148,7 @@
     """HTML paragraph default renderer"""
 
     label = _("Default rich text renderer")
+    weight = 10
 
     i18n_context_attrs = ('title', 'body',)
 
@@ -152,3 +162,69 @@
             renderer = self.illustration_renderer = self.illustration.get_renderer(self.request)
             if renderer is not None:
                 renderer.update()
+
+
+#
+# HTML paragraph renderer with logos
+#
+
+HTML_PARAGRAPH_WITH_LOGOS_RENDERER_SETTINGS_KEY = 'pyams_content.html.renderer:text-with-logos'
+
+
+@factory_config(IHTMLParagraphWithLogosRendererSettings)
+class HTMLParagraphWithLogosRendererSettings(Persistent, Location, InternalReferenceMixin):
+    """HTML paragraph with logos renderer settings"""
+
+    reference = FieldProperty(IHTMLParagraphWithLogosRendererSettings['reference'])
+    position = FieldProperty(IHTMLParagraphWithLogosRendererSettings['position'])
+    target_priority = FieldProperty(IHTMLParagraphWithLogosRendererSettings['target_priority'])
+    force_canonical_url = FieldProperty(IHTMLParagraphWithLogosRendererSettings['force_canonical_url'])
+
+
+@adapter_config(context=IHTMLParagraph, provides=IHTMLParagraphWithLogosRendererSettings)
+def html_paragraph_with_logos_renderer_settings_factory(context):
+    """HTML paragraph with logos renderer settings factory"""
+    return get_annotation_adapter(context, HTML_PARAGRAPH_WITH_LOGOS_RENDERER_SETTINGS_KEY,
+                                  IHTMLParagraphWithLogosRendererSettings)
+
+
+@adapter_config(name='text-with-logos',
+                context=(IHTMLParagraph, IPyAMSLayer),
+                provides=IContentRenderer)
+@template_config(template='templates/html-logos.pt', layer=IPyAMSLayer)
+class HTMLParagraphWithLogosRenderer(HTMLParagraphDefaultRenderer):
+    """HTML paragraph renderer with logos"""
+
+    label = _("Rich text renderer with logos")
+    weight = 20
+
+    settings_interface = IHTMLParagraphWithLogosRendererSettings
+
+    def get_internal_url(self, logo):
+        if logo is not None:
+            if self.settings.force_canonical_url:
+                url_getter = canonical_url
+            else:
+                url_getter = relative_url
+            return url_getter(logo, request=self.request)
+        return None
+
+    @staticmethod
+    def get_external_url(logo):
+        return logo.url
+
+    def get_logo_url(self):
+        priority = self.settings.target_priority
+        if priority == DISABLED_LINK:
+            return None
+        logo = self.settings.target
+        if logo is None:
+            return None
+        order = [self.get_external_url, self.get_internal_url]
+        if priority == INTERNAL_FIRST:
+            order = reversed(order)
+        for getter in order:
+            result = getter(logo)
+            if result is not None:
+                return result
+        return None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/component/paragraph/interfaces/html.py	Fri Nov 13 13:23:00 2020 +0100
@@ -0,0 +1,76 @@
+#
+# Copyright (c) 2015-2020 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.
+#
+
+"""PyAMS_default_theme.component  module
+
+"""
+
+from zope.schema import Bool, Choice
+from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
+
+from pyams_content.shared.logo import LOGO_CONTENT_TYPE
+from pyams_default_theme.shared.logo.interfaces import EXTERNAL_FIRST, TARGET_PRIORITY_VOCABULARY
+from pyams_sequence.interfaces import IInternalReference
+from pyams_sequence.schema import InternalReferenceField
+
+
+__docformat__ = 'restructuredtext'
+
+from pyams_default_theme import _
+
+
+ABOVE_ALIGN = 'above'
+LEFT_ALIGN = 'left'
+RIGHT_ALIGN = 'right'
+BELOW_ALIGN = 'below'
+
+LOGO_POSITION = (
+    {'id': ABOVE_ALIGN, 'title': _("Centered above text")},
+    {'id': LEFT_ALIGN, 'title': _("Left aligned (default)")},
+    {'id': RIGHT_ALIGN, 'title': _("Right aligned")},
+    {'id': BELOW_ALIGN, 'title': _("Centered below text")}
+)
+
+LOGO_POSITION_VOCABULARY = SimpleVocabulary([SimpleTerm(item['id'], title=item['title'])
+                                             for item in LOGO_POSITION])
+
+
+class IHTMLParagraphWithLogosRendererSettings(IInternalReference):
+    """HTML paragraph with logos renderer settings interface"""
+
+    reference = InternalReferenceField(title=_("Selected logo"),
+                                       description=_("Selected logo. You can "
+                                                     "search a reference using '+' followed by "
+                                                     "internal number, of by entering text "
+                                                     "matching content title."),
+                                       content_type=LOGO_CONTENT_TYPE,
+                                       required=True)
+
+    position = Choice(title=_("Logo position"),
+                      required=True,
+                      vocabulary=LOGO_POSITION_VOCABULARY,
+                      default=LEFT_ALIGN)
+
+    target_priority = Choice(title=_("Links priority"),
+                             description=_("Order in which internal and external links are "
+                                           "evaluated on logo"),
+                             required=True,
+                             vocabulary=TARGET_PRIORITY_VOCABULARY,
+                             default=EXTERNAL_FIRST)
+
+    force_canonical_url = Bool(title=_("Force canonical URL"),
+                               description=_("By default, internal links use a \"relative\" URL, "
+                                             "which tries to display link target in the current "
+                                             "context; by using a canonical URL, you can display "
+                                             "target in it's attachment context (if defined)"),
+                               required=False,
+                               default=False)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/component/paragraph/templates/html-logos.pt	Fri Nov 13 13:23:00 2020 +0100
@@ -0,0 +1,83 @@
+<tal:var define="renderer view.illustration_renderer;
+				 settings view.settings;
+				 position getattr(renderer, 'position', None) if renderer is not None else None;"
+		 switch="position">
+	<tal:var case="'before-title'">${structure:renderer.render()}</tal:var>
+	<h2 tal:define="title view.title"
+		tal:condition="title and (position != 'before-title')">${title}</h2>
+	<tal:var case="'before-body'">${structure:renderer.render()}</tal:var>
+	<tal:var define="logo settings.target"
+			 switch="logo is None">
+		<tal:if case="True">
+			<div>${structure:tales:html(view.body, 'oid_to_href;glossary')}</div>
+		</tal:if>
+		<tal:if case="False">
+			<tal:select define="url view.get_logo_url()"
+						switch="settings.position">
+				<tal:if case="'above'">
+					<div class="row">
+						<div class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-4">
+							<a tal:omit-tag="not:url"
+							   href="${url}" title="${logo.get_title(request)}">
+									${structure:tales:picture(logo.image,
+															  lg_width=2, md_width=2,
+															  sm_width=8, xs_width=8)}
+							</a>
+						</div>
+					</div>
+					<div>
+						${structure:tales:html(view.body, 'oid_to_href;glossary')}
+					</div>
+				</tal:if>
+				<tal:if case="'left'">
+					<div class="row">
+						<div class="col-xs-6 col-xs-offset-3 col-sm-3 col-sm-offset-0 col-md-2">
+							<a tal:omit-tag="not:url"
+							   href="${url}" title="${logo.get_title(request)}">
+								${structure:tales:picture(logo.image,
+														  lg_width=2, md_width=2,
+														  sm_width=2, xs_width=12)}
+							</a>
+						</div>
+						<div class="col-xs-12 col-sm-9 col-md-10">
+							${structure:tales:html(view.body, 'oid_to_href;glossary')}
+						</div>
+					</div>
+				</tal:if>
+				<tal:if case="'right'">
+					<div class="row">
+						<div class="col-xs-12 col-sm-9 col-md-10">
+							${structure:tales:html(view.body, 'oid_to_href;glossary')}
+						</div>
+						<div class="col-xs-6 col-xs-offset-3 col-sm-3 col-sm-offset-0 col-md-2">
+							<a tal:omit-tag="not:url"
+							   href="${url}" title="${logo.get_title(request)}">
+								${structure:tales:picture(logo.image,
+														  lg_width=2, md_width=2,
+														  sm_width=2, xs_width=12)}
+							</a>
+						</div>
+					</div>
+				</tal:if>
+				<tal:if case="'below'">
+					<div>
+						${structure:tales:html(view.body, 'oid_to_href;glossary')}
+					</div>
+					<div class="row">
+						<div class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-4">
+							<a tal:omit-tag="not:url"
+							   href="${url}" title="${logo.get_title(request)}">
+									${structure:tales:picture(logo.image,
+															  lg_width=2, md_width=2,
+															  sm_width=8, xs_width=8)}
+							</a>
+						</div>
+					</div>
+				</tal:if>
+			</tal:select>
+		</tal:if>
+	</tal:var>
+	<tal:var case="'after-body'">${structure:renderer.render()}</tal:var>
+	<div class="clearfix"></div>
+	${structure:provider:pyams.associations}
+</tal:var>