web/views/primary.py
changeset 7845 2172978be237
parent 7797 a71618a75b53
parent 7844 0208c65a88a5
child 7846 dd3f0871d8b7
equal deleted inserted replaced
7841:287813c487b7 7845:2172978be237
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    14 # details.
    14 # details.
    15 #
    15 #
    16 # You should have received a copy of the GNU Lesser General Public License along
    16 # You should have received a copy of the GNU Lesser General Public License along
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    18 """The default primary view"""
    18 """
       
    19 Public API of the PrimaryView class
       
    20 ````````````````````````````````````
       
    21 .. autoclass:: cubicweb.web.views.primary.PrimaryView
       
    22 
       
    23 Views that may be used to display an entity's attribute or relation
       
    24 ```````````````````````````````````````````````````````````````````
       
    25 
       
    26 Yoy may easily the display of an attribute or relation by simply configuring the
       
    27 view using one of `primaryview_display_ctrl` or `reledit_ctrl` to use one of the
       
    28 views describled below. For instance:
       
    29 
       
    30 .. sourcecode:: python
       
    31 
       
    32     primaryview_display_ctrl.tag_attribute(('Foo', 'bar'), {'vid': 'attribute'})
       
    33 
       
    34 
       
    35 .. autoclass:: AttributeView
       
    36 .. autoclass:: URLAttributeView
       
    37 """
    19 
    38 
    20 __docformat__ = "restructuredtext en"
    39 __docformat__ = "restructuredtext en"
    21 _ = unicode
    40 _ = unicode
    22 
    41 
    23 from warnings import warn
    42 from warnings import warn
    32 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
    51 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
    33 from cubicweb.web import uicfg, component
    52 from cubicweb.web import uicfg, component
    34 
    53 
    35 
    54 
    36 class PrimaryView(EntityView):
    55 class PrimaryView(EntityView):
    37     """the full view of an non final entity"""
    56     """
       
    57     The basic layout of a primary view is as in the :ref:`primary_view_layout`
       
    58     section. This layout is actually drawn by the `render_entity` method.
       
    59 
       
    60     The methods you may want to modify while customizing a ``PrimaryView``
       
    61     are:
       
    62 
       
    63     .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_title
       
    64     .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_attributes
       
    65     .. automethod:: cubicweb.web.views.primary.PrimaryView.render_entity_relations
       
    66     .. automethod:: cubicweb.web.views.primary.PrimaryView.render_side_boxes
       
    67 
       
    68     The placement of relations in the relations section or in side boxes
       
    69     can be controlled through the :ref:`primary_view_configuration` mechanism.
       
    70 
       
    71     .. automethod:: cubicweb.web.views.primary.PrimaryView.content_navigation_components
       
    72 
       
    73     Also, please note that by setting the following attributes in your
       
    74     subclass, you can already customize some of the rendering:
       
    75 
       
    76     :attr:`show_attr_label`
       
    77         Renders the attribute label next to the attribute value if set to `True`.
       
    78         Otherwise, does only display the attribute value.
       
    79 
       
    80     :attr:`show_rel_label`
       
    81         Renders the relation label next to the relation value if set to `True`.
       
    82         Otherwise, does only display the relation value.
       
    83 
       
    84     :attr:`skip_none`
       
    85         Does not render an attribute value that is None if set to `True`.
       
    86 
       
    87     :attr:`main_related_section`
       
    88         Renders the relations of the entity if set to `True`.
       
    89 
       
    90     A good practice is for you to identify the content of your entity type for
       
    91     which the default rendering does not answer your need so that you can focus
       
    92     on the specific method (from the list above) that needs to be modified. We
       
    93     do not advise you to overwrite ``render_entity`` unless you want a
       
    94     completely different layout.
       
    95     """
       
    96 
    38     __regid__ = 'primary'
    97     __regid__ = 'primary'
    39     title = _('primary')
    98     title = _('primary')
    40     show_attr_label = True
    99     show_attr_label = True
    41     show_rel_label = True
   100     show_rel_label = True
    42     skip_none = True
   101     skip_none = True
    93             self.render_side_boxes(boxes)
   152             self.render_side_boxes(boxes)
    94             self.w(u'</div>')
   153             self.w(u'</div>')
    95             self.w(u'</td></tr></table>')
   154             self.w(u'</td></tr></table>')
    96 
   155 
    97     def content_navigation_components(self, context):
   156     def content_navigation_components(self, context):
       
   157         """This method is applicable only for entity type implementing the
       
   158         interface `IPrevNext`. This interface is for entities which can be
       
   159         linked to a previous and/or next entity. This method will render the
       
   160         navigation links between entities of this type, either at the top or at
       
   161         the bottom of the page given the context (navcontent{top|bottom}).
       
   162         """
    98         self.w(u'<div class="%s">' % context)
   163         self.w(u'<div class="%s">' % context)
    99         for comp in self._cw.vreg['ctxcomponents'].poss_visible_objects(
   164         for comp in self._cw.vreg['ctxcomponents'].poss_visible_objects(
   100             self._cw, rset=self.cw_rset, view=self, context=context):
   165             self._cw, rset=self.cw_rset, view=self, context=context):
   101             # XXX bw compat code
   166             # XXX bw compat code
   102             try:
   167             try:
   104             except TypeError:
   169             except TypeError:
   105                 comp.render(w=self.w)
   170                 comp.render(w=self.w)
   106         self.w(u'</div>')
   171         self.w(u'</div>')
   107 
   172 
   108     def render_entity_title(self, entity):
   173     def render_entity_title(self, entity):
   109         """default implementation return dc_title"""
   174         """Renders the entity title, by default using entity's
       
   175         :meth:`dc_title()` method.
       
   176         """
   110         title = xml_escape(entity.dc_title())
   177         title = xml_escape(entity.dc_title())
   111         if title:
   178         if title:
   112             if self.is_primary():
   179             if self.is_primary():
   113                 self.w(u'<h1>%s</h1>' % title)
   180                 self.w(u'<h1>%s</h1>' % title)
   114             else:
   181             else:
   126     def summary(self, entity):
   193     def summary(self, entity):
   127         """default implementation return an empty string"""
   194         """default implementation return an empty string"""
   128         return u''
   195         return u''
   129 
   196 
   130     def render_entity_attributes(self, entity):
   197     def render_entity_attributes(self, entity):
       
   198         """Renders all attributes and relations in the 'attributes' section. The
       
   199         :attr:`skip_none` attribute controls the display of `None` valued
       
   200         attributes.
       
   201         """
   131         display_attributes = []
   202         display_attributes = []
   132         for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'):
   203         for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'):
   133             vid = dispctrl.get('vid', 'reledit')
   204             vid = dispctrl.get('vid', 'reledit')
   134             if rschema.final or vid == 'reledit' or dispctrl.get('rtypevid'):
   205             if rschema.final or vid == 'reledit' or dispctrl.get('rtypevid'):
   135                 value = entity.view(vid, rtype=rschema.type, role=role,
   206                 value = entity.view(vid, rtype=rschema.type, role=role,
   163 
   234 
   164     def render_attribute(self, label, value, table=False):
   235     def render_attribute(self, label, value, table=False):
   165         self.field(label, value, tr=False, table=table)
   236         self.field(label, value, tr=False, table=table)
   166 
   237 
   167     def render_entity_relations(self, entity):
   238     def render_entity_relations(self, entity):
       
   239         """Renders all relations in the 'relations' section."""
   168         for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'):
   240         for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'):
   169             if rschema.final or dispctrl.get('rtypevid'):
   241             if rschema.final or dispctrl.get('rtypevid'):
   170                 vid = dispctrl.get('vid', 'reledit')
   242                 vid = dispctrl.get('vid', 'reledit')
   171                 try:
   243                 try:
   172                     rview = self._cw.vreg['views'].select(
   244                     rview = self._cw.vreg['views'].select(
   210             self.w(u'<h4>%s</h4>' % label)
   282             self.w(u'<h4>%s</h4>' % label)
   211         self.w(value)
   283         self.w(value)
   212         self.w(u'</div>')
   284         self.w(u'</div>')
   213 
   285 
   214     def render_side_boxes(self, boxes):
   286     def render_side_boxes(self, boxes):
   215         """display side related relations:
   287         """Renders side boxes on the right side of the content. This will
   216         non-meta in a first step, meta in a second step
   288         generate a box for each relation in the 'sidebox' section, as well as
       
   289         explicit box appobjects selectable in this context.
   217         """
   290         """
   218         for box in boxes:
   291         for box in boxes:
   219             if isinstance(box, tuple):
   292             if isinstance(box, tuple):
   220                 try:
   293                 try:
   221                     label, rset, vid, dispctrl  = box
   294                     label, rset, vid, dispctrl  = box
   303     """Display a rset, usually containing entities linked to another entity
   376     """Display a rset, usually containing entities linked to another entity
   304     being displayed.
   377     being displayed.
   305 
   378 
   306     It will try to display nicely according to the number of items in the result
   379     It will try to display nicely according to the number of items in the result
   307     set.
   380     set.
       
   381 
       
   382     XXX include me in the doc
   308     """
   383     """
   309     __regid__ = 'autolimited'
   384     __regid__ = 'autolimited'
   310 
   385 
   311     def call(self, **kwargs):
   386     def call(self, **kwargs):
   312         if 'dispctrl' in self.cw_extra_kwargs:
   387         if 'dispctrl' in self.cw_extra_kwargs:
   345                     self._cw._('see them all')))
   420                     self._cw._('see them all')))
   346                 self.w(u'</div>')
   421                 self.w(u'</div>')
   347 
   422 
   348 
   423 
   349 class URLAttributeView(EntityView):
   424 class URLAttributeView(EntityView):
   350     """use this view for attributes whose value is an url and that you want
   425     """:__regid__: *urlattr*
   351     to display as clickable link
   426 
       
   427     This view will wrap an attribute value (hence expect a string) into an '<a>'
       
   428     HTML tag to display a clickable link.
   352     """
   429     """
   353     __regid__ = 'urlattr'
   430     __regid__ = 'urlattr'
   354     __select__ = EntityView.__select__ & match_kwargs('rtype')
   431     __select__ = EntityView.__select__ & match_kwargs('rtype')
   355 
   432 
   356     def cell_call(self, row, col, rtype, **kwargs):
   433     def entity_call(self, entity, rtype, **kwargs):
   357         entity = self.cw_rset.get_entity(row, col)
       
   358         url = entity.printable_value(rtype)
   434         url = entity.printable_value(rtype)
   359         if url:
   435         if url:
   360             self.w(u'<a href="%s">%s</a>' % (url, url))
   436             self.w(u'<a href="%s">%s</a>' % (url, url))
   361 
   437 
   362 class AttributeView(EntityView):
   438 class AttributeView(EntityView):
   363     """use this view on an entity as an alternative to more sophisticated
   439     """:__regid__: *attribute*
   364     views such as reledit.
   440 
   365 
   441     This view is generally used to disable the *reledit* feature. It works on
   366     Ex. usage:
   442     both relations and attributes.
   367 
       
   368     uicfg.primaryview_display_ctrl.tag_attribute(('Foo', 'bar'), {'vid': 'attribute'})
       
   369     """
   443     """
   370     __regid__ = 'attribute'
   444     __regid__ = 'attribute'
   371     __select__ = EntityView.__select__ & match_kwargs('rtype')
   445     __select__ = EntityView.__select__ & match_kwargs('rtype')
   372 
   446 
   373     def cell_call(self, row, col, rtype, role, **kwargs):
   447     def entity_call(self, entity, rtype, **kwargs):
   374         entity = self.cw_rset.get_entity(row, col)
       
   375         if self._cw.vreg.schema.rschema(rtype).final:
   448         if self._cw.vreg.schema.rschema(rtype).final:
   376             self.w(entity.printable_value(rtype))
   449             self.w(entity.printable_value(rtype))
   377         else:
   450         else:
   378             dispctrl = uicfg.primaryview_display_ctrl.etype_get(
   451             dispctrl = uicfg.primaryview_display_ctrl.etype_get(
   379                 entity.e_schema, rtype, role, '*')
   452                 entity.e_schema, rtype, role, '*')
   382                 self.wview('autolimited', rset, initargs={'dispctrl': dispctrl})
   455                 self.wview('autolimited', rset, initargs={'dispctrl': dispctrl})
   383 
   456 
   384 
   457 
   385 
   458 
   386 class ToolbarLayout(component.Layout):
   459 class ToolbarLayout(component.Layout):
       
   460     # XXX include me in the doc
   387     __select__ = match_context('ctxtoolbar')
   461     __select__ = match_context('ctxtoolbar')
   388 
   462 
   389     def render(self, w):
   463     def render(self, w):
   390         if self.init_rendering():
   464         if self.init_rendering():
   391             self.cw_extra_kwargs['view'].render_body(w)
   465             self.cw_extra_kwargs['view'].render_body(w)
       
   466 
   392 
   467 
   393 ## default primary ui configuration ###########################################
   468 ## default primary ui configuration ###########################################
   394 
   469 
   395 _pvs = uicfg.primaryview_section
   470 _pvs = uicfg.primaryview_section
   396 for rtype in META_RTYPES:
   471 for rtype in META_RTYPES: