22 from cubicweb.web.widgets import checkbox, InputWidget, ComboBoxWidget |
22 from cubicweb.web.widgets import checkbox, InputWidget, ComboBoxWidget |
23 from cubicweb.web.form import FormMixIn |
23 from cubicweb.web.form import FormMixIn |
24 from cubicweb.web.views.autoform import AutomaticEntityForm |
24 from cubicweb.web.views.autoform import AutomaticEntityForm |
25 |
25 |
26 _ = unicode |
26 _ = unicode |
27 |
27 |
28 |
28 |
29 class EditionForm(FormMixIn, EntityView): |
29 class EditionForm(FormMixIn, EntityView): |
30 """primary entity edition form |
30 """primary entity edition form |
31 |
31 |
32 When generating a new attribute_input, the editor will look for a method |
32 When generating a new attribute_input, the editor will look for a method |
33 named 'default_ATTRNAME' on the entity instance, where ATTRNAME is the |
33 named 'default_ATTRNAME' on the entity instance, where ATTRNAME is the |
34 name of the attribute being edited. You may use this feature to compute |
34 name of the attribute being edited. You may use this feature to compute |
35 dynamic default values such as the 'tomorrow' date or the user's login |
35 dynamic default values such as the 'tomorrow' date or the user's login |
36 being connected |
36 being connected |
37 """ |
37 """ |
38 id = 'edition' |
38 id = 'edition' |
39 __select__ = one_line_rset() & non_final_entity() |
39 __select__ = one_line_rset() & non_final_entity() |
40 |
40 |
41 title = _('edition') |
41 title = _('edition') |
42 controller = 'edit' |
42 controller = 'edit' |
43 skip_relations = set() |
43 skip_relations = set() |
44 |
44 |
45 EDITION_BODY = u'''\ |
45 EDITION_BODY = u'''\ |
46 %(errormsg)s |
46 %(errormsg)s |
47 <form id="%(formid)s" class="entityForm" cubicweb:target="eformframe" |
47 <form id="%(formid)s" class="entityForm" cubicweb:target="eformframe" |
48 method="post" onsubmit="%(onsubmit)s" enctype="%(enctype)s" action="%(action)s"> |
48 method="post" onsubmit="%(onsubmit)s" enctype="%(enctype)s" action="%(action)s"> |
49 %(title)s |
49 %(title)s |
172 # If we need to directly attach the new object to another one |
172 # If we need to directly attach the new object to another one |
173 for linkto in req.list_form_param('__linkto'): |
173 for linkto in req.list_form_param('__linkto'): |
174 self._hiddens.append( ('__linkto', linkto, '') ) |
174 self._hiddens.append( ('__linkto', linkto, '') ) |
175 msg = '%s %s' % (msg, self.req._('and linked')) |
175 msg = '%s %s' % (msg, self.req._('and linked')) |
176 self._hiddens.append( ('__message', msg, '') ) |
176 self._hiddens.append( ('__message', msg, '') ) |
177 |
177 |
178 |
178 |
179 def attributes_form(self, entity, kwargs, include_eid=True): |
179 def attributes_form(self, entity, kwargs, include_eid=True): |
180 """create a form to edit entity's attributes""" |
180 """create a form to edit entity's attributes""" |
181 html = [] |
181 html = [] |
182 w = html.append |
182 w = html.append |
183 eid = entity.eid |
183 eid = entity.eid |
206 |
206 |
207 def editable_attributes(self, entity): |
207 def editable_attributes(self, entity): |
208 # XXX both (add, delete) |
208 # XXX both (add, delete) |
209 return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add') |
209 return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add') |
210 if rschema != 'eid'] |
210 if rschema != 'eid'] |
211 |
211 |
212 def relations_form(self, entity, kwargs): |
212 def relations_form(self, entity, kwargs): |
213 srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add') |
213 srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add') |
214 if not srels_by_cat: |
214 if not srels_by_cat: |
215 return u'' |
215 return u'' |
216 req = self.req |
216 req = self.req |
265 w(u'<td id="unrelatedDivs_%s"></td>' % eid) |
265 w(u'<td id="unrelatedDivs_%s"></td>' % eid) |
266 w(u'</tr>') |
266 w(u'</tr>') |
267 w(u'</table>') |
267 w(u'</table>') |
268 w(u'</fieldset>') |
268 w(u'</fieldset>') |
269 return '\n'.join(html) |
269 return '\n'.join(html) |
270 |
270 |
271 def inline_entities_form(self, entity, kwargs): |
271 def inline_entities_form(self, entity, kwargs): |
272 """create a form to edit entity's inlined relations""" |
272 """create a form to edit entity's inlined relations""" |
273 result = [] |
273 result = [] |
274 _ = self.req._ |
274 _ = self.req._ |
275 for rschema, targettypes, x in entity.relations_by_category('inlineview', 'add'): |
275 for rschema, targettypes, x in entity.relations_by_category('inlineview', 'add'): |
284 if self.should_inline_relation_form(entity, rschema, targettype, x): |
284 if self.should_inline_relation_form(entity, rschema, targettype, x): |
285 result.append(u'<div id="inline%sslot">' % rschema) |
285 result.append(u'<div id="inline%sslot">' % rschema) |
286 existant = entity.has_eid() and entity.related(rschema) |
286 existant = entity.has_eid() and entity.related(rschema) |
287 if existant: |
287 if existant: |
288 # display inline-edition view for all existing related entities |
288 # display inline-edition view for all existing related entities |
289 result.append(self.view('inline-edition', existant, |
289 result.append(self.view('inline-edition', existant, |
290 ptype=entity.e_schema, peid=entity.eid, |
290 ptype=entity.e_schema, peid=entity.eid, |
291 rtype=rschema, role=x, **kwargs)) |
291 rtype=rschema, role=x, **kwargs)) |
292 if x == 'subject': |
292 if x == 'subject': |
293 card = rschema.rproperty(entity.e_schema, targettype, 'cardinality')[0] |
293 card = rschema.rproperty(entity.e_schema, targettype, 'cardinality')[0] |
294 else: |
294 else: |
316 result.append(u'<div class="trame_grise"> </div>') |
316 result.append(u'<div class="trame_grise"> </div>') |
317 result.append(u'</div>') |
317 result.append(u'</div>') |
318 return '\n'.join(result) |
318 return '\n'.join(result) |
319 |
319 |
320 # should_* method extracted to allow overriding |
320 # should_* method extracted to allow overriding |
321 |
321 |
322 def should_inline_relation_form(self, entity, rschema, targettype, role): |
322 def should_inline_relation_form(self, entity, rschema, targettype, role): |
323 return AutomaticEntityForm.rinlined.etype_get(entity.id, rschema, role, |
323 return AutomaticEntityForm.rinlined.etype_get(entity.id, rschema, role, |
324 targettype) |
324 targettype) |
325 |
325 |
326 def should_display_inline_relation_form(self, rschema, existant, card): |
326 def should_display_inline_relation_form(self, rschema, existant, card): |
327 return not existant and card in '1+' |
327 return not existant and card in '1+' |
328 |
328 |
329 def should_display_add_inline_relation_link(self, rschema, existant, card): |
329 def should_display_add_inline_relation_link(self, rschema, existant, card): |
330 return not existant or card in '+*' |
330 return not existant or card in '+*' |
331 |
331 |
332 def reset_url(self, entity): |
332 def reset_url(self, entity): |
333 return entity.absolute_url() |
333 return entity.absolute_url() |
334 |
334 |
335 def on_submit(self, entity): |
335 def on_submit(self, entity): |
336 return u'return freezeFormButtons(\'%s\')' % (self.domid) |
336 return u'return freezeFormButtons(\'%s\')' % (self.domid) |
337 |
337 |
338 def submited_message(self): |
338 def submited_message(self): |
339 return self.req._('element edited') |
339 return self.req._('element edited') |
340 |
340 |
341 |
341 |
342 |
342 |
343 class CreationForm(EditionForm): |
343 class CreationForm(EditionForm): |
344 __select__ = specified_etype_implements('Any') |
344 __select__ = specified_etype_implements('Any') |
345 # XXX bw compat, use View.registered since we don't want accept_compat |
345 # XXX bw compat, use View.registered since we don't want accept_compat |
346 # wrapper set in EntityView |
346 # wrapper set in EntityView |
347 registered = accepts_etype_compat(View.registered) |
347 registered = accepts_etype_compat(View.registered) |
348 id = 'creation' |
348 id = 'creation' |
349 title = _('creation') |
349 title = _('creation') |
350 |
350 |
351 def call(self, **kwargs): |
351 def call(self, **kwargs): |
352 """creation view for an entity""" |
352 """creation view for an entity""" |
353 self.req.add_js( ('cubicweb.ajax.js',) ) |
353 self.req.add_js( ('cubicweb.ajax.js',) ) |
354 self.initialize_varmaker() |
354 self.initialize_varmaker() |
355 etype = kwargs.pop('etype', self.req.form.get('etype')) |
355 etype = kwargs.pop('etype', self.req.form.get('etype')) |
383 return super(CreationForm, self).action_title(entity) |
383 return super(CreationForm, self).action_title(entity) |
384 |
384 |
385 @property |
385 @property |
386 def formid(self): |
386 def formid(self): |
387 return 'edition' |
387 return 'edition' |
388 |
388 |
389 def relations_form(self, entity, kwargs): |
389 def relations_form(self, entity, kwargs): |
390 return u'' |
390 return u'' |
391 |
391 |
392 def reset_url(self, entity=None): |
392 def reset_url(self, entity=None): |
393 return self.build_url(self.req.form.get('etype', '').lower()) |
393 return self.build_url(self.req.form.get('etype', '').lower()) |
394 |
394 |
395 def submited_message(self): |
395 def submited_message(self): |
396 return self.req._('element created') |
396 return self.req._('element created') |
397 |
397 |
398 def url(self): |
398 def url(self): |
399 """return the url associated with this view""" |
399 """return the url associated with this view""" |
400 return self.create_url(self.req.form.get('etype')) |
400 return self.create_url(self.req.form.get('etype')) |
401 |
401 |
402 |
402 |
403 class InlineFormMixIn(object): |
403 class InlineFormMixIn(object): |
404 |
404 |
405 @cached |
405 @cached |
406 def card(self, etype): |
406 def card(self, etype): |
407 return self.rschema.rproperty(self.parent_schema, etype, 'cardinality')[0] |
407 return self.rschema.rproperty(self.parent_schema, etype, 'cardinality')[0] |
408 |
408 |
409 def action_title(self, entity): |
409 def action_title(self, entity): |
410 return self.rschema.display_name(self.req, self.role) |
410 return self.rschema.display_name(self.req, self.role) |
411 |
411 |
412 def add_hidden_web_behaviour_params(self, entity): |
412 def add_hidden_web_behaviour_params(self, entity): |
413 pass |
413 pass |
414 |
414 |
415 def edit_form(self, entity, ptype, peid, rtype, |
415 def edit_form(self, entity, ptype, peid, rtype, |
416 role='subject', **kwargs): |
416 role='subject', **kwargs): |
417 self.rschema = self.schema.rschema(rtype) |
417 self.rschema = self.schema.rschema(rtype) |
418 self.role = role |
418 self.role = role |
419 self.parent_schema = self.schema.eschema(ptype) |
419 self.parent_schema = self.schema.eschema(ptype) |
420 self.parent_eid = peid |
420 self.parent_eid = peid |
421 super(InlineFormMixIn, self).edit_form(entity, kwargs) |
421 super(InlineFormMixIn, self).edit_form(entity, kwargs) |
422 |
422 |
423 def should_inline_relation_form(self, entity, rschema, targettype, role): |
423 def should_inline_relation_form(self, entity, rschema, targettype, role): |
424 if rschema == self.rschema: |
424 if rschema == self.rschema: |
425 return False |
425 return False |
426 return AutomaticEntityForm.rinlined.etype_get(entity.id, rschema, role, |
426 return AutomaticEntityForm.rinlined.etype_get(entity.id, rschema, role, |
427 targettype) |
427 targettype) |
453 'removemsg' : self.req.__('remove this %s' % entity.e_schema), |
453 'removemsg' : self.req.__('remove this %s' % entity.e_schema), |
454 'notice' : self.req._('click on the box to cancel the deletion'), |
454 'notice' : self.req._('click on the box to cancel the deletion'), |
455 } |
455 } |
456 ctx.update(local_ctx) |
456 ctx.update(local_ctx) |
457 return ctx |
457 return ctx |
458 |
458 |
459 |
459 |
460 class CopyEditionForm(EditionForm): |
460 class CopyEditionForm(EditionForm): |
461 id = 'copy' |
461 id = 'copy' |
462 title = _('copy edition') |
462 title = _('copy edition') |
463 |
463 |
464 def cell_call(self, row, col, **kwargs): |
464 def cell_call(self, row, col, **kwargs): |
465 self.req.add_js(('cubicweb.ajax.js',)) |
465 self.req.add_js(('cubicweb.ajax.js',)) |
466 entity = self.complete_entity(row, col, skip_bytes=True) |
466 entity = self.complete_entity(row, col, skip_bytes=True) |
467 # make a copy of entity to avoid altering the entity in the |
467 # make a copy of entity to avoid altering the entity in the |
468 # request's cache. |
468 # request's cache. |
469 self.newentity = copy(entity) |
469 self.newentity = copy(entity) |
470 self.copying = self.newentity.eid |
470 self.copying = self.newentity.eid |
471 self.newentity.eid = None |
471 self.newentity.eid = None |
472 self.edit_form(self.newentity, kwargs) |
472 self.edit_form(self.newentity, kwargs) |
473 del self.newentity |
473 del self.newentity |
480 # XXX above message should have style of a warning |
480 # XXX above message should have style of a warning |
481 |
481 |
482 @property |
482 @property |
483 def formid(self): |
483 def formid(self): |
484 return 'edition' |
484 return 'edition' |
485 |
485 |
486 def relations_form(self, entity, kwargs): |
486 def relations_form(self, entity, kwargs): |
487 return u'' |
487 return u'' |
488 |
488 |
489 def reset_url(self, entity): |
489 def reset_url(self, entity): |
490 return self.build_url('view', rql='Any X WHERE X eid %s' % self.copying) |
490 return self.build_url('view', rql='Any X WHERE X eid %s' % self.copying) |
491 |
491 |
492 def attributes_form(self, entity, kwargs, include_eid=True): |
492 def attributes_form(self, entity, kwargs, include_eid=True): |
493 # we don't want __clone_eid on inlined edited entities |
493 # we don't want __clone_eid on inlined edited entities |
494 if entity.eid == self.newentity.eid: |
494 if entity.eid == self.newentity.eid: |
495 self._hiddens.append((eid_param('__cloned_eid', entity.eid), self.copying, '')) |
495 self._hiddens.append((eid_param('__cloned_eid', entity.eid), self.copying, '')) |
496 return EditionForm.attributes_form(self, entity, kwargs, include_eid) |
496 return EditionForm.attributes_form(self, entity, kwargs, include_eid) |
497 |
497 |
498 def submited_message(self): |
498 def submited_message(self): |
499 return self.req._('element copied') |
499 return self.req._('element copied') |
500 |
500 |
501 |
501 |
502 class TableEditForm(FormMixIn, EntityView): |
502 class TableEditForm(FormMixIn, EntityView): |
503 id = 'muledit' |
503 id = 'muledit' |
504 title = _('multiple edit') |
504 title = _('multiple edit') |
505 |
505 |
506 EDITION_BODY = u'''<form method="post" id="entityForm" onsubmit="return validateForm('entityForm', null);" action="%(action)s"> |
506 EDITION_BODY = u'''<form method="post" id="entityForm" onsubmit="return validateForm('entityForm', null);" action="%(action)s"> |
558 'lines': u'\n'.join(self.edit_form(ent) for ent in self.rset.entities()), |
558 'lines': u'\n'.join(self.edit_form(ent) for ent in self.rset.entities()), |
559 'okvalue': _('button_ok').capitalize(), |
559 'okvalue': _('button_ok').capitalize(), |
560 'oktitle': _('validate modifications on selected items').capitalize(), |
560 'oktitle': _('validate modifications on selected items').capitalize(), |
561 'cancelvalue': _('button_reset').capitalize(), |
561 'cancelvalue': _('button_reset').capitalize(), |
562 'canceltitle': _('revert changes').capitalize(), |
562 'canceltitle': _('revert changes').capitalize(), |
563 } |
563 } |
564 self.w(self.EDITION_BODY % ctx) |
564 self.w(self.EDITION_BODY % ctx) |
565 |
565 |
566 |
566 |
567 def reset_url(self, entity=None): |
567 def reset_url(self, entity=None): |
568 self.build_url('view', rql=self.rset.printable_rql()) |
568 self.build_url('view', rql=self.rset.printable_rql()) |
569 |
569 |
570 def edit_form(self, entity): |
570 def edit_form(self, entity): |
571 html = [] |
571 html = [] |
572 w = html.append |
572 w = html.append |
573 entity.complete() |
573 entity.complete() |
574 eid = entity.eid |
574 eid = entity.eid |