23 Additional boxes (disabled by default): |
23 Additional boxes (disabled by default): |
24 * schema box |
24 * schema box |
25 * possible views box |
25 * possible views box |
26 * startup views box |
26 * startup views box |
27 """ |
27 """ |
|
28 from __future__ import with_statement |
28 |
29 |
29 __docformat__ = "restructuredtext en" |
30 __docformat__ = "restructuredtext en" |
30 _ = unicode |
31 _ = unicode |
31 |
32 |
32 from warnings import warn |
33 from warnings import warn |
33 |
34 |
34 from logilab.mtconverter import xml_escape |
35 from logilab.mtconverter import xml_escape |
35 from logilab.common.deprecation import class_deprecated |
36 from logilab.common.deprecation import class_deprecated |
36 |
37 |
37 from cubicweb import Unauthorized |
38 from cubicweb import Unauthorized |
38 from cubicweb.selectors import (match_user_groups, match_context, match_kwargs, |
39 from cubicweb.selectors import (match_user_groups, match_kwargs, |
39 non_final_entity, nonempty_rset) |
40 non_final_entity, nonempty_rset, |
|
41 match_context, contextual) |
|
42 from cubicweb.utils import wrap_on_write |
40 from cubicweb.view import EntityView |
43 from cubicweb.view import EntityView |
41 from cubicweb.schema import display_name |
44 from cubicweb.schema import display_name |
42 from cubicweb.web import box, htmlwidgets |
45 from cubicweb.web import component, box, htmlwidgets |
43 |
46 |
44 # XXX bw compat, some cubes import this class from here |
47 # XXX bw compat, some cubes import this class from here |
45 BoxTemplate = box.BoxTemplate |
48 BoxTemplate = box.BoxTemplate |
46 BoxHtml = htmlwidgets.BoxHtml |
49 BoxHtml = htmlwidgets.BoxHtml |
47 |
50 |
48 class EditBox(box.Box): # XXX rename to ActionsBox |
51 class EditBox(component.CtxComponent): # XXX rename to ActionsBox |
49 """ |
52 """ |
50 box with all actions impacting the entity displayed: edit, copy, delete |
53 box with all actions impacting the entity displayed: edit, copy, delete |
51 change state, add related entities |
54 change state, add related entities |
52 """ |
55 """ |
53 __regid__ = 'edit_box' |
56 __regid__ = 'edit_box' |
54 __select__ = box.Box.__select__ & non_final_entity() |
57 __select__ = component.CtxComponent.__select__ & non_final_entity() |
55 |
58 |
56 title = _('actions') |
59 title = _('actions') |
57 order = 2 |
60 order = 2 |
58 contextual = True |
61 contextual = True |
59 |
62 |
87 self._menus_in_order.remove(other_menu) |
90 self._menus_in_order.remove(other_menu) |
88 self._menus_in_order.append(other_menu) |
91 self._menus_in_order.append(other_menu) |
89 for submenu in self._menus_in_order: |
92 for submenu in self._menus_in_order: |
90 self.add_submenu(self, submenu) |
93 self.add_submenu(self, submenu) |
91 if not self.items: |
94 if not self.items: |
92 raise box.EmptyComponent() |
95 raise component.EmptyComponent() |
93 |
96 |
94 def render_title(self, w): |
97 def render_title(self, w): |
95 title = self._cw._(self.title) |
98 title = self._cw._(self.title) |
96 if self.cw_rset: |
99 if self.cw_rset: |
97 etypes = self.cw_rset.column_types(0) |
100 etypes = self.cw_rset.column_types(0) |
174 def init_rendering(self): |
177 def init_rendering(self): |
175 self.views = [v for v in self._cw.vreg['views'].possible_views(self._cw, |
178 self.views = [v for v in self._cw.vreg['views'].possible_views(self._cw, |
176 rset=self.cw_rset) |
179 rset=self.cw_rset) |
177 if v.category != 'startupview'] |
180 if v.category != 'startupview'] |
178 if not self.views: |
181 if not self.views: |
179 raise box.EmptyComponent() |
182 raise component.EmptyComponent() |
180 self.items = [] |
183 self.items = [] |
181 |
184 |
182 def render_body(self, w): |
185 def render_body(self, w): |
183 for category, views in box.sort_by_category(self.views): |
186 for category, views in box.sort_by_category(self.views): |
184 menu = htmlwidgets.BoxMenu(category) |
187 menu = htmlwidgets.BoxMenu(category) |
198 |
201 |
199 def init_rendering(self): |
202 def init_rendering(self): |
200 self.views = [v for v in self._cw.vreg['views'].possible_views(self._cw) |
203 self.views = [v for v in self._cw.vreg['views'].possible_views(self._cw) |
201 if v.category == 'startupview'] |
204 if v.category == 'startupview'] |
202 if not self.views: |
205 if not self.views: |
203 raise box.EmptyComponent() |
206 raise component.EmptyComponent() |
204 self.items = [] |
207 self.items = [] |
205 |
208 |
206 |
209 |
207 class RsetBox(box.Box): |
210 class RsetBox(component.CtxComponent): |
208 """helper view class to display an rset in a sidebox""" |
211 """helper view class to display an rset in a sidebox""" |
209 __select__ = nonempty_rset() & match_kwargs('title', 'vid') |
212 __select__ = nonempty_rset() & match_kwargs('title', 'vid') |
210 __regid__ = 'rsetbox' |
213 __regid__ = 'rsetbox' |
211 cw_property_defs = {} |
214 cw_property_defs = {} |
212 context = 'incontext' |
215 context = 'incontext' |
213 |
216 |
214 @property |
217 @property |
215 def domid(self): |
218 def domid(self): |
216 return super(RsetBox, self).domid + unicode(abs(id(self))) |
219 return super(RsetBox, self).domid + unicode(abs(id(self))) |
|
220 |
217 def render_title(self, w): |
221 def render_title(self, w): |
218 w(self.cw_extra_kwargs['title']) |
222 w(self.cw_extra_kwargs['title']) |
219 |
223 |
220 def render_body(self, w): |
224 def render_body(self, w): |
221 self._cw.view(self.cw_extra_kwargs['vid'], self.cw_rset, w=w) |
225 self._cw.view(self.cw_extra_kwargs['vid'], self.cw_rset, w=w) |
223 # helper classes ############################################################## |
227 # helper classes ############################################################## |
224 |
228 |
225 class SideBoxView(EntityView): |
229 class SideBoxView(EntityView): |
226 """helper view class to display some entities in a sidebox""" |
230 """helper view class to display some entities in a sidebox""" |
227 __metaclass__ = class_deprecated |
231 __metaclass__ = class_deprecated |
228 __deprecation_warning__ = 'SideBoxView is deprecated, use RsetBox instead' |
232 __deprecation_warning__ = '[3.10] SideBoxView is deprecated, use RsetBox instead (%(cls)s)' |
229 |
233 |
230 __regid__ = 'sidebox' |
234 __regid__ = 'sidebox' |
231 |
235 |
232 def call(self, **kwargs): |
236 def call(self, **kwargs): |
233 """display a list of entities by calling their <item_vid> view""" |
237 """display a list of entities by calling their <item_vid> view""" |
234 box = self._cw.vreg['boxes'].select('rsetbox', self._cw, rset=self.cw_rset, |
238 box = self._cw.vreg['ctxcomponents'].select( |
235 vid='autolimited', title=title, |
239 'rsetbox', self._cw, rset=self.cw_rset, vid='autolimited', |
236 **self.cw_extra_kwargs) |
240 title=title, **self.cw_extra_kwargs) |
237 box.render(self.w) |
241 box.render(self.w) |
238 |
242 |
239 |
243 |
240 class ContextualBoxLayout(box.Layout): |
244 class ContextualBoxLayout(component.Layout): |
241 __select__ = match_context('incontext', 'left', 'right') & box.contextual() |
245 __select__ = match_context('incontext', 'left', 'right') & contextual() |
242 # predefined class in cubicweb.css: contextualBox | contextFreeBox |
246 # predefined class in cubicweb.css: contextualBox | contextFreeBox |
243 # XXX: navigationBox | actionBox |
247 # XXX: navigationBox | actionBox |
244 cssclass = 'contextualBox' |
248 cssclass = 'contextualBox' |
245 |
249 |
246 def render(self, w): |
250 def render(self, w): |
247 view = self.cw_extra_kwargs['view'] |
251 if self.init_rendering(): |
248 try: |
252 view = self.cw_extra_kwargs['view'] |
249 view.init_rendering() |
253 w(u'<div class="%s %s" id="%s">' % (self.cssclass, view.cssclass, |
250 except Unauthorized, ex: |
254 view.domid)) |
251 self.warning("can't render %s: %s", view, ex) |
255 with wrap_on_write(w, u'<div class="boxTitle"><span>', |
252 return |
256 u'</span></div>') as wow: |
253 except box.EmptyComponent: |
257 view.render_title(wow) |
254 return |
258 w(u'<div class="boxBody">') |
255 w(u'<div class="%s %s" id="%s">' % (self.cssclass, view.cssclass, |
259 view.render_body(w) |
256 view.domid)) |
260 # boxFooter div is a CSS place holder (for shadow for example) |
257 w(u'<div class="boxTitle"><span>') |
261 w(u'</div><div class="boxFooter"></div></div>\n') |
258 view.render_title(w) |
|
259 w(u'</span></div>\n<div class="boxBody">') |
|
260 view.render_body(w) |
|
261 # boxFooter div is a CSS place holder (for shadow for example) |
|
262 w(u'</div><div class="boxFooter"></div></div>\n') |
|
263 |
262 |
264 |
263 |
265 class ContextFreeBoxLayout(ContextualBoxLayout): |
264 class ContextFreeBoxLayout(ContextualBoxLayout): |
266 __select__ = match_context('incontext', 'left', 'right') & ~box.contextual() |
265 __select__ = match_context('incontext', 'left', 'right') & ~contextual() |
267 cssclass = 'contextFreeBox' |
266 cssclass = 'contextFreeBox' |