# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1276182103 -7200
#      Thu Jun 10 17:01:43 2010 +0200
# Node ID c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d
# Parent  d32c5dffe4b182fd15f3f267aeb67383f15b1514
use standard form validation instead of custom json controller's methods, support to apply the commment section component on entity not yet created (will be created with the comment)

diff --git a/__pkginfo__.py b/__pkginfo__.py
--- a/__pkginfo__.py
+++ b/__pkginfo__.py
@@ -23,7 +23,7 @@
            'Programming Language :: JavaScript',
 ]
 
-__depends__ = {'cubicweb': '>= 3.6.0'}
+__depends__ = {'cubicweb': '>= 3.9.0'}
 
 # package ###
 
diff --git a/data/cubes.comment.js b/data/cubes.comment.js
--- a/data/cubes.comment.js
+++ b/data/cubes.comment.js
@@ -4,58 +4,40 @@
  *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
  */
 
-CubicWeb.require('python.js');
-CubicWeb.require('htmlhelpers.js');
-CubicWeb.require('ajax.js');
-
-function _getText(textarea) {
-    if (typeof(FCKeditor) != 'undefined') {
-        var fck = FCKeditorAPI.GetInstance(textarea.id);
-        if (fck) {
-            return fck.GetHTML();
-        }
-    }
-    return textarea.value;
-}
-
 /* this function is called on inlined-comment editions
  * It calls the [add|eid]_comment method on the jsoncontroller and [re]load
  * only the view for the added or edited comment
  */
-function processComment(eid, funcname, creation) {
+function processComment(eid, cancel, creation) {
     var divId = 'comment' + eid + 'Slot'
     var divNode = jQuery('#'+divId);
     var textarea = divNode.find('textarea')[0];
-    if (funcname) {
-        var format = 'text/html'; // no select widget if fckeditor is used
-        var select = divNode.find('select')[0];
-        if (select) {
-            format = firstSelected(select);
-        }
-        d = asyncRemoteExec(funcname, eid, _getText(textarea), format);
-        d.addCallback(function (neweid) {
-	    if (creation) {
-		var commentNode = jQuery('#comment'+ eid);
-		var ul = null;
-		if (!commentNode.length) {
-		    // we are adding a comment to the top level entity
-		    commentNode = jQuery('#commentsectionComponent');
-		    klass = 'comment';
-		} else {
-		    klass = 'section';
-		}
-		ul = commentNode.find('> ul:first');
-		if (!ul.length) {
-		    ul = jQuery(UL({'class': klass}));
-		    commentNode.append(ul);
-		}
-		ul.append(LI({'id': 'comment'+ neweid, 'class': 'comment'},
-			     DIV({'id': 'comment'+ neweid + 'Div'})));
-		divNode.remove();
-		eid = neweid;
-	    }
-	    replacePageChunk('comment' + eid + 'Div', rql_for_eid(eid), 'treeitem');
-        });
+    if (!cancel) {
+	validateForm('commentForm' + eid, null,
+		     function(result, formid, cbargs) {
+			 var neweid = result[2].eid;
+			 if (creation) {
+			     var commentNode = $('#comment'+ eid);
+			     var ul = null;
+			     if (!commentNode.length) {
+				 // we are adding a comment to the top level entity
+				 commentNode = $('#commentsectionComponent');
+				 klass = 'comment';
+			     } else {
+				 klass = 'section';
+			     }
+			     ul = commentNode.find('> ul:first');
+			     if (!ul.length) {
+				 ul = jQuery(UL({'class': klass}));
+				 commentNode.append(ul);
+			     }
+			     ul.append(LI({'id': 'comment'+ neweid, 'class': 'comment'},
+					  DIV({'id': 'comment'+ neweid + 'Div'})));
+			     divNode.remove();
+			 }
+			 var form = ajaxFuncArgs('render', null, 'views', 'treeitem', neweid);
+			 $('#comment' + neweid + 'Div').loadxhtml('json', form, null, null, true);
+		     });
     } else {
 	// comment cancelled, close div holding the form
         divNode.remove();
@@ -71,6 +53,3 @@
     $('html, body').animate({scrollTop:0}, 'fast');
     return false;
 }
-
-CubicWeb.provide('comment.js');
-
diff --git a/debian/control b/debian/control
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,7 @@
 
 Package: cubicweb-comment
 Architecture: all
-Depends: cubicweb-common (>= 3.6.0)
+Depends: cubicweb-common (>= 3.9.0)
 Description: comment component for the CubicWeb framework
  This CubicWeb component provides threadable comments.
  .
diff --git a/test/unittest_comment.py b/test/unittest_comment.py
--- a/test/unittest_comment.py
+++ b/test/unittest_comment.py
@@ -139,26 +139,6 @@
 
 ''')
 
-class CommentJsonControllerExtensionsTC(CubicWebTC):
-
-    def setup_database(self):
-        self.john = self.create_user(u'John')
-
-    def test_add_and_edit_comment(self):
-        # add comment
-        self.remote_call('add_comment', self.john.eid, u'yo', u'text/plain')
-        comment = self.entity('Any C,CT,F WHERE C content CT, C content_format F, '
-                              'C comments P, P eid %s' % self.john.eid)
-        self.assertEquals(comment.content, u'yo')
-        self.assertEquals(comment.content_format, u'text/plain')
-        # edit comment
-        self.remote_call('edit_comment', comment.eid, u'yipee', u'text/plain')
-        comment2 = self.entity('Any C,CT,F WHERE C content CT, C content_format F, '
-                               'C comments P, P eid %s' % self.john.eid)
-        self.assertEquals(comment.eid, comment2.eid)
-        self.assertEquals(comment2.content, u'yipee')
-        self.assertEquals(comment2.content_format, u'text/plain')
-
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
diff --git a/views.py b/views.py
--- a/views.py
+++ b/views.py
@@ -15,7 +15,9 @@
 from cubicweb.web import dumps
 
 from cubicweb.selectors import (implements, has_permission, authenticated_user,
-                                score_entity, relation_possible, one_line_rset)
+                                score_entity, relation_possible, one_line_rset,
+                                match_kwargs, match_form_params,
+                                partial_relation_possible, traced_selection)
 from cubicweb.view import EntityView
 from cubicweb.uilib import rql_for_eid, cut, safe_cut
 from cubicweb.mixins import TreeViewMixIn
@@ -193,15 +195,14 @@
 
 # comment forms ################################################################
 
-class InlineEditCommentForm(form.FormViewMixIn, EntityView):
+class InlineEditCommentFormView(form.FormViewMixIn, EntityView):
     __regid__ = 'editcommentform'
     __select__ = implements('Comment')
 
-    jsfunc = "processComment(%s, '%s', false)"
-    jsonmeth = 'edit_comment'
+    jsfunc = "processComment(%s, %s, false)"
 
-    def cell_call(self, row, col):
-        self.comment_form(self.cw_rset.get_entity(row, col))
+    def entity_call(self, entity):
+        self.comment_form(entity)
 
     def propose_to_login(self):
         self.w(u'<div class="warning">%s ' % self._cw._('You are not authenticated.'))
@@ -212,7 +213,7 @@
         self.w(u'</div>')
 
     def comment_form(self, commented, newcomment=None):
-        self._cw.add_js('cubes.comment.js')
+        self._cw.add_js(('cubicweb.edition.js', 'cubes.comment.js'))
         if newcomment is None:
             newcomment = commented
         if self._cw.cnx.anonymous_connection:
@@ -220,28 +221,53 @@
         # hack to avoid tabindex conflicts caused by Ajax requests
         self._cw.next_tabindex = count(20).next
         jseid = dumps(commented.eid)
-        cancel_action = self.jsfunc % (jseid, '')
-        buttons = [fw.Button(onclick=self.jsfunc % (jseid, self.jsonmeth)),
+        buttons = [fw.Button(onclick=self.jsfunc % (jseid, 'false')),
                    fw.Button(stdmsgs.BUTTON_CANCEL,
-                             onclick=cancel_action)]
-        form = self._cw.vreg['forms'].select('edition', self._cw,
-                                             entity=newcomment,
-                                             form_buttons=buttons)
+                             onclick=self.jsfunc % (jseid, 'true'))]
+        fvreg = self._cw.vreg['forms']
+        if newcomment is not None and not commented.has_eid():
+            form = fvreg.select('composite', self._cw, form_buttons=buttons,
+                                domid='commentForm%s' % commented.eid,
+                                form_renderer_id='default')
+            form.add_subform(fvreg.select('edition', self._cw, entity=commented,
+                                          mainform=False))
+            cform = fvreg.select('edition', self._cw, entity=newcomment,
+                                          mainform=False)
+            form.add_subform(cform)
+        else:
+            form = fvreg.select('edition', self._cw, entity=newcomment,
+                                domid='commentForm%s' % commented.eid,
+                                form_buttons=buttons)
+            cform = form
+        if newcomment is not None:
+            cform.append_field(cform.field_by_name('comments', 'subject',
+                                                eschema=newcomment.e_schema))
+            formvalues = {'comments': commented.eid}
+        else:
+            formvalues = {}
         self.w(u'<div id="comment%sSlot">%s</div>' % (
-            commented.eid, form.render(main_form_title=u'',
+            commented.eid, form.render(formvalues={'comments': commented.eid},
+                                       main_form_title=u'',
                                        display_label=False,
                                        display_relations_form=False)))
 
 
-class InlineAddCommentForm(InlineEditCommentForm):
+class InlineAddCommentFormView(InlineEditCommentFormView):
     __regid__ = 'addcommentform'
-    __select__ = relation_possible('comments', 'object', 'Comment', 'add')
+    __select__ = (relation_possible('comments', 'object', 'Comment', 'add')
+                  | match_form_params('etype'))
+
+    jsfunc = "processComment(%s, %s, true)"
 
-    jsfunc = "processComment(%s, '%s', true)"
-    jsonmeth = 'add_comment'
+    def call(self, **kwargs):
+        if self.cw_rset is None:
+            entity = self._cw.vreg['etypes'].etype_class(self._cw.form['etype'])(self._cw)
+            entity.eid = self._cw.varmaker.next()
+            self.entity_call(entity)
+        else:
+            super(InlineAddCommentFormView, self).call(**kwargs)
 
-    def cell_call(self, row, col):
-        commented = self.cw_rset.get_entity(row, col)
+    def entity_call(self, commented):
         newcomment = self._cw.vreg['etypes'].etype_class('Comment')(self._cw)
         newcomment.eid = self._cw.varmaker.next()
         self.comment_form(commented, newcomment)
@@ -254,40 +280,42 @@
     related to an object
     """
     __regid__ = 'commentsection'
-    __select__ = (component.EntityVComponent.__select__
+    __select__ = ((component.EntityVComponent.__select__ | match_kwargs('entity'))
                   & relation_possible('comments', 'object', 'Comment'))
 
     context = 'navcontentbottom'
 
-    def cell_call(self, row, col, view=None):
+    def entity_call(self, entity, view=None):
         req = self._cw
         req.add_js( ('cubicweb.ajax.js', 'cubes.comment.js') )
-        eid = self.cw_rset[row][col]
+        eid = entity.eid
         self.w(u'<div id="%s" class="%s" cubicweb:rooteid="%s">' % (
             self.div_id(), self.div_class(), eid))
-        rql = u'Any C,CD,CC,CCF,U,UL,US,UF ORDERBY CD WHERE C is Comment, '\
-              'C comments X, C creation_date CD, C content CC, C content_format CCF, ' \
-              'C created_by U?, U login UL, U firstname UF, U surname US, X eid %(x)s'
-        rset = req.execute(rql, {'x': eid}, 'x')
-        if rset.rowcount:
-            self.w(u'<h4>%s</h4>' % (req._('Comment_plural')))
-        if rset.rowcount:
-            self.w(u'<ul class="comment">')
-            for i in xrange(rset.rowcount):
-                self.wview('tree', rset, row=i)
-            self.w(u'</ul>')
+        if entity.has_eid():
+            rql = u'Any C,CD,CC,CCF,U,UL,US,UF ORDERBY CD WHERE C is Comment, '\
+                  'C comments X, C creation_date CD, C content CC, C content_format CCF, ' \
+                  'C created_by U?, U login UL, U firstname UF, U surname US, X eid %(x)s'
+            rset = req.execute(rql, {'x': eid})
+            if rset.rowcount:
+                self.w(u'<h4>%s</h4>' % (req._('Comment_plural')))
+                self.w(u'<ul class="comment">')
+                for i in xrange(rset.rowcount):
+                    self.wview('tree', rset, row=i)
+                self.w(u'</ul>')
         self.w(u'</div>')
-        addcomment = self._cw.vreg['actions'].select_or_none('reply_comment', req,
-                                                        rset=self.cw_rset,
-                                                        row=row, col=col)
+        addcomment = self._cw.vreg['actions'].select_or_none(
+            'reply_comment', req, entity=entity,
+            rset=entity.cw_rset, row=entity.cw_row, col=entity.cw_col)
         if addcomment is not None:
             self.w(u'<div id="comment%sHolder"></div>' % eid)
-            url = req.build_ajax_replace_url(
-                'comment%sHolder' % eid, rql_for_eid(eid), 'addcommentform')
+            params = self.cw_extra_kwargs
+            if entity.has_eid():
+                params['eid'] = eid
+            else:
+                params['etype'] = entity.__regid__
+            url = req.ajax_replace_url(
+                'comment%sHolder' % eid, vid='addcommentform', **params)
             self.w(u' (<a href="%s">%s</a>)' % (url, req._(addcomment.title)))
-            # XXX still necessary?
-            #if req.use_fckeditor() and req.property_value('ui.default-text-format') == 'text/html':
-            #    req.fckeditor_config()
 
 
 class UserLatestCommentsSection(component.EntityVComponent):
@@ -341,7 +369,9 @@
 class AddCommentAction(LinkToEntityAction):
     """add comment is like reply for everything but Comment"""
     __regid__ = 'reply_comment'
-    __select__ = LinkToEntityAction.__select__ & ~implements('Comment')
+    __select__ = ((LinkToEntityAction.__select__
+                   | (match_kwargs('entity') & partial_relation_possible(action='add', strict=True)))
+                   & ~implements('Comment'))
 
     rtype = 'comments'
     role = 'object'
@@ -374,20 +404,3 @@
 
     def url(self):
         return self._cw.build_url(rql=self.cw_rset.printable_rql(), vid='deleteconf')
-
-
-# JSONController extensions through monkey-patching ############################
-
-@monkeypatch(basecontrollers.JSonController)
-@basecontrollers.jsonize
-def js_add_comment(self, commented, text, format):
-    return self._cw.execute('INSERT Comment C: C comments X, C content %(text)s, '
-                            'C content_format %(format)s  WHERE X eid %(x)s',
-                            {'format' : format, 'text' : text, 'x' : commented}, 'x')[0][0]
-
-@monkeypatch(basecontrollers.JSonController)
-@basecontrollers.jsonize
-def js_edit_comment(self, comment, text, format):
-    self._cw.execute('SET C content %(text)s, C content_format %(format)s '
-                     'WHERE C eid %(x)s',
-                     {'format' : format, 'text' : text, 'x' : comment}, 'x')