src/pyams_skin/metas.py
changeset 517 bc05061ceebb
parent 516 f4bd4666c8d2
child 520 f810009afcc6
--- a/src/pyams_skin/metas.py	Tue Jan 29 10:48:24 2019 +0100
+++ b/src/pyams_skin/metas.py	Tue Jan 29 15:55:17 2019 +0100
@@ -21,9 +21,11 @@
 from pyams_skin.interfaces.configuration import IConfiguration
 from pyams_skin.interfaces.extension import IGoogleAnalyticsInfo
 from pyams_skin.interfaces.metas import IHTMLContentMetas, IMetaHeader
+from pyams_skin.layer import IPyAMSUserLayer
 from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
 from pyams_utils.interfaces.site import ISiteRoot
 from pyams_utils.interfaces.tales import ITALESExtension
+from pyams_utils.url import canonical_url
 
 
 #
@@ -54,102 +56,69 @@
 
 
 @implementer(IMetaHeader)
-class HTMLTagMeta(object):
+class BaseMeta(object):
+    """Base HTML meta header"""
+    
+    def __init__(self, tag='meta', value=None, **attrs):
+        self.tag = tag
+        self.value = value
+        self.attrs = attrs
+        
+    def render(self):
+        attributes = ' '.join(('{}="{}"'.format(k, v) for k, v in self.attrs.items()))
+        if self.value:
+            return '<{0} {1}>{2}</{0}>'.format(self.tag, attributes, self.value)
+        else:
+            return '<{} {} />'.format(self.tag, attributes)
+        
+    
+class HTMLTagMeta(BaseMeta):
     """HTML tag meta header"""
 
     def __init__(self, tag, content, **attrs):
-        self.tag = tag
-        self.content = escape_value(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)
+        super(HTMLTagMeta, self).__init__(tag, content, **attrs)
 
 
-@implementer(IMetaHeader)
-class HTTPEquivMeta(object):
+class HTTPEquivMeta(BaseMeta):
     """HTTP-Equiv meta header"""
 
     def __init__(self, http_equiv, value):
-        self.http_equiv = http_equiv
-        self.value = escape_value(value)
-
-    def render(self):
-        return '''<meta http-equiv="{http_equiv}" content="{value}" />'''.format(http_equiv=self.http_equiv,
-                                                                                 value=self.value)
+        super(HTTPEquivMeta, self).__init__(**{'http-equiv': http_equiv, 'content': escape_value(value)})
 
 
-@implementer(IMetaHeader)
-class ValueMeta(object):
+class ValueMeta(BaseMeta):
     """Basic value meta header"""
 
     def __init__(self, name, value):
-        self.name = name
-        self.value = escape_value(value)
-
-    def render(self):
-        return '''<meta {name}="{value}" />'''.format(name=self.name,
-                                                      value=self.value)
+        super(ValueMeta, self).__init__(**{name: escape_value(value)})
 
 
-@implementer(IMetaHeader)
-class ContentMeta(object):
+class ContentMeta(BaseMeta):
     """Content meta header"""
 
     def __init__(self, name, value):
-        self.name = name
-        self.value = escape_value(value)
-
-    def render(self):
-        return '''<meta name="{name}" content="{value}" />'''.format(name=self.name,
-                                                                     value=self.value)
+        super(ContentMeta, self).__init__(name=name, content=escape_value(value))
 
 
-@implementer(IMetaHeader)
-class PropertyMeta(object):
+class PropertyMeta(BaseMeta):
     """Property meta header"""
 
     def __init__(self, property, value):
-        self.property = property
-        self.value = escape_value(value)
-
-    def render(self):
-        return '''<meta property="{property}" content="{value}" />'''.format(property=self.property,
-                                                                             value=self.value)
+        super(PropertyMeta, self).__init__(property=property, content=escape_value(value))
 
 
-@implementer(IMetaHeader)
-class SchemaMeta(object):
+class SchemaMeta(BaseMeta):
     """Schema.org property meta header"""
 
     def __init__(self, name, value):
-        self.name = name
-        self.value = escape_value(value)
-
-    def render(self):
-        return '''<meta itemprop="{name}" content="{value}" />'''.format(name=self.name,
-                                                                         value=self.value)
+        super(SchemaMeta, self).__init__(itemprop=name, content=escape_value(value))
 
 
-@implementer(IMetaHeader)
-class LinkMeta(object):
+class LinkMeta(BaseMeta):
     """Link meta header"""
 
-    def __init__(self, rel, type, href, title=None):
-        self.rel = rel
-        self.type = type
-        self.href = escape_value(href)
-        self.title = title
-
-    def render(self):
-        title = ' title="{}"'.format(self.title) if self.title else ''
-        return '''<link rel="{rel}" type="{type}" href="{href}" {title} />'''.format(rel=self.rel,
-                                                                                     type=self.type,
-                                                                                     href=self.href,
-                                                                                     title=title)
+    def __init__(self, rel, type, href, **kwargs):
+        super(LinkMeta, self).__init__('link', rel=rel, type=type, href=escape_value(href), **kwargs)
 
 
 #
@@ -192,6 +161,17 @@
         yield ContentMeta('description', config.description)
 
 
+@adapter_config(name='canonical', context=(Interface, IPyAMSUserLayer, Interface), provides=IHTMLContentMetas)
+class CanonicalURLMetasAdapter(ContextRequestViewAdapter):
+    """Canonical URL metas adapter"""
+
+    order = 2
+
+    def get_metas(self):
+        target_url = canonical_url(self.context, self.request).replace('+', '%2B')
+        yield BaseMeta(rel='canonical', href=target_url)
+
+
 @adapter_config(name='content-type', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
 class ContentTypeMetasAdapter(ContextRequestViewAdapter):
     """Content-type metas adapter"""
@@ -204,11 +184,11 @@
         yield ValueMeta('charset', 'utf-8')
 
 
-@adapter_config(name='analytics', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
+@adapter_config(name='google-site-verification', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
 class VerificationCodeMetasAdapter(ContextRequestViewAdapter):
     """Google verification code metas adapter"""
 
-    order = 20
+    order = 11
 
     def __new__(cls, context, request, view):
         info = IGoogleAnalyticsInfo(request.root)