web/views/basetemplates.py
branchtls-sprint
changeset 823 cb8ccbef8fa5
parent 822 e3d8db01f3f5
child 826 51cb3d85c059
equal deleted inserted replaced
822:e3d8db01f3f5 823:cb8ccbef8fa5
     9 
     9 
    10 
    10 
    11 from logilab.mtconverter import html_escape
    11 from logilab.mtconverter import html_escape
    12 
    12 
    13 from cubicweb import NoSelectableObject, ObjectNotFound
    13 from cubicweb import NoSelectableObject, ObjectNotFound
       
    14 from cubicweb.vregistry import objectify_selector
    14 from cubicweb.selectors import match_kwargs
    15 from cubicweb.selectors import match_kwargs
    15 from cubicweb.view import View, MainTemplate,  NOINDEX, NOFOLLOW
    16 from cubicweb.view import View, MainTemplate,  NOINDEX, NOFOLLOW
    16 from cubicweb.utils import make_uid, UStringIO
    17 from cubicweb.utils import make_uid, UStringIO
    17 from cubicweb.web.views.baseviews import vid_from_rset
       
    18 
    18 
    19 # main templates ##############################################################
    19 # main templates ##############################################################
    20 
    20 
    21 class LogInOutTemplate(MainTemplate):
    21 class LogInOutTemplate(MainTemplate):
    22 
    22 
    62             indexurl = self.build_url('view', vid='index', __message=msg)
    62             indexurl = self.build_url('view', vid='index', __message=msg)
    63             w(u'<p><a href="%s">%s</a><p>' % (
    63             w(u'<p><a href="%s">%s</a><p>' % (
    64                 html_escape(indexurl),
    64                 html_escape(indexurl),
    65                 self.req._('go back to the index page')))
    65                 self.req._('go back to the index page')))
    66 
    66 
       
    67 @objectify_selector
       
    68 def templatable_view(cls, req, rset, *args, **kwargs):
       
    69     view = kwargs.pop('view', None)
       
    70     if view is None:
       
    71         return 1
       
    72     if view.binary:
       
    73         return 0
       
    74     if req.form.has_key('__notemplate'):
       
    75         return 0
       
    76     return view.templatable
       
    77 
       
    78 @objectify_selector
       
    79 def non_templatable_view(cls, req, rset, *args, **kwargs):
       
    80     return not templatable_view()(cls, req, rset, *args, **kwargs)
       
    81 
       
    82 
       
    83 class NonTemplatableViewTemplate(MainTemplate):
       
    84     """main template for any non templatable views (xml, binaries, etc.)"""
       
    85     id = 'main-template'
       
    86     __select__ = non_templatable_view()
       
    87     
       
    88     def call(self, view):
       
    89         view.set_request_content_type()
       
    90         self.set_stream(templatable=False)
       
    91         # have to replace our unicode stream using view's binary stream
       
    92         view.dispatch()
       
    93         assert self._stream, 'duh, template used as a sub-view ?? (%s)' % self._stream
       
    94         self._stream = view._stream
       
    95 
    67 
    96 
    68 class TheMainTemplate(MainTemplate):
    97 class TheMainTemplate(MainTemplate):
    69     """default main template :
    98     """default main template :
    70 
    99 
    71     - call header / footer templates
   100     - call header / footer templates
    72     - build result set
       
    73     - guess and call an appropriate view through the view manager
       
    74     """
   101     """
    75     id = 'main'
   102     id = 'main-template'
    76 
   103     __select__ = templatable_view()
    77     def _select_view_and_rset(self):
   104     
    78         req = self.req
   105     def call(self, view):
    79         if self.rset is None and not hasattr(req, '_rql_processed'):
   106         self.set_request_content_type()
    80             req._rql_processed = True
   107         self.template_header(self.content_type, view)
    81             rset = self.process_rql(req.form.get('rql'))
   108         w = self.w
    82         else:
   109         w(u'<div id="pageContent">\n')
    83             rset = self.rset
   110         vtitle = self.req.form.get('vtitle')
    84         # handle special "method" param when necessary
   111         if vtitle:
    85         # XXX this should probably not be in the template (controller ?), however:
   112             w(u'<h1 class="vtitle">%s</h1>\n' % html_escape(vtitle))
    86         #     * we need to have the displayed rset
   113         # display entity type restriction component
    87         #     * we don't want to handle it in each view
   114         etypefilter = self.vreg.select_component('etypenavigation',
    88         if rset and rset.rowcount == 1 and '__method' in req.form:
   115                                                  self.req, self.rset)
    89             entity = rset.get_entity(0, 0)
   116         if etypefilter and etypefilter.propval('visible'):
    90             try:
   117             etypefilter.dispatch(w=w)
    91                 method = getattr(entity, req.form.pop('__method'))
   118         self.nav_html = UStringIO()
    92                 method()
   119         self.pagination(self.req, self.rset, self.nav_html.write,
    93             except Exception, ex:
   120                         not (view and view.need_navigation))
    94                 self.exception('while handling __method')
   121         w(_(self.nav_html.getvalue()))
    95                 req.set_message(req._("error while handling __method: %s") % req._(ex))
   122         w(u'<div id="contentmain">\n')
    96         vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema)
   123         view.dispatch(w=w)
    97         try:
   124         w(u'</div>\n') # close id=contentmain
    98             view = self.vreg.select_view(vid, req, rset)
   125         w(_(self.nav_html.getvalue()))
    99         except ObjectNotFound:
   126         w(u'</div>\n') # closes id=pageContent
   100             self.warning("the view %s could not be found", vid)
   127         self.template_footer(view)
   101             req.set_message(req._("The view %s could not be found") % vid)
       
   102             vid = vid_from_rset(req, rset, self.schema)
       
   103             view = self.vreg.select_view(vid, req, rset)
       
   104         except NoSelectableObject:
       
   105             if rset:
       
   106                 req.set_message(req._("The view %s can not be applied to this query") % vid)
       
   107             else:
       
   108                 req.set_message(req._("You have no access to this view or it's not applyable to current data"))
       
   109             self.warning("the view %s can not be applied to this query", vid)
       
   110             vid = vid_from_rset(req, rset, self.schema)
       
   111             view = self.vreg.select_view(vid, req, rset)
       
   112         return view, rset
       
   113 
       
   114     def call(self):
       
   115         view, rset = self._select_view_and_rset()
       
   116         req = self.req
       
   117         # update breadcrumps **before** validating cache, unless the view
       
   118         # specifies explicitly it should not be added to breadcrumb or the
       
   119         # view is a binary view
       
   120         if view.add_to_breadcrumbs and not view.binary:
       
   121             req.update_breadcrumbs()
       
   122         view.set_http_cache_headers()
       
   123         req.validate_cache()
       
   124         with_templates = self.with_templates(view)
       
   125         if with_templates:
       
   126             self.set_request_content_type()
       
   127             content_type = self.content_type
       
   128             self.template_header(content_type, view)
       
   129         else:
       
   130             view.set_request_content_type()
       
   131             self.set_stream(templatable=False)
       
   132         self.wview('page-content', view=view, rset=rset)
       
   133         if with_templates:
       
   134             self.template_footer(view)
       
   135 
       
   136     def with_templates(self, view):
       
   137         return (not view.binary and view.templatable and
       
   138                 not self.req.form.has_key('__notemplate'))
       
   139 
       
   140     def process_rql(self, rql):
       
   141         """execute rql if specified"""
       
   142         if rql:
       
   143             self.ensure_ro_rql(rql)
       
   144             if not isinstance(rql, unicode):
       
   145                 rql = unicode(rql, self.req.encoding)
       
   146             pp = self.vreg.select_component('magicsearch', self.req)
       
   147             self.rset = pp.process_query(rql, self.req)
       
   148             return self.rset
       
   149         return None
       
   150 
   128 
   151     def template_header(self, content_type, view=None, page_title='', additional_headers=()):
   129     def template_header(self, content_type, view=None, page_title='', additional_headers=()):
   152         page_title = page_title or view.page_title()
   130         page_title = page_title or view.page_title()
   153         additional_headers = additional_headers or view.html_headers()
   131         additional_headers = additional_headers or view.html_headers()
   154         self.template_html_header(content_type, page_title, additional_headers)
   132         self.template_html_header(content_type, page_title, additional_headers)
   202         """by default, display informal messages in content header"""
   180         """by default, display informal messages in content header"""
   203         self.wview('contentheader', rset=self.rset, view=view)
   181         self.wview('contentheader', rset=self.rset, view=view)
   204 
   182 
   205     def content_footer(self, view=None):
   183     def content_footer(self, view=None):
   206         self.wview('contentfooter', rset=self.rset, view=view)
   184         self.wview('contentfooter', rset=self.rset, view=view)
   207 
       
   208 
       
   209 class PageContentTemplate(TheMainTemplate):
       
   210     id = 'page-content'
       
   211 
       
   212     def call(self, view=None, rset=None):
       
   213         if view is None:
       
   214             view, rset = self._select_view_and_rset()
       
   215         with_templates = self.with_templates(view)
       
   216         w = self.w
       
   217         if with_templates:
       
   218             w(u'<div id="pageContent">\n')
       
   219             vtitle = self.req.form.get('vtitle')
       
   220             if vtitle:
       
   221                 w(u'<h1 class="vtitle">%s</h1>\n' % html_escape(vtitle))
       
   222             # display entity type restriction component
       
   223             etypefilter = self.vreg.select_component('etypenavigation',
       
   224                                                      self.req, self.rset)
       
   225             if etypefilter and etypefilter.propval('visible'):
       
   226                 etypefilter.dispatch(w=w)
       
   227             self.nav_html = UStringIO()
       
   228             self.pagination(self.req, self.rset, self.nav_html.write,
       
   229                             not (view and view.need_navigation))
       
   230             w(_(self.nav_html.getvalue()))
       
   231             w(u'<div id="contentmain">\n')
       
   232         else:
       
   233             self.set_stream(templatable=False)            
       
   234         if view.binary:
       
   235             # have to replace our unicode stream using view's binary stream
       
   236             view.dispatch()
       
   237             assert self._stream, 'duh, template used as a sub-view ?? (%s)' % self._stream
       
   238             self._stream = view._stream
       
   239         else:
       
   240             view.dispatch(w=w)
       
   241         if with_templates:
       
   242             w(u'</div>\n') # close id=contentmain
       
   243             w(_(self.nav_html.getvalue()))
       
   244             w(u'</div>\n') # closes id=pageContent
       
   245 
   185 
   246 
   186 
   247 class ErrorTemplate(TheMainTemplate):
   187 class ErrorTemplate(TheMainTemplate):
   248     """fallback template if an internal error occured during displaying the
   188     """fallback template if an internal error occured during displaying the
   249     main template. This template may be called for authentication error,
   189     main template. This template may be called for authentication error,
   532         return req.url()
   472         return req.url()
   533     if config.get('https-url'):
   473     if config.get('https-url'):
   534         return req.url().replace(req.base_url(), config['https-url'])
   474         return req.url().replace(req.base_url(), config['https-url'])
   535     return req.url()
   475     return req.url()
   536 
   476 
       
   477 
       
   478 ## vregistry registration callback ############################################
       
   479 def registration_callback(vreg):
       
   480     vreg.register_all(globals().values(), modname=__name__)