--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/interfaces/metas.py Wed Jun 15 12:27:22 2016 +0200
@@ -0,0 +1,34 @@
+#
+# 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'
+
+# import standard library
+
+# import interfaces
+
+# import packages
+from zope.interface import Interface
+
+
+class IMetaHeader(Interface):
+ """Meta HTML header"""
+
+ def render(self):
+ """Render META header"""
+
+
+class IHTMLContentMetas(Interface):
+ """Get list of metas headers associated with given context"""
+
+ def get_metas(self):
+ """Get content metas"""
--- a/src/pyams_skin/interfaces/templates/fullpage-layout.pt Wed Jun 15 12:26:42 2016 +0200
+++ b/src/pyams_skin/interfaces/templates/fullpage-layout.pt Wed Jun 15 12:27:22 2016 +0200
@@ -1,16 +1,13 @@
<!DOCTYPE html>
-<html lang="fr-FR"
+<html lang="en" i18n:domain="pyams_skin"
tal:define="config extension:back_configuration;
static extension:static_configuration;"
tal:attributes="lang request.locale_name">
<head>
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta charset="utf-8">
+ <tal:var replace="structure extension:metas" />
- <title tal:content="view.title | context.title | config.title | nothing"></title>
-
- <meta name="HandheldFriendly" content="True">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+ <title tal:attributes="data-ams-title-prefix config.get_title_prefix(request)"
+ tal:content="view.title | context.title | config.title | nothing"></title>
<tal:if define="icon config.icon | nothing; url extension:absolute_url(icon);" condition="icon">
<!-- Favorite icon -->
@@ -26,7 +23,7 @@
<!-- Content -->
<div id="content" style="opacity: 1;">
<!--[if lt IE 9]>
- <h1>Votre navigateur est trop ancien. Veuillez installer une version 9 ou supérieure d'Internet Explorer.</h1>
+ <h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
<![endif]-->
<tal:var content="structure provider:pagelet" />
</div>
--- a/src/pyams_skin/interfaces/templates/fullpage-modal-layout.pt Wed Jun 15 12:26:42 2016 +0200
+++ b/src/pyams_skin/interfaces/templates/fullpage-modal-layout.pt Wed Jun 15 12:27:22 2016 +0200
@@ -1,16 +1,13 @@
<!DOCTYPE html>
-<html lang="fr-FR"
+<html lang="en" i18n:domain="pyams_skin"
tal:define="config extension:back_configuration;
static extension:static_configuration;"
tal:attributes="lang request.locale_name">
<head>
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta charset="utf-8">
+ <tal:var replace="structure extension:metas" />
- <title tal:content="view.title | context.title | config.title | nothing"></title>
-
- <meta name="HandheldFriendly" content="True">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+ <title tal:attributes="data-ams-title-prefix config.get_title_prefix(request)"
+ tal:content="view.title | context.title | config.title | nothing"></title>
<tal:if define="icon config.icon | nothing; url extension:absolute_url(icon);" condition="icon">
<!-- Favorite icon -->
@@ -26,7 +23,7 @@
<!-- Content -->
<div id="content" style="opacity: 1;">
<!--[if lt IE 9]>
- <h1>Your browser is too old. Please use Internet Explorer version 9 or later.</h1>
+ <h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
<![endif]-->
<div class="modal-dialog modal-medium"
tal:attributes="class string:modal-dialog ${view.dialog_class | 'modal-medium'}">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/metas.py Wed Jun 15 12:27:22 2016 +0200
@@ -0,0 +1,162 @@
+#
+# 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'
+
+
+# import standard library
+
+# import interfaces
+from pyams_skin.interfaces.extension import IGoogleAnalyticsInfo
+from pyams_skin.interfaces.metas import IHTMLContentMetas, IMetaHeader
+from pyams_utils.interfaces.tales import ITALESExtension
+from pyramid.interfaces import IRequest
+
+# import packages
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from zope.interface import implementer, Interface
+
+
+#
+# '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 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='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)
--- a/src/pyams_skin/templates/layout.pt Wed Jun 15 12:26:42 2016 +0200
+++ b/src/pyams_skin/templates/layout.pt Wed Jun 15 12:27:22 2016 +0200
@@ -1,19 +1,14 @@
<!DOCTYPE html>
-<html lang="fr"
+<html lang="en" i18n:domain="pyams_skin"
tal:define="config extension:back_configuration;
- static extension:static_configuration;
- userid request.authenticated_userid;"
+ static extension:static_configuration;"
tal:attributes="lang request.locale_name">
<head>
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta charset="utf-8">
+ <tal:var replace="structure extension:metas" />
<title tal:attributes="data-ams-title-prefix config.get_title_prefix(request)"
tal:content="config.title"></title>
- <meta name="HandheldFriendly" content="True">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
-
<tal:if define="icon config.icon | nothing; url extension:absolute_url(icon);" condition="icon">
<!-- Favorite icon -->
<link rel="shortcut icon" tal:attributes="href url" type="image/x-icon">
@@ -23,7 +18,7 @@
<tal:var replace="extension:resources" />
</head>
-<body tal:attributes="class static.body_css_class" i18n:domain="pyams_skin">
+<body tal:attributes="class static.body_css_class">
<!-- Page header -->
<header id="header">