web/views/reledit.py
changeset 7076 0eed6045d785
parent 7070 5f8e52d722c5
child 7077 784d6f300070
equal deleted inserted replaced
7070:5f8e52d722c5 7076:0eed6045d785
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    14 # details.
    14 # details.
    15 #
    15 #
    16 # You should have received a copy of the GNU Lesser General Public License along
    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/>.
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
    18 """the 'reedit' feature (eg edit attribute/relation from primary view"""
    18 """edit entity attributes/relations from any view, without going to the entity
       
    19 form
       
    20 """
    19 
    21 
    20 __docformat__ = "restructuredtext en"
    22 __docformat__ = "restructuredtext en"
    21 _ = unicode
    23 _ = unicode
    22 
    24 
    23 import copy
    25 import copy
    24 from warnings import warn
    26 from warnings import warn
    25 
    27 
    26 from logilab.mtconverter import xml_escape
    28 from logilab.mtconverter import xml_escape
    27 from logilab.common.deprecation import deprecated
    29 from logilab.common.deprecation import deprecated, class_renamed
       
    30 from logilab.common.decorators import cached
    28 
    31 
    29 from cubicweb import neg_role
    32 from cubicweb import neg_role
    30 from cubicweb.schema import display_name
    33 from cubicweb.schema import display_name
    31 from cubicweb.utils import json_dumps
    34 from cubicweb.utils import json_dumps
    32 from cubicweb.selectors import non_final_entity, match_kwargs
    35 from cubicweb.selectors import non_final_entity, match_kwargs
    41         return u''
    44         return u''
    42     def render(self, *_args, **_kwargs):
    45     def render(self, *_args, **_kwargs):
    43         return u''
    46         return u''
    44     def append_field(self, *args):
    47     def append_field(self, *args):
    45         pass
    48         pass
       
    49     def add_hidden(self, *args):
       
    50         pass
    46 
    51 
    47 rctrl = uicfg.reledit_ctrl
    52 rctrl = uicfg.reledit_ctrl
    48 
    53 
    49 class ClickAndEditFormView(EntityView):
    54 class AutoClickAndEditFormView(EntityView):
    50     __regid__ = 'doreledit'
    55     __regid__ = 'reledit'
    51     __select__ = non_final_entity() & match_kwargs('rtype')
    56     __select__ = non_final_entity() & match_kwargs('rtype')
    52 
    57 
    53     # ui side continuations
    58     # ui side continuations
    54     _onclick = (u"cw.reledit.loadInlineEditionForm('%(formid)s', %(eid)s, '%(rtype)s', '%(role)s', "
    59     _onclick = (u"cw.reledit.loadInlineEditionForm('%(formid)s', %(eid)s, '%(rtype)s', '%(role)s', "
    55                 "'%(divid)s', %(reload)s, '%(vid)s');")
    60                 "'%(divid)s', %(reload)s, '%(vid)s', '%(action)s');")
    56     _cancelclick = "cw.reledit.cleanupAfterCancel('%s')"
    61     _cancelclick = "cw.reledit.cleanupAfterCancel('%s')"
    57 
    62 
    58     # ui side actions/buttons
    63     # ui side actions/buttons
    59     _addzone = u'<img title="%(msg)s" src="%(logo)s" alt="%(msg)s"/>'
    64     _addzone = u'<img title="%(msg)s" src="%(logo)s" alt="%(msg)s"/>'
    60     _addmsg = _('click to add a value')
    65     _addmsg = _('click to add a value')
    73                   reload=False, # controls reloading the whole page after change
    78                   reload=False, # controls reloading the whole page after change
    74                                 # boolean, eid (to redirect), or
    79                                 # boolean, eid (to redirect), or
    75                                 # function taking the subject entity & returning a boolean or an eid
    80                                 # function taking the subject entity & returning a boolean or an eid
    76                   rvid=None,    # vid to be applied to other side of rtype (non final relations only)
    81                   rvid=None,    # vid to be applied to other side of rtype (non final relations only)
    77                   default_value=None,
    82                   default_value=None,
    78                   formid='base'
    83                   formid='base',
       
    84                   action=None
    79                   ):
    85                   ):
    80         """display field to edit entity's `rtype` relation on click"""
    86         """display field to edit entity's `rtype` relation on click"""
    81         assert rtype
    87         assert rtype
    82         assert role in ('subject', 'object'), '%s is not an acceptable role value' % role
       
    83         self._cw.add_css('cubicweb.form.css')
    88         self._cw.add_css('cubicweb.form.css')
    84         self._cw.add_js(('cubicweb.reledit.js', 'cubicweb.edition.js', 'cubicweb.ajax.js'))
    89         self._cw.add_js(('cubicweb.reledit.js', 'cubicweb.edition.js', 'cubicweb.ajax.js'))
    85         entity = self.cw_rset.get_entity(row, col)
    90         entity = self.cw_rset.get_entity(row, col)
    86         rschema = self._cw.vreg.schema[rtype]
    91         rschema = self._cw.vreg.schema[rtype]
    87         self._rules = rctrl.etype_get(entity.e_schema.type, rschema.type, role, '*')
    92         self._rules = rctrl.etype_get(self.entity.e_schema.type, rschema.type, role, '*')
    88         if rvid is not None or default_value is not None:
    93         if rvid is not None or default_value is not None:
    89             warn('[3.9] specifying rvid/default_value on select is deprecated, '
    94             warn('[3.9] specifying rvid/default_value on select is deprecated, '
    90                  'reledit_ctrl rtag to control this' % self, DeprecationWarning)
    95                  'reledit_ctrl rtag to control this' % self, DeprecationWarning)
    91         reload = self._compute_reload(entity, rschema, role, reload)
    96         reload = self._compute_reload(rschema, role, reload)
    92         divid = self._build_divid(rtype, role, entity.eid)
    97         divid = self._build_divid(rtype, role, self.entity.eid)
    93         if rschema.final:
    98         if rschema.final:
    94             self._handle_attribute(entity, rschema, role, divid, reload)
    99             self._handle_attribute(rschema, role, divid, reload, action)
    95         else:
   100         else:
    96             if self._is_composite():
   101             if self._is_composite():
    97                 self._handle_composite(entity, rschema, role, divid, reload, formid)
   102                 self._handle_composite(rschema, role, divid, reload, formid, action)
    98             else:
   103             else:
    99                 self._handle_relation(entity, rschema, role, divid, reload, formid)
   104                 self._handle_relation(rschema, role, divid, reload, formid, action)
   100 
   105 
   101     def _handle_attribute(self, entity, rschema, role, divid, reload):
   106     def _handle_attribute(self, rschema, role, divid, reload, action):
   102         rtype = rschema.type
   107         value = self.entity.printable_value(rschema.type)
   103         value = entity.printable_value(rtype)
   108         if not self._should_edit_attribute(rschema):
   104         if not self._should_edit_attribute(entity, rschema):
       
   105             self.w(value)
   109             self.w(value)
   106             return
   110             return
   107         display_label, related_entity = self._prepare_form(entity, rtype, role)
   111         form, renderer = self._build_form(self.entity, rschema, role, divid, 'base', reload, action)
   108         form, renderer = self._build_form(entity, rtype, role, divid, 'base',
       
   109                                           reload, display_label, related_entity)
       
   110         value = value or self._compute_default_value(rschema, role)
   112         value = value or self._compute_default_value(rschema, role)
   111         self.view_form(divid, value, form, renderer)
   113         self.view_form(divid, value, form, renderer)
   112 
   114 
   113     def _compute_formid_value(self, entity, rschema, role, rvid, formid):
   115     def _compute_formid_value(self, rschema, role, rvid, formid):
   114         related_rset = entity.related(rschema.type, role)
   116         related_rset = self.entity.related(rschema.type, role)
   115         if related_rset:
   117         if related_rset:
   116             value = self._cw.view(rvid, related_rset)
   118             value = self._cw.view(rvid, related_rset)
   117         else:
   119         else:
   118             value = self._compute_default_value(rschema, role)
   120             value = self._compute_default_value(rschema, role)
   119         if not self._should_edit_relation(entity, rschema, role):
   121         if not self._should_edit_relation(rschema, role):
   120             return None, value
   122             return None, value
   121         return formid, value
   123         return formid, value
   122 
   124 
   123     def _handle_relation(self, entity, rschema, role, divid, reload, formid):
   125     def _handle_relation(self, rschema, role, divid, reload, formid, action):
   124         rvid = self._rules.get('rvid', 'autolimited')
   126         rvid = self._rules.get('rvid', 'autolimited')
   125         formid, value = self._compute_formid_value(entity, rschema, role, rvid, formid)
   127         formid, value = self._compute_formid_value(rschema, role, rvid, formid)
   126         if formid is None:
   128         if formid is None:
   127             return self.w(value)
   129             return self.w(value)
   128         rtype = rschema.type
   130         form, renderer = self._build_form(self.entity,  rschema, role, divid, formid,
   129         display_label, related_entity = self._prepare_form(entity, rtype, role)
   131                                           reload, action, dict(vid=rvid))
   130         form, renderer = self._build_form(entity, rtype, role, divid, formid, reload,
       
   131                                           display_label, related_entity, dict(vid=rvid))
       
   132         self.view_form(divid, value, form, renderer)
   132         self.view_form(divid, value, form, renderer)
   133 
   133 
   134     def _handle_composite(self, entity, rschema, role, divid, reload, formid):
   134     def _handle_composite(self, rschema, role, divid, reload, formid, action):
   135         # this is for attribute-like composites (1 target type, 1 related entity at most, for now)
   135         # this is for attribute-like composites (1 target type, 1 related entity at most, for now)
   136         ttypes = self._compute_ttypes(rschema, role)
   136         entity = self.entity
   137         related_rset = entity.related(rschema.type, role)
   137         related_rset = entity.related(rschema.type, role)
   138         add_related = self._may_add_related(related_rset, entity, rschema, role, ttypes)
   138         add_related = self._may_add_related(related_rset, rschema, role)
   139         edit_related = self._may_edit_related_entity(related_rset, entity, rschema, role, ttypes)
   139         edit_related = self._may_edit_related_entity(related_rset, rschema, role)
   140         delete_related = edit_related and self._may_delete_related(related_rset, entity, rschema, role)
   140         delete_related = edit_related and self._may_delete_related(related_rset, rschema, role)
   141         rvid = self._rules.get('rvid', 'autolimited')
   141         rvid = self._rules.get('rvid', 'autolimited')
   142         formid, value = self._compute_formid_value(entity, rschema, role, rvid, formid)
   142         formid, value = self._compute_formid_value(rschema, role, rvid, formid)
   143         if formid is None or not (edit_related or add_related):
   143         if formid is None or not (edit_related or add_related):
   144             # till we learn to handle cases where not (edit_related or add_related)
   144             # till we learn to handle cases where not (edit_related or add_related)
   145             self.w(value)
   145             self.w(value)
   146             return
   146             return
   147         rtype = rschema.type
   147         form, renderer = self._build_form(entity, rschema, role, divid, formid,
   148         ttype = ttypes[0]
   148                                           reload, action, dict(vid=rvid))
   149         _fdata = self._prepare_composite_form(entity, rtype, role, edit_related,
       
   150                                               add_related and ttype)
       
   151         display_label, related_entity = _fdata
       
   152         form, renderer = self._build_form(entity, rtype, role, divid, formid, reload,
       
   153                                           display_label, related_entity, dict(vid=rvid))
       
   154         self.view_form(divid, value, form, renderer,
   149         self.view_form(divid, value, form, renderer,
   155                        edit_related, add_related, delete_related)
   150                        edit_related, add_related, delete_related)
   156 
   151 
       
   152     @cached
   157     def _compute_ttypes(self, rschema, role):
   153     def _compute_ttypes(self, rschema, role):
   158         dual_role = neg_role(role)
   154         dual_role = neg_role(role)
   159         return getattr(rschema, '%ss' % dual_role)()
   155         return getattr(rschema, '%ss' % dual_role)()
   160 
   156 
   161     def _compute_reload(self, entity, rschema, role, reload):
   157     def _compute_reload(self, rschema, role, reload):
   162         ctrl_reload = self._rules.get('reload', reload)
   158         ctrl_reload = self._rules.get('reload', reload)
   163         if callable(ctrl_reload):
   159         if callable(ctrl_reload):
   164             ctrl_reload = ctrl_reload(entity)
   160             ctrl_reload = ctrl_reload(self.entity)
   165         if isinstance(ctrl_reload, int) and ctrl_reload > 1: # not True/False
   161         if isinstance(ctrl_reload, int) and ctrl_reload > 1: # not True/False
   166             ctrl_reload = self._cw.build_url(ctrl_reload)
   162             ctrl_reload = self._cw.build_url(ctrl_reload)
   167         return ctrl_reload
   163         return ctrl_reload
   168 
   164 
   169     def _compute_default_value(self, rschema, role):
   165     def _compute_default_value(self, rschema, role):
   177         return xml_escape(default)
   173         return xml_escape(default)
   178 
   174 
   179     def _is_composite(self):
   175     def _is_composite(self):
   180         return self._rules.get('edit_target') == 'related'
   176         return self._rules.get('edit_target') == 'related'
   181 
   177 
   182     def _may_add_related(self, related_rset, entity, rschema, role, ttypes):
   178     def _may_add_related(self, related_rset, rschema, role):
   183         """ ok for attribute-like composite entities """
   179         """ ok for attribute-like composite entities """
       
   180         ttypes = self._compute_ttypes(rschema, role)
   184         if len(ttypes) > 1: # many etypes: learn how to do it
   181         if len(ttypes) > 1: # many etypes: learn how to do it
   185             return False
   182             return False
   186         rdef = rschema.role_rdef(entity.e_schema, ttypes[0], role)
   183         rdef = rschema.role_rdef(self.entity.e_schema, ttypes[0], role)
   187         card = rdef.role_cardinality(role)
   184         card = rdef.role_cardinality(role)
   188         if related_rset or card not in '?1':
   185         if related_rset or card not in '?1':
   189             return False
   186             return False
   190         if role == 'subject':
   187         if role == 'subject':
   191             kwargs = {'fromeid': entity.eid}
   188             kwargs = {'fromeid': self.entity.eid}
   192         else:
   189         else:
   193             kwargs = {'toeid': entity.eid}
   190             kwargs = {'toeid': self.entity.eid}
   194         return rdef.has_perm(self._cw, 'add', **kwargs)
   191         return rdef.has_perm(self._cw, 'add', **kwargs)
   195 
   192 
   196     def _may_edit_related_entity(self, related_rset, entity, rschema, role, ttypes):
   193     def _may_edit_related_entity(self, related_rset, rschema, role):
   197         """ controls the edition of the related entity """
   194         """ controls the edition of the related entity """
       
   195         ttypes = self._compute_ttypes(rschema, role)
   198         if len(ttypes) > 1 or len(related_rset.rows) != 1:
   196         if len(ttypes) > 1 or len(related_rset.rows) != 1:
   199             return False
   197             return False
   200         if entity.e_schema.rdef(rschema, role).role_cardinality(role) not in '?1':
   198         if self.entity.e_schema.rdef(rschema, role).role_cardinality(role) not in '?1':
   201             return False
   199             return False
   202         return related_rset.get_entity(0, 0).cw_has_perm('update')
   200         return related_rset.get_entity(0, 0).cw_has_perm('update')
   203 
   201 
   204     def _may_delete_related(self, related_rset, entity, rschema, role):
   202     def _may_delete_related(self, related_rset, rschema, role):
   205         # we assume may_edit_related, only 1 related entity
   203         # we assume may_edit_related, only 1 related entity
   206         if not related_rset:
   204         if not related_rset:
   207             return False
   205             return False
   208         rentity = related_rset.get_entity(0, 0)
   206         rentity = related_rset.get_entity(0, 0)
       
   207         entity = self.entity
   209         if role == 'subject':
   208         if role == 'subject':
   210             kwargs = {'fromeid': entity.eid, 'toeid': rentity.eid}
   209             kwargs = {'fromeid': entity.eid, 'toeid': rentity.eid}
   211         else:
   210         else:
   212             kwargs = {'fromeid': rentity.eid, 'toeid': entity.eid}
   211             kwargs = {'fromeid': rentity.eid, 'toeid': entity.eid}
   213         # NOTE: should be sufficient given a well built schema/security
   212         # NOTE: should be sufficient given a well built schema/security
   228 
   227 
   229     def _build_divid(self, rtype, role, entity_eid):
   228     def _build_divid(self, rtype, role, entity_eid):
   230         """ builds an id for the root div of a reledit widget """
   229         """ builds an id for the root div of a reledit widget """
   231         return '%s-%s-%s' % (rtype, role, entity_eid)
   230         return '%s-%s-%s' % (rtype, role, entity_eid)
   232 
   231 
   233     def _build_args(self, entity, rtype, role, formid, reload,
   232     def _build_args(self, entity, rtype, role, formid, reload, action,
   234                     extradata=None):
   233                     extradata=None):
   235         divid = self._build_divid(rtype, role, entity.eid)
   234         divid = self._build_divid(rtype, role, entity.eid)
   236         event_args = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, 'formid': formid,
   235         event_args = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, 'formid': formid,
   237                       'reload' : json_dumps(reload),
   236                       'reload' : json_dumps(reload), 'action': action,
   238                       'role' : role, 'vid' : u''}
   237                       'role' : role, 'vid' : u''}
   239         if extradata:
   238         if extradata:
   240             event_args.update(extradata)
   239             event_args.update(extradata)
   241         return event_args
   240         return event_args
   242 
   241 
   243     def _prepare_form(self, entity, _rtype, role):
   242     def _prepare_form(self, entity, rschema, role, action):
   244         display_label = False
   243         assert action in ('edit_rtype', 'edit_related', 'add', 'delete'), action
   245         related_entity = entity
   244         if action == 'edit_rtype':
   246         return display_label, related_entity
   245             return False, entity
   247 
   246         label = True
   248     def _prepare_composite_form(self, entity, rtype, role, edit_related, add_related):
   247         if action in ('edit_related', 'delete'):
   249         display_label = True
   248             edit_entity = entity.related(rschema, role).get_entity(0, 0)
   250         if edit_related and not add_related:
   249         elif action == 'add':
   251             related_entity = entity.related(rtype, role).get_entity(0, 0)
   250             add_etype = self._compute_ttypes(rschema, role)[0]
   252         elif add_related:
   251             _new_entity = self._cw.vreg['etypes'].etype_class(add_etype)(self._cw)
   253             _new_entity = self._cw.vreg['etypes'].etype_class(add_related)(self._cw)
       
   254             _new_entity.eid = self._cw.varmaker.next()
   252             _new_entity.eid = self._cw.varmaker.next()
   255             related_entity = _new_entity
   253             edit_entity = _new_entity
   256             # XXX see forms.py ~ 276 and entities.linked_to method
   254             # XXX see forms.py ~ 276 and entities.linked_to method
   257             #     is there another way ?
   255             #     is there another way ?
   258             self._cw.form['__linkto'] = '%s:%s:%s' % (rtype, entity.eid, neg_role(role))
   256             self._cw.form['__linkto'] = '%s:%s:%s' % (rschema, entity.eid, neg_role(role))
   259         return display_label, related_entity
   257         assert edit_entity
       
   258         return label, edit_entity
   260 
   259 
   261     def _build_renderer(self, related_entity, display_label):
   260     def _build_renderer(self, related_entity, display_label):
   262         return self._cw.vreg['formrenderers'].select(
   261         return self._cw.vreg['formrenderers'].select(
   263             self._form_renderer_id, self._cw, entity=related_entity,
   262             self._form_renderer_id, self._cw, entity=related_entity,
   264             display_label=display_label,
   263             display_label=display_label,
   265             table_class='attributeForm' if display_label else '',
   264             table_class='attributeForm' if display_label else '',
   266             display_help=False, button_bar_class='buttonbar',
   265             display_help=False, button_bar_class='buttonbar',
   267             display_progress_div=False)
   266             display_progress_div=False)
   268 
   267 
   269     def _build_form(self, entity, rtype, role, divid, formid, reload,
   268     def _build_form(self, entity, rschema, role, divid, formid, reload, action,
   270                     display_label, related_entity, extradata=None, **formargs):
   269                     extradata=None, **formargs):
   271         event_args = self._build_args(entity, rtype, role, formid,
   270         rtype = rschema.type
   272                                       reload, extradata)
   271         event_args = self._build_args(entity, rtype, role, formid, reload, action, extradata)
       
   272         if not action:
       
   273             form = _DummyForm()
       
   274             form.event_args = event_args
       
   275             return form, None
       
   276         label, edit_entity = self._prepare_form(entity, rschema, role, action)
   273         cancelclick = self._cancelclick % divid
   277         cancelclick = self._cancelclick % divid
   274         form = self._cw.vreg['forms'].select(
   278         form = self._cw.vreg['forms'].select(
   275             formid, self._cw, rset=related_entity.as_rset(), entity=related_entity,
   279             formid, self._cw, rset=edit_entity.as_rset(), entity=edit_entity,
   276             domid='%s-form' % divid, formtype='inlined',
   280             domid='%s-form' % divid, formtype='inlined',
   277             action=self._cw.build_url('validateform', __onsuccess='window.parent.cw.reledit.onSuccess'),
   281             action=self._cw.build_url('validateform', __onsuccess='window.parent.cw.reledit.onSuccess'),
   278             cwtarget='eformframe', cssclass='releditForm',
   282             cwtarget='eformframe', cssclass='releditForm',
   279             **formargs)
   283             **formargs)
   280         # pass reledit arguments
   284         # pass reledit arguments
   296                                  Button(stdmsgs.BUTTON_CANCEL, onclick=cancelclick)]
   300                                  Button(stdmsgs.BUTTON_CANCEL, onclick=cancelclick)]
   297         form.event_args = event_args
   301         form.event_args = event_args
   298         if formid == 'base':
   302         if formid == 'base':
   299             field = form.field_by_name(rtype, role, entity.e_schema)
   303             field = form.field_by_name(rtype, role, entity.e_schema)
   300             form.append_field(field)
   304             form.append_field(field)
   301         return form, self._build_renderer(related_entity, display_label)
   305         return form, self._build_renderer(edit_entity, label)
   302 
   306 
   303     def _should_edit_attribute(self, entity, rschema):
   307     def _should_edit_attribute(self, rschema):
       
   308         entity = self.entity
   304         rdef = entity.e_schema.rdef(rschema)
   309         rdef = entity.e_schema.rdef(rschema)
   305         # check permissions
   310         # check permissions
   306         if not entity.cw_has_perm('update'):
   311         if not entity.cw_has_perm('update'):
   307             return False
   312             return False
   308         rdef = entity.e_schema.rdef(rschema)
   313         rdef = entity.e_schema.rdef(rschema)
   310 
   315 
   311     should_edit_attributes = deprecated('[3.9] should_edit_attributes is deprecated,'
   316     should_edit_attributes = deprecated('[3.9] should_edit_attributes is deprecated,'
   312                                         ' use _should_edit_attribute instead',
   317                                         ' use _should_edit_attribute instead',
   313                                         _should_edit_attribute)
   318                                         _should_edit_attribute)
   314 
   319 
   315     def _should_edit_relation(self, entity, rschema, role):
   320     def _should_edit_relation(self, rschema, role):
   316         eeid = entity.eid
   321         eeid = self.entity.eid
   317         perm_args = {'fromeid': eeid} if role == 'subject' else {'toeid': eeid}
   322         perm_args = {'fromeid': eeid} if role == 'subject' else {'toeid': eeid}
   318         return rschema.has_perm(self._cw, 'add', **perm_args)
   323         return rschema.has_perm(self._cw, 'add', **perm_args)
   319 
   324 
   320     should_edit_relations = deprecated('[3.9] should_edit_relations is deprecated,'
   325     should_edit_relations = deprecated('[3.9] should_edit_relations is deprecated,'
   321                                        ' use _should_edit_relation instead',
   326                                        ' use _should_edit_relation instead',
   333         w(u'</div>')
   338         w(u'</div>')
   334         form.render(w=w, renderer=renderer)
   339         form.render(w=w, renderer=renderer)
   335         w(u'<div id="%s" class="editableField hidden">' % divid)
   340         w(u'<div id="%s" class="editableField hidden">' % divid)
   336 
   341 
   337     def _edit_action(self, divid, args, edit_related, add_related, _delete_related):
   342     def _edit_action(self, divid, args, edit_related, add_related, _delete_related):
       
   343         # XXX disambiguate wrt edit_related
   338         if not add_related: # currently, excludes edition
   344         if not add_related: # currently, excludes edition
   339             w = self.w
   345             w = self.w
   340             args['formid'] = 'edition' if edit_related else 'base'
   346             args['formid'] = 'edition' if edit_related else 'base'
       
   347             args['action'] = 'edit_related' if edit_related else 'edit_rtype'
   341             w(u'<div id="%s-update" class="editableField" onclick="%s" title="%s">' %
   348             w(u'<div id="%s-update" class="editableField" onclick="%s" title="%s">' %
   342               (divid, xml_escape(self._onclick % args), self._cw._(self._editzonemsg)))
   349               (divid, xml_escape(self._onclick % args), self._cw._(self._editzonemsg)))
   343             w(self._build_edit_zone())
   350             w(self._build_edit_zone())
   344             w(u'</div>')
   351             w(u'</div>')
   345 
   352 
   346     def _add_action(self, divid, args, _edit_related, add_related, _delete_related):
   353     def _add_action(self, divid, args, _edit_related, add_related, _delete_related):
   347         if add_related:
   354         if add_related:
   348             w = self.w
   355             w = self.w
   349             args['formid'] = 'edition' if add_related else 'base'
   356             args['formid'] = 'edition'
       
   357             args['action'] = 'add'
   350             w(u'<div id="%s-add" class="editableField" onclick="%s" title="%s">' %
   358             w(u'<div id="%s-add" class="editableField" onclick="%s" title="%s">' %
   351               (divid, xml_escape(self._onclick % args), self._cw._(self._addmsg)))
   359               (divid, xml_escape(self._onclick % args), self._cw._(self._addmsg)))
   352             w(self._build_add_zone())
   360             w(self._build_add_zone())
   353             w(u'</div>')
   361             w(u'</div>')
   354 
   362 
   355     def _del_action(self, divid, args, _edit_related, _add_related, delete_related):
   363     def _del_action(self, divid, args, _edit_related, _add_related, delete_related):
   356         if delete_related:
   364         if delete_related:
   357             w = self.w
   365             w = self.w
   358             args['formid'] = 'deleteconf'
   366             args['formid'] = 'deleteconf'
       
   367             args['action'] = 'delete'
   359             w(u'<div id="%s-delete" class="editableField" onclick="%s" title="%s">' %
   368             w(u'<div id="%s-delete" class="editableField" onclick="%s" title="%s">' %
   360               (divid, xml_escape(self._onclick % args), self._cw._(self._deletemsg)))
   369               (divid, xml_escape(self._onclick % args), self._cw._(self._deletemsg)))
   361             w(self._build_delete_zone())
   370             w(self._build_delete_zone())
   362             w(u'</div>')
   371             w(u'</div>')
   363 
   372 
   374         self._add_action(divid, args, edit_related, add_related, delete_related)
   383         self._add_action(divid, args, edit_related, add_related, delete_related)
   375         self._del_action(divid, args, edit_related, add_related, delete_related)
   384         self._del_action(divid, args, edit_related, add_related, delete_related)
   376         self._close_form_wrapper()
   385         self._close_form_wrapper()
   377 
   386 
   378 
   387 
   379 class AutoClickAndEditFormView(ClickAndEditFormView):
   388 ClickAndEditFormView = class_renamed('ClickAndEditFormView', AutoClickAndEditFormView)
   380     __regid__ = 'reledit'
       
   381 
       
   382     def _build_form(self, entity, rtype, role, divid, formid, reload,
       
   383                     display_label, related_entity, extradata=None, **formargs):
       
   384         event_args = self._build_args(entity, rtype, role, 'base',
       
   385                                       reload, extradata)
       
   386         form = _DummyForm()
       
   387         form.event_args = event_args
       
   388         return form, None