Portal status message
@@ -89,12 +89,14 @@
tal:attributes="href string:$portal_url/plone_control_panel"
i18n:translate="">
Site Setup
- ›
+
View Title
-
diff --git a/plone/app/discussion/browser/controlpanel.py b/plone/app/discussion/browser/controlpanel.py
index c330656..822ca2b 100644
--- a/plone/app/discussion/browser/controlpanel.py
+++ b/plone/app/discussion/browser/controlpanel.py
@@ -24,6 +24,7 @@ from z3c.form import button
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
from plone.app.discussion.interfaces import IDiscussionSettings, _
+from plone.app.discussion.upgrades import update_registry
class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
@@ -32,16 +33,18 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
schema = IDiscussionSettings
id = "DiscussionSettingsEditForm"
label = _(u"Discussion settings")
- description = _(u"help_discussion_settings_editform",
- default=u"Some discussion related settings are not "
- "located in the Discussion Control Panel.\n"
- "To enable comments for a specific content type, "
- "go to the Types Control Panel of this type and "
- "choose \"Allow comments\".\n"
- "To enable the moderation workflow for comments, "
- "go to the Types Control Panel, choose "
- "\"Comment\" and set workflow to "
- "\"Comment Review Workflow\".")
+ description = _(
+ u"help_discussion_settings_editform",
+ default=u"Some discussion related settings are not "
+ u"located in the Discussion Control Panel.\n"
+ u"To enable comments for a specific content type, "
+ u"go to the Types Control Panel of this type and "
+ u"choose \"Allow comments\".\n"
+ u"To enable the moderation workflow for comments, "
+ u"go to the Types Control Panel, choose "
+ u"\"Comment\" and set workflow to "
+ u"\"Comment Review Workflow\"."
+ )
def updateFields(self):
super(DiscussionSettingsEditForm, self).updateFields()
@@ -49,6 +52,8 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
SingleCheckBoxFieldWidget
self.fields['moderation_enabled'].widgetFactory = \
SingleCheckBoxFieldWidget
+ self.fields['edit_comment_enabled'].widgetFactory = \
+ SingleCheckBoxFieldWidget
self.fields['anonymous_comments'].widgetFactory = \
SingleCheckBoxFieldWidget
self.fields['show_commenter_image'].widgetFactory = \
@@ -59,7 +64,13 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
SingleCheckBoxFieldWidget
def updateWidgets(self):
- super(DiscussionSettingsEditForm, self).updateWidgets()
+ try:
+ super(DiscussionSettingsEditForm, self).updateWidgets()
+ except KeyError:
+ # upgrade profile not visible in prefs_install_products_form
+ # provide auto-upgrade
+ update_registry(self.context)
+ super(DiscussionSettingsEditForm, self).updateWidgets()
self.widgets['globally_enabled'].label = _(u"Enable Comments")
self.widgets['anonymous_comments'].label = _(u"Anonymous Comments")
self.widgets['show_commenter_image'].label = _(u"Commenter Image")
@@ -108,12 +119,17 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
output.append("globally_enabled")
# Comment moderation
- if 'one_state_workflow' not in workflow_chain and \
- 'comment_review_workflow' not in workflow_chain:
+ one_state_worklow_disabled = 'one_state_workflow' not in workflow_chain
+ comment_review_workflow_disabled = \
+ 'comment_review_workflow' not in workflow_chain
+ if one_state_worklow_disabled and comment_review_workflow_disabled:
output.append("moderation_custom")
elif settings.moderation_enabled:
output.append("moderation_enabled")
+ if settings.edit_comment_enabled:
+ output.append("edit_comment_enabled")
+
# Anonymous comments
if settings.anonymous_comments:
output.append("anonymous_comments")
@@ -151,8 +167,10 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
"""
wftool = getToolByName(self.context, "portal_workflow", None)
workflow_chain = wftool.getChainForPortalType('Discussion Item')
- if 'one_state_workflow' in workflow_chain \
- or 'comment_review_workflow' in workflow_chain:
+ one_state_workflow_enabled = 'one_state_workflow' in workflow_chain
+ comment_review_workflow_enabled = \
+ 'comment_review_workflow' in workflow_chain
+ if one_state_workflow_enabled or comment_review_workflow_enabled:
return
return True
@@ -176,7 +194,7 @@ def notify_configuration_changed(event):
# Discussion control panel setting changed
if event.record.fieldName == 'moderation_enabled':
# Moderation enabled has changed
- if event.record.value == True:
+ if event.record.value is True:
# Enable moderation workflow
wftool.setChainForPortalTypes(('Discussion Item',),
'comment_review_workflow')
diff --git a/plone/app/discussion/browser/conversation.py b/plone/app/discussion/browser/conversation.py
index e605354..3e05416 100644
--- a/plone/app/discussion/browser/conversation.py
+++ b/plone/app/discussion/browser/conversation.py
@@ -14,10 +14,22 @@ from Products.CMFPlone.interfaces import INonStructuralFolder
from plone.app.discussion.interfaces import IDiscussionSettings
+try:
+ from plone.dexterity.interfaces import IDexterityContent
+ DEXTERITY_INSTALLED = True
+except:
+ DEXTERITY_INSTALLED = False
+
class ConversationView(object):
def enabled(self):
+ if DEXTERITY_INSTALLED and IDexterityContent.providedBy(self.context):
+ return self._enabled_for_dexterity_types()
+ else:
+ return self._enabled_for_archetypes()
+
+ def _enabled_for_archetypes(self):
""" Returns True if discussion is enabled for this conversation.
This method checks five different settings in order to figure out if
@@ -52,8 +64,9 @@ class ConversationView(object):
return False
# Always return False if object is a folder
- if (IFolderish.providedBy(context) and
- not INonStructuralFolder.providedBy(context)):
+ context_is_folderish = IFolderish.providedBy(context)
+ context_is_structural = not INonStructuralFolder.providedBy(context)
+ if (context_is_folderish and context_is_structural):
return False
def traverse_parents(context):
@@ -61,8 +74,9 @@ class ConversationView(object):
# enabled in a parent folder.
for obj in aq_chain(context):
if not IPloneSiteRoot.providedBy(obj):
- if (IFolderish.providedBy(obj) and
- not INonStructuralFolder.providedBy(obj)):
+ obj_is_folderish = IFolderish.providedBy(obj)
+ obj_is_stuctural = not INonStructuralFolder.providedBy(obj)
+ if (obj_is_folderish and obj_is_stuctural):
flag = getattr(obj, 'allow_discussion', None)
if flag is not None:
return flag
@@ -94,3 +108,38 @@ class ConversationView(object):
return False
return True
+
+ def _enabled_for_dexterity_types(self):
+ """ Returns True if discussion is enabled for this conversation.
+
+ This method checks five different settings in order to figure out if
+ discussion is enable on a specific content object:
+
+ 1) Check if discussion is enabled globally in the plone.app.discussion
+ registry/control panel.
+
+ 2) Check if the allow_discussion boolean flag on the content object is
+ set. If it is set to True or False, return the value. If it set to
+ None, try further.
+
+ 3) Check if discussion is allowed for the content type.
+ """
+ context = aq_inner(self.context)
+
+ # Fetch discussion registry
+ registry = queryUtility(IRegistry)
+ settings = registry.forInterface(IDiscussionSettings, check=False)
+
+ # Check if discussion is allowed globally
+ if not settings.globally_enabled:
+ return False
+
+ # Check if discussion is allowed on the content object
+ if hasattr(context, "allow_discussion"):
+ if context.allow_discussion is not None:
+ return context.allow_discussion
+
+ # Check if discussion is allowed on the content type
+ portal_types = getToolByName(self, 'portal_types')
+ document_fti = getattr(portal_types, context.portal_type)
+ return document_fti.getProperty('allow_discussion')
diff --git a/plone/app/discussion/browser/javascripts/comments.js b/plone/app/discussion/browser/javascripts/comments.js
index f0de4b2..3060a3d 100644
--- a/plone/app/discussion/browser/javascripts/comments.js
+++ b/plone/app/discussion/browser/javascripts/comments.js
@@ -35,8 +35,9 @@
*/
reply_div.appendTo(comment_div).css("display", "none");
- /* Remove id="reply" attribute, since we use it to uniquely
+ /* Remove id="commenting" attribute, since we use it to uniquely define
the main reply form. */
+ // Still belongs to class="reply"
reply_div.removeAttr("id");
/* Hide the reply button (only hide, because we may want to show it
@@ -47,6 +48,13 @@
/* Fetch the reply form inside the reply div */
var reply_form = reply_div.find("form");
+ /* Change the id of the textarea of the reply form
+ * To avoid conflict later between textareas with same id 'form-widgets-comment-text' while implementing a seperate instance of TinyMCE
+ * */
+ reply_form.find('#formfield-form-widgets-comment-text').attr('id', 'formfield-form-widgets-new-textarea'+comment_id );
+ reply_form.find('#form-widgets-comment-text').attr('id', 'form-widgets-new-textarea'+comment_id );
+
+
/* Populate the hidden 'in_reply_to' field with the correct comment
id */
reply_form.find("input[name='form.widgets.in_reply_to']")
@@ -127,23 +135,23 @@
parents().
filter(".comment").
find(".reply-to-comment-button");
-
+
/* Find the reply-to-comment form and hide and remove it again. */
$.reply_to_comment_form = $(this).parents().filter(".reply");
$.reply_to_comment_form.slideUp("slow", function () {
$(this).remove();
});
-
+
/* Show the reply-to-comment button again. */
reply_to_comment_button.css("display", "inline");
-
+
});
/**********************************************************************
* Publish a single comment.
**********************************************************************/
- $("input[name='form.button.PublishComment']").live('click', function () {
+ $("input[name='form.button.PublishComment']").on('click', function () {
var trigger = this;
var form = $(this).parents("form");
var data = $(form).serialize();
@@ -151,7 +159,7 @@
$.ajax({
type: "GET",
url: form_url,
- data: "workflow_action=publish",
+ data: data,
context: trigger,
success: function (msg) {
// remove button (trigger object can't be directly removed)
@@ -165,11 +173,20 @@
return false;
});
+ /**********************************************************************
+ * Edit a comment
+ **********************************************************************/
+ $("form[name='edit']").prepOverlay({
+ cssclass: 'overlay-edit-comment',
+ width: '60%',
+ subtype: 'ajax',
+ filter: '#content>*'
+ })
/**********************************************************************
* Delete a comment and its answers.
**********************************************************************/
- $("input[name='form.button.DeleteComment']").live('click', function () {
+ $("input[name='form.button.DeleteComment']").on('click', function () {
var trigger = this;
var form = $(this).parents("form");
var data = $(form).serialize();
@@ -177,6 +194,7 @@
$.ajax({
type: 'POST',
url: form_url,
+ data: data,
context: $(trigger).parents(".comment"),
success: function (data) {
var comment = $(this);
diff --git a/plone/app/discussion/browser/javascripts/controlpanel.js b/plone/app/discussion/browser/javascripts/controlpanel.js
index 19f5898..e379f6f 100644
--- a/plone/app/discussion/browser/javascripts/controlpanel.js
+++ b/plone/app/discussion/browser/javascripts/controlpanel.js
@@ -7,39 +7,40 @@
// This unnamed function allows us to use $ inside of a block of code
// without permanently overwriting $.
// http://docs.jquery.com/Using_jQuery_with_Other_Libraries
-
+
/* Disable a control panel setting */
$.disableSettings = function (settings) {
$.each(settings, function (intIndex, setting) {
setting.addClass('unclickable');
var setting_field = $(setting).find("input,select");
setting_field.attr('disabled', 'disabled');
- });
+ });
};
-
+
/* Enable a control panel setting */
$.enableSettings = function (settings) {
$.each(settings, function (intIndex, setting) {
setting.removeClass('unclickable');
var setting_field = $(setting).find("input,select");
setting_field.removeAttr('disabled');
- });
+ });
};
-
+
/* Update settings */
$.updateSettings = function () {
-
+
var globally_enabled = $("#content").hasClass("globally_enabled");
var anonymous_comments = $("#content").hasClass("anonymous_comments");
var moderation_enabled = $("#content").hasClass("moderation_enabled");
var moderation_custom = $("#content").hasClass("moderation_custom");
var invalid_mail_setup = $("#content").hasClass("invalid_mail_setup");
-
+
/* If commenting is globally disabled, disable all settings. */
if (globally_enabled === true) {
$.enableSettings([
$('#formfield-form-widgets-anonymous_comments'),
$('#formfield-form-widgets-moderation_enabled'),
+ $('#formfield-form-widgets-edit_comment_enabled'),
$('#formfield-form-widgets-text_transform'),
$('#formfield-form-widgets-captcha'),
$('#formfield-form-widgets-show_commenter_image'),
@@ -52,6 +53,7 @@
$.disableSettings([
$('#formfield-form-widgets-anonymous_comments'),
$('#formfield-form-widgets-moderation_enabled'),
+ $('#formfield-form-widgets-edit_comment_enabled'),
$('#formfield-form-widgets-text_transform'),
$('#formfield-form-widgets-captcha'),
$('#formfield-form-widgets-show_commenter_image'),
@@ -60,7 +62,7 @@
$('#formfield-form-widgets-user_notification_enabled')
]);
}
-
+
/* If the mail setup is invalid, disable the mail settings. */
if (invalid_mail_setup === true) {
$.disableSettings([
@@ -73,14 +75,14 @@
/* Enable mail setup only if discussion is enabled. */
if (globally_enabled === true) {
$.enableSettings([
- $('#formfield-form-widgets-moderator_notification_enabled'),
- $('#formfield-form-widgets-moderator_email'),
+ $('#formfield-form-widgets-moderator_notification_enabled'),
+ $('#formfield-form-widgets-moderator_email'),
$('#formfield-form-widgets-user_notification_enabled')
]);
}
}
-
- /* If a custom workflow for comments is enabled, disable the moderation
+
+ /* If a custom workflow for comments is enabled, disable the moderation
switch. */
if (moderation_custom === true) {
$.disableSettings([
@@ -89,21 +91,21 @@
}
};
//#JSCOVERAGE_IF 0
-
+
/**************************************************************************
* Window Load Function: Executes when complete page is fully loaded,
* including all frames,
**************************************************************************/
$(window).load(function () {
-
+
// Update settings on page load
$.updateSettings();
-
+
// Set #content class and update settings afterwards
- $("input,select").live("change", function (e) {
+ $("input,select").on("change", function (e) {
var id = $(this).attr("id");
- if (id === "form-widgets-globally_enabled-0") {
- if ($(this).attr("checked") === true) {
+ if (id === "form-widgets-globally_enabled-0") {
+ if ($(this).attr("checked")) {
$("#content").addClass("globally_enabled");
}
else {
@@ -112,17 +114,16 @@
$.updateSettings();
}
});
-
+
/**********************************************************************
- * Remove the disabled attribute from all form elements before
+ * Remove the disabled attribute from all form elements before
* submitting the form. Otherwise the z3c.form will raise errors on
* the required attributes.
**********************************************************************/
$("form#DiscussionSettingsEditForm").bind("submit", function (e) {
$(this).find("input,select").removeAttr('disabled');
- $(this).submit();
});
-
+
});
//#JSCOVERAGE_ENDIF
diff --git a/plone/app/discussion/browser/javascripts/javascripts.txt b/plone/app/discussion/browser/javascripts/javascripts.txt
index 59fffb5..99f3056 100644
--- a/plone/app/discussion/browser/javascripts/javascripts.txt
+++ b/plone/app/discussion/browser/javascripts/javascripts.txt
@@ -17,7 +17,7 @@ content object. Each comment div has a unique id::
@@ -34,7 +34,7 @@ The comment form is rendered inside a "commenting" div::