|
1 # copyright 2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
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/>. |
|
18 """This module provide highlevel helpers to avoid uicfg boilerplate |
|
19 for most common tasks such as fields ordering, widget customization, etc. |
|
20 |
|
21 |
|
22 Here are a few helpers to customize *action box* rendering: |
|
23 |
|
24 .. autofunction:: cubicweb.web.uihelper.append_to_addmenu |
|
25 .. autofunction:: cubicweb.web.uihelper.remove_from_addmenu |
|
26 |
|
27 |
|
28 and a few other ones for *form configuration*: |
|
29 |
|
30 .. autofunction:: cubicweb.web.uihelper.set_fields_order |
|
31 .. autofunction:: cubicweb.web.uihelper.hide_field |
|
32 .. autofunction:: cubicweb.web.uihelper.hide_fields |
|
33 .. autofunction:: cubicweb.web.uihelper.set_field_kwargs |
|
34 .. autofunction:: cubicweb.web.uihelper.set_field |
|
35 .. autofunction:: cubicweb.web.uihelper.edit_inline |
|
36 .. autofunction:: cubicweb.web.uihelper.edit_as_attr |
|
37 .. autofunction:: cubicweb.web.uihelper.set_muledit_editable |
|
38 |
|
39 The module also provides a :class:`FormConfig` base class that lets you gather |
|
40 uicfg declaration in the scope of a single class, which can sometimes |
|
41 be clearer to read than a bunch of sequential function calls. |
|
42 |
|
43 .. autoclass:: cubicweb.web.uihelper.FormConfig |
|
44 |
|
45 """ |
|
46 __docformat__ = "restructuredtext en" |
|
47 |
|
48 from cubicweb.web import uicfg |
|
49 from functools import partial |
|
50 |
|
51 def _tag_rel(rtag, etype, attr, desttype='*', *args, **kwargs): |
|
52 if isinstance(attr, basestring): |
|
53 attr, role = attr, 'subject' |
|
54 else: |
|
55 attr, role = attr |
|
56 if role == 'subject': |
|
57 rtag.tag_subject_of((etype, attr, desttype), *args, **kwargs) |
|
58 else: |
|
59 rtag.tag_object_of((desttype, attr, etype), *args, **kwargs) |
|
60 |
|
61 |
|
62 ## generic uicfg helpers ###################################################### |
|
63 def append_to_addmenu(etype, attr, createdtype='*'): |
|
64 """adds `attr` in the actions box *addrelated* submenu of `etype`. |
|
65 |
|
66 :param etype: the entity type as a string |
|
67 :param attr: the name of the attribute or relation to hide |
|
68 |
|
69 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
70 |
|
71 """ |
|
72 _tag_rel(uicfg.actionbox_appearsin_addmenu, etype, attr, createdtype, True) |
|
73 |
|
74 def remove_from_addmenu(etype, attr, createdtype='*'): |
|
75 """removes `attr` from the actions box *addrelated* submenu of `etype`. |
|
76 |
|
77 :param etype: the entity type as a string |
|
78 :param attr: the name of the attribute or relation to hide |
|
79 |
|
80 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
81 """ |
|
82 _tag_rel(uicfg.actionbox_appearsin_addmenu, etype, attr, createdtype, False) |
|
83 |
|
84 |
|
85 ## form uicfg helpers ########################################################## |
|
86 def set_fields_order(etype, attrs): |
|
87 """specify the field order in `etype` main edition form. |
|
88 |
|
89 :param etype: the entity type as a string |
|
90 :param attrs: the ordered list of attribute names (or relations) |
|
91 |
|
92 `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_relation) |
|
93 |
|
94 Unspecified fields will be displayed after specified ones, their |
|
95 order being consistent with the schema definition. |
|
96 |
|
97 Examples: |
|
98 |
|
99 .. sourcecode:: python |
|
100 |
|
101 from cubicweb.web import uihelper |
|
102 uihelper.set_fields_order('CWUser', ('firstname', 'surname', 'login')) |
|
103 uihelper.set_fields_order('CWUser', ('firstname', ('in_group', 'subject'), 'surname', 'login')) |
|
104 |
|
105 """ |
|
106 afk = uicfg.autoform_field_kwargs |
|
107 for index, attr in enumerate(attrs): |
|
108 _tag_rel(afk, etype, attr, '*', {'order': index}) |
|
109 |
|
110 |
|
111 def hide_field(etype, attr, desttype='*', formtype='main'): |
|
112 """hide `attr` in `etype` forms. |
|
113 |
|
114 :param etype: the entity type as a string |
|
115 :param attr: the name of the attribute or relation to hide |
|
116 :param formtype: which form will be affected ('main', 'inlined', etc.), *main* by default. |
|
117 |
|
118 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
119 |
|
120 Examples: |
|
121 |
|
122 .. sourcecode:: python |
|
123 |
|
124 from cubicweb.web import uihelper |
|
125 uihelper.hide_field('CWUser', 'login') |
|
126 uihelper.hide_field('*', 'name') |
|
127 uihelper.hide_field('CWUser', 'use_email', formtype='inlined') |
|
128 |
|
129 """ |
|
130 _tag_rel(uicfg.autoform_section, etype, attr, desttype, |
|
131 formtype=formtype, section='hidden') |
|
132 |
|
133 |
|
134 def hide_fields(etype, attrs, formtype='main'): |
|
135 """simple for-loop wrapper around :func:`hide_field`. |
|
136 |
|
137 :param etype: the entity type as a string |
|
138 :param attrs: the ordered list of attribute names (or relations) |
|
139 :param formtype: which form will be affected ('main', 'inlined', etc.), *main* by default. |
|
140 |
|
141 `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_relation) |
|
142 |
|
143 Examples: |
|
144 |
|
145 .. sourcecode:: python |
|
146 |
|
147 from cubicweb.web import uihelper |
|
148 uihelper.hide_fields('CWUser', ('login', ('use_email', 'subject')), formtype='inlined') |
|
149 """ |
|
150 for field in fields: |
|
151 hide_field(etype, field, formtype=formtype) |
|
152 |
|
153 |
|
154 def set_field_kwargs(etype, attr, **kwargs): |
|
155 """tag `attr` field of `etype` with additional named paremeters. |
|
156 |
|
157 :param etype: the entity type as a string |
|
158 :param attr: the name of the attribute or relation |
|
159 |
|
160 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
161 |
|
162 Examples: |
|
163 |
|
164 .. sourcecode:: python |
|
165 |
|
166 from cubicweb.web import uihelper, formwidgets as fwdgs |
|
167 |
|
168 uihelper.set_field_kwargs('Person', 'works_for', widget=fwdgs.AutoCompletionWidget()) |
|
169 uihelper.set_field_kwargs('CWUser', 'login', label=_('login or email address'), |
|
170 widget=fwdgs.TextInput(attrs={'size': 30})) |
|
171 """ |
|
172 _tag_rel(uicfg.autoform_field_kwargs, etype, attr, '*', kwargs) |
|
173 |
|
174 |
|
175 def set_field(etype, attr, field): |
|
176 """sets the `attr` field of `etype`. |
|
177 |
|
178 :param etype: the entity type as a string |
|
179 :param attr: the name of the attribute or relation |
|
180 |
|
181 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
182 |
|
183 """ |
|
184 _tag_rel(uicfg.autoform_field, etype, attr, '*', field) |
|
185 |
|
186 |
|
187 def edit_inline(etype, attr, desttype='*', formtype=('main', 'inlined')): |
|
188 """edit `attr` with and inlined form. |
|
189 |
|
190 :param etype: the entity type as a string |
|
191 :param attr: the name of the attribute or relation |
|
192 :param desttype: the destination type(s) concerned, default is everything |
|
193 :param formtype: which form will be affected ('main', 'inlined', etc.), *main* and *inlined* by default. |
|
194 |
|
195 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
196 |
|
197 Examples: |
|
198 |
|
199 .. sourcecode:: python |
|
200 |
|
201 from cubicweb.web import uihelper |
|
202 |
|
203 uihelper.edit_inline('*', 'use_email') |
|
204 """ |
|
205 _tag_rel(uicfg.autoform_section, etype, attr, desttype, |
|
206 formtype=formtype, section='inlined') |
|
207 |
|
208 |
|
209 def edit_as_attr(etype, attr, desttype='*', formtype=('main', 'muledit')): |
|
210 """make `attr` appear in the *attributes* section of `etype` form. |
|
211 |
|
212 :param etype: the entity type as a string |
|
213 :param attr: the name of the attribute or relation |
|
214 :param desttype: the destination type(s) concerned, default is everything |
|
215 :param formtype: which form will be affected ('main', 'inlined', etc.), *main* and *muledit* by default. |
|
216 |
|
217 `attr` can be a string or 2-tuple (relname, role_of_etype_in_the_relation) |
|
218 |
|
219 Examples: |
|
220 |
|
221 .. sourcecode:: python |
|
222 |
|
223 from cubicweb.web import uihelper |
|
224 |
|
225 uihelper.edit_as_attr('CWUser', 'in_group') |
|
226 """ |
|
227 _tag_rel(uicfg.autoform_section, etype, attr, desttype, |
|
228 formtype=formtype, section='attributes') |
|
229 |
|
230 |
|
231 def set_muledit_editable(etype, attrs): |
|
232 """make `attrs` appear in muledit form of `etype`. |
|
233 |
|
234 :param etype: the entity type as a string |
|
235 :param attrs: the ordered list of attribute names (or relations) |
|
236 |
|
237 `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_relation) |
|
238 |
|
239 Examples: |
|
240 |
|
241 .. sourcecode:: python |
|
242 |
|
243 from cubicweb.web import uihelper |
|
244 |
|
245 uihelper.set_muledit_editable('CWUser', ('firstname', 'surname', 'in_group')) |
|
246 """ |
|
247 for attr in attrs: |
|
248 edit_as_attr(etype, attr, formtype='muledit') |
|
249 |
|
250 |
|
251 class meta_formconfig(type): |
|
252 """metaclass of FormConfig classes, only for easier declaration purpose""" |
|
253 def __init__(cls, name, bases, classdict): |
|
254 if cls.etype is None: |
|
255 return |
|
256 for attr_role in cls.hidden: |
|
257 hide_field(cls.etype, attr_role, formtype=cls.formtype) |
|
258 for attr_role in cls.rels_as_attrs: |
|
259 edit_as_attr(cls.etype, attr_role, formtype=cls.formtype) |
|
260 for attr_role in cls.inlined: |
|
261 edit_inline(cls.etype, attr_role, formtype=cls.formtype) |
|
262 for rtype, widget in cls.widgets.items(): |
|
263 set_field_kwargs(cls.etype, rtype, widget=widget) |
|
264 for rtype, field in cls.fields.items(): |
|
265 set_field(cls.etype, rtype, field) |
|
266 set_fields_order(cls.etype, cls.fields_order) |
|
267 super(meta_formconfig, cls).__init__(name, bases, classdict) |
|
268 |
|
269 |
|
270 class FormConfig: |
|
271 """helper base class to define uicfg rules on a given entity type. |
|
272 |
|
273 In all descriptions below, attributes list can either be a list of |
|
274 attribute names of a list of 2-tuples (relation name, role of |
|
275 the edited entity in the relation). |
|
276 |
|
277 **Attributes** |
|
278 |
|
279 :attr:`etype` |
|
280 which entity type the form config is for. This attribute is **mandatory** |
|
281 |
|
282 :attr:`formtype` |
|
283 the formtype the class tries toc customize (i.e. *main*, *inlined*, or *muledit*), |
|
284 default is *main*. |
|
285 |
|
286 :attr:`hidden` |
|
287 the list of attributes or relations to hide. |
|
288 |
|
289 :attr:`rels_as_attrs` |
|
290 the list of attributes to edit in the *attributes* section. |
|
291 |
|
292 :attr:`inlined` |
|
293 the list of attributes to edit in the *inlined* section. |
|
294 |
|
295 :attr:`fields_order` |
|
296 the list of attributes to edit, in the desired order. Unspecified |
|
297 fields will be displayed after specified ones, their order |
|
298 being consistent with the schema definition. |
|
299 |
|
300 :attr:`widgets` |
|
301 a dictionnary mapping attribute names to widget instances. |
|
302 |
|
303 :attr:`fields` |
|
304 a dictionnary mapping attribute names to field instances. |
|
305 |
|
306 Examples: |
|
307 |
|
308 .. sourcecode:: python |
|
309 |
|
310 from cubicweb.web import uihelper, formwidgets as fwdgs |
|
311 |
|
312 class LinkFormConfig(uihelper.FormConfig): |
|
313 etype = 'Link' |
|
314 hidden = ('title', 'description', 'embed') |
|
315 widgets = dict( |
|
316 url=fwdgs.TextInput(attrs={'size':40}), |
|
317 ) |
|
318 |
|
319 class UserFormConfig(uihelper.FormConfig): |
|
320 etype = 'CWUser' |
|
321 hidden = ('login',) |
|
322 rels_as_attrs = ('in_group',) |
|
323 fields_order = ('firstname', 'surname', 'in_group', 'use_email') |
|
324 inlined = ('use_email',) |
|
325 |
|
326 """ |
|
327 __metaclass__ = meta_formconfig |
|
328 formtype = 'main' |
|
329 etype = None # must be defined in concrete subclasses |
|
330 hidden = () |
|
331 rels_as_attrs = () |
|
332 inlined = () |
|
333 fields_order = () |
|
334 widgets = {} |
|
335 fields = {} |