Added PyAMS simple header
authorThierry Florac <thierry.florac@onf.fr>
Tue, 03 Jul 2018 12:18:33 +0200
changeset 66 6c410c0ee25c
parent 65 4ced68ece158
child 67 af7c769f195d
Added PyAMS simple header
src/pyams_default_theme/features/header/__init__.py
src/pyams_default_theme/features/header/interfaces.py
src/pyams_default_theme/features/header/skin/__init__.py
src/pyams_default_theme/features/header/skin/templates/simple-header.pt
src/pyams_default_theme/features/header/zmi/__init__.py
src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.mo
src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po
src/pyams_default_theme/locales/pyams_default_theme.pot
src/pyams_default_theme/resources/css/pyams-default.css
src/pyams_default_theme/resources/css/pyams-default.css.map
src/pyams_default_theme/resources/css/pyams-default.min.css
src/pyams_default_theme/resources/less/pyams-default.less
--- a/src/pyams_default_theme/features/header/__init__.py	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/features/header/__init__.py	Tue Jul 03 12:18:33 2018 +0200
@@ -17,11 +17,21 @@
 
 # import interfaces
 from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderSettings
+from pyams_content.features.menu.interfaces import IMenuLinksContainerTarget, IMenuLinksContainer
+from pyams_default_theme.features.header.interfaces import ISimpleHeaderRendererSettings, ISimpleHeaderTabsMenu
 from pyams_default_theme.layer import IPyAMSDefaultLayer
+from zope.location.interfaces import ISublocations
 
 # import packages
+from persistent import Persistent
+from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY
+from pyams_content.features.menu import Menu
+from pyams_file.property import FileProperty
+from pyams_utils.adapter import get_annotation_adapter, adapter_config, ContextAdapter
 from pyams_utils.traversing import get_parent
 from pyams_viewlet.viewlet import contentprovider_config, ViewContentProvider
+from zope.interface import implementer
+from zope.location import Location, locate
 
 
 @contentprovider_config(name='pyams.header', layer=IPyAMSDefaultLayer)
@@ -42,3 +52,37 @@
         if renderer is None:
             return ''
         return renderer.render()
