author | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> |
Fri, 24 Apr 2009 09:06:56 +0200 | |
branch | tls-sprint |
changeset 1466 | 07a2d0c387ca |
parent 1433 | 091ac3ba5d51 |
child 1511 | 514e4e53a3c7 |
permissions | -rw-r--r-- |
0 | 1 |
"""abstract component class and base components definition for CubicWeb web client |
2 |
||
3 |
:organization: Logilab |
|
640
8e64f12be69c
drop EntityAction usage in cw, upgrade rql_condition and friends
sylvain.thenault@logilab.fr
parents:
593
diff
changeset
|
4 |
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
0 | 5 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 |
""" |
|
7 |
__docformat__ = "restructuredtext en" |
|
8 |
||
681
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
9 |
from logilab.common.deprecation import class_renamed |
743 | 10 |
from logilab.mtconverter import html_escape |
661
4f61eb8a96b7
properly kill/depreciate component base class, only keep Component
sylvain.thenault@logilab.fr
parents:
659
diff
changeset
|
11 |
|
799
ad129d374ee2
fix page_size handling, use abstract_has_related_entities
sylvain.thenault@logilab.fr
parents:
747
diff
changeset
|
12 |
from cubicweb import role |
743 | 13 |
from cubicweb.utils import merge_dicts |
14 |
from cubicweb.view import View, Component |
|
655 | 15 |
from cubicweb.selectors import ( |
16 |
paginated_rset, one_line_rset, primary_view, match_context_prop, |
|
1132 | 17 |
partial_has_related_entities, condition_compat, accepts_compat, |
18 |
has_relation_compat) |
|
0 | 19 |
|
20 |
_ = unicode |
|
21 |
||
661
4f61eb8a96b7
properly kill/depreciate component base class, only keep Component
sylvain.thenault@logilab.fr
parents:
659
diff
changeset
|
22 |
class EntityVComponent(Component): |
0 | 23 |
"""abstract base class for additinal components displayed in content |
24 |
headers and footer according to: |
|
1433 | 25 |
|
0 | 26 |
* the displayed entity's type |
27 |
* a context (currently 'header' or 'footer') |
|
28 |
||
29 |
it should be configured using .accepts, .etype, .rtype, .target and |
|
30 |
.context class attributes |
|
31 |
""" |
|
1433 | 32 |
|
0 | 33 |
__registry__ = 'contentnavigation' |
742
99115e029dca
replaced most of __selectors__ assignments with __select__
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
687
diff
changeset
|
34 |
__select__ = one_line_rset() & primary_view() & match_context_prop() |
687
c23315c11185
removing explicit access to im_func, this is not necessary anymore
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
681
diff
changeset
|
35 |
registered = accepts_compat(has_relation_compat(condition_compat(View.registered))) |
1433 | 36 |
|
0 | 37 |
property_defs = { |
38 |
_('visible'): dict(type='Boolean', default=True, |
|
39 |
help=_('display the box or not')), |
|
40 |
_('order'): dict(type='Int', default=99, |
|
41 |
help=_('display order of the component')), |
|
42 |
_('context'): dict(type='String', default='header', |
|
1433 | 43 |
vocabulary=(_('navtop'), _('navbottom'), |
0 | 44 |
_('navcontenttop'), _('navcontentbottom')), |
45 |
#vocabulary=(_('header'), _('incontext'), _('footer')), |
|
46 |
help=_('context where this component should be displayed')), |
|
47 |
_('htmlclass'):dict(type='String', default='mainRelated', |
|
48 |
help=_('html class of the component')), |
|
49 |
} |
|
1433 | 50 |
|
0 | 51 |
context = 'navcontentbottom' # 'footer' | 'header' | 'incontext' |
1433 | 52 |
|
880 | 53 |
def call(self, view=None): |
529
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
54 |
return self.cell_call(0, 0, view) |
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
55 |
|
880 | 56 |
def cell_call(self, row, col, view=None): |
529
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
57 |
raise NotImplementedError() |
0 | 58 |
|
1433 | 59 |
|
661
4f61eb8a96b7
properly kill/depreciate component base class, only keep Component
sylvain.thenault@logilab.fr
parents:
659
diff
changeset
|
60 |
class NavigationComponent(Component): |
0 | 61 |
"""abstract base class for navigation components""" |
655 | 62 |
id = 'navigation' |
742
99115e029dca
replaced most of __selectors__ assignments with __select__
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
687
diff
changeset
|
63 |
__select__ = paginated_rset() |
1433 | 64 |
|
0 | 65 |
page_size_property = 'navigation.page-size' |
66 |
start_param = '__start' |
|
67 |
stop_param = '__stop' |
|
68 |
page_link_templ = u'<span class="slice"><a href="%s" title="%s">%s</a></span>' |
|
69 |
selected_page_link_templ = u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>' |
|
70 |
previous_page_link_templ = next_page_link_templ = page_link_templ |
|
71 |
no_previous_page_link = no_next_page_link = u'' |
|
1433 | 72 |
|
1339 | 73 |
def __init__(self, req, rset, **kwargs): |
74 |
super(NavigationComponent, self).__init__(req, rset, **kwargs) |
|
0 | 75 |
self.starting_from = 0 |
76 |
self.total = rset.rowcount |
|
77 |
||
78 |
def get_page_size(self): |
|
79 |
try: |
|
80 |
return self._page_size |
|
81 |
except AttributeError: |
|
822 | 82 |
page_size = self.extra_kwargs.get('page_size') |
83 |
if page_size is None: |
|
84 |
if 'page_size' in self.req.form: |
|
85 |
page_size = int(self.req.form['page_size']) |
|
86 |
else: |
|
87 |
page_size = self.req.property_value(self.page_size_property) |
|
799
ad129d374ee2
fix page_size handling, use abstract_has_related_entities
sylvain.thenault@logilab.fr
parents:
747
diff
changeset
|
88 |
self._page_size = page_size |
ad129d374ee2
fix page_size handling, use abstract_has_related_entities
sylvain.thenault@logilab.fr
parents:
747
diff
changeset
|
89 |
return page_size |
0 | 90 |
|
91 |
def set_page_size(self, page_size): |
|
92 |
self._page_size = page_size |
|
1433 | 93 |
|
0 | 94 |
page_size = property(get_page_size, set_page_size) |
1433 | 95 |
|
0 | 96 |
def page_boundaries(self): |
97 |
try: |
|
98 |
stop = int(self.req.form[self.stop_param]) + 1 |
|
99 |
start = int(self.req.form[self.start_param]) |
|
100 |
except KeyError: |
|
101 |
start, stop = 0, self.page_size |
|
102 |
self.starting_from = start |
|
103 |
return start, stop |
|
1433 | 104 |
|
0 | 105 |
def clean_params(self, params): |
106 |
if self.start_param in params: |
|
107 |
del params[self.start_param] |
|
108 |
if self.stop_param in params: |
|
109 |
del params[self.stop_param] |
|
110 |
||
111 |
def page_link(self, path, params, start, stop, content): |
|
112 |
url = self.build_url(path, **merge_dicts(params, {self.start_param : start, |
|
113 |
self.stop_param : stop,})) |
|
114 |
url = html_escape(url) |
|
115 |
if start == self.starting_from: |
|
116 |
return self.selected_page_link_templ % (url, content, content) |
|
117 |
return self.page_link_templ % (url, content, content) |
|
118 |
||
119 |
def previous_link(self, params, content='<<', title=_('previous_results')): |
|
120 |
start = self.starting_from |
|
121 |
if not start : |
|
122 |
return self.no_previous_page_link |
|
123 |
start = max(0, start - self.page_size) |
|
124 |
stop = start + self.page_size - 1 |
|
125 |
url = self.build_url(**merge_dicts(params, {self.start_param : start, |
|
126 |
self.stop_param : stop,})) |
|
127 |
url = html_escape(url) |
|
128 |
return self.previous_page_link_templ % (url, title, content) |
|
129 |
||
130 |
def next_link(self, params, content='>>', title=_('next_results')): |
|
131 |
start = self.starting_from + self.page_size |
|
132 |
if start >= self.total: |
|
133 |
return self.no_next_page_link |
|
134 |
stop = start + self.page_size - 1 |
|
135 |
url = self.build_url(**merge_dicts(params, {self.start_param : start, |
|
136 |
self.stop_param : stop,})) |
|
137 |
url = html_escape(url) |
|
138 |
return self.next_page_link_templ % (url, title, content) |
|
139 |
||
140 |
||
141 |
class RelatedObjectsVComponent(EntityVComponent): |
|
142 |
"""a section to display some related entities""" |
|
883
44f1aba675de
missing selectors, no more need for relation_possible when using has_related_entities (implied)
sylvain.thenault@logilab.fr
parents:
880
diff
changeset
|
143 |
__select__ = EntityVComponent.__select__ & partial_has_related_entities() |
1433 | 144 |
|
0 | 145 |
vid = 'list' |
1433 | 146 |
|
0 | 147 |
def rql(self): |
655 | 148 |
"""override this method if you want to use a custom rql query""" |
0 | 149 |
return None |
1433 | 150 |
|
529
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
151 |
def cell_call(self, row, col, view=None): |
0 | 152 |
rql = self.rql() |
153 |
if rql is None: |
|
529
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
154 |
entity = self.rset.get_entity(row, col) |
799
ad129d374ee2
fix page_size handling, use abstract_has_related_entities
sylvain.thenault@logilab.fr
parents:
747
diff
changeset
|
155 |
rset = entity.related(self.rtype, role(self)) |
0 | 156 |
else: |
529
6e84e93fa7ec
EntityVComponent should now implements cell_call
sylvain.thenault@logilab.fr
parents:
330
diff
changeset
|
157 |
eid = self.rset[row][col] |
0 | 158 |
rset = self.req.execute(self.rql(), {'x': eid}, 'x') |
159 |
if not rset.rowcount: |
|
160 |
return |
|
161 |
self.w(u'<div class="%s">' % self.div_class()) |
|
162 |
self.wview(self.vid, rset, title=self.req._(self.title).capitalize()) |
|
163 |
self.w(u'</div>') |
|
661
4f61eb8a96b7
properly kill/depreciate component base class, only keep Component
sylvain.thenault@logilab.fr
parents:
659
diff
changeset
|
164 |
|
4f61eb8a96b7
properly kill/depreciate component base class, only keep Component
sylvain.thenault@logilab.fr
parents:
659
diff
changeset
|
165 |
|
681
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
166 |
VComponent = class_renamed('VComponent', Component, |
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
167 |
'VComponent is deprecated, use Component') |
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
168 |
SingletonVComponent = class_renamed('SingletonVComponent', Component, |
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
169 |
'SingletonVComponent is deprecated, use ' |
7cb402fa3958
use class_renamed, not class_moved
sylvain.thenault@logilab.fr
parents:
670
diff
changeset
|
170 |
'Component and explicit registration control') |