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: |