116 |
116 |
117 .. More about inlined forms |
117 .. More about inlined forms |
118 .. Controlling the generic relation fields |
118 .. Controlling the generic relation fields |
119 """ |
119 """ |
120 |
120 |
121 |
|
122 from cubicweb import _ |
|
123 |
|
124 from warnings import warn |
|
125 |
|
126 from six.moves import range |
121 from six.moves import range |
127 |
122 |
128 from logilab.mtconverter import xml_escape |
123 from logilab.mtconverter import xml_escape |
129 from logilab.common.decorators import iclassmethod, cached |
124 from logilab.common.decorators import iclassmethod, cached |
130 from logilab.common.deprecation import deprecated |
|
131 from logilab.common.registry import NoSelectableObject |
125 from logilab.common.registry import NoSelectableObject |
132 |
126 |
133 from cubicweb import neg_role, uilib |
127 from cubicweb import neg_role, uilib |
134 from cubicweb.schema import display_name |
128 from cubicweb.schema import display_name |
135 from cubicweb.view import EntityView |
129 from cubicweb.view import EntityView |
235 mainform=False, |
229 mainform=False, |
236 parent_form=self.pform, |
230 parent_form=self.pform, |
237 **self.cw_extra_kwargs) |
231 **self.cw_extra_kwargs) |
238 if self.pform is None: |
232 if self.pform is None: |
239 form.restore_previous_post(form.session_key()) |
233 form.restore_previous_post(form.session_key()) |
240 #assert form.parent_form |
234 # assert form.parent_form |
241 self.add_hiddens(form, entity) |
235 self.add_hiddens(form, entity) |
242 return form |
236 return form |
243 |
237 |
244 def cell_call(self, row, col, i18nctx, **kwargs): |
238 def cell_call(self, row, col, i18nctx, **kwargs): |
245 """ |
239 """ |
259 creation form. |
253 creation form. |
260 """ |
254 """ |
261 entity = self._entity() |
255 entity = self._entity() |
262 rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), self.petype) |
256 rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), self.petype) |
263 card = rdef.role_cardinality(self.role) |
257 card = rdef.role_cardinality(self.role) |
264 if card == '1': # don't display remove link |
258 if card == '1': # don't display remove link |
265 return None |
259 return None |
266 # if cardinality is 1..n (+), dont display link to remove an inlined form for the first form |
260 # if cardinality is 1..n (+), dont display link to remove an inlined form for the first form |
267 # allowing to edit the relation. To detect so: |
261 # allowing to edit the relation. To detect so: |
268 # |
262 # |
269 # * if parent form (pform) is None, we're generated through an ajax call and so we know this |
263 # * if parent form (pform) is None, we're generated through an ajax call and so we know this |
292 try: |
286 try: |
293 self._cw.data[countkey] += 1 |
287 self._cw.data[countkey] += 1 |
294 except KeyError: |
288 except KeyError: |
295 self._cw.data[countkey] = 1 |
289 self._cw.data[countkey] = 1 |
296 self.form.render(w=self.w, divid=divid, title=title, removejs=removejs, |
290 self.form.render(w=self.w, divid=divid, title=title, removejs=removejs, |
297 i18nctx=i18nctx, counter=self._cw.data[countkey] , |
291 i18nctx=i18nctx, counter=self._cw.data[countkey], |
298 **kwargs) |
292 **kwargs) |
299 |
293 |
300 def form_title(self, entity, i18nctx): |
294 def form_title(self, entity, i18nctx): |
301 return self._cw.pgettext(i18nctx, entity.cw_etype) |
295 return self._cw.pgettext(i18nctx, entity.cw_etype) |
302 |
296 |
372 __regid__ = 'inline-addnew-link' |
366 __regid__ = 'inline-addnew-link' |
373 __select__ = (match_kwargs('peid', 'petype', 'rtype') |
367 __select__ = (match_kwargs('peid', 'petype', 'rtype') |
374 & specified_etype_implements('Any')) |
368 & specified_etype_implements('Any')) |
375 |
369 |
376 _select_attrs = InlineEntityCreationFormView._select_attrs + ('card',) |
370 _select_attrs = InlineEntityCreationFormView._select_attrs + ('card',) |
377 card = None # make pylint happy |
371 card = None # make pylint happy |
378 form = None # no actual form wrapped |
372 form = None # no actual form wrapped |
379 |
373 |
380 def call(self, i18nctx, **kwargs): |
374 def call(self, i18nctx, **kwargs): |
381 self._cw.set_varmaker() |
375 self._cw.set_varmaker() |
382 divid = "addNew%s%s%s:%s" % (self.etype, self.rtype, self.role, self.peid) |
376 divid = "addNew%s%s%s:%s" % (self.etype, self.rtype, self.role, self.peid) |
383 self.w(u'<div class="inlinedform" id="%s" cubicweb:limit="true">' |
377 self.w(u'<div class="inlinedform" id="%s" cubicweb:limit="true">' |
384 % divid) |
378 % divid) |
385 js = "addInlineCreationForm('%s', '%s', '%s', '%s', '%s', '%s')" % ( |
379 js = "addInlineCreationForm('%s', '%s', '%s', '%s', '%s', '%s')" % ( |
386 self.peid, self.petype, self.etype, self.rtype, self.role, i18nctx) |
380 self.peid, self.petype, self.etype, self.rtype, self.role, i18nctx) |
387 if self.pform.should_hide_add_new_relation_link(self.rtype, self.card): |
381 if self.pform.should_hide_add_new_relation_link(self.rtype, self.card): |
388 js = "toggleVisibility('%s'); %s" % (divid, js) |
382 js = "toggleVisibility('%s'); %s" % (divid, js) |
389 __ = self._cw.pgettext |
383 __ = self._cw.pgettext |
390 self.w(u'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>' |
384 self.w(u'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>' |
391 % (self.rtype, self.peid, js, __(i18nctx, 'add a %s' % self.etype))) |
385 % (self.rtype, self.peid, js, __(i18nctx, 'add a %s' % self.etype))) |
392 self.w(u'</div>') |
386 self.w(u'</div>') |
393 |
387 |
394 |
388 |
395 # generic relations handling ################################################## |
389 # generic relations handling ################################################## |
396 |
390 |
398 """return an identifier for a relation between two entities""" |
392 """return an identifier for a relation between two entities""" |
399 if role == 'subject': |
393 if role == 'subject': |
400 return u'%s:%s:%s' % (eid, rtype, reid) |
394 return u'%s:%s:%s' % (eid, rtype, reid) |
401 return u'%s:%s:%s' % (reid, rtype, eid) |
395 return u'%s:%s:%s' % (reid, rtype, eid) |
402 |
396 |
|
397 |
403 def toggleable_relation_link(eid, nodeid, label='x'): |
398 def toggleable_relation_link(eid, nodeid, label='x'): |
404 """return javascript snippet to delete/undelete a relation between two |
399 """return javascript snippet to delete/undelete a relation between two |
405 entities |
400 entities |
406 """ |
401 """ |
407 js = u"javascript: togglePendingDelete('%s', %s);" % ( |
402 js = u"javascript: togglePendingDelete('%s', %s);" % ( |
418 """ |
413 """ |
419 pending = req.session.data.get('pending_insert', ()) |
414 pending = req.session.data.get('pending_insert', ()) |
420 return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending |
415 return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending |
421 if eid is None or eid in (subj, obj)] |
416 if eid is None or eid in (subj, obj)] |
422 |
417 |
|
418 |
423 def get_pending_deletes(req, eid=None): |
419 def get_pending_deletes(req, eid=None): |
424 """shortcut to access req's pending_delete entry |
420 """shortcut to access req's pending_delete entry |
425 |
421 |
426 This is where are stored relations being removed while editing |
422 This is where are stored relations being removed while editing |
427 an entity. This used to be stored in a temporary cookie. |
423 an entity. This used to be stored in a temporary cookie. |
428 """ |
424 """ |
429 pending = req.session.data.get('pending_delete', ()) |
425 pending = req.session.data.get('pending_delete', ()) |
430 return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending |
426 return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending |
431 if eid is None or eid in (subj, obj)] |
427 if eid is None or eid in (subj, obj)] |
|
428 |
432 |
429 |
433 def parse_relations_descr(rdescr): |
430 def parse_relations_descr(rdescr): |
434 """parse a string describing some relations, in the form |
431 """parse a string describing some relations, in the form |
435 subjeids:rtype:objeids |
432 subjeids:rtype:objeids |
436 where subjeids and objeids are eids separeted by a underscore |
433 where subjeids and objeids are eids separeted by a underscore |
440 for rstr in rdescr: |
437 for rstr in rdescr: |
441 subjs, rtype, objs = rstr.split(':') |
438 subjs, rtype, objs = rstr.split(':') |
442 for subj in subjs.split('_'): |
439 for subj in subjs.split('_'): |
443 for obj in objs.split('_'): |
440 for obj in objs.split('_'): |
444 yield int(subj), rtype, int(obj) |
441 yield int(subj), rtype, int(obj) |
|
442 |
445 |
443 |
446 def delete_relations(req, rdefs): |
444 def delete_relations(req, rdefs): |
447 """delete relations from the repository""" |
445 """delete relations from the repository""" |
448 # FIXME convert to using the syntax subject:relation:eids |
446 # FIXME convert to using the syntax subject:relation:eids |
449 execute = req.execute |
447 execute = req.execute |
450 for subj, rtype, obj in parse_relations_descr(rdefs): |
448 for subj, rtype, obj in parse_relations_descr(rdefs): |
451 rql = 'DELETE X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype |
449 rql = 'DELETE X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype |
452 execute(rql, {'x': subj, 'y': obj}) |
450 execute(rql, {'x': subj, 'y': obj}) |
453 req.set_message(req._('relations deleted')) |
451 req.set_message(req._('relations deleted')) |
454 |
452 |
|
453 |
455 def insert_relations(req, rdefs): |
454 def insert_relations(req, rdefs): |
456 """insert relations into the repository""" |
455 """insert relations into the repository""" |
457 execute = req.execute |
456 execute = req.execute |
458 for subj, rtype, obj in parse_relations_descr(rdefs): |
457 for subj, rtype, obj in parse_relations_descr(rdefs): |
459 rql = 'SET X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype |
458 rql = 'SET X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype |
466 view = self._cw.vreg['views'].select('inline-creation', self._cw, |
465 view = self._cw.vreg['views'].select('inline-creation', self._cw, |
467 etype=ttype, rtype=rtype, role=role, |
466 etype=ttype, rtype=rtype, role=role, |
468 peid=peid, petype=petype) |
467 peid=peid, petype=petype) |
469 return self._call_view(view, i18nctx=i18nctx) |
468 return self._call_view(view, i18nctx=i18nctx) |
470 |
469 |
|
470 |
471 @ajaxfunc(output_type='json') |
471 @ajaxfunc(output_type='json') |
472 def validate_form(self, action, names, values): |
472 def validate_form(self, action, names, values): |
473 return self.validate_form(action, names, values) |
473 return self.validate_form(action, names, values) |
|
474 |
474 |
475 |
475 @ajaxfunc |
476 @ajaxfunc |
476 def cancel_edition(self, errorurl): |
477 def cancel_edition(self, errorurl): |
477 """cancelling edition from javascript |
478 """cancelling edition from javascript |
478 |
479 |
489 value = (int(eidfrom), rel, int(eidto)) |
490 value = (int(eidfrom), rel, int(eidto)) |
490 if value not in pendings: |
491 if value not in pendings: |
491 pendings.append(value) |
492 pendings.append(value) |
492 req.session.data[key] = pendings |
493 req.session.data[key] = pendings |
493 |
494 |
|
495 |
494 def _remove_pending(req, eidfrom, rel, eidto, kind): |
496 def _remove_pending(req, eidfrom, rel, eidto, kind): |
495 key = 'pending_%s' % kind |
497 key = 'pending_%s' % kind |
496 pendings = req.session.data[key] |
498 pendings = req.session.data[key] |
497 value = (int(eidfrom), rel, int(eidto)) |
499 value = (int(eidfrom), rel, int(eidto)) |
498 if value in pendings: |
500 if value in pendings: |
499 pendings.remove(value) |
501 pendings.remove(value) |
500 req.session.data[key] = pendings |
502 req.session.data[key] = pendings |
501 |
503 |
|
504 |
502 @ajaxfunc(output_type='json') |
505 @ajaxfunc(output_type='json') |
503 def remove_pending_insert(self, args): |
506 def remove_pending_insert(self, args): |
504 eidfrom, rel, eidto = args |
507 eidfrom, rel, eidto = args |
505 _remove_pending(self._cw, eidfrom, rel, eidto, 'insert') |
508 _remove_pending(self._cw, eidfrom, rel, eidto, 'insert') |
506 |
509 |
|
510 |
507 @ajaxfunc(output_type='json') |
511 @ajaxfunc(output_type='json') |
508 def add_pending_inserts(self, tripletlist): |
512 def add_pending_inserts(self, tripletlist): |
509 for eidfrom, rel, eidto in tripletlist: |
513 for eidfrom, rel, eidto in tripletlist: |
510 _add_pending(self._cw, eidfrom, rel, eidto, 'insert') |
514 _add_pending(self._cw, eidfrom, rel, eidto, 'insert') |
511 |
515 |
|
516 |
512 @ajaxfunc(output_type='json') |
517 @ajaxfunc(output_type='json') |
513 def remove_pending_delete(self, args): |
518 def remove_pending_delete(self, args): |
514 eidfrom, rel, eidto = args |
519 eidfrom, rel, eidto = args |
515 _remove_pending(self._cw, eidfrom, rel, eidto, 'delete') |
520 _remove_pending(self._cw, eidfrom, rel, eidto, 'delete') |
|
521 |
516 |
522 |
517 @ajaxfunc(output_type='json') |
523 @ajaxfunc(output_type='json') |
518 def add_pending_delete(self, args): |
524 def add_pending_delete(self, args): |
519 eidfrom, rel, eidto = args |
525 eidfrom, rel, eidto = args |
520 _add_pending(self._cw, eidfrom, rel, eidto, 'delete') |
526 _add_pending(self._cw, eidfrom, rel, eidto, 'delete') |
539 w(u'<ul class="list-unstyled">') |
544 w(u'<ul class="list-unstyled">') |
540 for viewparams in related: |
545 for viewparams in related: |
541 w(u'<li>%s<span id="span%s" class="%s">%s</span></li>' |
546 w(u'<li>%s<span id="span%s" class="%s">%s</span></li>' |
542 % (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) |
547 % (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) |
543 if not form.force_display and form.maxrelitems < len(related): |
548 if not form.force_display and form.maxrelitems < len(related): |
544 link = (u'<span>' |
549 link = (u'<span>[<a ' |
545 '[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]' |
550 'href="javascript: window.location.href+=\'&__force_display=1\'"' |
546 '</span>' % _('view all')) |
551 '>%s</a>]</span>' % _('view all')) |
547 w(u'<li>%s</li>' % link) |
552 w(u'<li>%s</li>' % link) |
548 w(u'</ul>') |
553 w(u'</ul>') |
549 w(u'</td>') |
554 w(u'</td>') |
550 w(u'</tr>') |
555 w(u'</tr>') |
551 pendings = list(field.restore_pending_inserts(form)) |
556 pendings = list(field.restore_pending_inserts(form)) |
617 else: |
622 else: |
618 haspermkwargs = {'toeid': entity.eid} |
623 haspermkwargs = {'toeid': entity.eid} |
619 if rschema.has_perm(form._cw, 'delete', **haspermkwargs): |
624 if rschema.has_perm(form._cw, 'delete', **haspermkwargs): |
620 toggleable_rel_link_func = toggleable_relation_link |
625 toggleable_rel_link_func = toggleable_relation_link |
621 else: |
626 else: |
622 toggleable_rel_link_func = lambda x, y, z: u'' |
627 def toggleable_rel_link_func(x, y, z): |
|
628 return u'' |
623 for row in range(rset.rowcount): |
629 for row in range(rset.rowcount): |
624 nodeid = relation_id(entity.eid, rschema, role, |
630 nodeid = relation_id(entity.eid, rschema, role, |
625 rset[row][0]) |
631 rset[row][0]) |
626 if nodeid in pending_deletes: |
632 if nodeid in pending_deletes: |
627 status, label = u'pendingDelete', '+' |
633 status, label = u'pendingDelete', '+' |
639 entity = form.edited_entity |
645 entity = form.edited_entity |
640 pending_inserts = set(get_pending_inserts(form._cw, form.edited_entity.eid)) |
646 pending_inserts = set(get_pending_inserts(form._cw, form.edited_entity.eid)) |
641 for pendingid in pending_inserts: |
647 for pendingid in pending_inserts: |
642 eidfrom, rtype, eidto = pendingid.split(':') |
648 eidfrom, rtype, eidto = pendingid.split(':') |
643 pendingid = 'id' + pendingid |
649 pendingid = 'id' + pendingid |
644 if int(eidfrom) == entity.eid: # subject |
650 if int(eidfrom) == entity.eid: # subject |
645 label = display_name(form._cw, rtype, 'subject', |
651 label = display_name(form._cw, rtype, 'subject', |
646 entity.cw_etype) |
652 entity.cw_etype) |
647 reid = eidto |
653 reid = eidto |
648 else: |
654 else: |
649 label = display_name(form._cw, rtype, 'object', |
655 label = display_name(form._cw, rtype, 'object', |
685 options += self._get_select_options(entity, rschema, role) |
691 options += self._get_select_options(entity, rschema, role) |
686 options += self._get_search_options(entity, rschema, role, targettypes) |
692 options += self._get_search_options(entity, rschema, role, targettypes) |
687 relname, role = self._cw.form.get('relation').rsplit('_', 1) |
693 relname, role = self._cw.form.get('relation').rsplit('_', 1) |
688 return u"""\ |
694 return u"""\ |
689 <div class="%s" id="%s"> |
695 <div class="%s" id="%s"> |
690 <select id="%s" onchange="javascript: addPendingInsert(this.options[this.selectedIndex], %s, %s, '%s');"> |
696 <select id="%s" |
|
697 onchange="javascript: addPendingInsert(this.options[this.selectedIndex], %s, %s, '%s');"> |
691 %s |
698 %s |
692 </select> |
699 </select> |
693 </div> |
700 </div> |
694 """ % (hidden and 'hidden' or '', divid, selectid, |
701 """ % (hidden and 'hidden' or '', divid, selectid, |
695 xml_escape(json_dumps(entity.eid)), is_cell and 'true' or 'null', relname, |
702 xml_escape(json_dumps(entity.eid)), is_cell and 'true' or 'null', |
696 '\n'.join(options)) |
703 relname, '\n'.join(options)) |
697 |
704 |
698 def _get_select_options(self, entity, rschema, role): |
705 def _get_select_options(self, entity, rschema, role): |
699 """add options to search among all entities of each possible type""" |
706 """add options to search among all entities of each possible type""" |
700 options = [] |
707 options = [] |
701 pending_inserts = get_pending_inserts(self._cw, entity.eid) |
708 pending_inserts = get_pending_inserts(self._cw, entity.eid) |
704 field = form.field_by_name(rschema, role, entity.e_schema) |
711 field = form.field_by_name(rschema, role, entity.e_schema) |
705 limit = self._cw.property_value('navigation.combobox-limit') |
712 limit = self._cw.property_value('navigation.combobox-limit') |
706 # NOTE: expect 'limit' arg on choices method of relation field |
713 # NOTE: expect 'limit' arg on choices method of relation field |
707 for eview, reid in field.vocabulary(form, limit=limit): |
714 for eview, reid in field.vocabulary(form, limit=limit): |
708 if reid is None: |
715 if reid is None: |
709 if eview: # skip blank value |
716 if eview: # skip blank value |
710 options.append('<option class="separator">-- %s --</option>' |
717 options.append('<option class="separator">-- %s --</option>' |
711 % xml_escape(eview)) |
718 % xml_escape(eview)) |
712 elif reid != ff.INTERNAL_FIELD_VALUE: |
719 elif reid != ff.INTERNAL_FIELD_VALUE: |
713 optionid = relation_id(entity.eid, rtype, role, reid) |
720 optionid = relation_id(entity.eid, rtype, role, reid) |
714 if optionid not in pending_inserts: |
721 if optionid not in pending_inserts: |
722 options = [] |
729 options = [] |
723 _ = self._cw._ |
730 _ = self._cw._ |
724 for eschema in targettypes: |
731 for eschema in targettypes: |
725 mode = '%s:%s:%s:%s' % (role, entity.eid, rschema.type, eschema) |
732 mode = '%s:%s:%s:%s' % (role, entity.eid, rschema.type, eschema) |
726 url = self._cw.build_url(entity.rest_path(), vid='search-associate', |
733 url = self._cw.build_url(entity.rest_path(), vid='search-associate', |
727 __mode=mode) |
734 __mode=mode) |
728 options.append((eschema.display_name(self._cw), |
735 options.append((eschema.display_name(self._cw), |
729 '<option value="%s">%s %s</option>' % ( |
736 '<option value="%s">%s %s</option>' % ( |
730 xml_escape(url), _('Search for'), eschema.display_name(self._cw)))) |
737 xml_escape(url), _('Search for'), eschema.display_name(self._cw)))) |
731 return [o for l, o in sorted(options)] |
738 return [o for l, o in sorted(options)] |
732 |
739 |
801 self.fieldsets_in_order = fsio |
808 self.fieldsets_in_order = fsio |
802 # add fields for relation whose target should have an inline form |
809 # add fields for relation whose target should have an inline form |
803 for formview in self.inlined_form_views(): |
810 for formview in self.inlined_form_views(): |
804 field = self._inlined_form_view_field(formview) |
811 field = self._inlined_form_view_field(formview) |
805 self.fields.append(field) |
812 self.fields.append(field) |
806 if not field.fieldset in fsio: |
813 if field.fieldset not in fsio: |
807 fsio.append(field.fieldset) |
814 fsio.append(field.fieldset) |
808 if self.formtype == 'main': |
815 if self.formtype == 'main': |
809 # add the generic relation field if necessary |
816 # add the generic relation field if necessary |
810 if entity.has_eid() and ( |
817 if entity.has_eid() and ( |
811 self.display_fields is None or |
818 self.display_fields is None or |
815 except f.FieldNotFound: |
822 except f.FieldNotFound: |
816 # no editable relation |
823 # no editable relation |
817 pass |
824 pass |
818 else: |
825 else: |
819 self.fields.append(field) |
826 self.fields.append(field) |
820 if not field.fieldset in fsio: |
827 if field.fieldset not in fsio: |
821 fsio.append(field.fieldset) |
828 fsio.append(field.fieldset) |
822 self.maxrelitems = self._cw.property_value('navigation.related-limit') |
829 self.maxrelitems = self._cw.property_value('navigation.related-limit') |
823 self.force_display = bool(self._cw.form.get('__force_display')) |
830 self.force_display = bool(self._cw.form.get('__force_display')) |
824 fnum = len(self.fields) |
831 fnum = len(self.fields) |
825 self.fields.sort(key=lambda f: f.order is None and fnum or f.order) |
832 self.fields.sort(key=lambda f: f.order is None and fnum or f.order) |
947 by default true if there is no related entity or if the relation has |
954 by default true if there is no related entity or if the relation has |
948 multiple cardinality and it is permitted to add the inlined object and |
955 multiple cardinality and it is permitted to add the inlined object and |
949 relation. |
956 relation. |
950 """ |
957 """ |
951 return (self.should_display_add_new_relation_link( |
958 return (self.should_display_add_new_relation_link( |
952 rschema, existing, card) and |
959 rschema, existing, card) and |
953 self.check_inlined_rdef_permissions( |
960 self.check_inlined_rdef_permissions( |
954 rschema, role, tschema, ttype)) |
961 rschema, role, tschema, ttype)) |
955 |
962 |
956 def check_inlined_rdef_permissions(self, rschema, role, tschema, ttype): |
963 def check_inlined_rdef_permissions(self, rschema, role, tschema, ttype): |
957 """return true if permissions are granted on the inlined object and |
964 """return true if permissions are granted on the inlined object and |
966 else: |
973 else: |
967 rdefkwargs = {'toeid': entity.eid} |
974 rdefkwargs = {'toeid': entity.eid} |
968 return rdef.has_perm(self._cw, 'add', **rdefkwargs) |
975 return rdef.has_perm(self._cw, 'add', **rdefkwargs) |
969 return rdef.may_have_permission('add', self._cw) |
976 return rdef.may_have_permission('add', self._cw) |
970 |
977 |
971 |
|
972 def should_hide_add_new_relation_link(self, rschema, card): |
978 def should_hide_add_new_relation_link(self, rschema, card): |
973 """return true if once an inlined creation form is added, the 'add new' |
979 """return true if once an inlined creation form is added, the 'add new' |
974 link should be hidden |
980 link should be hidden |
975 |
981 |
976 by default true if the relation has single cardinality |
982 by default true if the relation has single cardinality |
1007 # may be raised if user doesn't have the permission to add ttype entities (no checked |
1013 # may be raised if user doesn't have the permission to add ttype entities (no checked |
1008 # earlier) or if there is some custom selector on the view |
1014 # earlier) or if there is some custom selector on the view |
1009 pass |
1015 pass |
1010 |
1016 |
1011 |
1017 |
1012 ## default form ui configuration ############################################## |
1018 # default form ui configuration ############################################## |
1013 |
1019 |
1014 _AFS = uicfg.autoform_section |
1020 _AFS = uicfg.autoform_section |
1015 # use primary and not generated for eid since it has to be an hidden |
1021 # use primary and not generated for eid since it has to be an hidden |
1016 _AFS.tag_attribute(('*', 'eid'), 'main', 'hidden') |
1022 _AFS.tag_attribute(('*', 'eid'), 'main', 'hidden') |
1017 _AFS.tag_attribute(('*', 'eid'), 'muledit', 'attributes') |
1023 _AFS.tag_attribute(('*', 'eid'), 'muledit', 'attributes') |
1047 _AFFK.tag_attribute(('RQLExpression', 'expression'), |
1053 _AFFK.tag_attribute(('RQLExpression', 'expression'), |
1048 {'widget': fw.TextInput}) |
1054 {'widget': fw.TextInput}) |
1049 _AFFK.tag_subject_of(('TrInfo', 'wf_info_for', '*'), |
1055 _AFFK.tag_subject_of(('TrInfo', 'wf_info_for', '*'), |
1050 {'widget': fw.HiddenInput}) |
1056 {'widget': fw.HiddenInput}) |
1051 |
1057 |
|
1058 |
1052 def registration_callback(vreg): |
1059 def registration_callback(vreg): |
1053 global etype_relation_field |
1060 global etype_relation_field |
1054 |
1061 |
1055 def etype_relation_field(etype, rtype, role='subject'): |
1062 def etype_relation_field(etype, rtype, role='subject'): |
1056 try: |
1063 try: |