7 """ |
7 """ |
8 |
8 |
9 __docformat__ = "restructuredtext en" |
9 __docformat__ = "restructuredtext en" |
10 _ = unicode |
10 _ = unicode |
11 |
11 |
12 from logilab.common.decorators import cached |
12 from logilab.common.decorators import cached, iclassmethod |
13 |
13 |
14 from cubicweb import typed_eid |
14 from cubicweb import typed_eid |
15 from cubicweb.web import stdmsgs, uicfg |
15 from cubicweb.web import stdmsgs, uicfg |
16 from cubicweb.web import form, formwidgets as fwdgs |
16 from cubicweb.web import form, formwidgets as fwdgs |
17 from cubicweb.web.views import forms, editforms |
17 from cubicweb.web.views import forms, editforms, editviews |
18 |
18 |
19 _afs = uicfg.autoform_section |
19 _afs = uicfg.autoform_section |
20 |
20 |
21 class AutomaticEntityForm(forms.EntityFieldsForm): |
21 class AutomaticEntityForm(forms.EntityFieldsForm): |
22 """base automatic form to edit any entity. |
22 """base automatic form to edit any entity. |
41 # for attributes selection when searching in uicfg.autoform_section |
41 # for attributes selection when searching in uicfg.autoform_section |
42 formtype = 'main' |
42 formtype = 'main' |
43 # set this to a list of [(relation, role)] if you want to explictily tell |
43 # set this to a list of [(relation, role)] if you want to explictily tell |
44 # which relations should be edited |
44 # which relations should be edited |
45 display_fields = None |
45 display_fields = None |
|
46 |
|
47 def _generic_relations_field(self): |
|
48 try: |
|
49 srels_by_cat = self.srelations_by_category('generic', 'add', strict=True) |
|
50 warn('[3.6] %s: srelations_by_category is deprecated, use uicfg or ' |
|
51 'override editable_relations instead' % classid(form), |
|
52 DeprecationWarning) |
|
53 except AttributeError: |
|
54 srels_by_cat = self.editable_relations() |
|
55 if not srels_by_cat: |
|
56 raise form.FieldNotFound('_cw_generic_field') |
|
57 return editviews.GenericRelationsField(self.editable_relations()) |
|
58 |
|
59 @iclassmethod |
|
60 def field_by_name(cls_or_self, name, role=None, eschema=None): |
|
61 """return field with the given name and role. If field is not explicitly |
|
62 defined for the form but `eclass` is specified, guess_field will be |
|
63 called. |
|
64 """ |
|
65 try: |
|
66 return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role, eschema) |
|
67 except form.FieldNotFound: |
|
68 if name == '_cw_generic_field' and not isinstance(cls_or_self, type): |
|
69 return cls_or_self._generic_relations_field() |
|
70 raise |
46 |
71 |
47 # base automatic entity form methods ####################################### |
72 # base automatic entity form methods ####################################### |
48 |
73 |
49 def __init__(self, *args, **kwargs): |
74 def __init__(self, *args, **kwargs): |
50 super(AutomaticEntityForm, self).__init__(*args, **kwargs) |
75 super(AutomaticEntityForm, self).__init__(*args, **kwargs) |
62 eschema=entity.e_schema) |
87 eschema=entity.e_schema) |
63 self.fields.append(field) |
88 self.fields.append(field) |
64 except form.FieldNotFound: |
89 except form.FieldNotFound: |
65 # meta attribute such as <attr>_format |
90 # meta attribute such as <attr>_format |
66 continue |
91 continue |
|
92 if self.formtype == 'main' and entity.has_eid(): |
|
93 try: |
|
94 self.fields.append(self.field_by_name('_cw_generic_field')) |
|
95 except form.FieldNotFound: |
|
96 # no editable relation |
|
97 pass |
67 self.maxrelitems = self._cw.property_value('navigation.related-limit') |
98 self.maxrelitems = self._cw.property_value('navigation.related-limit') |
68 self.force_display = bool(self._cw.form.get('__force_display')) |
99 self.force_display = bool(self._cw.form.get('__force_display')) |
69 fnum = len(self.fields) |
100 fnum = len(self.fields) |
70 self.fields.sort(key=lambda f: f.order is None and fnum or f.order) |
101 self.fields.sort(key=lambda f: f.order is None and fnum or f.order) |
71 |
102 |
160 given category(ies) and permission |
191 given category(ies) and permission |
161 """ |
192 """ |
162 return self._relations_by_section('inlined') |
193 return self._relations_by_section('inlined') |
163 |
194 |
164 # generic relations modifier ############################################### |
195 # generic relations modifier ############################################### |
165 |
|
166 def relations_table(self): |
|
167 """yiels 3-tuples (rtype, target, related_list) |
|
168 where <related_list> itself a list of : |
|
169 - node_id (will be the entity element's DOM id) |
|
170 - appropriate javascript's togglePendingDelete() function call |
|
171 - status 'pendingdelete' or '' |
|
172 - oneline view of related entity |
|
173 """ |
|
174 entity = self.edited_entity |
|
175 pending_deletes = self._cw.get_pending_deletes(entity.eid) |
|
176 for label, rschema, role in self.editable_relations(): |
|
177 relatedrset = entity.related(rschema, role, limit=self.related_limit) |
|
178 if rschema.has_perm(self._cw, 'delete'): |
|
179 toggleable_rel_link_func = editforms.toggleable_relation_link |
|
180 else: |
|
181 toggleable_rel_link_func = lambda x, y, z: u'' |
|
182 related = [] |
|
183 for row in xrange(relatedrset.rowcount): |
|
184 nodeid = editforms.relation_id(entity.eid, rschema, role, |
|
185 relatedrset[row][0]) |
|
186 if nodeid in pending_deletes: |
|
187 status = u'pendingDelete' |
|
188 label = '+' |
|
189 else: |
|
190 status = u'' |
|
191 label = 'x' |
|
192 dellink = toggleable_rel_link_func(entity.eid, nodeid, label) |
|
193 eview = self._cw.view('oneline', relatedrset, row=row) |
|
194 related.append((nodeid, dellink, status, eview)) |
|
195 yield (rschema, role, related) |
|
196 |
|
197 def restore_pending_inserts(self, cell=False): |
|
198 """used to restore edition page as it was before clicking on |
|
199 'search for <some entity type>' |
|
200 """ |
|
201 eid = self.edited_entity.eid |
|
202 cell = cell and "div_insert_" or "tr" |
|
203 pending_inserts = set(self._cw.get_pending_inserts(eid)) |
|
204 for pendingid in pending_inserts: |
|
205 eidfrom, rtype, eidto = pendingid.split(':') |
|
206 if typed_eid(eidfrom) == eid: # subject |
|
207 label = display_name(self._cw, rtype, 'subject', |
|
208 self.edited_entity.__regid__) |
|
209 reid = eidto |
|
210 else: |
|
211 label = display_name(self._cw, rtype, 'object', |
|
212 self.edited_entity.__regid__) |
|
213 reid = eidfrom |
|
214 jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \ |
|
215 % (pendingid, cell, eid) |
|
216 rset = self._cw.eid_rset(reid) |
|
217 eview = self._cw.view('text', rset, row=0) |
|
218 # XXX find a clean way to handle baskets |
|
219 if rset.description[0][0] == 'Basket': |
|
220 eview = '%s (%s)' % (eview, display_name(self._cw, 'Basket')) |
|
221 yield rtype, pendingid, jscall, label, reid, eview |
|
222 |
196 |
223 # inlined forms support #################################################### |
197 # inlined forms support #################################################### |
224 |
198 |
225 @cached |
199 @cached |
226 def inlined_form_views(self): |
200 def inlined_form_views(self): |