diff --git a/test/unittest_views.py b/test/unittest_views.py new file mode 100644 index 0000000000000000000000000000000000000000..e912f1af89b2f8818a112950d39f8f0e386c7489_dGVzdC91bml0dGVzdF92aWV3cy5weQ== --- /dev/null +++ b/test/unittest_views.py @@ -0,0 +1,19 @@ +from logilab.common.testlib import unittest_main, tag + +from cubicweb.devtools.testlib import CubicWebTC +from cubicweb.devtools.htmlparser import XMLValidator + + +class BoostrapTheMainTemplateTC(CubicWebTC): + + @tag('index') + def test_valid_xhtml_index(self): + self.view('index') + + @tag('error') + def test_valid_xhtml_error(self): + valid = self.content_type_validators.get('text/html', XMLValidator)() + page = valid.parse_string(self.vreg['views'].main_template(self.request(), 'error-template')) + +if __name__ == '__main__': + unittest_main() diff --git a/views/basetemplates.py b/views/basetemplates.py index 292de533fa6918b70ed6639fef402cf1d92b740c_dmlld3MvYmFzZXRlbXBsYXRlcy5weQ==..e912f1af89b2f8818a112950d39f8f0e386c7489_dmlld3MvYmFzZXRlbXBsYXRlcy5weQ== 100644 --- a/views/basetemplates.py +++ b/views/basetemplates.py @@ -19,11 +19,5 @@ basetemplates.TheMainTemplate.doctype = HTML5 - -### XXX / TODOs -### -### <footer> is set by ContentFooter class. In orbui, it's set by -### the main template - @monkeypatch(basetemplates.TheMainTemplate) def call(self, view): @@ -28,4 +22,6 @@ @monkeypatch(basetemplates.TheMainTemplate) def call(self, view): + print self + self.grid_nb_cols = 12 self.set_request_content_type() self.template_header(self.content_type, view) @@ -30,25 +26,5 @@ self.set_request_content_type() self.template_header(self.content_type, view) - w = self.w - w(u'<div class="row">') - w(u'<div class="col-md-12" id="pageContent">') - vtitle = self._cw.form.get('vtitle') - if vtitle: - w(u'<div class="vtitle">%s</div>\n' % xml_escape(vtitle)) - # display entity type restriction component - etypefilter = self._cw.vreg['components'].select_or_none( - 'etypenavigation', self._cw, rset=self.cw_rset) - if etypefilter and etypefilter.cw_propval('visible'): - etypefilter.render(w=w) - nav_html = UStringIO() - if view and not view.handle_pagination: - view.paginate(w=nav_html.write) - w(nav_html.getvalue()) - w(u'<div id="contentmain">\n') - view.render(w=w) - w(u'</div>\n') # closes id=contentmain - w(nav_html.getvalue()) - w(u'</div>\n' # closes id=pageContent - u'</div>\n') # closes row + self.template_page_content(view) self.template_footer(view) @@ -53,6 +29,5 @@ self.template_footer(view) - @monkeypatch(basetemplates.TheMainTemplate) def template_html_header(self, content_type, page_title, additional_headers=()): @@ -81,4 +56,9 @@ @monkeypatch(basetemplates.TheMainTemplate) def template_body_header(self, view): + self.w(u'<body>\n') + self.wview('header', rset=self.cw_rset, view=view) + +@monkeypatch(basetemplates.TheMainTemplate) +def template_page_content(self, view): w = self.w @@ -84,5 +64,3 @@ w = self.w - w(u'<body>\n') - self.wview('header', rset=self.cw_rset, view=view) w(u'<div id="page" class="container">\n' u'<div class="row">\n') @@ -87,11 +65,33 @@ w(u'<div id="page" class="container">\n' u'<div class="row">\n') - #w(u'<div class="col-md-3">') - nb_boxes = self.nav_column(view, 'left') - #w(u'</div>') - if nb_boxes is not None and nb_boxes: - content_span = 9 - else: - content_span = 12 - w(u'<div id="contentColumn" class="col-md-%s">' % content_span) + left_boxes = list(self._cw.vreg['ctxcomponents'].poss_visible_objects( + self._cw, rset=self.cw_rset, view=view, context='left')) + right_boxes = list(self._cw.vreg['ctxcomponents'].poss_visible_objects( + self._cw, rset=self.cw_rset, view=view, context='right')) + nb_boxes = int(bool(left_boxes)) + int(bool(right_boxes)) + content_cols = 12 + if nb_boxes: + content_cols = self.grid_nb_cols-(3*nb_boxes) + self.nav_column(view, left_boxes, 'left') + self.content_column(view, content_cols) + self.nav_column(view, right_boxes, 'right') + self.w(u'</div>\n') # closes class=row + +@monkeypatch(basetemplates.TheMainTemplate) +def nav_column(self, view, boxes, context): + if boxes: + getlayout = self._cw.vreg['components'].select + self.w(u'<div id="aside-main-%s" class="col-md-3">\n' % + context) + self.w(u'<div class="navboxes" id="navColumn%s">\n' % context.capitalize()) + for box in boxes: + box.render(w=self.w, view=view) + self.w(u'</div>\n') + self.w(u'</div>\n') + return len(boxes) + +@monkeypatch(basetemplates.TheMainTemplate) +def content_column(self, view, content_cols): + w = self.w + w(u'<div id="contentColumn" class="col-md-%s">' % content_cols) components = self._cw.vreg['components'] @@ -97,7 +97,40 @@ components = self._cw.vreg['components'] + self.content_components(view, components) + self.content_header(view) + w(u'<div class="row">') + w(u'<div id="pageContent">') + vtitle = self._cw.form.get('vtitle') + if vtitle: + w(u'<div class="vtitle">%s</div>\n' % xml_escape(vtitle)) + self.content_navrestriction_components(view, components) + nav_html = UStringIO() + if view and not view.handle_pagination: + view.paginate(w=nav_html.write) + w(nav_html.getvalue()) + w(u'<div id="contentmain">\n') + view.render(w=w) + w(u'</div>\n') # closes id=contentmain + w(nav_html.getvalue()) + w(u'</div>\n' # closes id=pageContent + u'</div>\n') # closes row + self.content_footer(view) + w(u'</div>\n') # closes div#contentColumn in template_body_header + + +@monkeypatch(basetemplates.TheMainTemplate) +def content_footer(self, view=None): + # TODO : do not add the wrapping div if no data + self.w(u'<div class="row">') # metadata and so + self.wview('contentfooter', rset=self.cw_rset, view=view) + self.w(u'</div>\n') # closes row + + +@monkeypatch(basetemplates.TheMainTemplate) +def content_components(self, view, components): + """TODO : should use context""" rqlcomp = components.select_or_none('rqlinput', self._cw, rset=self.cw_rset) if rqlcomp: rqlcomp.render(w=self.w, view=view) msgcomp = components.select_or_none('applmessages', self._cw, rset=self.cw_rset) if msgcomp: msgcomp.render(w=self.w) @@ -98,10 +131,17 @@ rqlcomp = components.select_or_none('rqlinput', self._cw, rset=self.cw_rset) if rqlcomp: rqlcomp.render(w=self.w, view=view) msgcomp = components.select_or_none('applmessages', self._cw, rset=self.cw_rset) if msgcomp: msgcomp.render(w=self.w) - self.content_header(view) + +@monkeypatch(basetemplates.TheMainTemplate) +def content_navrestriction_components(self, view, components): + # display entity type restriction component + etypefilter = components.select_or_none( + 'etypenavigation', self._cw, rset=self.cw_rset) + if etypefilter and etypefilter.cw_propval('visible'): + etypefilter.render(w=self.w) @monkeypatch(basetemplates.TheMainTemplate) def template_footer(self, view=None): @@ -105,10 +145,4 @@ @monkeypatch(basetemplates.TheMainTemplate) def template_footer(self, view=None): - self.w(u'<div class="row">') - self.content_footer(view) - self.w(u'</div>') - self.w(u'</div>\n') # XXX closes div#contentColumn col-md-9 in template_body_header - self.nav_column(view, 'right') - self.w(u'</div>\n') # XXX closes div#page in template_body_header self.wview('footer', rset=self.cw_rset) @@ -114,23 +148,6 @@ self.wview('footer', rset=self.cw_rset) - self.w(u'</div>' # closes class="row" - u'</div>') # closes class="container" - self.w(u'</body>') - -@monkeypatch(basetemplates.TheMainTemplate) -def nav_column(self, view, context): - boxes = list(self._cw.vreg['ctxcomponents'].poss_visible_objects( - self._cw, rset=self.cw_rset, view=view, context=context)) - if boxes: - getlayout = self._cw.vreg['components'].select - self.w(u'<div id="aside-main-%s" class="col-md-3">\n' % - context) # XXX Should arrange Facets soon - self.w(u'<div class="navboxes" id="navColumn%s">\n' % context.capitalize()) - for box in boxes: - box.render(w=self.w, view=view) - self.w(u'</div>' - u'</div>') - return len(boxes) - + self.w(u'</div>\n') # closes id="page" + self.w(u'</body>\n') @monkeypatch(basetemplates.HTMLPageHeader) def main_header(self, view): @@ -149,12 +166,12 @@ for comp in components: comp.render(w=w) w(u' ') - w(u'</div>') - w(u'</div></div>\n') - + w(u'</div>\n') + w(u'</div>\n') # closes class="container, + w(u'</div>\n') # closes id="header" @monkeypatch(basetemplates.HTMLPageFooter) def call(self, **kwargs): self.w(u'<footer id="pagefooter">') self.w(u'<div id="footer" class="container">') self.footer_content() @@ -155,8 +172,8 @@ @monkeypatch(basetemplates.HTMLPageFooter) def call(self, **kwargs): self.w(u'<footer id="pagefooter">') self.w(u'<div id="footer" class="container">') self.footer_content() - self.w(u'</div>') - self.w(u'</footer>') + self.w(u'</div>\n') + self.w(u'</footer>\n')