38 |
38 |
39 class NoResultView(View): |
39 class NoResultView(View): |
40 """default view when no result has been found""" |
40 """default view when no result has been found""" |
41 __select__ = empty_rset() |
41 __select__ = empty_rset() |
42 id = 'noresult' |
42 id = 'noresult' |
43 |
43 |
44 def call(self, **kwargs): |
44 def call(self, **kwargs): |
45 self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n' |
45 self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n' |
46 % self.req._('No result matching query')) |
46 % self.req._('No result matching query')) |
47 |
47 |
48 |
48 |
49 class FinalView(AnyRsetView): |
49 class FinalView(AnyRsetView): |
50 """display values without any transformation (i.e. get a number for |
50 """display values without any transformation (i.e. get a number for |
51 entities) |
51 entities) |
52 """ |
52 """ |
53 id = 'final' |
53 id = 'final' |
54 # record generated i18n catalog messages |
54 # record generated i18n catalog messages |
55 _('%d years') |
55 _('%d years') |
56 _('%d months') |
56 _('%d months') |
64 _('%d weeks') |
64 _('%d weeks') |
65 _('%d days') |
65 _('%d days') |
66 _('%d hours') |
66 _('%d hours') |
67 _('%d minutes') |
67 _('%d minutes') |
68 _('%d seconds') |
68 _('%d seconds') |
69 |
69 |
70 def cell_call(self, row, col, props=None, displaytime=False, format='text/html'): |
70 def cell_call(self, row, col, props=None, displaytime=False, format='text/html'): |
71 etype = self.rset.description[row][col] |
71 etype = self.rset.description[row][col] |
72 value = self.rset.rows[row][col] |
72 value = self.rset.rows[row][col] |
73 if etype == 'String': |
73 if etype == 'String': |
74 entity, rtype = self.rset.related_entity(row, col) |
74 entity, rtype = self.rset.related_entity(row, col) |
75 if entity is not None: |
75 if entity is not None: |
76 # yes ! |
76 # yes ! |
77 self.w(entity.printable_value(rtype, value, format=format)) |
77 self.w(entity.printable_value(rtype, value, format=format)) |
78 return |
78 return |
79 if etype in ('Time', 'Interval'): |
79 if etype in ('Time', 'Interval'): |
80 # value is DateTimeDelta but we have no idea about what is the |
80 # value is DateTimeDelta but we have no idea about what is the |
81 # reference date here, so we can only approximate years and months |
81 # reference date here, so we can only approximate years and months |
82 if format == 'text/html': |
82 if format == 'text/html': |
83 space = ' ' |
83 space = ' ' |
84 else: |
84 else: |
85 space = ' ' |
85 space = ' ' |
98 else: |
98 else: |
99 self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds)) |
99 self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds)) |
100 return |
100 return |
101 self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime)) |
101 self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime)) |
102 |
102 |
103 |
103 |
104 PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity', |
104 PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity', |
105 'owned_by', 'created_by', |
105 'owned_by', 'created_by', |
106 'in_state', 'wf_info_for', 'require_permission', |
106 'in_state', 'wf_info_for', 'require_permission', |
107 'from_entity', 'to_entity', |
107 'from_entity', 'to_entity', |
108 'see_also']) |
108 'see_also']) |
109 |
109 |
110 class PrimaryView(EntityView): |
110 class PrimaryView(EntityView): |
123 <head> and </head> of the returned page |
123 <head> and </head> of the returned page |
124 |
124 |
125 by default primary views are indexed |
125 by default primary views are indexed |
126 """ |
126 """ |
127 return [] |
127 return [] |
128 |
128 |
129 def cell_call(self, row, col): |
129 def cell_call(self, row, col): |
130 self.row = row |
130 self.row = row |
131 # XXX move render_entity implementation here |
131 # XXX move render_entity implementation here |
132 self.render_entity(self.complete_entity(row, col)) |
132 self.render_entity(self.complete_entity(row, col)) |
133 |
133 |
134 def render_entity(self, entity): |
134 def render_entity(self, entity): |
135 """return html to display the given entity""" |
135 """return html to display the given entity""" |
136 siderelations = [] |
136 siderelations = [] |
137 self.render_entity_title(entity) |
137 self.render_entity_title(entity) |
138 self.render_entity_metadata(entity) |
138 self.render_entity_metadata(entity) |
148 self.w(u'</div>') |
148 self.w(u'</div>') |
149 # side boxes |
149 # side boxes |
150 self.w(u'<div class="primaryRight">') |
150 self.w(u'<div class="primaryRight">') |
151 self.render_side_related(entity, siderelations) |
151 self.render_side_related(entity, siderelations) |
152 self.w(u'</div>') |
152 self.w(u'</div>') |
153 self.w(u'<div class="clear"></div>') |
153 self.w(u'<div class="clear"></div>') |
154 self.content_navigation_components('navcontentbottom') |
154 self.content_navigation_components('navcontentbottom') |
155 |
155 |
156 def content_navigation_components(self, context): |
156 def content_navigation_components(self, context): |
157 self.w(u'<div class="%s">' % context) |
157 self.w(u'<div class="%s">' % context) |
158 for comp in self.vreg.possible_vobjects('contentnavigation', |
158 for comp in self.vreg.possible_vobjects('contentnavigation', |
163 except NotImplementedError: |
163 except NotImplementedError: |
164 warn('component %s doesnt implement cell_call, please update' |
164 warn('component %s doesnt implement cell_call, please update' |
165 % comp.__class__, DeprecationWarning) |
165 % comp.__class__, DeprecationWarning) |
166 comp.dispatch(w=self.w, view=self) |
166 comp.dispatch(w=self.w, view=self) |
167 self.w(u'</div>') |
167 self.w(u'</div>') |
168 |
168 |
169 def iter_attributes(self, entity): |
169 def iter_attributes(self, entity): |
170 for rschema, targetschema in entity.e_schema.attribute_definitions(): |
170 for rschema, targetschema in entity.e_schema.attribute_definitions(): |
171 if rschema.type in self.skip_attrs: |
171 if rschema.type in self.skip_attrs: |
172 continue |
172 continue |
173 yield rschema, targetschema |
173 yield rschema, targetschema |
174 |
174 |
175 def iter_relations(self, entity): |
175 def iter_relations(self, entity): |
176 skip = set(self.skip_rels) |
176 skip = set(self.skip_rels) |
177 skip.update(PRIMARY_SKIP_RELS) |
177 skip.update(PRIMARY_SKIP_RELS) |
178 for rschema, targetschemas, x in entity.e_schema.relation_definitions(): |
178 for rschema, targetschemas, x in entity.e_schema.relation_definitions(): |
179 if rschema.type in skip: |
179 if rschema.type in skip: |
183 def render_entity_title(self, entity): |
183 def render_entity_title(self, entity): |
184 title = self.content_title(entity) # deprecate content_title? |
184 title = self.content_title(entity) # deprecate content_title? |
185 if title: |
185 if title: |
186 self.w(u'<h1><span class="etype">%s</span> %s</h1>' |
186 self.w(u'<h1><span class="etype">%s</span> %s</h1>' |
187 % (entity.dc_type().capitalize(), title)) |
187 % (entity.dc_type().capitalize(), title)) |
188 |
188 |
189 def content_title(self, entity): |
189 def content_title(self, entity): |
190 """default implementation return an empty string""" |
190 """default implementation return an empty string""" |
191 return u'' |
191 return u'' |
192 |
192 |
193 def render_entity_metadata(self, entity): |
193 def render_entity_metadata(self, entity): |
194 entity.view('metadata', w=self.w) |
194 entity.view('metadata', w=self.w) |
195 summary = self.summary(entity) # deprecate summary? |
195 summary = self.summary(entity) # deprecate summary? |
196 if summary: |
196 if summary: |
197 self.w(u'<div class="summary">%s</div>' % summary) |
197 self.w(u'<div class="summary">%s</div>' % summary) |
198 |
198 |
199 def summary(self, entity): |
199 def summary(self, entity): |
200 """default implementation return an empty string""" |
200 """default implementation return an empty string""" |
201 return u'' |
201 return u'' |
202 |
202 |
203 def render_entity_attributes(self, entity, siderelations): |
203 def render_entity_attributes(self, entity, siderelations): |
204 for rschema, targetschema in self.iter_attributes(entity): |
204 for rschema, targetschema in self.iter_attributes(entity): |
205 attr = rschema.type |
205 attr = rschema.type |
206 if targetschema.type in ('Password', 'Bytes'): |
206 if targetschema.type in ('Password', 'Bytes'): |
207 continue |
207 continue |
261 try: |
261 try: |
262 box.dispatch(w=self.w, row=self.row) |
262 box.dispatch(w=self.w, row=self.row) |
263 except NotImplementedError: |
263 except NotImplementedError: |
264 # much probably a context insensitive box, which only implements |
264 # much probably a context insensitive box, which only implements |
265 # .call() and not cell_call() |
265 # .call() and not cell_call() |
266 box.dispatch(w=self.w) |
266 box.dispatch(w=self.w) |
267 |
267 |
268 def is_side_related(self, rschema, eschema): |
268 def is_side_related(self, rschema, eschema): |
269 return rschema.meta and \ |
269 return rschema.meta and \ |
270 not rschema.schema_relation() == eschema.schema_entity() |
270 not rschema.schema_relation() == eschema.schema_entity() |
271 |
271 |
272 def _render_related_entities(self, entity, rschema, related, |
272 def _render_related_entities(self, entity, rschema, related, |
296 self.req._('see them all')) |
296 self.req._('see them all')) |
297 value += '</div>' |
297 value += '</div>' |
298 label = display_name(self.req, rschema.type, role) |
298 label = display_name(self.req, rschema.type, role) |
299 self.field(label, value, show_label=show_label, w=self.w, tr=False) |
299 self.field(label, value, show_label=show_label, w=self.w, tr=False) |
300 |
300 |
301 |
301 |
302 class SecondaryView(EntityView): |
302 class SecondaryView(EntityView): |
303 id = 'secondary' |
303 id = 'secondary' |
304 title = _('secondary') |
304 title = _('secondary') |
305 |
305 |
306 def cell_call(self, row, col): |
306 def cell_call(self, row, col): |
307 """the secondary view for an entity |
307 """the secondary view for an entity |
308 secondary = icon + view(oneline) |
308 secondary = icon + view(oneline) |
309 """ |
309 """ |
310 entity = self.entity(row, col) |
310 entity = self.entity(row, col) |
312 self.wview('oneline', self.rset, row=row, col=col) |
312 self.wview('oneline', self.rset, row=row, col=col) |
313 |
313 |
314 |
314 |
315 class OneLineView(EntityView): |
315 class OneLineView(EntityView): |
316 id = 'oneline' |
316 id = 'oneline' |
317 title = _('oneline') |
317 title = _('oneline') |
318 |
318 |
319 def cell_call(self, row, col): |
319 def cell_call(self, row, col): |
320 """the one line view for an entity: linked text view |
320 """the one line view for an entity: linked text view |
321 """ |
321 """ |
322 entity = self.entity(row, col) |
322 entity = self.entity(row, col) |
343 raise NotImplementedError, self |
343 raise NotImplementedError, self |
344 for i in xrange(len(rset)): |
344 for i in xrange(len(rset)): |
345 self.wview(self.id, rset, row=i, **kwargs) |
345 self.wview(self.id, rset, row=i, **kwargs) |
346 if len(rset) > 1: |
346 if len(rset) > 1: |
347 self.w(u"\n") |
347 self.w(u"\n") |
348 |
348 |
349 def cell_call(self, row, col=0, **kwargs): |
349 def cell_call(self, row, col=0, **kwargs): |
350 entity = self.entity(row, col) |
350 entity = self.entity(row, col) |
351 self.w(cut(entity.dc_title(), |
351 self.w(cut(entity.dc_title(), |
352 self.req.property_value('navigation.short-line-size'))) |
352 self.req.property_value('navigation.short-line-size'))) |
353 |
353 |
354 |
354 |
355 class MetaDataView(EntityView): |
355 class MetaDataView(EntityView): |
356 """paragraph view of some metadata""" |
356 """paragraph view of some metadata""" |
357 id = 'metadata' |
357 id = 'metadata' |
358 show_eid = True |
358 show_eid = True |
359 |
359 |
360 def cell_call(self, row, col): |
360 def cell_call(self, row, col): |
361 _ = self.req._ |
361 _ = self.req._ |
362 entity = self.entity(row, col) |
362 entity = self.entity(row, col) |
363 self.w(u'<div class="metadata">') |
363 self.w(u'<div class="metadata">') |
364 if self.show_eid: |
364 if self.show_eid: |
366 if entity.modification_date != entity.creation_date: |
366 if entity.modification_date != entity.creation_date: |
367 self.w(u'<span>%s</span> ' % _('latest update on')) |
367 self.w(u'<span>%s</span> ' % _('latest update on')) |
368 self.w(u'<span class="value">%s</span>, ' |
368 self.w(u'<span class="value">%s</span>, ' |
369 % self.format_date(entity.modification_date)) |
369 % self.format_date(entity.modification_date)) |
370 # entities from external source may not have a creation date (eg ldap) |
370 # entities from external source may not have a creation date (eg ldap) |
371 if entity.creation_date: |
371 if entity.creation_date: |
372 self.w(u'<span>%s</span> ' % _('created on')) |
372 self.w(u'<span>%s</span> ' % _('created on')) |
373 self.w(u'<span class="value">%s</span>' |
373 self.w(u'<span class="value">%s</span>' |
374 % self.format_date(entity.creation_date)) |
374 % self.format_date(entity.creation_date)) |
375 if entity.creator: |
375 if entity.creator: |
376 self.w(u' <span>%s</span> ' % _('by')) |
376 self.w(u' <span>%s</span> ' % _('by')) |
406 self.w(u'<a href="%s" title="%s">' % (html_escape(entity.absolute_url()), |
406 self.w(u'<a href="%s" title="%s">' % (html_escape(entity.absolute_url()), |
407 html_escape(desc))) |
407 html_escape(desc))) |
408 self.w(html_escape(self.view('textincontext', self.rset, row=row, col=col))) |
408 self.w(html_escape(self.view('textincontext', self.rset, row=row, col=col))) |
409 self.w(u'</a>') |
409 self.w(u'</a>') |
410 |
410 |
411 |
411 |
412 class OutOfContextView(EntityView): |
412 class OutOfContextView(EntityView): |
413 id = 'outofcontext' |
413 id = 'outofcontext' |
414 |
414 |
415 def cell_call(self, row, col): |
415 def cell_call(self, row, col): |
416 self.w(u'<a href="%s">' % self.entity(row, col).absolute_url()) |
416 self.w(u'<a href="%s">' % self.entity(row, col).absolute_url()) |
417 self.w(html_escape(self.view('textoutofcontext', self.rset, row=row, col=col))) |
417 self.w(html_escape(self.view('textoutofcontext', self.rset, row=row, col=col))) |
418 self.w(u'</a>') |
418 self.w(u'</a>') |
419 |
419 |
420 |
420 |
421 # list views ################################################################## |
421 # list views ################################################################## |
422 |
422 |
423 class ListView(EntityView): |
423 class ListView(EntityView): |
424 id = 'list' |
424 id = 'list' |
425 title = _('list') |
425 title = _('list') |
426 item_vid = 'listitem' |
426 item_vid = 'listitem' |
427 |
427 |
428 def call(self, klass=None, title=None, subvid=None, listid=None, **kwargs): |
428 def call(self, klass=None, title=None, subvid=None, listid=None, **kwargs): |
429 """display a list of entities by calling their <item_vid> view |
429 """display a list of entities by calling their <item_vid> view |
430 |
430 |
431 :param listid: the DOM id to use for the root element |
431 :param listid: the DOM id to use for the root element |
432 """ |
432 """ |
433 if subvid is None and 'subvid' in self.req.form: |
433 if subvid is None and 'subvid' in self.req.form: |
434 subvid = self.req.form.pop('subvid') # consume it |
434 subvid = self.req.form.pop('subvid') # consume it |
435 if listid: |
435 if listid: |
472 if len(self.rset) == 1: |
472 if len(self.rset) == 1: |
473 entity = self.rset.get_entity(0, 0) |
473 entity = self.rset.get_entity(0, 0) |
474 return self.build_url(entity.rest_path(), vid=self.id) |
474 return self.build_url(entity.rest_path(), vid=self.id) |
475 return self.build_url(rql=self.rset.printable_rql(), vid=self.id) |
475 return self.build_url(rql=self.rset.printable_rql(), vid=self.id) |
476 |
476 |
477 |
477 |
478 class ListItemView(EntityView): |
478 class ListItemView(EntityView): |
479 id = 'listitem' |
479 id = 'listitem' |
480 |
480 |
481 @property |
481 @property |
482 def redirect_vid(self): |
482 def redirect_vid(self): |
483 if self.req.search_state[0] == 'normal': |
483 if self.req.search_state[0] == 'normal': |
484 return 'outofcontext' |
484 return 'outofcontext' |
485 return 'outofcontext-search' |
485 return 'outofcontext-search' |
486 |
486 |
487 def cell_call(self, row, col, vid=None, **kwargs): |
487 def cell_call(self, row, col, vid=None, **kwargs): |
488 if not vid: |
488 if not vid: |
489 vid = self.redirect_vid |
489 vid = self.redirect_vid |
490 try: |
490 try: |
491 self.wview(vid, self.rset, row=row, col=col, **kwargs) |
491 self.wview(vid, self.rset, row=row, col=col, **kwargs) |
502 |
502 |
503 |
503 |
504 class CSVView(SimpleListView): |
504 class CSVView(SimpleListView): |
505 id = 'csv' |
505 id = 'csv' |
506 redirect_vid = 'incontext' |
506 redirect_vid = 'incontext' |
507 |
507 |
508 def call(self, **kwargs): |
508 def call(self, **kwargs): |
509 rset = self.rset |
509 rset = self.rset |
510 for i in xrange(len(rset)): |
510 for i in xrange(len(rset)): |
511 self.cell_call(i, 0, vid=kwargs.get('vid')) |
511 self.cell_call(i, 0, vid=kwargs.get('vid')) |
512 if i < rset.rowcount-1: |
512 if i < rset.rowcount-1: |
513 self.w(u", ") |
513 self.w(u", ") |
514 |
514 |
515 |
515 |
516 class TreeItemView(ListItemView): |
516 class TreeItemView(ListItemView): |
517 id = 'treeitem' |
517 id = 'treeitem' |
518 |
518 |
519 def cell_call(self, row, col): |
519 def cell_call(self, row, col): |
520 self.wview('incontext', self.rset, row=row, col=col) |
520 self.wview('incontext', self.rset, row=row, col=col) |
521 |
521 |
522 |
522 |
523 class TextSearchResultView(EntityView): |
523 class TextSearchResultView(EntityView): |
550 if len(ctx) > 30: |
550 if len(ctx) > 30: |
551 contexts.append(u'...' + ctx[-30:]) |
551 contexts.append(u'...' + ctx[-30:]) |
552 else: |
552 else: |
553 contexts.append(ctx) |
553 contexts.append(ctx) |
554 value = u'\n' + highlighted.join(contexts) |
554 value = u'\n' + highlighted.join(contexts) |
555 self.w(value.replace('\n', '<br/>')) |
555 self.w(value.replace('\n', '<br/>')) |
556 |
556 |
557 |
557 |
558 class TooltipView(EntityView): |
558 class TooltipView(EntityView): |
559 """A entity view used in a tooltip""" |
559 """A entity view used in a tooltip""" |
560 id = 'tooltip' |
560 id = 'tooltip' |
577 XmlView = class_moved(xmlrss.XmlView) |
577 XmlView = class_moved(xmlrss.XmlView) |
578 XmlItemView = class_moved(xmlrss.XmlItemView) |
578 XmlItemView = class_moved(xmlrss.XmlItemView) |
579 XmlRsetView = class_moved(xmlrss.XmlRsetView) |
579 XmlRsetView = class_moved(xmlrss.XmlRsetView) |
580 RssView = class_moved(xmlrss.RssView) |
580 RssView = class_moved(xmlrss.RssView) |
581 RssItemView = class_moved(xmlrss.RssItemView) |
581 RssItemView = class_moved(xmlrss.RssItemView) |
582 |
582 |