[forms] don't display 'remove' link of inlined form for the first entity related using a '+' cardinality to its parent entity
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 08 Apr 2015 09:27:26 +0200
changeset 10519 0019b7888dd7
parent 10480 770b58f99e66
child 10520 d477e6447582
[forms] don't display 'remove' link of inlined form for the first entity related using a '+' cardinality to its parent entity Closes #5227394
web/test/unittest_views_forms.py
web/views/autoform.py
--- a/web/test/unittest_views_forms.py	Thu Jul 02 09:20:02 2015 +0200
+++ b/web/test/unittest_views_forms.py	Wed Apr 08 09:27:26 2015 +0200
@@ -16,7 +16,10 @@
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 
+from logilab.common import tempattr, attrdict
+
 from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.web.views.autoform import InlinedFormField
 
 class InlinedFormTC(CubicWebTC):
 
@@ -39,8 +42,33 @@
                 petype='Salesterm')
             self.assertEqual(formview.form.linked_to, {})
 
+    def test_remove_js_depending_on_cardinality(self):
+        with self.admin_access.web_request() as req:
+            formview = req.vreg['views'].select(
+                'inline-creation', req,
+                etype='File', rtype='described_by_test', role='subject',
+                peid='A',
+                petype='Salesterm')
+            # cardinality is 1, can't remove
+            self.assertIsNone(formview._get_removejs())
+            rdef = self.schema['Salesterm'].rdef('described_by_test')
+            with tempattr(rdef, 'cardinality', '?*'):
+                self.assertTrue(formview._get_removejs())
+            with tempattr(rdef, 'cardinality', '+*'):
+                # formview has no parent info (pform). This is what happens
+                # when an inline form is requested through AJAX.
+                self.assertTrue(formview._get_removejs())
+                fakeview = attrdict(dict(rtype='described_by_test', role='subject'))
+                # formview is first, can't be removed
+                formview.pform = attrdict(fields=[InlinedFormField(view=formview),
+                                                  InlinedFormField(view=fakeview)])
+                self.assertIsNone(formview._get_removejs())
+                # formview isn't first, can be removed
+                formview.pform = attrdict(fields=[InlinedFormField(view=fakeview),
+                                                  InlinedFormField(view=formview)])
+                self.assertTrue(formview._get_removejs())
+
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
-
--- a/web/views/autoform.py	Thu Jul 02 09:20:02 2015 +0200
+++ b/web/views/autoform.py	Wed Apr 08 09:27:26 2015 +0200
@@ -214,6 +214,12 @@
         return self.cw_rset.get_entity(self.cw_row, self.cw_col)
 
     @property
+    def petype(self):
+        assert isinstance(self.peid, int)
+        pentity = self._cw.entity_from_eid(self.peid)
+        return pentity.e_schema.type
+
+    @property
     @cached
     def form(self):
         entity = self._entity()
@@ -249,12 +255,25 @@
         creation form.
         """
         entity = self._entity()
-        if isinstance(self.peid, int):
-            pentity = self._cw.entity_from_eid(self.peid)
-            petype = pentity.e_schema.type
-            rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), petype)
-            card= rdef.role_cardinality(self.role)
-            if card == '1': # don't display remove link
+        rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), self.petype)
+        card = rdef.role_cardinality(self.role)
+        if card == '1': # don't display remove link
+            return None
+        # if cardinality is 1..n (+), dont display link to remove an inlined form for the first form
+        # allowing to edit the relation. To detect so:
+        #
+        # * if parent form (pform) is None, we're generated through an ajax call and so we know this
+        #   is not the first form
+        #
+        # * if parent form is not None, look for previous InlinedFormField in the parent's form
+        #   fields
+        if card == '+' and self.pform is not None:
+            # retrieve all field'views handling this relation and return None if we're the first of
+            # them
+            first_view = next(iter((f.view for f in self.pform.fields
+                                    if isinstance(f, InlinedFormField)
+                                    and f.view.rtype == self.rtype and f.view.role == self.role)))
+            if self == first_view:
                 return None
         return self.removejs and self.removejs % (
             self.peid, self.rtype, entity.eid)
@@ -314,7 +333,7 @@
     def removejs(self):
         entity = self._entity()
         rdef = entity.e_schema.rdef(self.rtype, neg_role(self.role), self.petype)
-        card= rdef.role_cardinality(self.role)
+        card = rdef.role_cardinality(self.role)
         # when one is adding an inline entity for a relation of a single card,
         # the 'add a new xxx' link disappears. If the user then cancel the addition,
         # we have to make this link appears back. This is done by giving add new link