Use jinja to display the header and the side boxes
authorJuliette Belin <juliette.belin@logilab.fr>
Fri, 03 Feb 2017 13:47:58 +0100
changeset 50 df90f18336c3
parent 36 9956f59f05f9
child 51 954fb42ee5fb
Use jinja to display the header and the side boxes
__pkginfo__.py
data/cubes.sherpa.css
data/images/logo_SHERPA_2.png
uiprops.py
views/__init__.py
views/homepage.py
views/templates.py
views/templates/maintemplate.jinja2
views/urls.py
--- a/__pkginfo__.py	Fri Jan 20 17:05:49 2017 +0100
+++ b/__pkginfo__.py	Fri Feb 03 13:47:58 2017 +0100
@@ -23,6 +23,7 @@
     'cubicweb-seda': None,
     'cubicweb-registration': None,
     'cubicweb-rememberme': None,
+    'jinja2': None,
 }
 
 __recommends__ = {}
--- a/data/cubes.sherpa.css	Fri Jan 20 17:05:49 2017 +0100
+++ b/data/cubes.sherpa.css	Fri Feb 03 13:47:58 2017 +0100
@@ -37,6 +37,7 @@
   background-color: #ffffff;
   border-radius: 0;
   border-bottom: 1.2em solid #0d4e96;
+  margin-bottom: 0;
 }
 
 .navbar-sherpa .logoSHERPA {
@@ -44,7 +45,6 @@
   display: block;
   height: 8em;
   padding: 5px;
-  box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.3);
 }
 
 .navbar-sherpa .logoSIAF {
@@ -70,21 +70,26 @@
   border-radius: 0;
 }
 
-
 /*breadcrumbs */
 
+#breadcrumbs_wrapper {
+  background-color: #0b6ba8;
+}
 #breadcrumbs{
-  background-color: #0d4e96;
+  background-color: #0b6ba8;
   color: #fff;
   padding: 0;
   border-radius: 0;
   list-style: none;
-  text-align: center;
   font-size: 1.3em;
-  padding-bottom: 0.8em;
+  padding: 0.8em 0 0.8em 0;
+  margin-bottom: 0;
 }
 
 /* aside */
+#aside-main-left {
+  margin-top : 3em;
+}
 
 #aside-main-left .panel-heading,
 #aside-main-left .facetTitle,
@@ -246,6 +251,24 @@
   color: #000;
 }
 
+#contentmain #presentation,
+#contentmain #seda {
+  padding-bottom: 3.5em;
+}
+
+#contentmain #projetSherpa::before,
+#contentmain #seda::before {
+  display: block;
+  margin: auto;
+  content: " ";
+  border-bottom: 5px solid #999999;
+  width: 130px;
+}
+
+#contentmain #projetSherpa {
+  padding-bottom: 3.5em;
+}
+
 #contentmain #accueil h1 {
   padding-bottom: 0.1em;
   margin: auto;
@@ -295,7 +318,7 @@
 }
 
 #contentmain .utilisation {
-  padding-right : 5em;
+  padding : 0 5% 0 5%;
 }
 
 #contentmain .utilisation h4 {
Binary file data/images/logo_SHERPA_2.png has changed
--- a/uiprops.py	Fri Jan 20 17:05:49 2017 +0100
+++ b/uiprops.py	Fri Feb 03 13:47:58 2017 +0100
@@ -2,3 +2,5 @@
 STYLESHEETS.extend([
     data('cubes.sherpa.css')
 ])
+
+JAVASCRIPTS.extend([])
--- a/views/__init__.py	Fri Jan 20 17:05:49 2017 +0100
+++ b/views/__init__.py	Fri Feb 03 13:47:58 2017 +0100
@@ -14,51 +14,14 @@
 # You should have received a copy of the GNU Lesser General Public License along
 # with this program. If not, see <http://www.gnu.org/licenses/>.
 
-from logilab.common.decorators import monkeypatch
-from cubes.squareui.views.basetemplates import basetemplates
-from cubicweb.web.views import baseviews, startup
-from os.path import dirname, join
-
-# Bootstrap configuration.
-basetemplates.TheMainTemplate.twbs_container_cls = 'container-fluid'
-
-# Display header-right components in a specific div, not using 'nav' bootstrap style and handle an
-# 'active' class in the nav component (main-navigation)
+from jinja2 import Environment, PackageLoader
 
