51 cubicweb:displayactions CDATA #IMPLIED |
51 cubicweb:displayactions CDATA #IMPLIED |
52 cubicweb:fallbackvid CDATA #IMPLIED |
52 cubicweb:fallbackvid CDATA #IMPLIED |
53 cubicweb:vid CDATA #IMPLIED |
53 cubicweb:vid CDATA #IMPLIED |
54 cubicweb:rql CDATA #IMPLIED |
54 cubicweb:rql CDATA #IMPLIED |
55 cubicweb:actualrql CDATA #IMPLIED |
55 cubicweb:actualrql CDATA #IMPLIED |
56 cubicweb:rooteid CDATA #IMPLIED |
56 cubicweb:rooteid CDATA #IMPLIED |
57 cubicweb:dataurl CDATA #IMPLIED |
57 cubicweb:dataurl CDATA #IMPLIED |
58 cubicweb:size CDATA #IMPLIED |
58 cubicweb:size CDATA #IMPLIED |
59 cubicweb:tlunit CDATA #IMPLIED |
59 cubicweb:tlunit CDATA #IMPLIED |
60 cubicweb:loadurl CDATA #IMPLIED |
60 cubicweb:loadurl CDATA #IMPLIED |
61 cubicweb:lazyloadurl CDATA #IMPLIED |
|
62 cubicweb:uselabel CDATA #IMPLIED |
61 cubicweb:uselabel CDATA #IMPLIED |
63 cubicweb:facetargs CDATA #IMPLIED |
62 cubicweb:facetargs CDATA #IMPLIED |
64 cubicweb:facetName CDATA #IMPLIED |
63 cubicweb:facetName CDATA #IMPLIED |
65 "> ] ''' |
64 "> ] ''' |
66 |
65 |
72 """abstract view class, used as base for every renderable object such |
71 """abstract view class, used as base for every renderable object such |
73 as views, templates, some components...web |
72 as views, templates, some components...web |
74 |
73 |
75 A view is instantiated to render a [part of a] result set. View |
74 A view is instantiated to render a [part of a] result set. View |
76 subclasses may be parametred using the following class attributes: |
75 subclasses may be parametred using the following class attributes: |
77 |
76 |
78 * `templatable` indicates if the view may be embeded in a main |
77 * `templatable` indicates if the view may be embeded in a main |
79 template or if it has to be rendered standalone (i.e. XML for |
78 template or if it has to be rendered standalone (i.e. XML for |
80 instance) |
79 instance) |
81 * if the view is not templatable, it should set the `content_type` class |
80 * if the view is not templatable, it should set the `content_type` class |
82 attribute to the correct MIME type (text/xhtml by default) |
81 attribute to the correct MIME type (text/xhtml by default) |
86 At instantiation time, the standard `req`, `rset`, and `cursor` |
85 At instantiation time, the standard `req`, `rset`, and `cursor` |
87 attributes are added and the `w` attribute will be set at rendering |
86 attributes are added and the `w` attribute will be set at rendering |
88 time to a write function to use. |
87 time to a write function to use. |
89 """ |
88 """ |
90 __registry__ = 'views' |
89 __registry__ = 'views' |
91 |
90 |
92 templatable = True |
91 templatable = True |
93 need_navigation = True |
92 need_navigation = True |
94 # content_type = 'application/xhtml+xml' # text/xhtml' |
93 # content_type = 'application/xhtml+xml' # text/xhtml' |
95 binary = False |
94 binary = False |
96 add_to_breadcrumbs = True |
95 add_to_breadcrumbs = True |
97 category = 'view' |
96 category = 'view' |
98 |
97 |
99 def __init__(self, req, rset): |
98 def __init__(self, req, rset): |
100 super(View, self).__init__(req, rset) |
99 super(View, self).__init__(req, rset) |
101 self.w = None |
100 self.w = None |
102 |
101 |
103 @property |
102 @property |
104 def content_type(self): |
103 def content_type(self): |
105 if self.req.xhtml_browser(): |
104 if self.req.xhtml_browser(): |
106 return 'application/xhtml+xml' |
105 return 'application/xhtml+xml' |
107 return 'text/html' |
106 return 'text/html' |
108 |
107 |
109 def set_stream(self, w=None): |
108 def set_stream(self, w=None): |
110 if self.w is not None: |
109 if self.w is not None: |
111 return |
110 return |
112 if w is None: |
111 if w is None: |
113 if self.binary: |
112 if self.binary: |
119 stream = None |
118 stream = None |
120 self.w = w |
119 self.w = w |
121 return stream |
120 return stream |
122 |
121 |
123 # main view interface ##################################################### |
122 # main view interface ##################################################### |
124 |
123 |
125 def dispatch(self, w=None, **context): |
124 def dispatch(self, w=None, **context): |
126 """called to render a view object for a result set. |
125 """called to render a view object for a result set. |
127 |
126 |
128 This method is a dispatched to an actual method selected |
127 This method is a dispatched to an actual method selected |
129 according to optional row and col parameters, which are locating |
128 according to optional row and col parameters, which are locating |
130 a particular row or cell in the result set: |
129 a particular row or cell in the result set: |
131 |
130 |
132 * if row [and col] are specified, `cell_call` is called |
131 * if row [and col] are specified, `cell_call` is called |
133 * if none of them is supplied, the view is considered to apply on |
132 * if none of them is supplied, the view is considered to apply on |
134 the whole result set (which may be None in this case), `call` is |
133 the whole result set (which may be None in this case), `call` is |
135 called |
134 called |
136 """ |
135 """ |
148 return self._stream.getvalue() |
147 return self._stream.getvalue() |
149 |
148 |
150 # should default .call() method add a <div classs="section"> around each |
149 # should default .call() method add a <div classs="section"> around each |
151 # rset item |
150 # rset item |
152 add_div_section = True |
151 add_div_section = True |
153 |
152 |
154 def call(self, **kwargs): |
153 def call(self, **kwargs): |
155 """the view is called for an entire result set, by default loop |
154 """the view is called for an entire result set, by default loop |
156 other rows of the result set and call the same view on the |
155 other rows of the result set and call the same view on the |
157 particular row |
156 particular row |
158 |
157 |
170 self.w(u"</div>") |
169 self.w(u"</div>") |
171 |
170 |
172 def cell_call(self, row, col, **kwargs): |
171 def cell_call(self, row, col, **kwargs): |
173 """the view is called for a particular result set cell""" |
172 """the view is called for a particular result set cell""" |
174 raise NotImplementedError, self |
173 raise NotImplementedError, self |
175 |
174 |
176 def linkable(self): |
175 def linkable(self): |
177 """return True if the view may be linked in a menu |
176 """return True if the view may be linked in a menu |
178 |
177 |
179 by default views without title are not meant to be displayed |
178 by default views without title are not meant to be displayed |
180 """ |
179 """ |
181 if not getattr(self, 'title', None): |
180 if not getattr(self, 'title', None): |
182 return False |
181 return False |
183 return True |
182 return True |
184 |
183 |
185 def is_primary(self): |
184 def is_primary(self): |
186 return self.id == 'primary' |
185 return self.id == 'primary' |
187 |
186 |
188 def url(self): |
187 def url(self): |
189 """return the url associated with this view. Should not be |
188 """return the url associated with this view. Should not be |
190 necessary for non linkable views, but a default implementation |
189 necessary for non linkable views, but a default implementation |
191 is provided anyway. |
190 is provided anyway. |
192 """ |
191 """ |
198 def set_request_content_type(self): |
197 def set_request_content_type(self): |
199 """set the content type returned by this view""" |
198 """set the content type returned by this view""" |
200 self.req.set_content_type(self.content_type) |
199 self.req.set_content_type(self.content_type) |
201 |
200 |
202 # view utilities ########################################################## |
201 # view utilities ########################################################## |
203 |
202 |
204 def view(self, __vid, rset, __fallback_vid=None, **kwargs): |
203 def view(self, __vid, rset, __fallback_vid=None, **kwargs): |
205 """shortcut to self.vreg.render method avoiding to pass self.req""" |
204 """shortcut to self.vreg.render method avoiding to pass self.req""" |
206 try: |
205 try: |
207 view = self.vreg.select_view(__vid, self.req, rset, **kwargs) |
206 view = self.vreg.select_view(__vid, self.req, rset, **kwargs) |
208 except NoSelectableObject: |
207 except NoSelectableObject: |
209 if __fallback_vid is None: |
208 if __fallback_vid is None: |
210 raise |
209 raise |
211 view = self.vreg.select_view(__fallback_vid, self.req, rset, **kwargs) |
210 view = self.vreg.select_view(__fallback_vid, self.req, rset, **kwargs) |
212 return view.dispatch(**kwargs) |
211 return view.dispatch(**kwargs) |
213 |
212 |
214 def wview(self, __vid, rset, __fallback_vid=None, **kwargs): |
213 def wview(self, __vid, rset, __fallback_vid=None, **kwargs): |
215 """shortcut to self.view method automatically passing self.w as argument |
214 """shortcut to self.view method automatically passing self.w as argument |
216 """ |
215 """ |
217 self.view(__vid, rset, __fallback_vid, w=self.w, **kwargs) |
216 self.view(__vid, rset, __fallback_vid, w=self.w, **kwargs) |
218 |
217 |
235 row=row) |
234 row=row) |
236 if action: |
235 if action: |
237 label = label or self.req._(action.title) |
236 label = label or self.req._(action.title) |
238 return u'<a href="%s">%s</a>' % (html_escape(action.url()), label) |
237 return u'<a href="%s">%s</a>' % (html_escape(action.url()), label) |
239 return u'' |
238 return u'' |
240 |
239 |
241 def html_headers(self): |
240 def html_headers(self): |
242 """return a list of html headers (eg something to be inserted between |
241 """return a list of html headers (eg something to be inserted between |
243 <head> and </head> of the returned page |
242 <head> and </head> of the returned page |
244 |
243 |
245 by default return a meta tag to disable robot indexation of the page |
244 by default return a meta tag to disable robot indexation of the page |
246 """ |
245 """ |
247 return [NOINDEX] |
246 return [NOINDEX] |
248 |
247 |
249 def page_title(self): |
248 def page_title(self): |
250 """returns a title according to the result set - used for the |
249 """returns a title according to the result set - used for the |
251 title in the HTML header |
250 title in the HTML header |
252 """ |
251 """ |
253 vtitle = self.req.form.get('vtitle') |
252 vtitle = self.req.form.get('vtitle') |
293 |
292 |
294 def create_url(self, etype, **kwargs): |
293 def create_url(self, etype, **kwargs): |
295 """ return the url of the entity creation form for a given entity type""" |
294 """ return the url of the entity creation form for a given entity type""" |
296 return self.req.build_url('add/%s'%etype, **kwargs) |
295 return self.req.build_url('add/%s'%etype, **kwargs) |
297 |
296 |
298 |
297 |
299 # concrete views base classes ################################################# |
298 # concrete views base classes ################################################# |
300 |
299 |
301 class EntityView(View): |
300 class EntityView(View): |
302 """base class for views applying on an entity (i.e. uniform result set) |
301 """base class for views applying on an entity (i.e. uniform result set) |
303 """ |
302 """ |
304 __registerer__ = accepts_registerer |
303 __registerer__ = accepts_registerer |
305 __selectors__ = (accept,) |
304 __selectors__ = (accept,) |
306 category = 'entityview' |
305 category = 'entityview' |
307 |
306 |
308 def field(self, label, value, row=True, show_label=True, w=None, tr=True): |
307 def field(self, label, value, row=True, show_label=True, w=None, tr=True): |
309 """ read-only field """ |
308 """ read-only field """ |
310 if w is None: |
309 if w is None: |
311 w = self.w |
310 w = self.w |
312 if row: |
311 if row: |
317 w(u'<span class="label">%s</span>' % label) |
316 w(u'<span class="label">%s</span>' % label) |
318 w(u'<div class="field">%s</div>' % value) |
317 w(u'<div class="field">%s</div>' % value) |
319 if row: |
318 if row: |
320 w(u'</div>') |
319 w(u'</div>') |
321 |
320 |
322 |
321 |
323 class StartupView(View): |
322 class StartupView(View): |
324 """base class for views which doesn't need a particular result set |
323 """base class for views which doesn't need a particular result set |
325 to be displayed (so they can always be displayed !) |
324 to be displayed (so they can always be displayed !) |
326 """ |
325 """ |
327 __registerer__ = priority_registerer |
326 __registerer__ = priority_registerer |
328 __selectors__ = (match_user_group, none_rset) |
327 __selectors__ = (match_user_group, none_rset) |
329 require_groups = () |
328 require_groups = () |
330 category = 'startupview' |
329 category = 'startupview' |
331 |
330 |
332 def url(self): |
331 def url(self): |
333 """return the url associated with this view. We can omit rql here""" |
332 """return the url associated with this view. We can omit rql here""" |
334 return self.build_url('view', vid=self.id) |
333 return self.build_url('view', vid=self.id) |
335 |
334 |
336 def html_headers(self): |
335 def html_headers(self): |
346 """base class for entity views which may also be applied to None |
345 """base class for entity views which may also be applied to None |
347 result set (usually a default rql is provided by the view class) |
346 result set (usually a default rql is provided by the view class) |
348 """ |
347 """ |
349 __registerer__ = accepts_registerer |
348 __registerer__ = accepts_registerer |
350 __selectors__ = (chainfirst(none_rset, accept),) |
349 __selectors__ = (chainfirst(none_rset, accept),) |
351 |
350 |
352 default_rql = None |
351 default_rql = None |
353 |
352 |
354 def __init__(self, req, rset): |
353 def __init__(self, req, rset): |
355 super(EntityStartupView, self).__init__(req, rset) |
354 super(EntityStartupView, self).__init__(req, rset) |
356 if rset is None: |
355 if rset is None: |
357 # this instance is not in the "entityview" category |
356 # this instance is not in the "entityview" category |
358 self.category = 'startupview' |
357 self.category = 'startupview' |
359 |
358 |
360 def startup_rql(self): |
359 def startup_rql(self): |
361 """return some rql to be executedif the result set is None""" |
360 """return some rql to be executedif the result set is None""" |
362 return self.default_rql |
361 return self.default_rql |
363 |
362 |
364 def call(self, **kwargs): |
363 def call(self, **kwargs): |
365 """override call to execute rql returned by the .startup_rql |
364 """override call to execute rql returned by the .startup_rql |
366 method if necessary |
365 method if necessary |
367 """ |
366 """ |
368 if self.rset is None: |
367 if self.rset is None: |
377 """ |
376 """ |
378 if not self.__select__(self.req, self.rset): |
377 if not self.__select__(self.req, self.rset): |
379 return self.build_url(vid=self.id) |
378 return self.build_url(vid=self.id) |
380 return super(EntityStartupView, self).url() |
379 return super(EntityStartupView, self).url() |
381 |
380 |
382 |
381 |
383 class AnyRsetView(View): |
382 class AnyRsetView(View): |
384 """base class for views applying on any non empty result sets""" |
383 """base class for views applying on any non empty result sets""" |
385 __registerer__ = priority_registerer |
384 __registerer__ = priority_registerer |
386 __selectors__ = (nonempty_rset,) |
385 __selectors__ = (nonempty_rset,) |
387 |
386 |
388 category = 'anyrsetview' |
387 category = 'anyrsetview' |
389 |
388 |
390 def columns_labels(self, tr=True): |
389 def columns_labels(self, tr=True): |
391 if tr: |
390 if tr: |
392 translate = display_name |
391 translate = display_name |
393 else: |
392 else: |
394 translate = lambda req, val: val |
393 translate = lambda req, val: val |
401 for et in self.rset.column_types(colindex)) |
400 for et in self.rset.column_types(colindex)) |
402 else: |
401 else: |
403 label = translate(self.req, attr) |
402 label = translate(self.req, attr) |
404 labels.append(label) |
403 labels.append(label) |
405 return labels |
404 return labels |
406 |
405 |
407 |
406 |
408 class EmptyRsetView(View): |
407 class EmptyRsetView(View): |
409 """base class for views applying on any empty result sets""" |
408 """base class for views applying on any empty result sets""" |
410 __registerer__ = priority_registerer |
409 __registerer__ = priority_registerer |
411 __selectors__ = (empty_rset,) |
410 __selectors__ = (empty_rset,) |
420 __registry__ = 'templates' |
419 __registry__ = 'templates' |
421 __registerer__ = priority_registerer |
420 __registerer__ = priority_registerer |
422 __selectors__ = (match_user_group,) |
421 __selectors__ = (match_user_group,) |
423 |
422 |
424 require_groups = () |
423 require_groups = () |
425 |
424 |
426 def template(self, oid, **kwargs): |
425 def template(self, oid, **kwargs): |
427 """shortcut to self.registry.render method on the templates registry""" |
426 """shortcut to self.registry.render method on the templates registry""" |
428 w = kwargs.pop('w', self.w) |
427 w = kwargs.pop('w', self.w) |
429 self.vreg.render('templates', oid, self.req, w=w, **kwargs) |
428 self.vreg.render('templates', oid, self.req, w=w, **kwargs) |
430 |
429 |