src/pyams_skin/metas.py
changeset 474 7bb070e90138
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/metas.py	Wed Dec 05 13:13:47 2018 +0100
@@ -0,0 +1,199 @@
+#
+# 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'
+
+from pyramid.interfaces import IRequest
+from zope.interface import Interface, implementer
+
+from pyams_i18n.interfaces import II18n
+from pyams_skin.interfaces.configuration import IConfiguration
+from pyams_skin.interfaces.extension import IGoogleAnalyticsInfo
+from pyams_skin.interfaces.metas import IHTMLContentMetas, IMetaHeader
+from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
+from pyams_utils.interfaces.site import ISiteRoot
+from pyams_utils.interfaces.tales import ITALESExtension
+
+
+#
+# 'metas' TALES extension
+#
+
+@adapter_config(name='metas', context=(Interface, IRequest, Interface), provides=ITALESExtension)
+class MetasTalesExtension(ContextRequestViewAdapter):
+    """extension:metas TALES extension"""
+
+    def render(self, context=None):
+        if context is None:
+            context = self.context
+        result = []
+        for name, adapter in sorted(self.request.registry.getAdapters((context, self.request, self.view),
+                                                                      IHTMLContentMetas),
+                                    key=lambda x: getattr(x[1], 'order', 9999)):
+            result.extend([meta.render() for meta in adapter.get_metas()])
+        return '\n\t'.join(result)
+
+
+#
+# Custom metas headers
+#
+
+@implementer(IMetaHeader)
+class HTMLTagMeta(object):
+    """HTML tag meta header"""
+
+    def __init__(self, tag, content, **attrs):
+        self.tag = tag
+        self.content = content
+        self.attrs = attrs
+
+    def render(self):
+        return '''<{tag} {attrs}>{content}</{tag}>'''.format(tag=self.tag,
+                                                             attrs=' '.join(('{0}="{1}"'.format(*value) for value in
+                                                                             self.attrs.items())),
+                                                             content=self.content)
+
+
+@implementer(IMetaHeader)
+class HTTPEquivMeta(object):
+    """HTTP-Equiv meta header"""
+
+    def __init__(self, http_equiv, value):
+        self.http_equiv = http_equiv
+        self.value = value
+
+    def render(self):
+        return '''<meta http-equiv="{http_equiv}" content="{value}" />'''.format(http_equiv=self.http_equiv,
+                                                                                 value=self.value)
+
+
+@implementer(IMetaHeader)
+class ValueMeta(object):
+    """Basic value meta header"""
+
+    def __init__(self, name, value):
+        self.name = name
+        self.value = value
+
+    def render(self):
+        return '''<meta {name}="{value}" />'''.format(name=self.name,
+                                                      value=self.value)
+
+
+@implementer(IMetaHeader)
+class ContentMeta(object):
+    """Content meta header"""
+
+    def __init__(self, name, value):
+        self.name = name
+        self.value = value
+
+    def render(self):
+        return '''<meta name="{name}" content="{value}" />'''.format(name=self.name,
+                                                                     value=self.value)
+
+
+@implementer(IMetaHeader)
+class PropertyMeta(object):
+    """Property meta header"""
+
+    def __init__(self, property, value):
+        self.property = property
+        self.value = value
+
+    def render(self):
+        return '''<meta property="{property}" content="{value}" />'''.format(property=self.property,
+                                                                             value=self.value)
+
+
+@implementer(IMetaHeader)
+class LinkMeta(object):
+    """Link meta header"""
+
+    def __init__(self, rel, type, href):
+        self.rel = rel
+        self.type = type
+        self.href = href
+
+    def render(self):
+        return '''<link rel="{rel}" type="{type}" href="{href}" />'''.format(rel=self.rel,
+                                                                             type=self.type,
+                                                                             href=self.href)
+
+
+#
+# Default metas headers
+#
+
+@adapter_config(name='layout', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
+class LayoutMetasAdapter(ContextRequestViewAdapter):
+    """Basic layout metas adapter"""
+
+    order = -1
+
+    @staticmethod
+    def get_metas():
+        yield HTTPEquivMeta('X-UA-Compatible', 'IE=edge,chrome=1')
+        yield ContentMeta('HandheldFriendly', 'True')
+        yield ContentMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no')
+
+
+@adapter_config(name='title', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
+class TitleMetasAdapter(ContextRequestViewAdapter):
+    """Title metas adapter"""
+
+    order = 1
+
+    def get_metas(self):
+        title = II18n(self.context).query_attribute('title', request=self.request)
+        yield HTMLTagMeta('title', title)
+
+
+@adapter_config(name='title', context=(ISiteRoot, Interface, Interface), provides=IHTMLContentMetas)
+class SiteRootTitleMetasAdapter(ContextRequestViewAdapter):
+    """Site root title metas adapter"""
+
+    order = 1
+
+    def get_metas(self):
+        config = IConfiguration(self.context)
+        yield HTMLTagMeta('title', config.title)
+        yield ContentMeta('description', config.description)
+
+
+@adapter_config(name='content-type', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
+class ContentTypeMetasAdapter(ContextRequestViewAdapter):
+    """Content-type metas adapter"""
+
+    order = 10
+
+    @staticmethod
+    def get_metas():
+        yield HTTPEquivMeta('Content-Type', 'text/html; charset=utf-8')
+        yield ValueMeta('charset', 'utf-8')
+
+
+@adapter_config(name='analytics', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
+class VerificationCodeMetasAdapter(ContextRequestViewAdapter):
+    """Google verification code metas adapter"""
+
+    order = 20
+
+    def __new__(cls, context, request, view):
+        info = IGoogleAnalyticsInfo(request.root)
+        if not info.verification_code:
+            return None
+        return ContextRequestViewAdapter.__new__(cls)
+
+    def get_metas(self):
+        info = IGoogleAnalyticsInfo(self.request.root)
+        yield ContentMeta('google-site-verification', info.verification_code)