diff --git a/__pkginfo__.py b/__pkginfo__.py index d32c5dffe4b182fd15f3f267aeb67383f15b1514_X19wa2dpbmZvX18ucHk=..c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d_X19wa2dpbmZvX18ucHk= 100644 --- 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 index d32c5dffe4b182fd15f3f267aeb67383f15b1514_ZGF0YS9jdWJlcy5jb21tZW50Lmpz..c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d_ZGF0YS9jdWJlcy5jb21tZW50Lmpz 100644 --- a/data/cubes.comment.js +++ b/data/cubes.comment.js @@ -4,21 +4,7 @@ * :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 */ @@ -21,8 +7,8 @@ /* 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]; @@ -26,36 +12,32 @@ 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 index d32c5dffe4b182fd15f3f267aeb67383f15b1514_ZGViaWFuL2NvbnRyb2w=..c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d_ZGViaWFuL2NvbnRyb2w= 100644 --- 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 index d32c5dffe4b182fd15f3f267aeb67383f15b1514_dGVzdC91bml0dGVzdF9jb21tZW50LnB5..c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d_dGVzdC91bml0dGVzdF9jb21tZW50LnB5 100644 --- 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 index d32c5dffe4b182fd15f3f267aeb67383f15b1514_dmlld3MucHk=..c6e6d5adc287a3996fa5fd47e5bc88ba29c6257d_dmlld3MucHk= 100644 --- 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,7 +195,7 @@ # comment forms ################################################################ -class InlineEditCommentForm(form.FormViewMixIn, EntityView): +class InlineEditCommentFormView(form.FormViewMixIn, EntityView): __regid__ = 'editcommentform' __select__ = implements('Comment') @@ -197,6 +199,5 @@ __regid__ = 'editcommentform' __select__ = implements('Comment') - jsfunc = "processComment(%s, '%s', false)" - jsonmeth = 'edit_comment' + jsfunc = "processComment(%s, %s, false)" @@ -202,6 +203,6 @@ - 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,6 +221,5 @@ # 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, @@ -225,6 +225,24 @@ 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>' % ( @@ -230,6 +248,7 @@ 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))) @@ -232,6 +251,6 @@ display_label=False, display_relations_form=False))) -class InlineAddCommentForm(InlineEditCommentForm): +class InlineAddCommentFormView(InlineEditCommentFormView): __regid__ = 'addcommentform' @@ -237,3 +256,6 @@ __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)" @@ -239,4 +261,9 @@ - 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) @@ -242,6 +269,5 @@ - 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,8 +280,8 @@ related to an object """ __regid__ = 'commentsection' - __select__ = (component.EntityVComponent.__select__ + __select__ = ((component.EntityVComponent.__select__ | match_kwargs('entity')) & relation_possible('comments', 'object', 'Comment')) context = 'navcontentbottom' @@ -258,7 +284,7 @@ & 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') ) @@ -263,5 +289,5 @@ 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)) @@ -266,14 +292,14 @@ 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>') @@ -279,6 +305,6 @@ 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) @@ -283,5 +309,10 @@ 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))) @@ -287,7 +318,4 @@ 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')