kill separate attribute client-side handling #473636 stable
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Mon, 19 Oct 2009 20:33:30 +0200
branchstable
changeset 3742 20f429eb5f46
parent 3741 3864c7dfddf0
child 3743 4b683fe21160
kill separate attribute client-side handling #473636
devtools/fill.py
web/data/cubicweb.edition.js
web/views/basecontrollers.py
web/views/editforms.py
--- a/devtools/fill.py	Mon Oct 19 20:26:22 2009 +0200
+++ b/devtools/fill.py	Mon Oct 19 20:33:30 2009 +0200
@@ -308,13 +308,16 @@
 
 
 
-def select(constraints, cursor, selectvar='O'):
+def select(constraints, cursor, selectvar='O', objtype=None):
     """returns list of eids matching <constraints>
 
     <selectvar> should be either 'O' or 'S' to match schema definitions
     """
     try:
-        rset = cursor.execute('Any %s WHERE %s' % (selectvar, constraints))
+        rql = 'Any %s WHERE %s' % (selectvar, constraints)
+        if objtype:
+            rql += ', %s is %s' % (selectvar, objtype)
+        rset = cursor.execute(rql)
     except:
         print "could restrict eid_list with given constraints (%r)" % constraints
         return []
@@ -335,6 +338,14 @@
     gen = RelationsQueriesGenerator(schema, cursor, existingrels)
     return gen.compute_queries(edict, ignored_relations)
 
+def composite_relation(rschema):
+    for obj in rschema.objects():
+        if obj.objrproperty(rschema, 'composite') == 'subject':
+            return True
+    for obj in rschema.subjects():
+        if obj.subjrproperty(rschema, 'composite') == 'object':
+            return True
+    return False
 
 class RelationsQueriesGenerator(object):
     rql_tmpl = 'SET S %s O WHERE S eid %%(subjeid)s, O eid %%(objeid)s'
@@ -346,8 +357,9 @@
     def compute_queries(self, edict, ignored_relations):
         queries = []
         #   1/ skip final relations and explictly ignored relations
-        rels = [rschema for rschema in self.schema.relations()
-                if not (rschema.final or rschema in ignored_relations)]
+        rels = sorted([rschema for rschema in self.schema.relations()
+                       if not (rschema.final or rschema in ignored_relations)],
+                      key=lambda x:not composite_relation(x))
         # for each relation
         #   2/ take each possible couple (subj, obj)
         #   3/ analyze cardinality of relation
@@ -355,6 +367,7 @@
         #      b/ else insert N relations where N is the mininum
         #         of 20 and the number of existing targetable entities
         for rschema in rels:
+            print rschema
             sym = set()
             sedict = deepcopy(edict)
             oedict = deepcopy(edict)
@@ -366,7 +379,7 @@
                     continue
                 subjcard, objcard = rschema.rproperty(subj, obj, 'cardinality')
                 # process mandatory relations first
-                if subjcard in '1+' or objcard in '1+':
+                if subjcard in '1+' or objcard in '1+' or composite_relation(rschema):
                     queries += self.make_relation_queries(sedict, oedict,
                                                           rschema, subj, obj)
                 else:
@@ -399,10 +412,9 @@
             # restrict object eids if possible
             # XXX the attempt to restrict below in completely wrong
             # disabling it for now
-            objeids = select(restrictions, self.cursor)
+            objeids = select(restrictions, self.cursor, objtype=obj)
         else:
             objeids = oedict.get(obj, frozenset())
-##         objeids = oedict.get(obj, frozenset())
         if subjcard in '?1' or objcard in '?1':
             for subjeid, objeid in used:
                 if subjcard in '?1' and subjeid in subjeids:
@@ -461,8 +473,8 @@
 
 def check_card_satisfied(card, remaining, subj, rschema, obj):
     if card in '1+' and remaining:
-        raise Exception("can't satisfy cardinality %s for relation %s %s %s"
-                        % (card, subj, rschema, obj))
+        print "can't satisfy cardinality %s for relation %s %s %s" % (card, subj, rschema, obj)
+        
 
 def choose_eid(values, avoid):
     values = tuple(values)
--- a/web/data/cubicweb.edition.js	Mon Oct 19 20:26:22 2009 +0200
+++ b/web/data/cubicweb.edition.js	Mon Oct 19 20:33:30 2009 +0200
@@ -465,44 +465,6 @@
  * @param default_value : value if the field is empty
  * @param lzone : html fragment (string) for a clic-zone triggering actual edition
  */
-function inlineValidateAttributeForm(rtype, eid, divid, reload, default_value) {
-    try {
-	var form = getNode(divid+'-form');
-	if (typeof FCKeditorAPI != "undefined") {
-	    for ( var name in FCKeditorAPI.__Instances ) {
-		var oEditor = FCKeditorAPI.__Instances[name] ;
-		if ( oEditor.GetParentForm() == form ) {
-		    oEditor.UpdateLinkedField();
-		}
-	    }
-	}
-	var zipped = formContents(form);
-	var d = asyncRemoteExec('edit_field', 'apply', zipped[0], zipped[1],
-                                rtype, eid, default_value);
-    } catch (ex) {
-	log('got exception', ex);
-	return false;
-    }
-    d.addCallback(function (result, req) {
-        if (handleFormValidationResponse(divid+'-form', noop, noop, result)) {
-          if (reload) {
-	    document.location.href = result[1].split('?')[0];
-	  } else {
-	    var fieldview = getNode('value-' + divid);
-	    // XXX using innerHTML is very fragile and won't work if
-	    // we mix XHTML and HTML
-	    fieldview.innerHTML = result[2];
-	    // switch inline form off only if no error
-	    if (result[0]) {
-		// hide global error messages
-		hideInlineEdit(eid, rtype, divid);
-	    }
-	  }
-        }
-	return false;
-    });
-    return false;
-}
 
 function inlineValidateRelationForm(rtype, role, eid, divid, reload, vid,
                                     default_value, lzone) {
@@ -518,13 +480,12 @@
     d.addCallback(function (result, req) {
 	if (handleFormValidationResponse(divid+'-form', noop, noop, result)) {
           if (reload) {
-            document.location.href = result[1].split('?')[0];
+            document.location.reload();
           } else {
-            var d = asyncRemoteExec('reledit_form', eid, rtype, role, default_value, lzone);
-            d.addCallback(function (result) {
-              // XXX brittle ... replace with loadxhtml
-              jQuery('#'+divid+'-reledit').replaceWith(result);
-            });
+              var args = {fname: 'reledit_form', rtype: rtype, role: role, eid: eid, divid: divid,
+                          reload: reload, vid: vid, default_value: default_value, landing_zone: lzone};
+            log('DONE');
+              jQuery('#'+divid+'-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
           }
 	}
         return false;
--- a/web/views/basecontrollers.py	Mon Oct 19 20:26:22 2009 +0200
+++ b/web/views/basecontrollers.py	Mon Oct 19 20:33:30 2009 +0200
@@ -397,26 +397,15 @@
         self.req.form = self._rebuild_posted_form(names, values, action)
         return _validate_form(self.req, self.vreg)
 
-    @jsonize
-    def js_edit_field(self, action, names, values, rtype, eid, default):
-        success, args, _ = self.validate_form(action, names, values)
-        if success:
-            # Any X,N where we don't seem to use N is an optimisation
-            # printable_value won't need to query N again
-            rset = self.req.execute('Any X,N WHERE X eid %%(x)s, X %s N' % rtype,
-                                    {'x': eid}, 'x')
-            entity = rset.get_entity(0, 0)
-            value = entity.printable_value(rtype) or default
-            return (success, args, value)
-        else:
-            return (success, args, None)
-
-    @jsonize
-    def js_reledit_form(self, eid, rtype, role, default, lzone):
-        """XXX we should get rid of this and use loadxhtml"""
-        entity = self.req.entity_from_eid(eid)
-        return entity.view('reledit', rtype=rtype, role=role,
-                           default=default, landing_zone=lzone)
+    @xhtmlize
+    def js_reledit_form(self):
+        args = dict((x,self.req.form[x])
+                    for x in frozenset(('rtype', 'role', 'reload', 'landing_zone')))
+        entity = self.req.entity_from_eid(int(self.req.form['eid']))
+        # note: default is reserved in js land
+        args['default'] = self.req.form['default_value']
+        args['reload'] = simplejson.loads(args['reload'])
+        return entity.view('reledit', **args)
 
     @jsonize
     def js_i18n(self, msgids):
--- a/web/views/editforms.py	Mon Oct 19 20:26:22 2009 +0200
+++ b/web/views/editforms.py	Mon Oct 19 20:33:30 2009 +0200
@@ -112,6 +112,9 @@
     attrcategories = ('primary', 'secondary', 'metadata')
 
     _onclick = u"showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
+    _onsubmit = ("return inlineValidateRelationForm('%(rtype)s', '%(role)s', '%(eid)s', "
+                 "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');")
+    _cancelclick = "hideInlineEdit(%s,\'%s\',\'%s\')"
     _defaultlandingzone = (u'<img title="%(msg)s" '
                            'src="data/accessories-text-editor.png" '
                            'alt="%(msg)s"/>')
@@ -134,16 +137,16 @@
             display_help=False, display_fields=[(rtype, role)], table_class='',
             button_bar_class='buttonbar', display_progress_div=False)
 
-    def _build_form(self, entity, rtype, role, formid, default, onsubmit, reload,
+    def _build_form(self, entity, rtype, role, formid, default, reload,
                   extradata=None, **formargs):
-        divid = 'd%s' % make_uid('%s-%s' % (rtype, entity.eid))
+        divid = '%s-%s-%s' % (entity.eid, rtype, role)
         event_data = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype,
-                      'reload' : dumps(reload), 'default' : default}
+                      'reload' : dumps(reload), 'default' : default, 'role' : role, 'vid' : u'',
+                      'lzone' : self._build_landing_zone(None)}
         if extradata:
             event_data.update(extradata)
-        onsubmit %= event_data
-        cancelclick = "hideInlineEdit(%s,\'%s\',\'%s\')" % (entity.eid, rtype,
-                                                            divid)
+        onsubmit = self._onsubmit % event_data
+        cancelclick = self._cancelclick % (entity.eid, rtype, divid)
         form = self.vreg['forms'].select(
             formid, self.req, entity=entity, domid='%s-form' % divid,
             cssstyle='display: none', onsubmit=onsubmit, action='#',
@@ -162,7 +165,7 @@
                   ):
         """display field to edit entity's `rtype` relation on click"""
         assert rtype
-        assert role in ('subject', 'object')
+        assert role in ('subject', 'object'), '%s is not an acceptable role value' % role
         if default is None:
             default = xml_escape(self.req._('<no value>'))
         entity = self.entity(row, col)
@@ -170,17 +173,14 @@
         lzone = self._build_landing_zone(landing_zone)
         # compute value, checking perms, build form
         if rschema.final:
-            onsubmit = ("return inlineValidateAttributeForm('%(rtype)s', '%(eid)s', '%(divid)s', "
-                        "%(reload)s, '%(default)s');")
-            form = self._build_form(
-                entity, rtype, role, 'edition', default, onsubmit, reload,
-                attrcategories=self.attrcategories)
+            form = self._build_form(entity, rtype, role, 'edition', default, reload,
+                                    attrcategories=self.attrcategories)
             if not self.should_edit_attribute(entity, rschema, role, form):
                 self.w(entity.printable_value(rtype))
                 return
             value = entity.printable_value(rtype) or default
-            self.attribute_form(lzone, value, form,
-                                 self._build_renderer(entity, rtype, role))
+            self.relation_form(lzone, value, form,
+                               self._build_renderer(entity, rtype, role))
         else:
             if rvid is None:
                 rvid = self._compute_best_vid(entity.e_schema, rschema, role)
@@ -193,11 +193,8 @@
                 if rset:
                     self.w(value)
                 return
-            onsubmit = ("return inlineValidateRelationForm('%(rtype)s', '%(role)s', '%(eid)s', "
-                        "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');")
-            form = self._build_form(
-                entity, rtype, role, 'base', default, onsubmit, reload,
-                dict(vid=rvid, role=role, lzone=lzone))
+            form = self._build_form(entity, rtype, role, 'base', default, reload,
+                                    dict(vid=rvid, lzone=lzone))
             field = guess_field(entity.e_schema, entity.schema.rschema(rtype), role)
             form.append_field(field)
             self.relation_form(lzone, value, form,
@@ -227,26 +224,6 @@
             return False
         return True
 
-    def attribute_form(self, lzone, value, form, renderer):
-        """div (class=field)
-              +-xxx div
-              |  +-xxx div (class=editableField)
-              |  |  +-landing zone
-              |  +-value-xxx div
-              |     +-value
-              +-form-xxx div
-        """
-        w = self.w
-        w(u'<div class="field">')
-        w(u'<div id="%s" style="display: inline">' % form.event_data['divid'])
-        w(tags.div(lzone, klass='editableField',
-                   onclick=self._onclick % form.event_data))
-        w(u'<div id="value-%s" style="display: inline">%s</div>' %
-               (form.event_data['divid'], value))
-        w(u'</div>')
-        w(form.form_render(renderer=renderer))
-        w(u'</div>')
-
     def relation_form(self, lzone, value, form, renderer):
         """xxx-reledit div (class=field)
               +-xxx div (class="editableField")