src/pyams_skin/metas.py
changeset 474 7bb070e90138
equal deleted inserted replaced
-1:000000000000 474:7bb070e90138
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 from pyramid.interfaces import IRequest
       
    16 from zope.interface import Interface, implementer
       
    17 
       
    18 from pyams_i18n.interfaces import II18n
       
    19 from pyams_skin.interfaces.configuration import IConfiguration
       
    20 from pyams_skin.interfaces.extension import IGoogleAnalyticsInfo
       
    21 from pyams_skin.interfaces.metas import IHTMLContentMetas, IMetaHeader
       
    22 from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config
       
    23 from pyams_utils.interfaces.site import ISiteRoot
       
    24 from pyams_utils.interfaces.tales import ITALESExtension
       
    25 
       
    26 
       
    27 #
       
    28 # 'metas' TALES extension
       
    29 #
       
    30 
       
    31 @adapter_config(name='metas', context=(Interface, IRequest, Interface), provides=ITALESExtension)
       
    32 class MetasTalesExtension(ContextRequestViewAdapter):
       
    33     """extension:metas TALES extension"""
       
    34 
       
    35     def render(self, context=None):
       
    36         if context is None:
       
    37             context = self.context
       
    38         result = []
       
    39         for name, adapter in sorted(self.request.registry.getAdapters((context, self.request, self.view),
       
    40                                                                       IHTMLContentMetas),
       
    41                                     key=lambda x: getattr(x[1], 'order', 9999)):
       
    42             result.extend([meta.render() for meta in adapter.get_metas()])
       
    43         return '\n\t'.join(result)
       
    44 
       
    45 
       
    46 #
       
    47 # Custom metas headers
       
    48 #
       
    49 
       
    50 @implementer(IMetaHeader)
       
    51 class HTMLTagMeta(object):
       
    52     """HTML tag meta header"""
       
    53 
       
    54     def __init__(self, tag, content, **attrs):
       
    55         self.tag = tag
       
    56         self.content = content
       
    57         self.attrs = attrs
       
    58 
       
    59     def render(self):
       
    60         return '''<{tag} {attrs}>{content}</{tag}>'''.format(tag=self.tag,
       
    61                                                              attrs=' '.join(('{0}="{1}"'.format(*value) for value in
       
    62                                                                              self.attrs.items())),
       
    63                                                              content=self.content)
       
    64 
       
    65 
       
    66 @implementer(IMetaHeader)
       
    67 class HTTPEquivMeta(object):
       
    68     """HTTP-Equiv meta header"""
       
    69 
       
    70     def __init__(self, http_equiv, value):
       
    71         self.http_equiv = http_equiv
       
    72         self.value = value
       
    73 
       
    74     def render(self):
       
    75         return '''<meta http-equiv="{http_equiv}" content="{value}" />'''.format(http_equiv=self.http_equiv,
       
    76                                                                                  value=self.value)
       
    77 
       
    78 
       
    79 @implementer(IMetaHeader)
       
    80 class ValueMeta(object):
       
    81     """Basic value meta header"""
       
    82 
       
    83     def __init__(self, name, value):
       
    84         self.name = name
       
    85         self.value = value
       
    86 
       
    87     def render(self):
       
    88         return '''<meta {name}="{value}" />'''.format(name=self.name,
       
    89                                                       value=self.value)
       
    90 
       
    91 
       
    92 @implementer(IMetaHeader)
       
    93 class ContentMeta(object):
       
    94     """Content meta header"""
       
    95 
       
    96     def __init__(self, name, value):
       
    97         self.name = name
       
    98         self.value = value
       
    99 
       
   100     def render(self):
       
   101         return '''<meta name="{name}" content="{value}" />'''.format(name=self.name,
       
   102                                                                      value=self.value)
       
   103 
       
   104 
       
   105 @implementer(IMetaHeader)
       
   106 class PropertyMeta(object):
       
   107     """Property meta header"""
       
   108 
       
   109     def __init__(self, property, value):
       
   110         self.property = property
       
   111         self.value = value
       
   112 
       
   113     def render(self):
       
   114         return '''<meta property="{property}" content="{value}" />'''.format(property=self.property,
       
   115                                                                              value=self.value)
       
   116 
       
   117 
       
   118 @implementer(IMetaHeader)
       
   119 class LinkMeta(object):
       
   120     """Link meta header"""
       
   121 
       
   122     def __init__(self, rel, type, href):
       
   123         self.rel = rel
       
   124         self.type = type
       
   125         self.href = href
       
   126 
       
   127     def render(self):
       
   128         return '''<link rel="{rel}" type="{type}" href="{href}" />'''.format(rel=self.rel,
       
   129                                                                              type=self.type,
       
   130                                                                              href=self.href)
       
   131 
       
   132 
       
   133 #
       
   134 # Default metas headers
       
   135 #
       
   136 
       
   137 @adapter_config(name='layout', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
       
   138 class LayoutMetasAdapter(ContextRequestViewAdapter):
       
   139     """Basic layout metas adapter"""
       
   140 
       
   141     order = -1
       
   142 
       
   143     @staticmethod
       
   144     def get_metas():
       
   145         yield HTTPEquivMeta('X-UA-Compatible', 'IE=edge,chrome=1')
       
   146         yield ContentMeta('HandheldFriendly', 'True')
       
   147         yield ContentMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no')
       
   148 
       
   149 
       
   150 @adapter_config(name='title', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
       
   151 class TitleMetasAdapter(ContextRequestViewAdapter):
       
   152     """Title metas adapter"""
       
   153 
       
   154     order = 1
       
   155 
       
   156     def get_metas(self):
       
   157         title = II18n(self.context).query_attribute('title', request=self.request)
       
   158         yield HTMLTagMeta('title', title)
       
   159 
       
   160 
       
   161 @adapter_config(name='title', context=(ISiteRoot, Interface, Interface), provides=IHTMLContentMetas)
       
   162 class SiteRootTitleMetasAdapter(ContextRequestViewAdapter):
       
   163     """Site root title metas adapter"""
       
   164 
       
   165     order = 1
       
   166 
       
   167     def get_metas(self):
       
   168         config = IConfiguration(self.context)
       
   169         yield HTMLTagMeta('title', config.title)
       
   170         yield ContentMeta('description', config.description)
       
   171 
       
   172 
       
   173 @adapter_config(name='content-type', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
       
   174 class ContentTypeMetasAdapter(ContextRequestViewAdapter):
       
   175     """Content-type metas adapter"""
       
   176 
       
   177     order = 10
       
   178 
       
   179     @staticmethod
       
   180     def get_metas():
       
   181         yield HTTPEquivMeta('Content-Type', 'text/html; charset=utf-8')
       
   182         yield ValueMeta('charset', 'utf-8')
       
   183 
       
   184 
       
   185 @adapter_config(name='analytics', context=(Interface, Interface, Interface), provides=IHTMLContentMetas)
       
   186 class VerificationCodeMetasAdapter(ContextRequestViewAdapter):
       
   187     """Google verification code metas adapter"""
       
   188 
       
   189     order = 20
       
   190 
       
   191     def __new__(cls, context, request, view):
       
   192         info = IGoogleAnalyticsInfo(request.root)
       
   193         if not info.verification_code:
       
   194             return None
       
   195         return ContextRequestViewAdapter.__new__(cls)
       
   196 
       
   197     def get_metas(self):
       
   198         info = IGoogleAnalyticsInfo(self.request.root)
       
   199         yield ContentMeta('google-site-verification', info.verification_code)