view.py
changeset 3451 6b46d73823f5
parent 3369 7b88d12b4ee2
child 3720 5376aaadd16b
equal deleted inserted replaced
3448:495862266785 3451:6b46d73823f5
   104         super(View, self).__init__(req, rset=rset, **kwargs)
   104         super(View, self).__init__(req, rset=rset, **kwargs)
   105         self.w = None
   105         self.w = None
   106 
   106 
   107     @property
   107     @property
   108     def content_type(self):
   108     def content_type(self):
   109         return self.req.html_content_type()
   109         return self._cw.html_content_type()
   110 
   110 
   111     def set_stream(self, w=None):
   111     def set_stream(self, w=None):
   112         if self.w is not None:
   112         if self.w is not None:
   113             return
   113             return
   114         if w is None:
   114         if w is None:
   153         """render a precompiled page template with variables in the given
   153         """render a precompiled page template with variables in the given
   154         dictionary as context
   154         dictionary as context
   155         """
   155         """
   156         from cubicweb.ext.tal import CubicWebContext
   156         from cubicweb.ext.tal import CubicWebContext
   157         context = CubicWebContext()
   157         context = CubicWebContext()
   158         context.update({'self': self, 'rset': self.rset, '_' : self.req._,
   158         context.update({'self': self, 'rset': self.cw_rset, '_' : self._cw._,
   159                         'req': self.req, 'user': self.req.user})
   159                         'req': self._cw, 'user': self._cw.user})
   160         context.update(variables)
   160         context.update(variables)
   161         output = UStringIO()
   161         output = UStringIO()
   162         template.expand(context, output)
   162         template.expand(context, output)
   163         return output.getvalue()
   163         return output.getvalue()
   164 
   164 
   173         other rows of the result set and call the same view on the
   173         other rows of the result set and call the same view on the
   174         particular row
   174         particular row
   175 
   175 
   176         Views applicable on None result sets have to override this method
   176         Views applicable on None result sets have to override this method
   177         """
   177         """
   178         rset = self.rset
   178         rset = self.cw_rset
   179         if rset is None:
   179         if rset is None:
   180             raise NotImplementedError, self
   180             raise NotImplementedError, self
   181         wrap = self.templatable and len(rset) > 1 and self.add_div_section
   181         wrap = self.templatable and len(rset) > 1 and self.add_div_section
   182         for i in xrange(len(rset)):
   182         for i in xrange(len(rset)):
   183             if wrap:
   183             if wrap:
   184                 self.w(u'<div class="section">')
   184                 self.w(u'<div class="section">')
   185             self.wview(self.id, rset, row=i, **kwargs)
   185             self.wview(self.__regid__, rset, row=i, **kwargs)
   186             if wrap:
   186             if wrap:
   187                 self.w(u"</div>")
   187                 self.w(u"</div>")
   188 
   188 
   189     def cell_call(self, row, col, **kwargs):
   189     def cell_call(self, row, col, **kwargs):
   190         """the view is called for a particular result set cell"""
   190         """the view is called for a particular result set cell"""
   198         if not getattr(self, 'title', None):
   198         if not getattr(self, 'title', None):
   199             return False
   199             return False
   200         return True
   200         return True
   201 
   201 
   202     def is_primary(self):
   202     def is_primary(self):
   203         return self.id == 'primary'
   203         return self.__regid__ == 'primary'
   204 
   204 
   205     def url(self):
   205     def url(self):
   206         """return the url associated with this view. Should not be
   206         """return the url associated with this view. Should not be
   207         necessary for non linkable views, but a default implementation
   207         necessary for non linkable views, but a default implementation
   208         is provided anyway.
   208         is provided anyway.
   209         """
   209         """
   210         rset = self.rset
   210         rset = self.cw_rset
   211         if rset is None:
   211         if rset is None:
   212             return self.build_url('view', vid=self.id)
   212             return self._cw.build_url('view', vid=self.__regid__)
   213         coltypes = rset.column_types(0)
   213         coltypes = rset.column_types(0)
   214         if len(coltypes) == 1:
   214         if len(coltypes) == 1:
   215             etype = iter(coltypes).next()
   215             etype = iter(coltypes).next()
   216             if not self.schema.eschema(etype).is_final():
   216             if not self._cw.schema.eschema(etype).is_final():
   217                 if len(rset) == 1:
   217                 if len(rset) == 1:
   218                     entity = rset.get_entity(0, 0)
   218                     entity = rset.get_entity(0, 0)
   219                     return entity.absolute_url(vid=self.id)
   219                     return entity.absolute_url(vid=self.__regid__)
   220             # don't want to generate /<etype> url if there is some restriction
   220             # don't want to generate /<etype> url if there is some restriction
   221             # on something else than the entity type
   221             # on something else than the entity type
   222             restr = rset.syntax_tree().children[0].where
   222             restr = rset.syntax_tree().children[0].where
   223             # XXX norestriction is not correct here. For instance, in cases like
   223             # XXX norestriction is not correct here. For instance, in cases like
   224             # "Any P,N WHERE P is Project, P name N" norestriction should equal
   224             # "Any P,N WHERE P is Project, P name N" norestriction should equal
   225             # True
   225             # True
   226             norestriction = (isinstance(restr, nodes.Relation) and
   226             norestriction = (isinstance(restr, nodes.Relation) and
   227                              restr.is_types_restriction())
   227                              restr.is_types_restriction())
   228             if norestriction:
   228             if norestriction:
   229                 return self.build_url(etype.lower(), vid=self.id)
   229                 return self._cw.build_url(etype.lower(), vid=self.__regid__)
   230         return self.build_url('view', rql=rset.printable_rql(), vid=self.id)
   230         return self._cw.build_url('view', rql=rset.printable_rql(), vid=self.__regid__)
   231 
   231 
   232     def set_request_content_type(self):
   232     def set_request_content_type(self):
   233         """set the content type returned by this view"""
   233         """set the content type returned by this view"""
   234         self.req.set_content_type(self.content_type)
   234         self._cw.set_content_type(self.content_type)
   235 
   235 
   236     # view utilities ##########################################################
   236     # view utilities ##########################################################
   237 
   237 
   238     def wview(self, __vid, rset=None, __fallback_vid=None, **kwargs):
   238     def wview(self, __vid, rset=None, __fallback_vid=None, **kwargs):
   239         """shortcut to self.view method automatically passing self.w as argument
   239         """shortcut to self.view method automatically passing self.w as argument
   240         """
   240         """
   241         self.view(__vid, rset, __fallback_vid, w=self.w, **kwargs)
   241         self._cw.view(__vid, rset, __fallback_vid, w=self.w, **kwargs)
   242 
   242 
   243     # XXX Template bw compat
   243     # XXX Template bw compat
   244     template = deprecated('[3.4] .template is deprecated, use .view')(wview)
   244     template = deprecated('[3.4] .template is deprecated, use .view')(wview)
   245 
   245 
   246     def whead(self, data):
   246     def whead(self, data):
   247         self.req.html_headers.write(data)
   247         self._cw.html_headers.write(data)
   248 
   248 
   249     def wdata(self, data):
   249     def wdata(self, data):
   250         """simple helper that escapes `data` and writes into `self.w`"""
   250         """simple helper that escapes `data` and writes into `self.w`"""
   251         self.w(xml_escape(data))
   251         self.w(xml_escape(data))
   252 
   252 
   260 
   260 
   261     def page_title(self):
   261     def page_title(self):
   262         """returns a title according to the result set - used for the
   262         """returns a title according to the result set - used for the
   263         title in the HTML header
   263         title in the HTML header
   264         """
   264         """
   265         vtitle = self.req.form.get('vtitle')
   265         vtitle = self._cw.form.get('vtitle')
   266         if vtitle:
   266         if vtitle:
   267             return self.req._(vtitle)
   267             return self._cw._(vtitle)
   268         # class defined title will only be used if the resulting title doesn't
   268         # class defined title will only be used if the resulting title doesn't
   269         # seem clear enough
   269         # seem clear enough
   270         vtitle = getattr(self, 'title', None) or u''
   270         vtitle = getattr(self, 'title', None) or u''
   271         if vtitle:
   271         if vtitle:
   272             vtitle = self.req._(vtitle)
   272             vtitle = self._cw._(vtitle)
   273         rset = self.rset
   273         rset = self.cw_rset
   274         if rset and rset.rowcount:
   274         if rset and rset.rowcount:
   275             if rset.rowcount == 1:
   275             if rset.rowcount == 1:
   276                 try:
   276                 try:
   277                     entity = self.complete_entity(0)
   277                     entity = rset.complete_entity(0, 0)
   278                     # use long_title to get context information if any
   278                     # use long_title to get context information if any
   279                     clabel = entity.dc_long_title()
   279                     clabel = entity.dc_long_title()
   280                 except NotAnEntity:
   280                 except NotAnEntity:
   281                     clabel = display_name(self.req, rset.description[0][0])
   281                     clabel = display_name(self._cw, rset.description[0][0])
   282                     clabel = u'%s (%s)' % (clabel, vtitle)
   282                     clabel = u'%s (%s)' % (clabel, vtitle)
   283             else :
   283             else :
   284                 etypes = rset.column_types(0)
   284                 etypes = rset.column_types(0)
   285                 if len(etypes) == 1:
   285                 if len(etypes) == 1:
   286                     etype = iter(etypes).next()
   286                     etype = iter(etypes).next()
   287                     clabel = display_name(self.req, etype, 'plural')
   287                     clabel = display_name(self._cw, etype, 'plural')
   288                 else :
   288                 else :
   289                     clabel = u'#[*] (%s)' % vtitle
   289                     clabel = u'#[*] (%s)' % vtitle
   290         else:
   290         else:
   291             clabel = vtitle
   291             clabel = vtitle
   292         return u'%s (%s)' % (clabel, self.req.property_value('ui.site-title'))
   292         return u'%s (%s)' % (clabel, self._cw.property_value('ui.site-title'))
   293 
   293 
   294     def output_url_builder( self, name, url, args ):
   294     def output_url_builder( self, name, url, args ):
   295         self.w(u'<script language="JavaScript"><!--\n' \
   295         self.w(u'<script language="JavaScript"><!--\n' \
   296                u'function %s( %s ) {\n' % (name, ','.join(args) ) )
   296                u'function %s( %s ) {\n' % (name, ','.join(args) ) )
   297         url_parts = url.split("%s")
   297         url_parts = url.split("%s")
   303         self.w('\n document.window.href=url;\n')
   303         self.w('\n document.window.href=url;\n')
   304         self.w('}\n-->\n</script>\n')
   304         self.w('}\n-->\n</script>\n')
   305 
   305 
   306     def create_url(self, etype, **kwargs):
   306     def create_url(self, etype, **kwargs):
   307         """ return the url of the entity creation form for a given entity type"""
   307         """ return the url of the entity creation form for a given entity type"""
   308         return self.req.build_url('add/%s'%etype, **kwargs)
   308         return self._cw.build_url('add/%s'%etype, **kwargs)
   309 
   309 
   310     def field(self, label, value, row=True, show_label=True, w=None, tr=True):
   310     def field(self, label, value, row=True, show_label=True, w=None, tr=True):
   311         """ read-only field """
   311         """ read-only field """
   312         if w is None:
   312         if w is None:
   313             w = self.w
   313             w = self.w
   314         if row:
   314         if row:
   315             w(u'<div class="row">')
   315             w(u'<div class="row">')
   316         if show_label and label:
   316         if show_label and label:
   317             if tr:
   317             if tr:
   318                 label = display_name(self.req, label)
   318                 label = display_name(self._cw, label)
   319             w(u'<span class="label">%s</span>' % label)
   319             w(u'<span class="label">%s</span>' % label)
   320         w(u'<div class="field">%s</div>' % value)
   320         w(u'<div class="field">%s</div>' % value)
   321         if row:
   321         if row:
   322             w(u'</div>')
   322             w(u'</div>')
   323 
   323 
   368 
   368 
   369     def call(self, **kwargs):
   369     def call(self, **kwargs):
   370         """override call to execute rql returned by the .startup_rql method if
   370         """override call to execute rql returned by the .startup_rql method if
   371         necessary
   371         necessary
   372         """
   372         """
   373         if self.rset is None:
   373         rset = self.cw_rset
   374             self.rset = self.req.execute(self.startup_rql())
   374         if rset is None:
   375         rset = self.rset
   375             rset = self.cw_rset = self._cw.execute(self.startup_rql())
   376         for i in xrange(len(rset)):
   376         for i in xrange(len(rset)):
   377             self.wview(self.id, rset, row=i, **kwargs)
   377             self.wview(self.__regid__, rset, row=i, **kwargs)
   378 
   378 
   379 
   379 
   380 class AnyRsetView(View):
   380 class AnyRsetView(View):
   381     """base class for views applying on any non empty result sets"""
   381     """base class for views applying on any non empty result sets"""
   382     __select__ = nonempty_rset()
   382     __select__ = nonempty_rset()
   383 
   383 
   384     category = 'anyrsetview'
   384     category = 'anyrsetview'
   385 
   385 
   386     def columns_labels(self, mainindex=0, tr=True):
   386     def columns_labels(self, mainindex=0, tr=True):
   387         if tr:
   387         if tr:
   388             translate = lambda val, req=self.req: display_name(req, val)
   388             translate = lambda val, req=self._cw: display_name(req, val)
   389         else:
   389         else:
   390             translate = lambda val: val
   390             translate = lambda val: val
   391         # XXX [0] because of missing Union support
   391         # XXX [0] because of missing Union support
   392         rqlstdescr = self.rset.syntax_tree().get_description(mainindex,
   392         rqlstdescr = self.cw_rset.syntax_tree().get_description(mainindex,
   393                                                              translate)[0]
   393                                                                 translate)[0]
   394         labels = []
   394         labels = []
   395         for colindex, label in enumerate(rqlstdescr):
   395         for colindex, label in enumerate(rqlstdescr):
   396             # compute column header
   396             # compute column header
   397             if label == 'Any': # find a better label
   397             if label == 'Any': # find a better label
   398                 label = ','.join(translate(et)
   398                 label = ','.join(translate(et)
   399                                  for et in self.rset.column_types(colindex))
   399                                  for et in self.cw_rset.column_types(colindex))
   400             labels.append(label)
   400             labels.append(label)
   401         return labels
   401         return labels
   402 
   402 
   403 
   403 
   404 # concrete template base classes ##############################################
   404 # concrete template base classes ##############################################
   409     one to display error if the first one failed
   409     one to display error if the first one failed
   410     """
   410     """
   411 
   411 
   412     @property
   412     @property
   413     def doctype(self):
   413     def doctype(self):
   414         if self.req.xhtml_browser():
   414         if self._cw.xhtml_browser():
   415             return STRICT_DOCTYPE
   415             return STRICT_DOCTYPE
   416         return STRICT_DOCTYPE_NOEXT
   416         return STRICT_DOCTYPE_NOEXT
   417 
   417 
   418     def set_stream(self, w=None):
   418     def set_stream(self, w=None):
   419         if self.w is not None:
   419         if self.w is not None:
   420             return
   420             return
   421         if w is None:
   421         if w is None:
   422             if self.binary:
   422             if self.binary:
   423                 self._stream = stream = StringIO()
   423                 self._stream = stream = StringIO()
   424             else:
   424             else:
   425                 self._stream = stream = HTMLStream(self.req)
   425                 self._stream = stream = HTMLStream(self._cw)
   426             w = stream.write
   426             w = stream.write
   427         else:
   427         else:
   428             stream = None
   428             stream = None
   429         self.w = w
   429         self.w = w
   430         return stream
   430         return stream
   445 
   445 
   446     def user_callback(self, cb, args, msg=None, nonify=False):
   446     def user_callback(self, cb, args, msg=None, nonify=False):
   447         """register the given user callback and return an url to call it ready to be
   447         """register the given user callback and return an url to call it ready to be
   448         inserted in html
   448         inserted in html
   449         """
   449         """
   450         self.req.add_js('cubicweb.ajax.js')
   450         self._cw.add_js('cubicweb.ajax.js')
   451         if nonify:
   451         if nonify:
   452             _cb = cb
   452             _cb = cb
   453             def cb(*args):
   453             def cb(*args):
   454                 _cb(*args)
   454                 _cb(*args)
   455         cbname = self.req.register_onetime_callback(cb, *args)
   455         cbname = self._cw.register_onetime_callback(cb, *args)
   456         return self.build_js(cbname, xml_escape(msg or ''))
   456         return self.build_js(cbname, xml_escape(msg or ''))
   457 
   457 
   458     def build_update_js_call(self, cbname, msg):
   458     def build_update_js_call(self, cbname, msg):
   459         rql = xml_escape(self.rset.printable_rql())
   459         rql = xml_escape(self.cw_rset.printable_rql())
   460         return "javascript:userCallbackThenUpdateUI('%s', '%s', '%s', '%s', '%s', '%s')" % (
   460         return "javascript:userCallbackThenUpdateUI('%s', '%s', '%s', '%s', '%s', '%s')" % (
   461             cbname, self.id, rql, msg, self.__registry__, self.div_id())
   461             cbname, self.__regid__, rql, msg, self.__registry__, self.div_id())
   462 
   462 
   463     def build_reload_js_call(self, cbname, msg):
   463     def build_reload_js_call(self, cbname, msg):
   464         return "javascript:userCallbackThenReloadPage('%s', '%s')" % (cbname, msg)
   464         return "javascript:userCallbackThenReloadPage('%s', '%s')" % (cbname, msg)
   465 
   465 
   466     build_js = build_update_js_call # expect updatable component by default
   466     build_js = build_update_js_call # expect updatable component by default
   475     __select__ = yes()
   475     __select__ = yes()
   476 
   476 
   477     # XXX huummm, much probably useless
   477     # XXX huummm, much probably useless
   478     htmlclass = 'mainRelated'
   478     htmlclass = 'mainRelated'
   479     def div_class(self):
   479     def div_class(self):
   480         return '%s %s' % (self.htmlclass, self.id)
   480         return '%s %s' % (self.htmlclass, self.__regid__)
   481 
   481 
   482     # XXX a generic '%s%s' % (self.id, self.__registry__.capitalize()) would probably be nicer
   482     # XXX a generic '%s%s' % (self.__regid__, self.__registry__.capitalize()) would probably be nicer
   483     def div_id(self):
   483     def div_id(self):
   484         return '%sComponent' % self.id
   484         return '%sComponent' % self.__regid__