diff --git a/common/static/images/spinner-on-grey.gif b/common/static/images/spinner-on-grey.gif
new file mode 100644
index 0000000000..f43d52e4f4
Binary files /dev/null and b/common/static/images/spinner-on-grey.gif differ
diff --git a/common/static/images/spinner.gif b/common/static/images/spinner.gif
index b2f94cd12c..e23eb78abe 100644
Binary files a/common/static/images/spinner.gif and b/common/static/images/spinner.gif differ
diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/django_comment_client/forum/views.py
index f9e1baa8ed..2c919acc48 100644
--- a/lms/djangoapps/django_comment_client/forum/views.py
+++ b/lms/djangoapps/django_comment_client/forum/views.py
@@ -227,6 +227,7 @@ def forum_form_discussion(request, course_id):
'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info),escapedict),
'course_id': course.id,
'category_map': category_map,
+ 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
}
# print "start rendering.."
return render_to_response('discussion/index.html', context)
@@ -273,6 +274,8 @@ def single_thread(request, course_id, discussion_id, thread_id):
thread['courseware_location'] = courseware_context['courseware_location']
thread['courseware_title'] = courseware_context['courseware_title']
+ threads = [utils.safe_content(thread) for thread in threads]
+
#recent_active_threads = cc.search_recent_active_threads(
# course_id,
# recursive=False,
@@ -304,6 +307,7 @@ def single_thread(request, course_id, discussion_id, thread_id):
'thread_id': thread_id,
'threads': saxutils.escape(json.dumps(threads), escapedict),
'category_map': category_map,
+ 'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
}
return render_to_response('discussion/single_thread.html', context)
@@ -314,10 +318,12 @@ def user_profile(request, course_id, user_id):
course = get_course_with_access(request.user, course_id, 'load')
try:
profiled_user = cc.User(id=user_id, course_id=course_id)
+
query_params = {
'page': request.GET.get('page', 1),
- 'per_page': INLINE_THREADS_PER_PAGE,
- }
+ 'per_page': THREADS_PER_PAGE, # more than threads_per_page to show more activities
+ }
+
threads, page, num_pages = profiled_user.active_threads(query_params)
query_params['page'] = page
query_params['num_pages'] = num_pages
diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py
index 1a24bdf565..4ceea6b82c 100644
--- a/lms/djangoapps/django_comment_client/utils.py
+++ b/lms/djangoapps/django_comment_client/utils.py
@@ -39,6 +39,14 @@ def strip_blank(dic):
def merge_dict(dic1, dic2):
return dict(dic1.items() + dic2.items())
+def get_role_ids(course_id):
+ roles = Role.objects.filter(course_id=course_id)
+ staff = list(User.objects.filter(is_staff=True).values_list('id', flat=True))
+ roles_with_ids = {'Staff': staff}
+ for role in roles:
+ roles_with_ids[role.name] = list(role.users.values_list('id', flat=True))
+ return roles_with_ids
+
def get_full_modules():
global _FULLMODULES
if not _FULLMODULES:
@@ -273,7 +281,7 @@ def safe_content(content):
'created_at', 'updated_at', 'depth', 'type',
'commentable_id', 'comments_count', 'at_position_list',
'children', 'highlighted_title', 'highlighted_body',
- 'courseware_title', 'courseware_location'
+ 'courseware_title', 'courseware_location', 'tags'
]
if content.get('anonymous') is False:
diff --git a/lms/static/coffee/src/discussion/discussion_module_view.coffee b/lms/static/coffee/src/discussion/discussion_module_view.coffee
index d7a555f004..2d2f3eaa04 100644
--- a/lms/static/coffee/src/discussion/discussion_module_view.coffee
+++ b/lms/static/coffee/src/discussion/discussion_module_view.coffee
@@ -9,7 +9,8 @@ if Backbone?
paginationTemplate: -> DiscussionUtil.getTemplate("_pagination")
page_re: /\?discussion_page=(\d+)/
initialize: ->
- # Set the page if it was set in the URL. This is used to allow deep linking to pages
+ @toggleDiscussionBtn = @$(".discussion-show")
+ # Set the page if it was set in the URL. This is used to allow deep linking to pages
match = @page_re.exec(window.location.href)
if match
@page = parseInt(match[1])
@@ -18,31 +19,38 @@ if Backbone?
toggleNewPost: (event) ->
event.preventDefault()
- if @newPostForm.is(':hidden')
+ if !@newPostForm
+ @toggleDiscussion()
+ @isWaitingOnNewPost = true;
+ return
+ if @showed
@newPostForm.slideDown(300)
else
- @newPostForm.slideUp(300)
+ @newPostForm.show()
+ @toggleDiscussionBtn.addClass('shown')
+ @toggleDiscussionBtn.find('.button-text').html("Hide Discussion")
+ @$("section.discussion").slideDown()
+ @showed = true
hideNewPost: (event) ->
event.preventDefault()
@newPostForm.slideUp(300)
toggleDiscussion: (event) ->
- thisButton = $(event.target).closest('a')
if @showed
@$("section.discussion").slideUp()
- thisButton.removeClass('shown')
- thisButton.find('.button-text').html("Show Discussion")
+ @toggleDiscussionBtn.removeClass('shown')
+ @toggleDiscussionBtn.find('.button-text').html("Show Discussion")
@showed = false
else
- thisButton.addClass('shown')
- thisButton.find('.button-text').html("Hide Discussion")
+ @toggleDiscussionBtn.addClass('shown')
+ @toggleDiscussionBtn.find('.button-text').html("Hide Discussion")
if @retrieved
@$("section.discussion").slideDown()
@showed = true
else
- $elem = $(event.target)
+ $elem = @toggleDiscussionBtn
@loadPage $elem
loadPage: ($elem)=>
@@ -59,7 +67,7 @@ if Backbone?
renderDiscussion: ($elem, response, textStatus, discussionId) =>
window.user = new DiscussionUser(response.user_info)
Content.loadContentInfos(response.annotated_content_info)
- $elem.html("Hide Discussion")
+ # $elem.html("Hide Discussion")
@discussion = new Discussion()
@discussion.reset(response.discussion_data, {silent: false})
$discussion = $(Mustache.render $("script#_inline_discussion").html(), {'threads':response.discussion_data, 'discussionId': discussionId})
@@ -77,6 +85,8 @@ if Backbone?
@retrieved = true
@showed = true
@renderPagination(2, response.num_pages)
+ if @isWaitingOnNewPost
+ @newPostForm.show()
addThread: (thread, collection, options) =>
# TODO: When doing pagination, this will need to repaginate. Perhaps just reload page 1?
diff --git a/lms/static/coffee/src/discussion/discussion_router.coffee b/lms/static/coffee/src/discussion/discussion_router.coffee
index 53ada7a596..14ee1b52f3 100644
--- a/lms/static/coffee/src/discussion/discussion_router.coffee
+++ b/lms/static/coffee/src/discussion/discussion_router.coffee
@@ -26,12 +26,16 @@ if Backbone?
@thread = @discussion.get(thread_id)
@setActiveThread()
if(@main)
+ @main.cleanup()
@main.undelegateEvents()
@main = new DiscussionThreadView(el: $(".discussion-column"), model: @thread)
@main.render()
@main.on "thread:responses:rendered", =>
@nav.updateSidebar()
+ @main.on "tag:selected", (tag) =>
+ search = "[#{tag}]"
+ @nav.setAndSearchFor(search)
navigateToThread: (thread_id) =>
thread = @discussion.get(thread_id)
diff --git a/lms/static/coffee/src/discussion/utils.coffee b/lms/static/coffee/src/discussion/utils.coffee
index 07a23a4ca6..52a0b510ac 100644
--- a/lms/static/coffee/src/discussion/utils.coffee
+++ b/lms/static/coffee/src/discussion/utils.coffee
@@ -15,6 +15,11 @@ class @DiscussionUtil
@getTemplate: (id) ->
$("script##{id}").html()
+ @isStaff: (user_id) ->
+ ids = $("#discussion-container").data("roles")
+ staff = _.union(ids['Staff'], ids['Moderator'], ids['Administrator'])
+ _.include(staff, parseInt(user_id))
+
@bulkUpdateContentInfo: (infos) ->
for id, info of infos
Content.getContent(id).updateInfo(info)
@@ -71,7 +76,7 @@ class @DiscussionUtil
params["loadingCallback"].apply(params["$loading"])
else
params["$loading"].loading()
- $.ajax(params).always ->
+ request = $.ajax(params).always ->
if $elem
$elem.removeAttr("disabled")
if params["$loading"]
@@ -79,6 +84,7 @@ class @DiscussionUtil
params["loadedCallback"].apply(params["$loading"])
else
params["$loading"].loaded()
+ return request
@get: ($elem, url, data, success) ->
@safeAjax
diff --git a/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee b/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
index fef8b311a7..e0502d892a 100644
--- a/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
+++ b/lms/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
@@ -142,7 +142,10 @@ if Backbone?
setTimeout (-> @$(".post-search-field").focus()), 200
toggleTopicDrop: (event) =>
+ event.preventDefault()
event.stopPropagation()
+ if @current_search != ""
+ @clearSearch()
@$(".search").removeClass('is-open')
@$(".browse").addClass('is-open')
@$(".browse").toggleClass('is-dropped')
@@ -235,6 +238,11 @@ if Backbone?
text = @$(".post-search-field").val()
@searchFor(text)
+ setAndSearchFor: (text) ->
+ @showSearch()
+ @$(".post-search-field").val(text)
+ @searchFor(text)
+
searchFor: (text, callback, value) ->
@current_search = text
url = DiscussionUtil.urlFor("search")
diff --git a/lms/static/coffee/src/discussion/views/discussion_thread_view.coffee b/lms/static/coffee/src/discussion/views/discussion_thread_view.coffee
index f56a47b85d..d53a447880 100644
--- a/lms/static/coffee/src/discussion/views/discussion_thread_view.coffee
+++ b/lms/static/coffee/src/discussion/views/discussion_thread_view.coffee
@@ -3,6 +3,7 @@ if Backbone?
events:
"click .discussion-submit-post": "submitComment"
+ "click .thread-tag": "tagSelected"
$: (selector) ->
@$el.find(selector)
@@ -14,19 +15,39 @@ if Backbone?
render: ->
@template = _.template($("#thread-template").html())
@$el.html(@template(@model.toJSON()))
+ @$el.find(".loading").hide()
@delegateEvents()
@renderShowView()
@renderAttrs()
+ @renderTags()
@$("span.timeago").timeago()
@makeWmdEditor "reply-body"
@renderResponses()
@
- renderResponses: ->
- DiscussionUtil.safeAjax
+ cleanup: ->
+ if @responsesRequest?
+ @responsesRequest.abort()
+
+ renderTags: ->
+ tags = $('
')
+ for tag in @model.get("tags")
+ tags.append("
#{tag}")
+ @$(".post-body").after(tags)
+
+ tagSelected: (e) ->
+ @trigger "tag:selected", $(e.target).html()
+
+
+ renderResponses: ->
+ setTimeout(=>
+ @$el.find(".loading").show()
+ , 200)
+ @responsesRequest = DiscussionUtil.safeAjax
url: "/courses/#{$$course_id}/discussion/forum/#{@model.get('commentable_id')}/threads/#{@model.id}"
success: (data, textStatus, xhr) =>
+ @responsesRequest = null
@$el.find(".loading").remove()
Content.loadContentInfos(data['annotated_content_info'])
comments = new Comments(data['content']['children'])
diff --git a/lms/static/coffee/src/discussion/views/response_comment_view.coffee b/lms/static/coffee/src/discussion/views/response_comment_view.coffee
index 34cbaac7ad..fbd3b917a1 100644
--- a/lms/static/coffee/src/discussion/views/response_comment_view.coffee
+++ b/lms/static/coffee/src/discussion/views/response_comment_view.coffee
@@ -18,6 +18,7 @@ if Backbone?
@initLocal()
@delegateEvents()
@renderAttrs()
+ @markAsStaff()
@$el.find(".timeago").timeago()
@convertMath()
@
@@ -29,3 +30,7 @@ if Backbone?
body.children("p").each (index, elem) ->
$(elem).replaceWith($(elem).html())
MathJax.Hub.Queue ["Typeset", MathJax.Hub, body[0]]
+
+ markAsStaff: ->
+ if DiscussionUtil.isStaff(@model.get("user_id"))
+ @$el.find("a").after('
staff')
diff --git a/lms/static/coffee/src/discussion/views/thread_response_view.coffee b/lms/static/coffee/src/discussion/views/thread_response_view.coffee
index f4719800cc..c6f0643de6 100644
--- a/lms/static/coffee/src/discussion/views/thread_response_view.coffee
+++ b/lms/static/coffee/src/discussion/views/thread_response_view.coffee
@@ -18,6 +18,7 @@ if Backbone?
@renderAttrs()
@$el.find(".posted-details").timeago()
@convertMath()
+ @markAsStaff()
@renderComments()
@
@@ -26,6 +27,11 @@ if Backbone?
element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html()
MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]]
+ markAsStaff: ->
+ if DiscussionUtil.isStaff(@model.get("user_id"))
+ @$el.addClass("staff")
+ @$el.prepend('
staff
')
+
renderComments: ->
comments = new Comments()
comments.comparator = (comment) ->
diff --git a/lms/static/sass/_discussion.scss b/lms/static/sass/_discussion.scss
index 35632af9dc..e75c05c140 100644
--- a/lms/static/sass/_discussion.scss
+++ b/lms/static/sass/_discussion.scss
@@ -274,20 +274,23 @@ body.discussion {
width: 100%;
margin-bottom: 20px;
@include clearfix;
+ @include box-sizing(border-box);
+
+ .form-row {
+ margin-top: 20px;
+ }
+
.post-cancel {
@include white-button;
- border-color: #444;
float: left;
margin: 10px 0 0 15px;
}
.post-update {
-
@include blue-button;
float: left;
height: 37px;
margin-top: 10px;
- border-color: #333;
padding-bottom: 2px;
&:hover {
@@ -301,13 +304,28 @@ body.discussion {
padding: 0 10px;
box-sizing: border-box;
border-radius: 3px;
- border: 1px solid #333;
+ border: 1px solid #aaa;
font-size: 16px;
- font-family: 'Open Sans', sans-serif;
+ font-family: $sans-serif;
color: #333;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) inset;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15) inset;
}
+ .tagsinput {
+ padding: 10px;
+ @include box-sizing(border-box);
+ border: 1px solid #aaa;
+ border-radius: 3px;
+ background: #fff;
+ font-family: 'Monaco', monospace;
+ font-size: 13px;
+ line-height: 1.6;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) inset;
+
+ span.tag {
+ margin-bottom: 0;
+ }
+ }
}
.new-post-form {
@@ -1006,8 +1024,14 @@ body.discussion {
.post-list {
background-color: #ddd;
+
.loading {
padding: 15px 0;
+ background: #f6f6f6;
+
+ .loading-animation {
+ background-image: url(../images/spinner-on-grey.gif);
+ }
}
a {
@@ -1231,6 +1255,12 @@ body.discussion {
font-style: italic;
color: #888;
+ .username {
+ display: block;
+ font-size: 16px;
+ font-weight: 700;
+ }
+
span {
font-style: italic;
}
@@ -1309,7 +1339,7 @@ body.discussion {
> li {
position: relative;
margin: 0 -10px 30px;
- padding: 26px 30px 30px;
+ padding: 26px 30px 20px;
border-radius: 3px;
border: 1px solid #b2b2b2;
box-shadow: 0 1px 3px rgba(0, 0, 0, .15);
@@ -1573,6 +1603,7 @@ body.discussion {
.discussion-reply-new {
padding: 20px;
@include clearfix;
+ @include transition(opacity .2s);
h4 {
font-size: 16px;
@@ -1619,8 +1650,9 @@ body.discussion {
.discussion-module {
@extend .discussion-body;
+ position: relative;
margin: 20px 0;
- padding: 20px 20px 28px 20px;
+ padding: 20px;
background: #f6f6f6 !important;
border-radius: 3px;
@@ -1633,10 +1665,13 @@ body.discussion {
}
}
+ .loading-animation {
+ background-image: url(../images/spinner-on-grey.gif);
+ }
+
.discussion-show {
- display: block;
- width: 200px;
- margin: auto;
+ position: relative;
+ top: 3px;
font-size: 14px;
text-align: center;
@@ -1660,10 +1695,11 @@ body.discussion {
.new-post-btn {
display: inline-block;
+ float: right;
}
section.discussion {
- margin-top: 20px;
+ margin-top: 30px;
.threads {
margin-top: 20px;
@@ -1715,6 +1751,16 @@ body.discussion {
padding-bottom: 0;
margin-bottom: 15px;
+ .posted-details {
+ margin-top: 4px;
+
+ .username {
+ display: inline;
+ font-size: 14px;
+ font-weight: 700;
+ }
+ }
+
h3 {
font-size: 19px;
font-weight: 700;
@@ -1758,13 +1804,16 @@ body.discussion {
margin-top: 10px;
header {
- padding-bottom: 0em;
- margin-bottom: 5px;
+ padding-bottom: 0;
+ margin-bottom: 15px;
.posted-by {
- font-size: 0.8em;
+ float: left;
+ margin-right: 5px;
+ font-size: 16px;
}
}
+
.response-body {
margin-bottom: 0.2em;
font-size: 14px;
@@ -2169,4 +2218,4 @@ body.discussion {
.discussion-user-threads {
@extend .discussion-module
-}
+}
\ No newline at end of file
diff --git a/lms/templates/discussion/_discussion_module.html b/lms/templates/discussion/_discussion_module.html
index 5c44495c08..bb172093f6 100644
--- a/lms/templates/discussion/_discussion_module.html
+++ b/lms/templates/discussion/_discussion_module.html
@@ -2,4 +2,5 @@
diff --git a/lms/templates/discussion/_underscore_templates.html b/lms/templates/discussion/_underscore_templates.html
index 2c3585bb58..6c951b2253 100644
--- a/lms/templates/discussion/_underscore_templates.html
+++ b/lms/templates/discussion/_underscore_templates.html
@@ -25,10 +25,11 @@
+ ${'<%- votes["up_count"] %>'}
${'<%- title %>'}
- ${'<%- created_at %>'} by
${"<% if (!obj.anonymous) { %>"}
- ${'<%- username %>'}
+ ${'<%- username %>'}
${"<% } else {print('anonymous');} %>"}
+ ${'<%- created_at %>'}
+
• This thread is closed.
diff --git a/lms/templates/discussion/index.html b/lms/templates/discussion/index.html
index 53cbe2d9ed..a0cdcdcb44 100644
--- a/lms/templates/discussion/index.html
+++ b/lms/templates/discussion/index.html
@@ -23,7 +23,7 @@
-
+
@@ -36,4 +36,4 @@
<%include file="_underscore_templates.html" />
-<%include file="_thread_list_template.html" />
\ No newline at end of file
+<%include file="_thread_list_template.html" />
diff --git a/lms/templates/discussion/mustache/_inline_discussion.mustache b/lms/templates/discussion/mustache/_inline_discussion.mustache
index de15431ca1..22c0564426 100644
--- a/lms/templates/discussion/mustache/_inline_discussion.mustache
+++ b/lms/templates/discussion/mustache/_inline_discussion.mustache
@@ -1,5 +1,5 @@
- New Post
+
diff --git a/lms/templates/discussion/mustache/_inline_thread.mustache b/lms/templates/discussion/mustache/_inline_thread.mustache
index 3875c9e7bc..a874b728ce 100644
--- a/lms/templates/discussion/mustache/_inline_thread.mustache
+++ b/lms/templates/discussion/mustache/_inline_thread.mustache
@@ -5,13 +5,15 @@
+ {{votes.up_count}}
{{title}}
- {{created_at}} by
{{#user}}
- {{username}}
+ {{username}}
{{/user}}
{{^user}}
anonymous
{{/user}}
+
+ {{created_at}}
+
• This thread is closed.
diff --git a/lms/templates/discussion/single_thread.html b/lms/templates/discussion/single_thread.html
index 2ddeae4613..0cc1f28b24 100644
--- a/lms/templates/discussion/single_thread.html
+++ b/lms/templates/discussion/single_thread.html
@@ -24,7 +24,7 @@
<%include file="_new_post.html" />
-