+
+
+#
+# Simple header renderer settings
+#
+
+SIMPLE_HEADER_TABS_KEY = '{0}::tabs'.format(ASSOCIATION_CONTAINER_KEY)
+
+
+@implementer(ISimpleHeaderRendererSettings, IMenuLinksContainerTarget)
+class SimpleHeaderRendererSettings(Persistent, Location):
+    """Simple header renderer settings"""
+
+    banner = FileProperty(ISimpleHeaderRendererSettings['banner'])
+    logo = FileProperty(ISimpleHeaderRendererSettings['logo'])
+
+    @property
+    def tabs(self):
+        return get_annotation_adapter(self, SIMPLE_HEADER_TABS_KEY, Menu,
+                                      markers=ISimpleHeaderTabsMenu, name='++ass++tabs')
+
+
+@adapter_config(name='tabs', context=ISimpleHeaderRendererSettings, provides=IMenuLinksContainer)
+def simple_header_tabs_links_adapter(context):
+    """Simple header tabs links adapter"""
+    return context.tabs
+
+
+@adapter_config(name='links', context=ISimpleHeaderRendererSettings, provides=ISublocations)
+class SimpleHeaderRendererSettingsSublocations(ContextAdapter):
+    """Simple header renderer settings sub-locations adapter"""
+
+    def sublocations(self):
+        return self.context.tabs.values()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/interfaces.py	Tue Jul 03 12:18:33 2018 +0200
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2008-2018 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_content.features.header.interfaces import IHeaderRendererSettings
+
+# import packages
+from pyams_file.schema import ImageField
+from zope.interface import Interface, Attribute
+
+from pyams_default_theme import _
+
+
+class ISimpleHeaderRendererSettings(IHeaderRendererSettings):
+    """Simple header renderer settings"""
+
+    banner = ImageField(title=_("Banner image"),
+                        description=_("Image displayed as header background"),
+                        required=False)
+
+    logo = ImageField(title=_("Logo"),
+                      description=_("Logo displayed in header"),
+                      required=False)
+
+    tabs = Attribute("Top tabs list")
+
+
+class ISimpleHeaderTabsMenu(Interface):
+    """Simple header menu marker interface"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/skin/__init__.py	Tue Jul 03 12:18:33 2018 +0200
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2008-2018 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_content.component.association.interfaces import IAssociationInfo
+from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderRenderer, IHeaderSettings, \
+    IHeaderRendererSettings
+from pyams_default_theme.features.header.interfaces import ISimpleHeaderRendererSettings
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_content.features.header.skin import BaseHeaderRenderer
+from pyams_default_theme.features.header import SimpleHeaderRendererSettings
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+
+from pyams_default_theme import _
+
+
+SIMPLE_HEADER_RENDERER_NAME = 'PyAMS simple header'
+
+
+#
+# Simple header renderer
+#
+
+@adapter_config(name=SIMPLE_HEADER_RENDERER_NAME, context=(IHeaderTarget, IPyAMSLayer), provides=IHeaderRenderer)
+@adapter_config(name=SIMPLE_HEADER_RENDERER_NAME, context=(IHeaderSettings, IPyAMSLayer), provides=IHeaderRenderer)
+@template_config(template='templates/simple-header.pt', layer=IPyAMSLayer)
+class SimpleHeaderRenderer(BaseHeaderRenderer):
+    """Simple header renderer"""
+
+    name = SIMPLE_HEADER_RENDERER_NAME
+    label = _("PyAMS simple header with banner and tabs")
+    weight = 1
+
+    settings_key = 'PyAMS::simple'
+    settings_interface = ISimpleHeaderRendererSettings
+
+    @staticmethod
+    def get_link_info(link):
+        return IAssociationInfo(link)
+
+
+@adapter_config(context=SimpleHeaderRenderer, provides=IHeaderRendererSettings)
+def simple_header_renderer_settings_factory(context):
+    """Simple header renderer settings factory"""
+    return SimpleHeaderRendererSettings()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/skin/templates/simple-header.pt	Tue Jul 03 12:18:33 2018 +0200
@@ -0,0 +1,24 @@
+<div class="header header-simple"
+	 tal:define="settings view.settings" i18n:domain="pyams_default_theme">
+	<div class="banner">
+		<tal:if define="banner settings.banner"
+				condition="banner">
+			<img class="banner"
+				 tal:define="src extension:absolute_url(banner)"
+				 tal:attributes="src string:${src}?_=${extension:timestamp(banner)}" />
+		</tal:if>
+		<tal:if define="logo settings.logo"
+				condition="logo">
+			<img class="logo"
+				 tal:define="src extension:absolute_url(settings.logo, '++thumb++200x200')"
+				 tal:attributes="src string:${src}?_=${extension:timestamp(logo)}" />
+		</tal:if>
+	</div>
+	<tal:loop repeat="link settings.tabs.get_visible_items()">
+		<a tal:define="info view.get_link_info(link);
+					   href link.get_url(request)"
+		   tal:condition="href"
+		   tal:content="info.user_title"
+		   tal:attributes="href href">Link</a><br />
+	</tal:loop>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/zmi/__init__.py	Tue Jul 03 12:18:33 2018 +0200
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2008-2018 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_default_theme.features.header import ISimpleHeaderRendererSettings, ISimpleHeaderTabsMenu
+from pyams_form.interfaces.form import IInnerSubForm
+from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION
+from pyams_skin.layer import IPyAMSLayer
+from transaction.interfaces import ITransactionManager
+
+# import packages
+from pyams_content.features.header.zmi import HeaderSettingsRendererSettingsEditForm
+from pyams_content.features.menu.zmi import LinksTable, IMenuLinksView, MenuLinksView
+from pyams_skin.event import get_json_widget_refresh_event
+from pyams_utils.adapter import adapter_config
+from pyams_zmi.form import InnerAdminEditForm
+from z3c.form import field
+
+from pyams_default_theme import _
+
+
+@adapter_config(name='simple-header-properties',
+                context=(ISimpleHeaderRendererSettings, IPyAMSLayer, HeaderSettingsRendererSettingsEditForm),
+                provides=IInnerSubForm)
+class SimpleHeaderPropertiesEditForm(InnerAdminEditForm):
+    """Simple header properties edit form"""
+
+    legend = None
+    edit_permission = MANAGE_TEMPLATE_PERMISSION
+    weight = 1
+
+    fields = field.Fields(ISimpleHeaderRendererSettings)
+
+    def get_ajax_output(self, changes):
+        output = super(SimpleHeaderPropertiesEditForm, self).get_ajax_output(changes)
+        updated = changes.get(ISimpleHeaderRendererSettings, ())
+        if updated:
+            ITransactionManager(self.context).commit()
+            if 'banner' in updated:
+                output.setdefault('events', []).append(
+                    get_json_widget_refresh_event(self.context, self.request,
+                                                  SimpleHeaderPropertiesEditForm, 'banner'))
+            if 'logo' in updated:
+                output.setdefault('events', []).append(
+                    get_json_widget_refresh_event(self.context, self.request,
+                                                  SimpleHeaderPropertiesEditForm, 'logo'))
+        return output
+
+
+#
+# Header top tabs table view
+#
+
+class TabsAssociationsTable(LinksTable):
+    """Simple header tabs associations table"""
+
+    associations_name = 'tabs'
+
+
+@adapter_config(name='simple-header-tabs',
+                context=(ISimpleHeaderRendererSettings, IPyAMSLayer, HeaderSettingsRendererSettingsEditForm),
+                provides=IInnerSubForm)
+@adapter_config(name='++ass++tabs', context=(ISimpleHeaderTabsMenu, IPyAMSLayer), provides=IMenuLinksView)
+class SimpleHeaderTabsView(MenuLinksView):
+    """Simple header tabs view"""
+
+    title = _("Top tabs")
+
+    table_class = TabsAssociationsTable
+    weight = 10
Binary file src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.mo has changed
--- a/src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po	Tue Jul 03 12:18:33 2018 +0200
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-20 14:40+0200\n"
+"POT-Creation-Date: 2018-07-03 09:32+0200\n"
 "PO-Revision-Date: 2017-06-07 12:41+0200\n"
 "Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
 "Language-Team: French\n"
@@ -248,6 +248,30 @@
 msgid "Label associated with second level options menu"
 msgstr "Libellé associé au second niveau de sélection"
 
+#: src/pyams_default_theme/features/header/interfaces.py:31
+msgid "Banner image"
+msgstr "Bandeau"
+
+#: src/pyams_default_theme/features/header/interfaces.py:32
+msgid "Image displayed as header background"
+msgstr "Image affichée en tête de page"
+
+#: src/pyams_default_theme/features/header/interfaces.py:35
+msgid "Logo"
+msgstr "Logo"
+
+#: src/pyams_default_theme/features/header/interfaces.py:36
+msgid "Logo displayed in header"
+msgstr "Logo superposé au bandeau"
+
+#: src/pyams_default_theme/features/header/zmi/__init__.py:81
+msgid "Top tabs"
+msgstr "Onglets de navigation"
+
+#: src/pyams_default_theme/features/header/skin/__init__.py:48
+msgid "PyAMS simple header with banner and tabs"
+msgstr "PyAMS: en-tête simple avec bandeau et onglets de navigation"
+
 #~ msgid "Search..."
 #~ msgstr "Chercher..."
 
--- a/src/pyams_default_theme/locales/pyams_default_theme.pot	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/locales/pyams_default_theme.pot	Tue Jul 03 12:18:33 2018 +0200
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-20 14:40+0200\n"
+"POT-Creation-Date: 2018-07-03 09:32+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -230,3 +230,27 @@
 #: ./src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:35
 msgid "Label associated with second level options menu"
 msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:31
+msgid "Banner image"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:32
+msgid "Image displayed as header background"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:35
+msgid "Logo"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:36
+msgid "Logo displayed in header"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/zmi/__init__.py:81
+msgid "Top tabs"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/skin/__init__.py:48
+msgid "PyAMS simple header with banner and tabs"
+msgstr ""
--- a/src/pyams_default_theme/resources/css/pyams-default.css	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/resources/css/pyams-default.css	Tue Jul 03 12:18:33 2018 +0200
@@ -1,3 +1,19 @@
+body {
+  max-width: 950px;
+  margin: 0 auto;
+}
+body .header-simple .banner {
+  position: relative;
+}
+body .header-simple .banner img.banner {
+  width: 100%;
+}
+body .header-simple .banner img.logo {
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  max-height: calc(80%);
+}
 @media only screen and (min-width: 1200px) {
   .portal-page .slot.col-lg-0 {
     display: none;
@@ -18,3 +34,4 @@
     display: none;
   }
 }
+/*# sourceMappingURL=pyams-default.css.map */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/resources/css/pyams-default.css.map	Tue Jul 03 12:18:33 2018 +0200
@@ -0,0 +1,1 @@
+{"version":3,"sources":["../less/pyams-default.less"],"names":[],"mappings":"AAAA;EACC,gBAAA;EACA,cAAA;;AAFD,IAIC,eACC;EACC,kBAAA;;AAGC,IALH,eACC,QAGC,IACE;EACA,WAAA;;AAED,IARH,eACC,QAGC,IAIE;EACA,kBAAA;EACA,SAAA;EACA,UAAA;EACA,YAAY,SAAZ;;AAUH,wBAA2C;EAC1C,YAFF,MAEG;IACA,aAAA;;;AAGF,wBAA0C,uBAAwB;EACjE,YAPF,MAOG;IACA,aAAA;;;AAGF,wBAA0C,uBAAuB;EAChE,YAZF,MAYG;IACA,aAAA;;;AAGF,wBAA0C;EACzC,YAjBF,MAiBG;IACA,aAAA","file":"pyams-default.css"}
\ No newline at end of file
--- a/src/pyams_default_theme/resources/css/pyams-default.min.css	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/resources/css/pyams-default.min.css	Tue Jul 03 12:18:33 2018 +0200
@@ -1,1 +1,1 @@
-@media only screen and (min-width:1200px){.portal-page .slot.col-lg-0{display:none}}@media only screen and (min-width:992px) and (max-width:1199px){.portal-page .slot.col-md-0{display:none}}@media only screen and (min-width:768px) and (max-width:991px){.portal-page .slot.col-sm-0{display:none}}@media only screen and (max-width:767px){.portal-page .slot.col-xs-0{display:none}}
\ No newline at end of file
+body{max-width:950px;margin:0 auto}body .header-simple .banner{position:relative}body .header-simple .banner img.banner{width:100%}body .header-simple .banner img.logo{position:absolute;top:10px;left:10px;max-height:calc(80%)}@media only screen and (min-width:1200px){.portal-page .slot.col-lg-0{display:none}}@media only screen and (min-width:992px) and (max-width:1199px){.portal-page .slot.col-md-0{display:none}}@media only screen and (min-width:768px) and (max-width:991px){.portal-page .slot.col-sm-0{display:none}}@media only screen and (max-width:767px){.portal-page .slot.col-xs-0{display:none}}
--- a/src/pyams_default_theme/resources/less/pyams-default.less	Mon Jul 02 17:13:16 2018 +0200
+++ b/src/pyams_default_theme/resources/less/pyams-default.less	Tue Jul 03 12:18:33 2018 +0200
@@ -1,3 +1,26 @@
+body {
+	max-width: 950px;
+	margin: 0 auto;
+
+	.header-simple {
+		.banner {
+			position: relative;
+
+			img {
+				&.banner {
+					width: 100%;
+				}
+				&.logo {
+					position: absolute;
+					top: 10px;
+					left: 10px;
+					max-height: calc(100% - 20px);
+				}
+			}
+		}
+	}
+}
+
 .portal-page {
 
 	.slot {