-@monkeypatch(basetemplates.HTMLPageHeader)
-def main_header(self, view):
-    w = self.w
-    w(u'''<nav class="navbar navbar-default navbar-sherpa" role="banner">
-    <div class="container-fluid">
-        <div class="col-md-2 hidden-xs hidden-sm">
-            <a href="/"><img src="{logo_SIAF}" class="logoSIAF" /></a>
-        </div>
-        <div class="col-md-7 col-xs-8">
-            <a href="/">
-                <div class='col-md-6 col-md-offset-3 col-xs-12 col-sm-12'>
-                    <h1>Service Heberg&eacute; pour la R&eacute;daction de Profils d&#39;Archivage</h1>
-                </div>
-                <div class='col-md-2  hidden-xs hidden-sm'>
-                    <img src="{logo_SHERPA}" class="logoSHERPA"/>
-                </div>
-            </a>
-        </div>'''.format(logo_SIAF=self._cw.data_url('images/logo_SIAF.png'),
-                    logo_SHERPA=self._cw.data_url('images/logo_SHERPA.png')
-            ))
-    w(u'''<div class="col-md-2 col-md-offset-1 col-xs-4">
-    <div class="pull-left dropdown col-md-12">''')
-    components = self.get_components(view, context='header-right')
-    for comp in components:
-        comp.render(w=w)
-    w(u'''</div></div>
-    </nav>''')
-
-class SherpaIndexView(startup.IndexView):
-
-    def call(self, **kwargs):
-        with open(join(dirname(__file__), 'index.html')) as stream:
-            self.w(stream.read().decode("UTF8"))
+env = Environment(loader=PackageLoader('cubes.sherpa.views'))
 
 
-def registration_callback(vreg):
-    vreg.register_and_replace(SherpaIndexView, startup.IndexView)
+class JinjaViewMixin(object):
+    template_name = None
+
+    def call_template(self, **ctx):
+        t = env.get_template(self.template_name)
+        self.w(t.render(**ctx))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/homepage.py	Fri Feb 03 13:47:58 2017 +0100
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# copyright 2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""sherpa views/homepage views and components"""
+
+from six import text_type as unicode
+from os.path import dirname, join
+from cubicweb.web.component import CtxComponent
+from cubicweb.web.views import startup
+
+
+_ = unicode
+
+
+class HomepageAbstractComponent(CtxComponent):
+    __abstract__ = True
+    context = 'homepage'
+
+    def render(self, w, view=None):
+        self._render(w)
+
+    def _render(self, w):
+        raise NotImplementedError
+
+
+class SherpaIndexView(startup.IndexView):
+
+    def call(self, **kwargs):
+        with open(join(dirname(__file__), 'index.html')) as stream:
+            self.w(stream.read().decode("UTF8"))
+
+
+def registration_callback(vreg):
+    vreg.register_and_replace(SherpaIndexView, startup.IndexView)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/templates.py	Fri Feb 03 13:47:58 2017 +0100
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+# copyright 2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""sherpa views/templates"""
+
+from six import string_types, text_type as _
+from cwtags import tag as T
+from logilab.common.decorators import monkeypatch
+from cubicweb.utils import json_dumps, HTMLHead, UStringIO
+from cubicweb.web.views import basetemplates
+from . import JinjaViewMixin
+
+
+# Bootstrap configuration.
+basetemplates.TheMainTemplate.twbs_container_cls = 'container-fluid'
+
+@monkeypatch(HTMLHead)
+def add_onload(self, jscode):
+    """original `add_onload` implementation use `$(cw)`
+    but `cw` variable is not available
+    in francearchive, use `$` instead"""
+    self.add_post_inline_script(u"""$(function() {
+  %s
+});""" % jscode)
+
+class SherpaMainTemplate(JinjaViewMixin, basetemplates.TheMainTemplate):
+
+    template_name = 'maintemplate.jinja2'
+
+    def _handle_added_resources(self, tmpl_context):
+        """fetch all resources added with add_{js,css}, etc.
+
+        and backport them into ``tmpl_context`` to feed the main jinja template
+        """
+        # handle define_var() calls
+        var_stmts = [(var, json_dumps(value))
+                     for var, value, override in self._cw.html_headers.jsvars]
+        tmpl_context['js_vars'] = var_stmts
+
+        # handle add_js() calls
+        print 'head', self._cw.html_headers.jsfiles
+        current_jsfiles = tmpl_context['jsfiles']
+        for jsfile in self._cw.html_headers.jsfiles:
+            if jsfile not in current_jsfiles:
+                current_jsfiles.append(jsfile)
+
+        # handle add_onload() calls
+        tmpl_context['inline_scripts'] = self._cw.html_headers.post_inlined_scripts
+        # handle add_css() calls
+        current_cssfiles = tmpl_context['cssfiles']
+        for cssfile, media in self._cw.html_headers.cssfiles:
+            if cssfile not in current_cssfiles:
+                current_cssfiles.append(cssfile)
+
+    def call(self, view):
+        self.set_request_content_type()
+        self._cw.html_headers.define_var('BASE_URL', self._cw.build_url(''))
+        context = self.template_context(view)
+        page_content = view.render()
+        context.update(getattr(view, 'template_context', lambda: {})())
+        self._handle_added_resources(context)
+        context['page_content'] = page_content
+        self.call_template(**context)
+
+
+    def template_context(self, view):
+
+        req = self._cw
+
+        left_boxes = list(self._cw.vreg['ctxcomponents'].poss_visible_objects(
+            req, rset=self.cw_rset, view=view, context='left'))
+
+        stream = UStringIO()
+        for box in left_boxes:
+            box.render(w=stream.write, view=view)
+        left_boxes_html = stream.getvalue()
+
+        ctx = {
+            'header_row': None,
+            'title': view.page_title(),
+            'base_url': self._cw.build_url(''),
+            'data_url': self._cw.datadir_url,
+            'cssfiles': self._cw.uiprops['STYLESHEETS'],
+            'jsfiles': self._cw.uiprops['JAVASCRIPTS'],
+            'page_id': 'contentmain',
+            '_': self._cw._,
+            'side_box': {
+                'resources': [
+                    {'url': self._cw.build_url('shema_seda'),
+                     'label': _('Schema du SEDA 2.0')},
+                    {'url': self._cw.build_url('dictionnaire'),
+                     'label': _('Dictionnaire des balises')},
+                    {'url': self._cw.build_url('documentation_fonctionnelle'),
+                     'label': _('Documentation fonctionnelle')},
+                    {'url': self._cw.build_url('documentation_technique'),
+                     'label': _('Documentation technique')},
+                ],
+                'goTo_links': [
+                    {'url': self._cw.build_url('#'),
+                     'label': _("Unites d'archive")},
+                    {'url': self._cw.build_url('SEDAArchiveTransfer'),
+                     'label': _('Profils SEDA')},
+                    {'url': self._cw.build_url('#'),
+                     'label': _("Mode d'emploi")},
+                    {'url': self._cw.build_url('#'),
+                    'label': _('Le projet Sherpa')},
+                ]
+            },
+            'left_boxes': left_boxes_html,
+            'footer': {
+                'copyright': '### copyright ###',
+                'contact': 'mailto:#'
+            },
+            'user': req.user.login,
+            'current_url': req.relative_path(),
+        }
+
+        breadcrumbs = []
+        if self.cw_rset and len(self.cw_rset) == 1:
+            entity = self.cw_rset.one()
+            ibc = entity.cw_adapt_to('IBreadCrumbs')
+            if ibc is not None:
+                for bc_element in ibc.breadcrumbs():
+                    if isinstance(bc_element, (list, tuple)):
+                        breadcrumbs.append(bc_element)
+                    elif isinstance(bc_element, string_types):
+                        breadcrumbs.append((None, bc_element))
+                    else:
+                        breadcrumbs.append((bc_element.absolute_url(),
+                                            bc_element.dc_title()))
+                ctx['breadcrumbs'] = breadcrumbs
+
+        print ctx['left_boxes']
+        return ctx
+
+def registration_callback(vreg):
+    vreg.register_and_replace(SherpaMainTemplate, basetemplates.TheMainTemplate)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/templates/maintemplate.jinja2	Fri Feb 03 13:47:58 2017 +0100
@@ -0,0 +1,134 @@
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, width=device-width" />
+    <meta name="theme-color" content="#ffffff">
+
+    <title>{{ title }}</title>
+    <script>
+      {% for varname, value in js_vars %}
+        var {{ varname }} = {{ value }};
+      {% endfor %}
+    </script>
+    {% for css in cssfiles %}
+      <link rel="stylesheet" href="{{ css }}" type="text/css" media="all" />
+    {% endfor %}
+
+  </head>
+  <body>
+
+    <nav class="navbar navbar-default navbar-sherpa" role="banner">
+      <div class="container-fluid">
+          <div class="col-md-2 hidden-xs hidden-sm">
+              <a href="{{ base_url }}"><img src="{{ data_url }}images/logo_SIAF.png" class="logoSIAF" /></a>
+          </div>
+          <div class="col-md-7 col-xs-8">
+              <a href="/">
+                  <div class='col-md-6 col-md-offset-3 col-xs-12 col-sm-12'>
+                      <h1>Service Heberg&eacute; pour la R&eacute;daction de Profils d&#39;Archivage</h1>
+                  </div>
+                  <div class='col-md-2'>
+                      <img src="{{ data_url }}images/logo_SHERPA_2.png" class="img-responsive logoSHERPA"/>
+                  </div>
+              </a>
+          </div>
+          <div class="col-md-2 col-md-offset-1 col-xs-4">
+
+            {{ login_html }}
+            {% block login %}
+
+              <span class="login">
+                {{ user }}<i class="icon-user"></i>
+                <a href="{{ base_url }}{{ "login" if isanon else "logout" }}?postlogin_path={{ current_url }}">
+                  <i class="fa fa-{{ "sign-in" if isanon else "sign-out" }}"></i>
+                </a>
+              </span>
+
+            {% endblock %}
+
+            {% block adminpanel %}
+              {% if not isanon %}
+                <div id="admin-panel"></div>
+              {% endif %}
+            {% endblock %}
+
+          </div>
+      </div>
+    </nav>
+
+    {% if breadcrumbs %}
+    <div id="breadcrumbs_wrapper">
+      <ul id="breadcrumbs" class="breadcrumb col-md-offset-2">
+        {% for url, label in breadcrumbs %}
+          {% if url and not loop.last %}
+            <li><a href="{{ url }}">{{ label }}</a></li>
+          {% else %}
+            <li>{{ label }}</li>
+          {% endif %}
+        {% endfor %}
+      </ul>
+    </div>
+    {% endif %}
+
+    <div id="{{page_id}}" class="container-fluid" role="main">
+
+      <aside id="aside-main-left" class="col-md-2 cwjs-aside">
+
+        <div class="panel panel-default contextFreeBox facet_filterbox" id="facet_filterbox">
+        <div class="panel-heading">
+           <div class="panel-title">Navigation</div>
+        </div>
+        <div class="panel-body">
+          <ul class="list-unstyled">
+            {% for page in side_box.goTo_links %}
+            <li class="facetvalue"><a href='{{ page.url }}'> {{ page.label }}</a></li>
+            {% endfor %}
+          </ul>
+        </div>
+      </div>
+
+        <div class="panel panel-default contextFreeBox facet_filterbox" id="facet_filterbox">
+        <div class="panel-heading">
+           <div class="panel-title">Resources</div>
+        </div>
+        <div class="panel-body">
+          <ul class="list-unstyled">
+            {% for resource in side_box.resources %}
+            <li class="facetvalue"><a href='{{ resource.url }}'> {{ resource.label }}</a></li>
+            {% endfor %}
+          </ul>
+        </div>
+      </div>
+
+        {{ left_boxes }}
+      </aside>
+
+      <div class="col-md-10">
+        <div class="row">
+          {{ page_content }}
+        </div>
+      </div>
+  </div>
+
+  <div class="container-fluid">
+    <footer role="contentinfo" id="pagefooter">
+      <div id="copyright">
+        <span>{{ footer.copyright }}</span>
+        <span><a href="{{ footer.contact.url }}">contact</a></span>
+      </div>
+    </footer>
+  </div>
+
+  {% for js in jsfiles %}
+    <script src="{{ js }}"></script>
+  {% endfor %}
+  {% for inlinescript in inline_scripts %}
+    <script type="text/javascript">
+      {{ inlinescript }}
+    </script>
+  {% endfor %}
+
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/views/urls.py	Fri Feb 03 13:47:58 2017 +0100
@@ -0,0 +1,11 @@
+from cubicweb.web.views.urlrewrite import SimpleReqRewriter, rgx
+
+
+class SherpaReqRewriter(SimpleReqRewriter):
+    rules = [
+        (rgx('/project'), dict(vid='sherpa-project'))
+    ]
+
+
+def registration_callback(vreg):
+    vreg.register(SherpaReqRewriter)