Commit c1a38a6d by David Baumgold Committed by Andy Armstrong

Pull discussion underscore templates out into individual files

No need to go through Mako
parent 505b6473
from pkg_resources import resource_string
import json
from xblock.core import XBlock
from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor
from xmodule.editing_module import MetadataOnlyEditingDescriptor
......@@ -41,7 +43,20 @@ class DiscussionFields(object):
sort_key = String(scope=Scope.settings)
def has_permission(user, permission, course_id):
"""
Copied from django_comment_client/permissions.py because I can't import
that file from here. It causes the xmodule_assets command to fail.
"""
return any(role.has_permission(permission)
for role in user.roles.filter(course_id=course_id))
@XBlock.wants('user')
class DiscussionModule(DiscussionFields, XModule):
"""
XModule for discussion forums.
"""
js = {
'coffee': [
resource_string(__name__, 'js/src/discussion/display.coffee')
......@@ -53,9 +68,26 @@ class DiscussionModule(DiscussionFields, XModule):
js_module_name = "InlineDiscussion"
def get_html(self):
course = self.get_course()
user = None
user_service = self.runtime.service(self, 'user')
if user_service:
user = user_service._django_user # pylint: disable=protected-access
if user:
course_key = course.id # pylint: disable=no-member
can_create_comment = has_permission(user, "create_comment", course_key)
can_create_subcomment = has_permission(user, "create_sub_comment", course_key)
can_create_thread = has_permission(user, "create_thread", course_key)
else:
can_create_comment = False
can_create_subcomment = False
can_create_thread = False
context = {
'discussion_id': self.discussion_id,
'course': self.get_course(),
'course': course,
'can_create_comment': json.dumps(can_create_comment),
'can_create_subcomment': json.dumps(can_create_subcomment),
'can_create_thread': can_create_thread,
}
if getattr(self.system, 'is_author_mode', False):
template = 'discussion/_discussion_module_studio.html'
......
......@@ -415,7 +415,7 @@ describe "DiscussionThreadListView", ->
it "for answered question", ->
renderSingleThreadWithProps({thread_type: "question", endorsed: true})
expect($(".forum-nav-thread-wrapper-0 .icon")).toHaveClass("fa-check")
expect($(".forum-nav-thread-wrapper-0 .icon")).toHaveClass("fa-check-square-o")
expect($(".forum-nav-thread-wrapper-0 .sr")).toHaveText("answered question")
it "for unanswered question", ->
......
......@@ -80,16 +80,16 @@ describe "DiscussionThreadView", ->
expect(view.$('.display-vote').is(":visible")).toBe(not originallyClosed)
_.each(["tab", "inline"], (mode) =>
it 'Test that in #{mode} mode when a closed thread is opened the comment form is displayed', ->
it "Test that in #{mode} mode when a closed thread is opened the comment form is displayed", ->
checkCommentForm(true, mode)
it 'Test that in #{mode} mode when a open thread is closed the comment form is hidden', ->
it "Test that in #{mode} mode when a open thread is closed the comment form is hidden", ->
checkCommentForm(false, mode)
it 'Test that in #{mode} mode when a closed thread is opened the vote button is displayed and vote count is hidden', ->
it "Test that in #{mode} mode when a closed thread is opened the vote button is displayed and vote count is hidden", ->
checkVoteDisplay(true, mode)
it 'Test that in #{mode} mode when a open thread is closed the vote button is hidden and vote count is displayed', ->
it "Test that in #{mode} mode when a open thread is closed the vote button is hidden and vote count is displayed", ->
checkVoteDisplay(false, mode)
)
......
......@@ -180,7 +180,7 @@ describe "NewPostView", ->
eventSpy = jasmine.createSpy('eventSpy')
view.listenTo(view, "newPost:cancel", eventSpy)
view.$(".post-errors").html("<li class='post-error'>Title can't be empty</li>")
view.$("label[for$='post-type-discussion']").click()
view.$("label[for$='post-type-question']").click()
view.$(".js-post-title").val("Test Title")
view.$(".js-post-body textarea").val("Test body")
view.$(".wmd-preview p").html("Test body")
......@@ -192,8 +192,8 @@ describe "NewPostView", ->
view.$(".cancel").click()
expect(eventSpy).toHaveBeenCalled()
expect(view.$(".post-errors").html()).toEqual("");
expect($("input[id$='post-type-question']")).toBeChecked()
expect($("input[id$='post-type-discussion']")).not.toBeChecked()
expect($("input[id$='post-type-discussion']")).toBeChecked()
expect($("input[id$='post-type-question']")).not.toBeChecked()
expect(view.$(".js-post-title").val()).toEqual("");
expect(view.$(".js-post-body textarea").val()).toEqual("");
expect(view.$(".js-follow")).toBeChecked()
......
......@@ -5,6 +5,7 @@ if Backbone?
DiscussionUtil.loadRolesFromContainer()
element = $(elem)
window.$$course_id = element.data("course-id")
window.courseName = element.data("course-name")
user_info = element.data("user-info")
sort_preference = element.data("sort-preference")
threads = element.data("threads")
......
......@@ -248,7 +248,7 @@ if Backbone?
@$(".forum-nav-thread[data-id='#{thread_id}'] .forum-nav-thread-link").addClass("is-active").find(".forum-nav-thread-wrapper-1").prepend('<span class="sr">' + gettext("Current conversation") + '</span>')
goHome: ->
@template = _.template($("#discussion-home").html())
@template = _.template($("#discussion-home-template").html())
$(".forum-content").html(@template)
$(".forum-nav-thread-list a").removeClass("is-active").find(".sr").remove()
$("input.email-setting").bind "click", @updateEmailNotifications
......
......@@ -50,7 +50,13 @@ if Backbone?
renderTemplate: ->
@template = _.template($("#thread-template").html())
@template(@model.toJSON())
templateData = @model.toJSON()
container = $("#discussion-container")
if !container.length
# inline discussion
container = $(".discussion-module")
templateData.can_create_comment = container.data("user-create-comment")
@template(templateData)
render: ->
@$el.html(@renderTemplate())
......
......@@ -19,6 +19,11 @@ if Backbone?
templateData = @model.toJSON()
templateData.wmdId = @model.id ? (new Date()).getTime()
container = $("#discussion-container")
if !container.length
# inline discussion
container = $(".discussion-module")
templateData.create_sub_comment = container.data("user-create-subcomment")
@template(templateData)
render: ->
......
<div class="discussion-article blank-slate">
<section class="home-header">
<span class="label"><%- gettext("DISCUSSION HOME:") %></span>
<% if (window.courseName) { %>
<h1 class="home-title"><%- window.courseName %></h1>
<% } %>
</section>
<% if (window.ENABLE_DISCUSSION_HOME_PANEL) { %>
<span class="label label-settings">
<%- interpolate(gettext("How to use %(platform_name)s discussions"), {platform_name: window.PLATFORM_NAME}, true) %>
</span>
<table class="home-helpgrid">
<tr class="helpgrid-row helpgrid-row-navigation">
<td class="row-title"><%- gettext("Find discussions") %></td>
<td class="row-item">
<i class="icon fa fa-reorder"></i>
<span class="row-description"><%- gettext("Focus in on specific topics") %></span>
</td>
<td class="row-item">
<i class="icon fa fa-search"></i>
<span class="row-description"><%- gettext("Search for specific posts") %></span>
</td>
<td class="row-item">
<i class="icon fa fa-sort"></i>
<span class="row-description"><%- gettext("Sort by date, vote, or comments") %></span>
</td>
</tr>
<tr class="helpgrid-row helpgrid-row-participation">
<td class="row-title"><%- gettext("Engage with posts") %></td>
<td class="row-item">
<i class="icon fa fa-plus"></i>
<span class="row-description"><%- gettext("Upvote posts and good responses") %></span>
</td>
<td class="row-item">
<i class="icon fa fa-flag"></i>
<span class="row-description"><%- gettext("Report Forum Misuse") %></span>
</td>
<td class="row-item">
<i class="icon fa fa-star"></i>
<span class="row-description"><%- gettext("Follow posts for updates") %></span>
</td>
</tr>
<tr class="helpgrid-row helpgrid-row-notification">
<td class="row-title"><%- gettext('Receive updates') %></td>
<td class="row-item-full" colspan="3">
<label for="email-setting-checkbox">
<span class="sr"><%- gettext("Toggle Notifications Setting") %></span>
<span class="notification-checkbox">
<input type="checkbox" id="email-setting-checkbox" class="email-setting" name="email-notification"/>
<i class="icon fa fa-envelope"></i>
</span>
</label>
<span class="row-description"><%- gettext("Check this box to receive an email digest once a day notifying you about new, unread activity from posts you are following.") %></span>
</td>
</tr>
</table>
<% } %>
</div>
<li class="actions-item">
<a href="javascript:void(0)" class="action-button action-answer" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Mark as Answer") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Mark as Answer") %></span>
<span class="label-checked"><%- gettext("Unmark as Answer") %></span>
</span>
<span class="action-icon"><i class="icon fa fa-ok"></i></span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-list-item action-close" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Close") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Close") %></span>
<span class="label-checked"><%- gettext("Open") %></span>
</span>
<span class="action-icon">
<i class="icon fa fa-lock"></i>
</span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-list-item action-delete" role="button">
<span class="action-label"><%- gettext("Delete") %></span>
<span class="action-icon"><i class="icon fa fa-remove"></i></span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-list-item action-edit" role="button">
<span class="action-label"><%- gettext("Edit") %></span>
<span class="action-icon"><i class="icon fa fa-pencil"></i></span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-button action-endorse" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Endorse") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Endorse") %></span>
<span class="label-checked"><%- gettext("Unendorse") %></span>
</span>
<span class="action-icon"><i class="icon fa fa-ok"></i></span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-button action-follow" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Follow") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Follow") %></span>
<span class="label-checked"><%- gettext("Unfollow") %></span>
</span>
<span class="action-icon"><i class="icon fa fa-star"></i></span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-list-item action-pin" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Pin") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Pin") %></span>
<span class="label-checked"><%- gettext("Unpin") %></span>
</span>
<span class="action-icon">
<i class="icon fa fa-thumb-tack"></i>
</span>
</a>
</li>
<li class="actions-item">
<a href="javascript:void(0)" class="action-list-item action-report" role="checkbox" aria-checked="false">
<span class="sr"><%- gettext("Report abuse") %></span>
<span class="action-label" aria-hidden="true">
<span class="label-unchecked"><%- gettext("Report") %></span>
<span class="label-checked"><%- gettext("Unreport") %></span>
</span>
<span class="action-icon">
<i class="icon fa fa-flag"></i>
</span>
</a>
</li>
<li class="actions-item">
<span aria-hidden="true" class="display-vote" >
<span class="vote-count"></span>
</span>
<a href="#" class="action-button action-vote" role="checkbox" aria-checked="false">
<% // Vote counts are populated by JS %>
<span class="sr"><%- gettext("Vote for this post,") %>&nbsp;</span>
<span class="sr js-sr-vote-count"></span>
<span class="action-label" aria-hidden="true">
<span class="vote-count"></span>
</span>
<span class="action-icon" aria-hidden="true">
<i class="icon fa fa-plus"></i>
</span>
</a>
</li>
<ul class="<%= contentType %>-actions-list">
<% _.each(primaryActions, function(action) { print(_.template($('#forum-action-' + action).html(), {})) }) %>
<li class="actions-item is-visible">
<div class="more-wrapper">
<a href="javascript:void(0)" class="action-button action-more" role="button" aria-haspopup="true" aria-controls="action-menu-<%= contentId %>">
<span class="action-label"><%- gettext("More") %></span>
<span class="action-icon"><i class="icon fa fa-ellipsis-h"></i></span>
</a>
<div class="actions-dropdown" id="action-menu-<%= contentType %>" aria-expanded="false">
<ul class="actions-dropdown-list">
<% _.each(secondaryActions, function(action) { print(_.template($('#forum-action-' + action).html(), {})) }) %>
</ul>
</div>
</div>
</li>
</ul>
<li role="menuitem" class="topic-menu-item">
<span class="topic-title"><%- text %></span>
<ul role="menu" class="topic-submenu"><%= entries %></ul>
</li>
<li role="menuitem" class="topic-menu-item">
<a href="#" class="topic-title" data-discussion-id="<%- id %>" data-cohorted="<%- is_cohorted %>"><%- text %></a>
</li>
<form class="forum-new-post-form">
<ul class="post-errors" style="display: none"></ul>
<div class="forum-new-post-form-wrapper"></div>
<% if (cohort_options) { %>
<div class="post-field group-selector-wrapper <% if (!is_commentable_cohorted) { print('disabled'); } %>">
<label class="field-label">
<span class="field-label-text">
<% //Translators: This labels the selector for which group of students can view a post %>
<%- gettext("Visible To:") %>
</span><select aria-describedby="field_help_visible_to" class="field-input js-group-select" name="group_id" <% if (!is_commentable_cohorted) { print("disabled"); } %>>
<option value=""><%- gettext("All Groups") %></option>
<% _.each(cohort_options, function(opt) { %>
<option value="<%= opt.value %>" <% if (opt.selected) { print("selected"); } %>><%- opt.text %></option>
<% }); %>
</select>
</label><div class="field-help" id="field_help_visible_to">
<%- gettext("Discussion admins, moderators, and TAs can make their posts visible to all students or specify a single cohort.") %>
</div>
</div>
<% } %>
<div class="post-field">
<label class="field-label">
<span class="sr"><%- gettext("Title:") %></span>
<input aria-describedby="field_help_title" type="text" class="field-input js-post-title" name="title" placeholder="<%- gettext('Title') %>">
</label><span class="field-help" id="field_help_title">
<%- gettext("Add a clear and descriptive title to encourage participation.") %>
</span>
</div>
<div class="post-field js-post-body editor" name="body" data-placeholder="<%- gettext('Enter your question or comment') %>"></div>
<div class="post-options">
<label class="post-option is-enabled">
<input type="checkbox" name="follow" class="post-option-input js-follow" checked>
<i class="icon fa fa-star"></i><%- gettext("follow this post") %>
</label>
<% if (allow_anonymous) { %>
<label class="post-option">
<input type="checkbox" name="anonymous" class="post-option-input js-anon">
<%- gettext("post anonymously") %>
</label>
<% } %>
<% if (allow_anonymous_to_peers) { %>
<label class="post-option">
<input type="checkbox" name="anonymous_to_peers" class="post-option-input js-anon-peers">
<%- gettext("post anonymously to classmates") %>
</label>
<% } %>
</div>
<div>
<input type="submit" class="submit" value="<%- gettext('Add Post') %>">
<a href="#" class="cancel"><%- gettext('Cancel') %></a>
</div>
</form>
<% if (username) { %>
<a href="<%- user_url %>" class="username"><%- username %></a>
<% if (is_community_ta) { %>
<span class="user-label-community-ta"><%- gettext("Community TA") %></span>
<% } else if (is_staff) { %>
<span class="user-label-staff"><%- gettext("Staff") %></span>
<% } %>
<% } else { %>
<%- gettext('anonymous') %>
<% } %>
<div class="edit-post-form" id="comment_<%- id %>">
<h1><%- gettext("Editing comment") %></h1>
<ul class="edit-comment-form-errors"></ul>
<div class="form-row">
<div class="edit-comment-body" name="body" data-id="<%- id %>"><%- body %></div>
</div>
<input type="submit" id="edit-comment-submit" class="post-update" value="<%- gettext("Update comment") %>">
<a href="#" class="post-cancel"><%- gettext("Cancel") %></a>
</div>
<div id="comment_<%- id %>">
<div class="response-body"><%- body %></div>
<%=
_.template(
$('#forum-actions').html(),
{
contentId: cid,
contentType: 'comment',
primaryActions: [],
secondaryActions: ['edit', 'delete', 'report']
}
)
%>
<p class="posted-details">
<%
var time_ago = interpolate(
'<span class="timeago" title="%(time)s">%(time)s</span>',
{time: created_at},
true
);
%>
<%= interpolate(
// Translators: 'timeago' is a placeholder for a fuzzy, relative timestamp (see: https://github.com/rmm5t/jquery-timeago)
gettext("posted %(time_ago)s by %(author)s"),
{time_ago: time_ago, author: author_display},
true
) %>
</p>
<div class="post-labels">
<span class="post-label-reported"><i class="icon fa fa-flag"></i><%- gettext("Reported") %></span>
</div>
</div>
<div class="search-alert" id="search-alert-<%- cid %>">
<div class="search-alert-content">
<p class="message"><%= message %></p>
</div>
<div class="search-alert-controls">
<a href="#" class="dismiss control control-dismiss"><i class="icon fa fa-remove"></i></a>
</div>
</div>
<h1><%- gettext("Editing post") %></h1>
<ul class="post-errors"></ul>
<div class="forum-edit-post-form-wrapper"></div>
<div class="form-row">
<label class="sr" for="edit-post-title"><%- gettext("Edit post title") %></label>
<input type="text" id="edit-post-title" class="edit-post-title" name="title" value="<%-title %>" placeholder="<%- gettext('Title') %>">
</div>
<div class="form-row">
<div class="edit-post-body" name="body"><%- body %></div>
</div>
<input type="submit" id="edit-post-submit" class="post-update" value="<%- gettext("Update post") %>">
<a href="#" class="post-cancel"><%- gettext("Cancel") %></a>
<li data-id="<%- id %>" class="forum-nav-thread<% if (typeof(read) != "undefined" && !read) { %> is-unread<% } %>">
<a href="#" class="forum-nav-thread-link">
<div class="forum-nav-thread-wrapper-0">
<%
var icon_class, sr_text;
if (thread_type === "discussion") {
icon_class = "fa-comments";
// Translators: This is a label for a Discussion forum thread
sr_text = gettext("discussion");
} else if (endorsed) {
icon_class = "fa-check-square-o";
// Translators: This is a label for a Question forum thread with a marked answer
sr_text = gettext("answered question");
} else {
icon_class = "fa-question";
// Translators: This is a label for a Question forum thread without a marked answer
sr_text = gettext("unanswered question");
}
%>
<span class="sr"><%= sr_text %></span>
<i class="icon fa <%= icon_class %>"></i>
</div><div class="forum-nav-thread-wrapper-1">
<span class="forum-nav-thread-title"><%- title %></span>
<% if(typeof(subscribed) === "undefined") { var subscribed = null; } %>
<% if(pinned || subscribed || staff_authored || community_ta_authored) { %>
<ul class="forum-nav-thread-labels">
<% if (pinned) { %>
<li class="post-label-pinned">
<i class="icon fa fa-thumb-tack"></i>
<% // Translators: This is a label for a forum thread that has been pinned %>
<%- gettext("Pinned") %>
</li>
<% } %>
<% if (subscribed) { %>
<li class="post-label-following">
<i class="icon fa fa-star"></i>
<% // Translators: This is a label for a forum thread that the user is subscribed to %>
<%- gettext("Following") %>
</li>
<% } %>
<% if (staff_authored) { %>
<li class="post-label-by-staff">
<i class="icon fa fa-user"></i>
<% // Translators: This is a label for a forum thread that was authored by a member of the course staff %>
<%- gettext("By: Staff") %>
</li>
<% } %>
<% if (community_ta_authored) { %>
<li class="post-label-by-community-ta">
<i class="icon fa fa-user"></i>
<% // Translators: This is a label for a forum thread that was authored by a community TA %>
<%- gettext("By: Community TA") %>
</li>
<% } %>
</ul>
<% } %>
</div><div class="forum-nav-thread-wrapper-2">
<%
// Translators: 'votes_count' is a numerical placeholder for a specific discussion thread; 'span_start' and 'span_end' placeholders refer to HTML markup. Please translate the word 'votes'.
var fmt = ngettext(
"%(votes_count)s%(span_start)s vote %(span_end)s",
"%(votes_count)s%(span_start)s votes %(span_end)s",
votes['up_count']
);
%>
<span class="forum-nav-thread-votes-count">
+<%- interpolate(fmt, {
votes_count: votes['up_count'],
span_start: '<span class="sr">',
span_end: '</span>'
}, true)
%>
</span>
<span class="forum-nav-thread-comments-count <% if (unread_comments_count > 0) { %>is-unread<% } %>">
<%
var fmt;
// Counts in data do not include the post itself, but the UI should
var data = {
'span_sr_open': '<span class="sr">',
'span_close': '</span>',
'unread_comments_count': unread_comments_count + (read ? 0 : 1),
'comments_count': comments_count + 1
};
if (unread_comments_count > 0) {
// Translators: 'comments_count' and 'unread_comments_count' are numerical placeholders for a specific discussion thread; 'span_*' placeholders refer to HTML markup. Please translate the word 'comments'.
fmt = gettext('%(comments_count)s %(span_sr_open)scomments (%(unread_comments_count)s unread comments)%(span_close)s');
} else {
// Translators: 'comments_count' is a numerical placeholder for a specific discussion thread; 'span_*' placeholders refer to HTML markup. Please translate the word 'comments'.
fmt = gettext('%(comments_count)s %(span_sr_open)scomments %(span_close)s');
}
print(interpolate(fmt, data, true));
%>
</span>
</div>
</a>
</li>
<div class="edit-post-form">
<h1><%- gettext("Editing response") %></h1>
<ul class="edit-post-form-errors"></ul>
<div class="form-row">
<div class="edit-post-body" name="body" data-id="<%- id %>"><%- body %></div>
</div>
<input type="submit" id="edit-response-submit"class="post-update" value="<%- gettext("Update response") %>">
<a href="#" class="post-cancel"><%- gettext("Cancel") %></a>
</div>
<header>
<div class="response-header-content">
<%= author_display %>
<p class="posted-details">
<span class="timeago" title="<%= created_at %>"><%= created_at %></span>
<% if (obj.endorsement) { %>
-
<%
var fmt = null;
if (thread.get("thread_type") == "question") {
if (endorsement.username) {
// Translators: time_ago is a placeholder for a fuzzy, relative timestamp
// like "4 hours ago" or "about a month ago"
fmt = gettext("marked as answer %(time_ago)s by %(user)s");
} else {
// Translators: time_ago is a placeholder for a fuzzy, relative timestamp
// like "4 hours ago" or "about a month ago"
fmt = gettext("marked as answer %(time_ago)s");
}
} else {
if (endorsement.username) {
// Translators: time_ago is a placeholder for a fuzzy, relative timestamp
// like "4 hours ago" or "about a month ago"
fmt = gettext("endorsed %(time_ago)s by %(user)s");
} else {
// Translators: time_ago is a placeholder for a fuzzy, relative timestamp
// like "4 hours ago" or "about a month ago"
fmt = gettext("endorsed %(time_ago)s");
}
}
var time_ago = interpolate(
'<span class="timeago" title="%(time)s">%(time)s</span>',
{time: endorsement.time},
true
);
%>
<%= interpolate(fmt, {time_ago: time_ago, user: endorser_display}, true) %>
<% } %>
</p>
<div class="post-labels">
<span class="post-label-reported"><i class="icon fa fa-flag"></i><%- gettext("Reported") %></span>
</div>
</div>
<div class="response-header-actions">
<%=
_.template(
$('#forum-actions').html(),
{
contentId: cid,
contentType: 'response',
primaryActions: ['vote', thread.get('thread_type') == 'question' ? 'answer' : 'endorse'],
secondaryActions: ['edit', 'delete', 'report']
}
)
%>
</div>
</header>
<div class="response-body"><%- body %></div>
<div class="discussion-response"></div>
<a href="#" class="action-show-comments">
<%
var fmts = ngettext(
"Show Comment (%(num_comments)s)",
"Show Comments (%(num_comments)s)",
comments.length
);
print(interpolate(fmts, {num_comments: comments.length}, true));
%>
<i class="icon fa fa-caret-down"></i>
</a>
<ol class="comments">
<li class="new-comment">
<% if (create_sub_comment) { %>
<form class="comment-form" data-id="<%- wmdId %>">
<ul class="discussion-errors"></ul>
<label class="sr" for="add-new-comment"><%- gettext("Add a comment") %></label>
<div class="comment-body" id="add-new-comment" data-id="<%- wmdId %>"
data-placeholder="<%- gettext('Add a comment') %>"></div>
<div class="comment-post-control">
<a class="discussion-submit-comment control-button" href="#"><%- gettext("Submit") %></a>
</div>
</form>
<% } %>
</li>
</ol>
<div class="post-field">
<div class="field-label">
<span class="field-label-text">
<% // Translators: This is the label for a control to select a forum post type %>
<%- gettext("Post type:") %>
</span><fieldset class="field-input"><legend class="sr"><%- gettext("Post type:") %></legend>
<input aria-describedby="field_help_post_type" type="radio" name="<%= form_id %>-post-type" class="post-type-input" id="<%= form_id %>-post-type-question" value="question">
<label for="<%= form_id %>-post-type-question" class="post-type-label">
<i class="icon fa fa-question"></i>
<% // Translators: This is a forum post type %>
<%- gettext("Question") %>
</label>
<input aria-describedby="field_help_post_type" type="radio" name="<%= form_id %>-post-type" class="post-type-input" id="<%= form_id %>-post-type-discussion" value="discussion" checked>
<label for="<%= form_id %>-post-type-discussion" class="post-type-label">
<i class="icon fa fa-comments"></i>
<% // Translators: This is a forum post type %>
<%- gettext("Discussion") %>
</label>
</fieldset>
</div><span class="field-help" id="field_help_post_type">
<%- gettext("Questions raise issues that need answers. Discussions share ideas and start conversations.") %>
</span>
</div>
<article class="discussion-article" data-id="<%- id %>">
<div class="thread-wrapper" tabindex="-1">
<div class="forum-thread-main-wrapper">
<div class="thread-content-wrapper"></div>
<div class="post-extended-content">
<ol class="responses js-marked-answer-list"></ol>
</div>
</div>
<div class="post-extended-content">
<div class="response-count"/>
<div class="add-response">
<button class="button add-response-btn">
<i class="icon fa fa-reply"></i>
<span class="add-response-btn-text"><%- gettext("Add a Response") %></span>
</button>
</div>
<ol class="responses js-response-list"/>
<div class="response-pagination"/>
<div class="post-status-closed bottom-post-status" style="display: none">
<%- gettext("This thread is closed.") %>
</div>
<% if (can_create_comment) { %>
<form class="discussion-reply-new" data-id="<%- id %>">
<h4><%- gettext("Post a response:") %></h4>
<ul class="discussion-errors"></ul>
<div class="reply-body" data-id="<%- id %>"></div>
<div class="reply-post-control">
<a class="discussion-submit-post control-button" href="#"><%- gettext("Submit") %></a>
</div>
</form>
<% } %>
</div>
</div>
<div class="post-tools">
<a href="javascript:void(0)" class="forum-thread-expand"><span class="icon fa fa-plus"/><%- gettext("Expand discussion") %></a>
<a href="javascript:void(0)" class="forum-thread-collapse"><span class="icon fa fa-minus"/><%- gettext("Collapse discussion") %></a>
</div>
</article>
<% // Using div here instead of label because we are using a non-native control %>
<div class="field-label">
<span class="field-label-text"><%- gettext("Topic Area:") %></span><div class="field-input post-topic">
<a href="#" class="post-topic-button">
<span class="sr"><%- gettext("Discussion topics; current selection is: ") %></span>
<span class="js-selected-topic"></span>
<span class="drop-arrow" aria-hidden="true">▾</span>
</a>
<div class="topic-menu-wrapper">
<label class="topic-filter-label">
<span class="sr"><%- gettext("Filter topics") %></span>
<input aria-describedby="field_help_topic_area" type="text" class="topic-filter-input" placeholder="<%- gettext('Filter topics') %>">
</label>
<ul class="topic-menu" role="menu"><%= topics_html %></ul>
</div>
</div>
</div><span class="field-help" id="field_help_topic_area">
<%- gettext("Add your post to a relevant topic to help others find it.") %>
</span>
# -*- coding: utf-8 -*-
"""Test for Discussion Xmodule functional logic."""
from mock import Mock
from . import BaseTestXmodule
from courseware.module_render import get_module_for_descriptor_internal
class DiscussionModuleTest(BaseTestXmodule):
"""Logic tests for Discussion Xmodule."""
CATEGORY = "discussion"
def test_html_with_user(self):
discussion = get_module_for_descriptor_internal(
user=self.users[0],
descriptor=self.item_descriptor,
student_data=Mock(name='student_data'),
course_id=self.course.id,
track_function=Mock(name='track_function'),
xqueue_callback_url_prefix=Mock(name='xqueue_callback_url_prefix'),
request_token='request_token',
)
fragment = discussion.render('student_view')
html = fragment.content
self.assertIn('data-user-create-comment="false"', html)
self.assertIn('data-user-create-subcomment="false"', html)
......@@ -276,6 +276,11 @@ def forum_form_discussion(request, course_key):
'threads': _attr_safe_json(threads),
'thread_pages': query_params['num_pages'],
'user_info': _attr_safe_json(user_info),
'can_create_comment': _attr_safe_json(
has_permission(request.user, "create_comment", course.id)),
'can_create_subcomment': _attr_safe_json(
has_permission(request.user, "create_sub_comment", course.id)),
'can_create_thread': has_permission(request.user, "create_thread", course.id),
'flag_moderator': bool(
has_permission(request.user, 'openclose_thread', course.id) or
has_access(request.user, 'staff', course)
......@@ -375,6 +380,11 @@ def single_thread(request, course_key, discussion_id, thread_id):
'csrf': csrf(request)['csrf_token'],
'init': '', # TODO: What is this?
'user_info': _attr_safe_json(user_info),
'can_create_comment': _attr_safe_json(
has_permission(request.user, "create_comment", course.id)),
'can_create_subcomment': _attr_safe_json(
has_permission(request.user, "create_sub_comment", course.id)),
'can_create_thread': has_permission(request.user, "create_thread", course.id),
'annotated_content_info': _attr_safe_json(annotated_content_info),
'course': course,
#'recent_active_threads': recent_active_threads,
......
<%include file="_underscore_templates.html" />
<%!
from django.utils.translation import ugettext as _
from django_comment_client.permissions import has_permission
%>
<div class="discussion-module" data-discussion-id="${discussion_id | h}">
<div class="discussion-module" data-discussion-id="${discussion_id | h}" data-user-create-comment="${can_create_comment}" data-user-create-subcomment="${can_create_subcomment}">
<a class="discussion-show control-button" href="javascript:void(0)" data-discussion-id="${discussion_id | h}" role="button"><span class="show-hide-discussion-icon"></span><span class="button-text">${_("Show Discussion")}</span></a>
% if has_permission(user, 'create_thread', course.id):
% if can_create_thread:
<a href="#" class="new-post-btn" role="button"><span class="icon fa fa-edit new-post-icon"></span>${_("New Post")}</a>
% endif
</div>
......@@ -28,7 +28,10 @@ from django.core.urlresolvers import reverse
<section class="discussion container" id="discussion-container"
data-roles="${roles}"
data-course-id="${course_id | h}"
data-course-name="${course.display_name_with_default}"
data-user-info="${user_info}"
data-user-create-comment="${can_create_comment}"
data-user-create-subcomment="${can_create_subcomment}"
data-threads="${threads}"
data-thread-pages="${thread_pages}"
data-content-info="${annotated_content_info}"
......
......@@ -34,7 +34,7 @@ from django.template.defaultfilters import escapejs
</nav>
</section>
<section class="course-content container discussion-user-threads" data-course-id="${course.id | h}" data-threads="${threads}" data-user-info="${user_info}" data-page="${page}" data-num-pages="${num_pages}"/>
<section class="course-content container discussion-user-threads" data-course-id="${course.id | h}" data-course-name="${course.display_name_with_default}" data-threads="${threads}" data-user-info="${user_info}" data-page="${page}" data-num-pages="${num_pages}"/>
</div>
</section>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment