# HG changeset patch # User Katia Saurfelt <katia.saurfelt@logilab.fr> # Date 1394618165 -3600 # Wed Mar 12 10:56:05 2014 +0100 # Node ID 50d7d3b4a41e37c059cdfbb8710aee83898af12c # Parent 9d85cd2fb37b102068df68ef57b0ad88bede2f51 [header] make `main_header` more bootstrap compilant (related to #3597030) diff --git a/doc/html_page_header.rst b/doc/html_page_header.rst new file mode 100644 --- /dev/null +++ b/doc/html_page_header.rst @@ -0,0 +1,28 @@ +class HTMLPageHeader +==================== + +This class has been completly rewritten. + +* new context `header-logo` has been introducted for logo and site + title (used by `basecomponents.ApplLogo` and + `basecomponents.ApplicationName`) to be displyed on the very left of + the navbar. + +* Breadcumbs habe been removed from the header to a specific div. + +* A new dict `headers_classes` now provids the match between context + and bootsrap classes :: + + basetemplates.HTMLPageHeader.headers_classes = { + 'header-left':'navbar-left', + 'header-right':'navbar-right', + } + + +* A new dict `css` provides the possiliblity to easily customize the + header navbar and breadcrumbs :: + + basetemplates.HTMLPageHeader.css = { + 'header-navbar' : 'navbar-default', + 'breadcrumbs' : 'cw-breadcrumbs-default' + } diff --git a/views/__init__.py b/views/__init__.py --- a/views/__init__.py +++ b/views/__init__.py @@ -16,3 +16,16 @@ # with this program. If not, see <http://www.gnu.org/licenses/>. """cubicweb-squareui views/forms/actions/components for web ui""" +from cubicweb.web.views.boxes import ContextualBoxLayout, contextual + +_ = unicode + +class SimpleBoxContextFreeBoxLayout(ContextualBoxLayout): + __select__ = ~contextual() + cssclass = 'contextFreeBox' + __regid__ = 'simple-layout' + + def render(self, w): + if self.init_rendering(): + view = self.cw_extra_kwargs['view'] + view.render_body(w) diff --git a/views/basetemplates.py b/views/basetemplates.py --- a/views/basetemplates.py +++ b/views/basetemplates.py @@ -12,8 +12,11 @@ from logilab.mtconverter import xml_escape from cubicweb.utils import UStringIO -from cubicweb.web.views import basetemplates +from cubicweb.web.views import basetemplates, \ + basecomponents + +from cubicweb.web.views.boxes import SearchBox HTML5 = u'<!DOCTYPE html>' @@ -92,12 +95,11 @@ @monkeypatch(basetemplates.TheMainTemplate) def content_column(self, view, content_cols): w = self.w - w(u'<div id="contentColumn" class="col-md-%s">' % content_cols) + w(u'<div id="pageContent" class="col-md-%(col)s" role="main">' % { + 'col': content_cols}) 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)) @@ -110,8 +112,6 @@ 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 @@ -148,26 +148,117 @@ self.w(u'</div>\n') # closes id="page" self.w(u'</body>\n') + +# main header + +basecomponents.ApplLogo.context = 'header-logo' +# use basecomponents.ApplicationName.visible = False +basecomponents.ApplicationName.context = 'header-logo' +basecomponents.ApplLogo.order = 1 +basecomponents.ApplicationName.order = 10 +basecomponents.CookieLoginComponent.order = 10 +basecomponents.AuthenticatedUserStatus.order = 5 +SearchBox.order = 0 +SearchBox.context = 'header-right' +SearchBox.layout_id = 'simple-layout' + +basetemplates.HTMLPageHeader.headers_classes = { + 'header-left':'navbar-left', + 'header-right':'navbar-right', + } + +@monkeypatch(basetemplates.HTMLPageHeader) +def call(self, view, **kwargs): + self.main_header(view) + self.breadcrumbs(view) + self.state_header() + +def get_components(self, view, context): + ctxcomponents = self._cw.vreg['ctxcomponents'] + return ctxcomponents.poss_visible_objects(self._cw, + rset=self.cw_rset, + view=view, + context=context) + +basetemplates.HTMLPageHeader.get_components = get_components +basetemplates.HTMLPageHeader.css = {'header-navbar' : 'navbar-default', + 'breadcrumbs' : 'cw-breadcrumbs-default'} + @monkeypatch(basetemplates.HTMLPageHeader) def main_header(self, view): - """build the top menu with authentification info and the rql box""" - spans = {'headtext': 'col-md-2', - 'header-center': 'col-md-9', - 'header-right': 'col-md-1 pull-right', - } w = self.w - w(u'<div id="header" class="navbar navbar-default" role="navigation">' - u'<div class="container">') - for colid, context in self.headers: - w(u'<div id="%s" class="%s">' % (colid, spans.get(colid, 'col-md-2'))) - components = self._cw.vreg['ctxcomponents'].poss_visible_objects( - self._cw, rset=self.cw_rset, view=view, context=context) - for comp in components: - comp.render(w=w) - w(u' ') - w(u'</div>\n') - w(u'</div>\n') # closes class="container, - w(u'</div>\n') # closes id="header" + title = self._cw.property_value('ui.site-title') + w(u'<header class="navbar %s" role="banner">' % + self.css.get('header-navbar', 'header-navbar')) + w(u'<nav class="container-fluid">') + self.dispaly_navbar_header(w, view) + self.display_header_components(w, view, 'header-left') + self.display_header_components(w, view, 'header-right') + w(u'</nav></header>') + +def dispaly_navbar_header(self, w, view): + w(u'''<div class="navbar-header"> + <button class="navbar-toggle" data-target="#tools-group" data-toggle="collapse" type="button"> + <span class="sr-only">%(toggle_label)s</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button>''' % {'toggle_label':self._cw._('Toggle navigation')}) + components = self.get_components(view, context='header-logo') + if components: + for component in components: + component.render(w=w) + w(u'</div>') + +basetemplates.HTMLPageHeader.dispaly_navbar_header = dispaly_navbar_header + +def display_header_components(self, w, view, context): + components = self.get_components(view, context=context) + if components: + w(u'<div id="tools-group" class="collapse navbar-collapse">') + w(u'<ul class="nav navbar-nav %s">' % \ + self.headers_classes[context]) + for component in components: + w(u'<li>') + component.render(w=w) + w(u'</li>') + w(u'</ul>') + w(u'</div>') + +basetemplates.HTMLPageHeader.display_header_components = display_header_components + +@monkeypatch(basetemplates.HTMLPageHeader) +def breadcrumbs(self, view): + components = self.get_components(view, context='header-center') + if components: + self.w(u'<nav role="navigation" class="%s">' % + self.css.get('breadcrumbs', 'breadcrumbs-defaul')) + self.w(u'<div class="container">') + for component in components: + component.render(w=self.w) + self.w(u'</div>') + self.w(u'</nav>') + +@monkeypatch(basetemplates.HTMLPageHeader) +def state_header(self): + state = self._cw.search_state + if state[0] == 'normal': + return + _ = self._cw._ + value = self._cw.view('oneline', self._cw.eid_rset(state[1][1])) + target, eid, r_type, searched_type = self._cw.search_state[1] + cancel_link = u'<a href="%(url)s" role="button" title="%(title)s">[%(title)s]</a>' % { + 'url' : self._cw.build_url(str(eid), + vid='edition', __mode='normal'), + 'title': _('cancel')} + msg = ' '.join((_("searching for"), + display_name(self._cw, state[1][3]), + _("to associate with"), value, + _("by relation"), + '<strong>"%s"</strong>' % \ + display_name(self._cw, state[1][2], state[1][0]), + cancel_link)) + return self.w(u'<div class="alert alert-info">%s</div>' % msg) @monkeypatch(basetemplates.HTMLPageFooter) def call(self, **kwargs): @@ -176,3 +267,7 @@ self.footer_content() self.w(u'</div>\n') self.w(u'</footer>\n') + +def registration_callback(vreg): + vreg.register_all(globals().values(), __name__) + vreg.unregister(actions.CancelSelectAction)