web/views/baseforms.py
branchtls-sprint
changeset 1802 d628defebc17
parent 1540 996355824825
child 1977 606923dff11b
equal deleted inserted replaced
1801:672acc730ce5 1802:d628defebc17
    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
   133             }
   133             }
   134 
   134 
   135     @property
   135     @property
   136     def formid(self):
   136     def formid(self):
   137         return self.id
   137         return self.id
   138     
   138 
   139     def action_title(self, entity):
   139     def action_title(self, entity):
   140         """form's title"""
   140         """form's title"""
   141         ptitle = self.req._(self.title)
   141         ptitle = self.req._(self.title)
   142         return u'<div class="formTitle"><span>%s %s</span></div>' % (
   142         return u'<div class="formTitle"><span>%s %s</span></div>' % (
   143             entity.dc_type(), ptitle and '(%s)' % ptitle)
   143             entity.dc_type(), ptitle and '(%s)' % ptitle)
   153                               % (iid, name, value))
   153                               % (iid, name, value))
   154             else:
   154             else:
   155                 output.append(u'<input type="hidden" name="%s" value="%s" />'
   155                 output.append(u'<input type="hidden" name="%s" value="%s" />'
   156                               % (name, value))
   156                               % (name, value))
   157         return u'\n'.join(output)
   157         return u'\n'.join(output)
   158                 
   158 
   159     def add_hidden_web_behaviour_params(self, entity):
   159     def add_hidden_web_behaviour_params(self, entity):
   160         """inserts hidden params controlling how errors and redirection
   160         """inserts hidden params controlling how errors and redirection
   161         should be handled
   161         should be handled
   162         """
   162         """
   163         req = self.req
   163         req = self.req
   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">&nbsp;</div>')
   316                     result.append(u'<div class="trame_grise">&nbsp;</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">
   524         <input class="validateButton" type="submit"  value="%(okvalue)s" title="%(oktitle)s" />
   524         <input class="validateButton" type="submit"  value="%(okvalue)s" title="%(oktitle)s" />
   525         <input class="validateButton" type="reset" name="__action_cancel" value="%(cancelvalue)s" title="%(canceltitle)s" />
   525         <input class="validateButton" type="reset" name="__action_cancel" value="%(cancelvalue)s" title="%(canceltitle)s" />
   526       </td>
   526       </td>
   527     </tr>
   527     </tr>
   528   </table>
   528   </table>
   529   </fieldset>    
   529   </fieldset>
   530 </form>
   530 </form>
   531 '''
   531 '''
   532 
   532 
   533     WIDGET_CELL = u'''\
   533     WIDGET_CELL = u'''\
   534 <td%(csscls)s>
   534 <td%(csscls)s>
   535   %(error)s
   535   %(error)s
   536   <div>%(widget)s</div>
   536   <div>%(widget)s</div>
   537 </td>'''
   537 </td>'''
   538     
   538 
   539     def call(self, **kwargs):
   539     def call(self, **kwargs):
   540         """a view to edit multiple entities of the same type
   540         """a view to edit multiple entities of the same type
   541         the first column should be the eid
   541         the first column should be the eid
   542         """
   542         """
   543         req = self.req
   543         req = self.req
   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