doc/book/en/development/devweb/views/basetemplates.rst
branchstable
changeset 5284 ad922b7449aa
parent 5269 2e5bc78d05f3
child 5290 15846058378b
equal deleted inserted replaced
5283:9ad0eaa09d34 5284:ad922b7449aa
     1 .. -*- coding: utf-8 -*-
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 .. |cubicweb| replace:: *CubicWeb*
     2 
     4 
     3 .. _templates:
     5 .. _templates:
     4 
     6 
     5 Templates
     7 Templates
     6 =========
     8 =========
     7 
     9 
     8 [WRITE ME]
    10 Templates are the entry point for the |cubicweb| view system. As seen
       
    11 in :ref:`views_base_class`, there are two kinds of views: the
       
    12 templatable and non-templatable.
     9 
    13 
    10 * talk about main templates, etc.
    14 Non-templatable views are standalone. They are responsible for all the
       
    15 details such as setting a proper content type (or mime type), the
       
    16 proper document headers, namespaces, etc. Examples are pure xml views
       
    17 such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked
       
    18 Data`_, etc.).
       
    19 
       
    20 .. _`SIOC`: http://sioc-project.org/
       
    21 .. _`DOAP`: http://trac.usefulinc.com/doap
       
    22 .. _`FOAF`: http://www.foaf-project.org/
       
    23 .. _`Linked Data`: http://linkeddata.org/
       
    24 
       
    25 Templatable views are not concerned with such pesky details. They
       
    26 leave it to the template. Conversely, the template's main job is to:
       
    27 
       
    28 * set up the proper document header and content type
       
    29 * define the general layout of a document
       
    30 * invoke adequate views in the various sections of the document
    11 
    31 
    12 
    32 
       
    33 Look at :mod:`cubicweb.web.views.basetemplates` and you will find the
       
    34 base templates used to generate (X)HTML for your application. The most
       
    35 important template there is `TheMainTemplate`.
    13 
    36 
    14 Look at ``cubicweb/web/views/basetemplates.py`` and you will
    37 .. _the_main_template_layout:
    15 find the base templates used to generate HTML for your application.
    38 
       
    39 TheMainTemplate
       
    40 ---------------
       
    41 
       
    42 Layout and sections
       
    43 ```````````````````
    16 
    44 
    17 A page is composed as indicated on the schema below :
    45 A page is composed as indicated on the schema below :
    18 
    46 
    19 .. image:: ../../../images/main_template.png
    47 .. image:: ../../../images/main_template.png
    20 
    48 
    21 In this section we will go through a couple of the primary templates
    49 The sections dispatches specific views:
    22 you must be interested in, that is to say, the HTMLPageHeader,
       
    23 the HTMLPageFooter and the TheMainTemplate.
       
    24 
    50 
       
    51 * `header`: the rendering of the header is delegated to the
       
    52   `htmlheader` view, whose default implementation can be found in
       
    53   ``basetemplates.py`` and which does the following things:
    25 
    54 
    26 HTMLPageHeader
    55     * inject the favicon if there is one
    27 --------------
    56     * inject the global style sheets and javascript resources
       
    57     * call and display a link to an rss component if there is one available
    28 
    58 
    29 Customize header
    59   it also sets up the page title, and fills the actual
    30 ~~~~~~~~~~~~~~~~
    60   `header` section with top-level components, using the `header` view, which:
    31 
    61 
    32 Let's now move the search box in the header and remove the login form
    62     * tries to display a logo, the name of the application and the `breadcrumbs`
    33 from the header. We'll show how to move it to the left column of the application.
    63     * provides a login status area
       
    64     * provides a login box (hiden by default)
    34 
    65 
    35 Let's say we do not want anymore the login menu to be in the header, but we
    66 * `left column`: this is filled with all selectable boxes matching the
    36 prefer it to be in the left column just below the logo. As the left column is
    67   `left` context (there is also a right column but nowadays it is
    37 rendered by ``TheMainTemplate``, we will show how to do it in TheMainTemplate_.
    68   seldom used due to bad usability)
    38 
    69 
    39 First, to remove the login menu, we just need to comment out the display of the
    70 * `contentcol`: this is the central column; it is filled with:
    40 login component such as follows : ::
       
    41 
    71 
    42   class MyHTMLPageHeader(HTMLPageHeader):
    72     * the `rqlinput` view (hidden by default)
       
    73     * the `applmessages` component
       
    74     * the `contentheader` view which in turns dispatches all available
       
    75       content navigation components having the `navtop` context (this
       
    76       is used to navigate through entities implementing the IPrevNext
       
    77       interface)
       
    78     * the view that was given as input to the template's `call`
       
    79       method, also dealing with pagination concerns
       
    80     * the `contentfooter`
    43 
    81 
    44       def main_header(self, view):
    82 * `footer`: adds all footer actions
    45           """build the top menu with authentification info and the rql box"""
       
    46           self.w(u'<table id="header"><tr>\n')
       
    47           self.w(u'<td id="firstcolumn">')
       
    48           self._cw.vreg.select_component('logo', self._cw, self.cw_rset).dispatch(w=self.w)
       
    49           self.w(u'</td>\n')
       
    50           # appliname and breadcrumbs
       
    51           self.w(u'<td id="headtext">')
       
    52           comp = self._cw.vreg.select_component('appliname', self._cw, self.cw_rset)
       
    53           if comp and comp.propval('visible'):
       
    54               comp.dispatch(w=self.w)
       
    55           comp = self._cw.vreg.select_component('breadcrumbs', self._cw, self.cw_rset, view=view)
       
    56           if comp and comp.propval('visible'):
       
    57               comp.dispatch(w=self.w, view=view)
       
    58           self.w(u'</td>')
       
    59           # logged user and help
       
    60           #self.w(u'<td>\n')
       
    61           #comp = self._cw.vreg.select_component('loggeduserlink', self._cw, self.cw_rset)
       
    62           #comp.dispatch(w=self.w)
       
    63           #self.w(u'</td><td>')
       
    64 
    83 
    65           self.w(u'<td>')
    84 .. note::
    66           helpcomp = self._cw.vreg.select_component('help', self._cw, self.cw_rset)
       
    67           if helpcomp: # may not be available if Card is not defined in the schema
       
    68               helpcomp.dispatch(w=self.w)
       
    69           self.w(u'</td>')
       
    70           # lastcolumn
       
    71           self.w(u'<td id="lastcolumn">')
       
    72           self.w(u'</td>\n')
       
    73           self.w(u'</tr></table>\n')
       
    74           self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden',
       
    75                         title=False, message=False)
       
    76 
    85 
       
    86   How and why a view object is given to the main template is explained
       
    87   in the :ref:`publisher` chapter.
    77 
    88 
    78 
    89 Class attributes
    79 .. image:: ../../../images/lax-book.06-header-no-login.en.png
    90 ````````````````
    80 
       
    81 Let's now move the search box in the top-right header area. To do so, we will
       
    82 first create a method to get the search box display and insert it in the header
       
    83 table.
       
    84 
       
    85 ::
       
    86 
       
    87  from cubicweb.web.views.basetemplates import HTMLPageHeader
       
    88  class MyHTMLPageHeader(HTMLPageHeader):
       
    89     def main_header(self, view):
       
    90         """build the top menu with authentification info and the rql box"""
       
    91         self.w(u'<table id="header"><tr>\n')
       
    92         self.w(u'<td id="firstcolumn">')
       
    93         self._cw.vreg.select_component('logo', self._cw, self.cw_rset).dispatch(w=self.w)
       
    94         self.w(u'</td>\n')
       
    95         # appliname and breadcrumbs
       
    96         self.w(u'<td id="headtext">')
       
    97         comp = self._cw.vreg.select_component('appliname', self._cw, self.cw_rset)
       
    98         if comp and comp.propval('visible'):
       
    99             comp.dispatch(w=self.w)
       
   100         comp = self._cw.vreg.select_component('breadcrumbs', self._cw, self.cw_rset, view=view)
       
   101         if comp and comp.propval('visible'):
       
   102             comp.dispatch(w=self.w, view=view)
       
   103         self.w(u'</td>')
       
   104 
       
   105         # logged user and help
       
   106         #self.w(u'<td>\n')
       
   107         #comp = self._cw.vreg.select_component('loggeduserlink', self._cw, self.cw_rset)
       
   108         #comp.dispatch(w=self.w)
       
   109         #self.w(u'</td><td>')
       
   110 
       
   111         # search box
       
   112         self.w(u'<td>')
       
   113         self.get_searchbox(view, 'left')
       
   114         self.w(u'</td>')
       
   115 
       
   116         self.w(u'<td>')
       
   117         helpcomp = self._cw.vreg.select_component('help', self._cw, self.cw_rset)
       
   118         if helpcomp: # may not be available if Card is not defined in the schema
       
   119             helpcomp.dispatch(w=self.w)
       
   120         self.w(u'</td>')
       
   121         # lastcolumn
       
   122         self.w(u'<td id="lastcolumn">')
       
   123         self.w(u'</td>\n')
       
   124         self.w(u'</tr></table>\n')
       
   125         self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden',
       
   126                       title=False, message=False)
       
   127 
       
   128     def get_searchbox(self, view, context):
       
   129         boxes = list(self._cw.vreg.poss_visible_objects('boxes', self._cw, self.cw_rset,
       
   130                                                     view=view, context=context))
       
   131         if boxes:
       
   132             for box in boxes:
       
   133                 if box.__regid__ == 'search_box':
       
   134                     box.dispatch(w=self.w, view=view)
       
   135 
       
   136 
       
   137 
       
   138 
       
   139 HTMLPageFooter
       
   140 --------------
       
   141 
       
   142 If you want to change the footer for example, look
       
   143 for HTMLPageFooter and override it in your views file as in :
       
   144 ::
       
   145 
       
   146   form cubicweb.web.views.basetemplates import HTMLPageFooter
       
   147   class MyHTMLPageFooter(HTMLPageFooter):
       
   148       def call(self, **kwargs):
       
   149           self.w(u'<div class="footer">')
       
   150           self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
       
   151           self.w(u'</div>')
       
   152 
       
   153 Updating a view does not require any restart of the server. By reloading
       
   154 the page you can see your new page footer.
       
   155 
       
   156 
       
   157 TheMainTemplate
       
   158 ---------------
       
   159 .. _TheMainTemplate:
       
   160 
       
   161 TheMainTemplate is responsible for the general layout of the entire application.
       
   162 It defines the template of ``__regid__ = main`` that is used by the instance.
       
   163 
       
   164 The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`)
       
   165 builds the page based on the following pattern:
       
   166 
       
   167 .. image:: ../../../images/main_template_layout.png
       
   168 
       
   169 The rectangle containing `view.dispatch()` represents the area where the content
       
   170 view has to be displayed. The others represents sub-templates called to complete
       
   171 the page. A default implementation of those is provided in
       
   172 `cubicweb.views.basetemplates`. You can, of course, overload those sub-templates
       
   173 to implement your own customization of the HTML page.
       
   174 
    91 
   175 We can also control certain aspects of the main template thanks to the following
    92 We can also control certain aspects of the main template thanks to the following
   176 forms parameters:
    93 forms parameters:
   177 
    94 
   178 * `__notemplate`, if present (whatever the value assigned), only the content view
    95 * `__notemplate`, if present (whatever the value assigned), only the content view
   182 * `__method`, if the result set to render contains only one entity and this
    99 * `__method`, if the result set to render contains only one entity and this
   183   parameter is set, it refers to a method to call on the entity by passing it
   100   parameter is set, it refers to a method to call on the entity by passing it
   184   the dictionary of the forms parameters, before going the classic way (through
   101   the dictionary of the forms parameters, before going the classic way (through
   185   step 1 and 2 described juste above)
   102   step 1 and 2 described juste above)
   186 
   103 
   187 The MainTemplate is a bit complex as it tries to accomodate many
   104 Other templates
   188 different cases. We are now about to go through it and cutomize entirely
   105 ---------------
   189 our application.
   106 
       
   107 Other standard templates include:
       
   108 
       
   109 * `login` and `logout`
       
   110 
       
   111 * `error-template`