From 1c9029c163f1e9fa9dcb213c4923e8f0cb613175 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Wed, 22 Aug 2012 22:57:14 -0700 Subject: [PATCH 01/18] cs188 styling --- lms/static/sass/course.scss | 6 ++++ .../course/courseware/courses/_cs188.scss | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 lms/static/sass/course/courseware/courses/_cs188.scss diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss index 824e84fade..6c63c17f1f 100644 --- a/lms/static/sass/course.scss +++ b/lms/static/sass/course.scss @@ -21,6 +21,12 @@ @import 'course/courseware/sidebar'; @import 'course/courseware/amplifier'; + +// course-specific courseware (all styles in these files should be gated by a +// course-specific class). This should be replaced with a better way of +// providing course-specific styling. +@import "course/courseware/courses/_cs188.scss"; + // wiki @import "course/wiki/basic-html"; @import "course/wiki/sidebar"; diff --git a/lms/static/sass/course/courseware/courses/_cs188.scss b/lms/static/sass/course/courseware/courses/_cs188.scss new file mode 100644 index 0000000000..b069061e6b --- /dev/null +++ b/lms/static/sass/course/courseware/courses/_cs188.scss @@ -0,0 +1,32 @@ +body.cs188 { + + .course-content{ + + .project { + ul, ol { + margin-top: 3px; + list-style: disc; + ul, ol { + margin: 0px; + } + } + } + + h3, h4 { + font-weight: bold; + a { + color: inherit; + } + } + + h4 { + font-size: 1em; + } + + p, .code_snippet { + margin-bottom: 1.416em; + } + + } + +} From 0757712e4b2555aac90f40ff0614031e69b389b1 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Wed, 22 Aug 2012 23:11:51 -0700 Subject: [PATCH 02/18] Get rid of inline flag for choicegroup, radiogroup, and checkboxgroup. This should be done via CSS. This change only affects radiogroup and checkboxgroup as far as changing the behavior goes --- common/lib/capa/capa/inputtypes.py | 6 +++--- common/lib/capa/capa/templates/choicegroup.html | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index f19e7555a1..ad54736359 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -185,7 +185,7 @@ def choicegroup(element, value, status, render_template, msg=''): if choice.text is not None: ctext += choice.text # TODO: fix order? choices.append((choice.get("name"), ctext)) - context = {'id': eid, 'value': value, 'state': status, 'input_type': type, 'choices': choices, 'inline': True, 'name_array_suffix': ''} + context = {'id': eid, 'value': value, 'state': status, 'input_type': type, 'choices': choices, 'name_array_suffix': ''} html = render_template("choicegroup.html", context) return etree.XML(html) @@ -226,7 +226,7 @@ def radiogroup(element, value, status, render_template, msg=''): choices = extract_choices(element) - context = {'id': eid, 'value': value, 'state': status, 'input_type': 'radio', 'choices': choices, 'inline': False, 'name_array_suffix': '[]'} + context = {'id': eid, 'value': value, 'state': status, 'input_type': 'radio', 'choices': choices, 'name_array_suffix': '[]'} html = render_template("choicegroup.html", context) return etree.XML(html) @@ -244,7 +244,7 @@ def checkboxgroup(element, value, status, render_template, msg=''): choices = extract_choices(element) - context = {'id': eid, 'value': value, 'state': status, 'input_type': 'checkbox', 'choices': choices, 'inline': False, 'name_array_suffix': '[]'} + context = {'id': eid, 'value': value, 'state': status, 'input_type': 'checkbox', 'choices': choices, 'name_array_suffix': '[]'} html = render_template("choicegroup.html", context) return etree.XML(html) diff --git a/common/lib/capa/capa/templates/choicegroup.html b/common/lib/capa/capa/templates/choicegroup.html index 3beb45e073..2bed2d875e 100644 --- a/common/lib/capa/capa/templates/choicegroup.html +++ b/common/lib/capa/capa/templates/choicegroup.html @@ -6,9 +6,6 @@ checked="true" % endif /> ${choice_description} - % if not inline: -
- % endif % endfor From 45431ae789f79b20c284b4879edc994807c19dc0 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Wed, 22 Aug 2012 19:41:08 -0700 Subject: [PATCH 03/18] scroll to top after reloading threads --- lms/static/coffee/src/discussion/discussion.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 04eed9bf9c..4764784789 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -45,6 +45,7 @@ class @DiscussionView extends Backbone.View @model.reset(response.discussionData, { silent: false }) view = new DiscussionView el: $discussion[0], model: @model DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + $("html, body").animate({ scrollTop: 0 }, 0) loadSimilarPost: (event) -> $title = @$(".new-post-title") From 4dae36cd8ecc82b57c140bafa10023f236fbc5c7 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Wed, 22 Aug 2012 20:13:42 -0700 Subject: [PATCH 04/18] only execude code when backbone is defined --- .../coffee/src/discussion/content.coffee | 755 +++++++++--------- .../coffee/src/discussion/discussion.coffee | 289 +++---- .../src/discussion/discussion_module.coffee | 63 +- lms/static/coffee/src/discussion/main.coffee | 3 +- 4 files changed, 557 insertions(+), 553 deletions(-) diff --git a/lms/static/coffee/src/discussion/content.coffee b/lms/static/coffee/src/discussion/content.coffee index d427a348b3..69073e1890 100644 --- a/lms/static/coffee/src/discussion/content.coffee +++ b/lms/static/coffee/src/discussion/content.coffee @@ -1,410 +1,411 @@ -class @Content extends Backbone.Model +if Backbone? + class @Content extends Backbone.Model - template: -> DiscussionUtil.getTemplate('_content') + template: -> DiscussionUtil.getTemplate('_content') - actions: - editable: '.admin-edit' - can_reply: '.discussion-reply' - can_endorse: '.admin-endorse' - can_delete: '.admin-delete' - can_openclose: '.admin-openclose' - - urlMappers: {} + actions: + editable: '.admin-edit' + can_reply: '.discussion-reply' + can_endorse: '.admin-endorse' + can_delete: '.admin-delete' + can_openclose: '.admin-openclose' + + urlMappers: {} - urlFor: (name) -> - @urlMappers[name].apply(@) + urlFor: (name) -> + @urlMappers[name].apply(@) - can: (action) -> - DiscussionUtil.getContentInfo @id, action + can: (action) -> + DiscussionUtil.getContentInfo @id, action - updateInfo: (info) -> - @set('ability', info.ability) - @set('voted', info.voted) - @set('subscribed', info.subscribed) + updateInfo: (info) -> + @set('ability', info.ability) + @set('voted', info.voted) + @set('subscribed', info.subscribed) - addComment: (comment, options) -> - options ||= {} - if not options.silent + addComment: (comment, options) -> + options ||= {} + if not options.silent + thread = @get('thread') + comments_count = parseInt(thread.get('comments_count')) + thread.set('comments_count', comments_count + 1) + @get('children').push comment + model = new Comment $.extend {}, comment, { thread: @get('thread') } + @get('comments').add model + model + + removeComment: (comment) -> thread = @get('thread') comments_count = parseInt(thread.get('comments_count')) - thread.set('comments_count', comments_count + 1) - @get('children').push comment - model = new Comment $.extend {}, comment, { thread: @get('thread') } - @get('comments').add model - model + thread.set('comments_count', comments_count - 1 - comment.getCommentsCount()) - removeComment: (comment) -> - thread = @get('thread') - comments_count = parseInt(thread.get('comments_count')) - thread.set('comments_count', comments_count - 1 - comment.getCommentsCount()) + resetComments: (children) -> + @set 'children', [] + @set 'comments', new Comments() + for comment in (children || []) + @addComment comment, { silent: true } - resetComments: (children) -> - @set 'children', [] - @set 'comments', new Comments() - for comment in (children || []) - @addComment comment, { silent: true } - - initialize: -> - DiscussionUtil.addContent @id, @ - @resetComments(@get('children')) - - -class @ContentView extends Backbone.View - - $: (selector) -> - @$local.find(selector) - - partial: - endorsed: (endorsed) -> - if endorsed - @$el.addClass("endorsed") - else - @$el.removeClass("endorsed") - - closed: (closed) -> # we should just re-render the whole thread, or update according to new abilities - if closed - @$el.addClass("closed") - @$(".admin-openclose").text "Re-open Thread" - else - @$el.removeClass("closed") - @$(".admin-openclose").text "Close Thread" - - voted: (voted) -> - @$(".discussion-vote-up").removeClass("voted") if voted != "up" - @$(".discussion-vote-down").removeClass("voted") if voted != "down" - @$(".discussion-vote-#{voted}").addClass("voted") if voted in ["up", "down"] - - votes_point: (votes_point) -> - @$(".discussion-votes-point").html(votes_point) - - comments_count: (comments_count) -> - @$(".comments-count").html(comments_count) + initialize: -> + DiscussionUtil.addContent @id, @ + @resetComments(@get('children')) - subscribed: (subscribed) -> - if subscribed - @$(".discussion-follow-thread").addClass("discussion-unfollow-thread").html("Unfollow") + + class @ContentView extends Backbone.View + + $: (selector) -> + @$local.find(selector) + + partial: + endorsed: (endorsed) -> + if endorsed + @$el.addClass("endorsed") + else + @$el.removeClass("endorsed") + + closed: (closed) -> # we should just re-render the whole thread, or update according to new abilities + if closed + @$el.addClass("closed") + @$(".admin-openclose").text "Re-open Thread" + else + @$el.removeClass("closed") + @$(".admin-openclose").text "Close Thread" + + voted: (voted) -> + @$(".discussion-vote-up").removeClass("voted") if voted != "up" + @$(".discussion-vote-down").removeClass("voted") if voted != "down" + @$(".discussion-vote-#{voted}").addClass("voted") if voted in ["up", "down"] + + votes_point: (votes_point) -> + @$(".discussion-votes-point").html(votes_point) + + comments_count: (comments_count) -> + @$(".comments-count").html(comments_count) + + subscribed: (subscribed) -> + if subscribed + @$(".discussion-follow-thread").addClass("discussion-unfollow-thread").html("Unfollow") + else + @$(".discussion-follow-thread").removeClass("discussion-unfollow-thread").html("Follow") + + ability: (ability) -> + for action, elemSelector of @model.actions + if not ability[action] + @$(elemSelector).parent().remove() + + $discussionContent: -> + @_discussionContent ||= @$el.children(".discussion-content") + + $showComments: -> + @_showComments ||= @$(".discussion-show-comments") + + updateShowComments: -> + if @showed + @$showComments().html @$showComments().html().replace "Show", "Hide" else - @$(".discussion-follow-thread").removeClass("discussion-unfollow-thread").html("Follow") + @$showComments().html @$showComments().html().replace "Hide", "Show" - ability: (ability) -> - for action, elemSelector of @model.actions - if not ability[action] - @$(elemSelector).parent().remove() - - $discussionContent: -> - @_discussionContent ||= @$el.children(".discussion-content") - - $showComments: -> - @_showComments ||= @$(".discussion-show-comments") - - updateShowComments: -> - if @showed - @$showComments().html @$showComments().html().replace "Show", "Hide" - else - @$showComments().html @$showComments().html().replace "Hide", "Show" - - retrieved: -> - @$showComments().hasClass("retrieved") - - hideSingleThread: (event) -> - @$el.children(".comments").hide() - @showed = false - @updateShowComments() - - showSingleThread: (event) -> - if @retrieved() - @$el.children(".comments").show() - @showed = true + retrieved: -> + @$showComments().hasClass("retrieved") + + hideSingleThread: (event) -> + @$el.children(".comments").hide() + @showed = false @updateShowComments() - else - $elem = $.merge @$(".thread-title"), @$showComments() - url = @model.urlFor('retrieve') - DiscussionUtil.get $elem, url, {}, (response, textStatus) => + + showSingleThread: (event) -> + if @retrieved() + @$el.children(".comments").show() @showed = true @updateShowComments() - @$showComments().addClass("retrieved") - @$el.children(".comments").replaceWith response.html - @model.resetComments response.content.children - @initCommentViews() - DiscussionUtil.bulkUpdateContentInfo response.annotated_content_info - - toggleSingleThread: (event) -> - if @showed - @hideSingleThread(event) - else - @showSingleThread(event) - - initCommentViews: -> - @$el.children(".comments").children(".comment").each (index, elem) => - model = @model.get('comments').find $(elem).attr("_id") - if not model.view - commentView = new CommentView el: elem, model: model - - reply: -> - if @model.get('type') == 'thread' - @showSingleThread() - $replyView = @$(".discussion-reply-new") - if $replyView.length - $replyView.show() - else - view = {} - view.id = @model.id - view.showWatchCheckbox = not @model.get('thread').get('subscribed') - html = Mustache.render DiscussionUtil.getTemplate('_reply'), view - @$discussionContent().append html - DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "reply-body" - @$(".discussion-submit-post").click $.proxy(@submitReply, @) - @$(".discussion-cancel-post").click $.proxy(@cancelReply, @) - @$(".discussion-reply").hide() - @$(".discussion-edit").hide() - - submitReply: (event) -> - url = @model.urlFor('reply') - - body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "reply-body" - - anonymous = false || @$(".discussion-post-anonymously").is(":checked") - autowatch = false || @$(".discussion-auto-watch").is(":checked") - - DiscussionUtil.safeAjax - $elem: $(event.target) - url: url - type: "POST" - dataType: 'json' - data: - body: body - anonymous: anonymous - auto_subscribe: autowatch - error: DiscussionUtil.formErrorHandler @$(".discussion-errors") - success: (response, textStatus) => - DiscussionUtil.clearFormErrors @$(".discussion-errors") - $comment = $(response.html) - @$el.children(".comments").prepend $comment - DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "reply-body", "" - comment = @model.addComment response.content - commentView = new CommentView el: $comment[0], model: comment - comment.updateInfo response.annotated_content_info - @cancelReply() - - cancelReply: -> - $replyView = @$(".discussion-reply-new") - if $replyView.length - $replyView.hide() - @$(".discussion-reply").show() - @$(".discussion-edit").show() - - unvote: (event) -> - url = @model.urlFor('unvote') - $elem = @$(".discussion-vote") - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('voted', '') - @model.set('votes_point', response.votes.point) - - vote: (event, value) -> - url = @model.urlFor("#{value}vote") - $elem = @$(".discussion-vote") - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('voted', value) - @model.set('votes_point', response.votes.point) - - toggleVote: (event) -> - $elem = $(event.target) - value = $elem.attr("value") - if @model.get("voted") == value - @unvote(event) - else - @vote(event, value) - - toggleEndorse: (event) -> - $elem = $(event.target) - url = @model.urlFor('endorse') - endorsed = @model.get('endorsed') - data = { endorsed: not endorsed } - DiscussionUtil.post $elem, url, data, (response, textStatus) => - @model.set('endorsed', not endorsed) - - toggleFollow: (event) -> - $elem = $(event.target) - subscribed = @model.get('subscribed') - if subscribed - url = @model.urlFor('unfollow') - else - url = @model.urlFor('follow') - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('subscribed', not subscribed) - - toggleClosed: (event) -> - $elem = $(event.target) - url = @model.urlFor('close') - closed = @model.get('closed') - data = { closed: not closed } - DiscussionUtil.post $elem, url, data, (response, textStatus) => - @model.set('closed', not closed) - - edit: (event) -> - @$(".discussion-content-wrapper").hide() - $editView = @$(".discussion-content-edit") - if $editView.length - $editView.show() - else - view = {} - view.id = @model.id - if @model.get('type') == 'thread' - view.title = @$(".thread-raw-title").html() - view.body = @$(".thread-raw-body").html() - view.tags = @$(".thread-raw-tags").html() else - view.body = @$(".comment-raw-body").html() - @$discussionContent().append Mustache.render DiscussionUtil.getTemplate("_edit_#{@model.get('type')}"), view - Discussion.makeWmdEditor @$el, $.proxy(@$, @), "#{@model.get('type')}-body-edit" - @$(".thread-tags-edit").tagsInput DiscussionUtil.tagsInputOptions() - @$(".discussion-submit-update").unbind("click").click $.proxy(@submitEdit, @) - @$(".discussion-cancel-update").unbind("click").click $.proxy(@cancelEdit, @) + $elem = $.merge @$(".thread-title"), @$showComments() + url = @model.urlFor('retrieve') + DiscussionUtil.get $elem, url, {}, (response, textStatus) => + @showed = true + @updateShowComments() + @$showComments().addClass("retrieved") + @$el.children(".comments").replaceWith response.html + @model.resetComments response.content.children + @initCommentViews() + DiscussionUtil.bulkUpdateContentInfo response.annotated_content_info - submitEdit: (event) -> + toggleSingleThread: (event) -> + if @showed + @hideSingleThread(event) + else + @showSingleThread(event) + + initCommentViews: -> + @$el.children(".comments").children(".comment").each (index, elem) => + model = @model.get('comments').find $(elem).attr("_id") + if not model.view + commentView = new CommentView el: elem, model: model - url = @model.urlFor('update') - data = {} - if @model.get('type') == 'thread' - data.title = @$(".thread-title-edit").val() - data.body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "thread-body-edit" - data.tags = @$(".thread-tags-edit").val() - else - data.body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "comment-body-edit" - DiscussionUtil.safeAjax - $elem: $(event.target) - url: url - type: "POST" - dataType: 'json' - data: data - error: DiscussionUtil.formErrorHandler @$(".discussion-update-errors") - success: (response, textStatus) => - DiscussionUtil.clearFormErrors @$(".discussion-update-errors") - @$discussionContent().replaceWith(response.html) - @model.set response.content - @model.updateInfo response.annotated_content_info + reply: -> + if @model.get('type') == 'thread' + @showSingleThread() + $replyView = @$(".discussion-reply-new") + if $replyView.length + $replyView.show() + else + view = {} + view.id = @model.id + view.showWatchCheckbox = not @model.get('thread').get('subscribed') + html = Mustache.render DiscussionUtil.getTemplate('_reply'), view + @$discussionContent().append html + DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "reply-body" + @$(".discussion-submit-post").click $.proxy(@submitReply, @) + @$(".discussion-cancel-post").click $.proxy(@cancelReply, @) + @$(".discussion-reply").hide() + @$(".discussion-edit").hide() - cancelEdit: (event) -> - @$(".discussion-content-edit").hide() - @$(".discussion-content-wrapper").show() + submitReply: (event) -> + url = @model.urlFor('reply') - delete: (event) -> - url = @model.urlFor('delete') - if @model.get('type') == 'thread' - c = confirm "Are you sure to delete thread \"#{@model.get('title')}\"?" - else - c = confirm "Are you sure to delete this comment? " - if not c - return - $elem = $(event.target) - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @$el.remove() - @model.get('thread').removeComment(@model) + body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "reply-body" + + anonymous = false || @$(".discussion-post-anonymously").is(":checked") + autowatch = false || @$(".discussion-auto-watch").is(":checked") + + DiscussionUtil.safeAjax + $elem: $(event.target) + url: url + type: "POST" + dataType: 'json' + data: + body: body + anonymous: anonymous + auto_subscribe: autowatch + error: DiscussionUtil.formErrorHandler @$(".discussion-errors") + success: (response, textStatus) => + DiscussionUtil.clearFormErrors @$(".discussion-errors") + $comment = $(response.html) + @$el.children(".comments").prepend $comment + DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "reply-body", "" + comment = @model.addComment response.content + commentView = new CommentView el: $comment[0], model: comment + comment.updateInfo response.annotated_content_info + @cancelReply() + + cancelReply: -> + $replyView = @$(".discussion-reply-new") + if $replyView.length + $replyView.hide() + @$(".discussion-reply").show() + @$(".discussion-edit").show() + + unvote: (event) -> + url = @model.urlFor('unvote') + $elem = @$(".discussion-vote") + DiscussionUtil.post $elem, url, {}, (response, textStatus) => + @model.set('voted', '') + @model.set('votes_point', response.votes.point) + + vote: (event, value) -> + url = @model.urlFor("#{value}vote") + $elem = @$(".discussion-vote") + DiscussionUtil.post $elem, url, {}, (response, textStatus) => + @model.set('voted', value) + @model.set('votes_point', response.votes.point) + + toggleVote: (event) -> + $elem = $(event.target) + value = $elem.attr("value") + if @model.get("voted") == value + @unvote(event) + else + @vote(event, value) + + toggleEndorse: (event) -> + $elem = $(event.target) + url = @model.urlFor('endorse') + endorsed = @model.get('endorsed') + data = { endorsed: not endorsed } + DiscussionUtil.post $elem, url, data, (response, textStatus) => + @model.set('endorsed', not endorsed) + + toggleFollow: (event) -> + $elem = $(event.target) + subscribed = @model.get('subscribed') + if subscribed + url = @model.urlFor('unfollow') + else + url = @model.urlFor('follow') + DiscussionUtil.post $elem, url, {}, (response, textStatus) => + @model.set('subscribed', not subscribed) + + toggleClosed: (event) -> + $elem = $(event.target) + url = @model.urlFor('close') + closed = @model.get('closed') + data = { closed: not closed } + DiscussionUtil.post $elem, url, data, (response, textStatus) => + @model.set('closed', not closed) + + edit: (event) -> + @$(".discussion-content-wrapper").hide() + $editView = @$(".discussion-content-edit") + if $editView.length + $editView.show() + else + view = {} + view.id = @model.id + if @model.get('type') == 'thread' + view.title = @$(".thread-raw-title").html() + view.body = @$(".thread-raw-body").html() + view.tags = @$(".thread-raw-tags").html() + else + view.body = @$(".comment-raw-body").html() + @$discussionContent().append Mustache.render DiscussionUtil.getTemplate("_edit_#{@model.get('type')}"), view + Discussion.makeWmdEditor @$el, $.proxy(@$, @), "#{@model.get('type')}-body-edit" + @$(".thread-tags-edit").tagsInput DiscussionUtil.tagsInputOptions() + @$(".discussion-submit-update").unbind("click").click $.proxy(@submitEdit, @) + @$(".discussion-cancel-update").unbind("click").click $.proxy(@cancelEdit, @) + + submitEdit: (event) -> + + url = @model.urlFor('update') + data = {} + if @model.get('type') == 'thread' + data.title = @$(".thread-title-edit").val() + data.body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "thread-body-edit" + data.tags = @$(".thread-tags-edit").val() + else + data.body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "comment-body-edit" + DiscussionUtil.safeAjax + $elem: $(event.target) + url: url + type: "POST" + dataType: 'json' + data: data + error: DiscussionUtil.formErrorHandler @$(".discussion-update-errors") + success: (response, textStatus) => + DiscussionUtil.clearFormErrors @$(".discussion-update-errors") + @$discussionContent().replaceWith(response.html) + @model.set response.content + @model.updateInfo response.annotated_content_info + + cancelEdit: (event) -> + @$(".discussion-content-edit").hide() + @$(".discussion-content-wrapper").show() + + delete: (event) -> + url = @model.urlFor('delete') + if @model.get('type') == 'thread' + c = confirm "Are you sure to delete thread \"#{@model.get('title')}\"?" + else + c = confirm "Are you sure to delete this comment? " + if not c + return + $elem = $(event.target) + DiscussionUtil.post $elem, url, {}, (response, textStatus) => + @$el.remove() + @model.get('thread').removeComment(@model) + + events: + "click .discussion-follow-thread": "toggleFollow" + "click .thread-title": "toggleSingleThread" + "click .discussion-show-comments": "toggleSingleThread" + "click .discussion-reply-thread": "reply" + "click .discussion-reply-comment": "reply" + "click .discussion-cancel-reply": "cancelReply" + "click .discussion-vote-up": "toggleVote" + "click .discussion-vote-down": "toggleVote" + "click .admin-endorse": "toggleEndorse" + "click .admin-openclose": "toggleClosed" + "click .admin-edit": "edit" + "click .admin-delete": "delete" + + initLocal: -> + @$local = @$el.children(".local") + @$delegateElement = @$local + + initTitle: -> + $contentTitle = @$(".thread-title") + if $contentTitle.length + $contentTitle.html DiscussionUtil.unescapeHighlightTag DiscussionUtil.stripLatexHighlight $contentTitle.html() + + initBody: -> + $contentBody = @$(".content-body") + $contentBody.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight $contentBody.html() + MathJax.Hub.Queue ["Typeset", MathJax.Hub, $contentBody.attr("id")] + + initTimeago: -> + @$("span.timeago").timeago() + + initPermalink: -> + @$(".discussion-permanent-link").attr "href", @model.permalink() + + renderPartial: -> + for attr, value of @model.changedAttributes() + if @partial[attr] + @partial[attr].apply(@, [value]) + + initBindings: -> + @model.view = @ + @model.bind('change', @renderPartial, @) + + initialize: -> + @initBindings() + @initLocal() + @initTimeago() + @initTitle() + @initBody() + @initCommentViews() - events: - "click .discussion-follow-thread": "toggleFollow" - "click .thread-title": "toggleSingleThread" - "click .discussion-show-comments": "toggleSingleThread" - "click .discussion-reply-thread": "reply" - "click .discussion-reply-comment": "reply" - "click .discussion-cancel-reply": "cancelReply" - "click .discussion-vote-up": "toggleVote" - "click .discussion-vote-down": "toggleVote" - "click .admin-endorse": "toggleEndorse" - "click .admin-openclose": "toggleClosed" - "click .admin-edit": "edit" - "click .admin-delete": "delete" + class @Thread extends @Content + urlMappers: + 'retrieve' : -> DiscussionUtil.urlFor('retrieve_single_thread', @discussion.id, @id) + 'reply' : -> DiscussionUtil.urlFor('create_comment', @id) + 'unvote' : -> DiscussionUtil.urlFor("undo_vote_for_#{@get('type')}", @id) + 'upvote' : -> DiscussionUtil.urlFor("upvote_#{@get('type')}", @id) + 'downvote' : -> DiscussionUtil.urlFor("downvote_#{@get('type')}", @id) + 'close' : -> DiscussionUtil.urlFor('openclose_thread', @id) + 'update' : -> DiscussionUtil.urlFor('update_thread', @id) + 'delete' : -> DiscussionUtil.urlFor('delete_thread', @id) + 'follow' : -> DiscussionUtil.urlFor('follow_thread', @id) + 'unfollow' : -> DiscussionUtil.urlFor('unfollow_thread', @id) - initLocal: -> - @$local = @$el.children(".local") - @$delegateElement = @$local + initialize: -> + @set('thread', @) + super() - initTitle: -> - $contentTitle = @$(".thread-title") - if $contentTitle.length - $contentTitle.html DiscussionUtil.unescapeHighlightTag DiscussionUtil.stripLatexHighlight $contentTitle.html() + permalink: -> + discussion_id = @get('commentable_id') + return Discussion.urlFor("permanent_link_thread", discussion_id, @id) - initBody: -> - $contentBody = @$(".content-body") - $contentBody.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight $contentBody.html() - MathJax.Hub.Queue ["Typeset", MathJax.Hub, $contentBody.attr("id")] + class @ThreadView extends @ContentView - initTimeago: -> - @$("span.timeago").timeago() + class @Comment extends @Content + urlMappers: + 'reply': -> DiscussionUtil.urlFor('create_sub_comment', @id) + 'unvote': -> DiscussionUtil.urlFor("undo_vote_for_#{@get('type')}", @id) + 'upvote': -> DiscussionUtil.urlFor("upvote_#{@get('type')}", @id) + 'downvote': -> DiscussionUtil.urlFor("downvote_#{@get('type')}", @id) + 'endorse': -> DiscussionUtil.urlFor('endorse_comment', @id) + 'update': -> DiscussionUtil.urlFor('update_comment', @id) + 'delete': -> DiscussionUtil.urlFor('delete_comment', @id) - initPermalink: -> - @$(".discussion-permanent-link").attr "href", @model.permalink() + permalink: -> + thread_id = @get('thread').id + discussion_id = @get('thread').get('commentable_id') + return Discussion.urlFor("permanent_link_comment", discussion_id, thread_id, @id) - renderPartial: -> - for attr, value of @model.changedAttributes() - if @partial[attr] - @partial[attr].apply(@, [value]) + getCommentsCount: -> + count = 0 + @get('comments').each (comment) -> + count += comment.getCommentsCount() + 1 + count - initBindings: -> - @model.view = @ - @model.bind('change', @renderPartial, @) + class @CommentView extends @ContentView - initialize: -> - @initBindings() - @initLocal() - @initTimeago() - @initTitle() - @initBody() - @initCommentViews() - -class @Thread extends @Content - urlMappers: - 'retrieve' : -> DiscussionUtil.urlFor('retrieve_single_thread', @discussion.id, @id) - 'reply' : -> DiscussionUtil.urlFor('create_comment', @id) - 'unvote' : -> DiscussionUtil.urlFor("undo_vote_for_#{@get('type')}", @id) - 'upvote' : -> DiscussionUtil.urlFor("upvote_#{@get('type')}", @id) - 'downvote' : -> DiscussionUtil.urlFor("downvote_#{@get('type')}", @id) - 'close' : -> DiscussionUtil.urlFor('openclose_thread', @id) - 'update' : -> DiscussionUtil.urlFor('update_thread', @id) - 'delete' : -> DiscussionUtil.urlFor('delete_thread', @id) - 'follow' : -> DiscussionUtil.urlFor('follow_thread', @id) - 'unfollow' : -> DiscussionUtil.urlFor('unfollow_thread', @id) + class @Comments extends Backbone.Collection - initialize: -> - @set('thread', @) - super() + model: Comment - permalink: -> - discussion_id = @get('commentable_id') - return Discussion.urlFor("permanent_link_thread", discussion_id, @id) + initialize: -> + @bind "add", (item) => + item.collection = @ -class @ThreadView extends @ContentView - -class @Comment extends @Content - urlMappers: - 'reply': -> DiscussionUtil.urlFor('create_sub_comment', @id) - 'unvote': -> DiscussionUtil.urlFor("undo_vote_for_#{@get('type')}", @id) - 'upvote': -> DiscussionUtil.urlFor("upvote_#{@get('type')}", @id) - 'downvote': -> DiscussionUtil.urlFor("downvote_#{@get('type')}", @id) - 'endorse': -> DiscussionUtil.urlFor('endorse_comment', @id) - 'update': -> DiscussionUtil.urlFor('update_comment', @id) - 'delete': -> DiscussionUtil.urlFor('delete_comment', @id) - - permalink: -> - thread_id = @get('thread').id - discussion_id = @get('thread').get('commentable_id') - return Discussion.urlFor("permanent_link_comment", discussion_id, thread_id, @id) - - getCommentsCount: -> - count = 0 - @get('comments').each (comment) -> - count += comment.getCommentsCount() + 1 - count - -class @CommentView extends @ContentView - -class @Comments extends Backbone.Collection - - model: Comment - - initialize: -> - @bind "add", (item) => - item.collection = @ - - find: (id) -> - _.first @where(id: id) + find: (id) -> + _.first @where(id: id) diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 4764784789..0b6c59964b 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -1,168 +1,169 @@ -class @Discussion extends Backbone.Collection - model: Thread +if Backbone? + class @Discussion extends Backbone.Collection + model: Thread - initialize: -> - DiscussionUtil.addDiscussion @id, @ - @bind "add", (item) => - item.discussion = @ + initialize: -> + DiscussionUtil.addDiscussion @id, @ + @bind "add", (item) => + item.discussion = @ - find: (id) -> - _.first @where(id: id) + find: (id) -> + _.first @where(id: id) - addThread: (thread, options) -> - options ||= {} - model = new Thread thread - @add model - model + addThread: (thread, options) -> + options ||= {} + model = new Thread thread + @add model + model -class @DiscussionView extends Backbone.View + class @DiscussionView extends Backbone.View - $: (selector) -> - @$local.find(selector) + $: (selector) -> + @$local.find(selector) - initLocal: -> - @$local = @$el.children(".local") - @$delegateElement = @$local + initLocal: -> + @$local = @$el.children(".local") + @$delegateElement = @$local - initialize: -> - @initLocal() - @model.id = @$el.attr("_id") - @model.view = @ - @$el.children(".threads").children(".thread").each (index, elem) => - threadView = new ThreadView el: elem, model: @model.find $(elem).attr("_id") - if @$el.hasClass("forum-discussion") - $(".discussion-sidebar").find(".sidebar-new-post-button") - .unbind('click').click $.proxy @newPost, @ - else if @$el.hasClass("inline-discussion") - @newPost() + initialize: -> + @initLocal() + @model.id = @$el.attr("_id") + @model.view = @ + @$el.children(".threads").children(".thread").each (index, elem) => + threadView = new ThreadView el: elem, model: @model.find $(elem).attr("_id") + if @$el.hasClass("forum-discussion") + $(".discussion-sidebar").find(".sidebar-new-post-button") + .unbind('click').click $.proxy @newPost, @ + else if @$el.hasClass("inline-discussion") + @newPost() - reload: ($elem, url) -> - if not url then return - DiscussionUtil.get $elem, url, {}, (response, textStatus) => - $parent = @$el.parent() - @$el.replaceWith(response.html) - $discussion = $parent.find("section.discussion") - @model.reset(response.discussionData, { silent: false }) - view = new DiscussionView el: $discussion[0], model: @model - DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) - $("html, body").animate({ scrollTop: 0 }, 0) + reload: ($elem, url) -> + if not url then return + DiscussionUtil.get $elem, url, {}, (response, textStatus) => + $parent = @$el.parent() + @$el.replaceWith(response.html) + $discussion = $parent.find("section.discussion") + @model.reset(response.discussionData, { silent: false }) + view = new DiscussionView el: $discussion[0], model: @model + DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + $("html, body").animate({ scrollTop: 0 }, 0) - loadSimilarPost: (event) -> - $title = @$(".new-post-title") - $wrapper = @$(".new-post-similar-posts-wrapper") - $similarPosts = @$(".new-post-similar-posts") - prevText = $title.attr("prev-text") - text = $title.val() - if text == prevText - if @$(".similar-post").length - $wrapper.show() - else if $.trim(text).length - $elem = $(event.target) - url = DiscussionUtil.urlFor 'search_similar_threads', @model.id - data = { text: @$(".new-post-title").val() } - DiscussionUtil.get $elem, url, data, (response, textStatus) => - $similarPosts.empty() - if $.type(response) == "array" and response.length + loadSimilarPost: (event) -> + $title = @$(".new-post-title") + $wrapper = @$(".new-post-similar-posts-wrapper") + $similarPosts = @$(".new-post-similar-posts") + prevText = $title.attr("prev-text") + text = $title.val() + if text == prevText + if @$(".similar-post").length $wrapper.show() - for thread in response - $similarPost = $("").addClass("similar-post") - .html(thread["title"]) - .attr("href", "javascript:void(0)") #TODO - .appendTo($similarPosts) - else - $wrapper.hide() - else - $wrapper.hide() - $title.attr("prev-text", text) + else if $.trim(text).length + $elem = $(event.target) + url = DiscussionUtil.urlFor 'search_similar_threads', @model.id + data = { text: @$(".new-post-title").val() } + DiscussionUtil.get $elem, url, data, (response, textStatus) => + $similarPosts.empty() + if $.type(response) == "array" and response.length + $wrapper.show() + for thread in response + $similarPost = $("").addClass("similar-post") + .html(thread["title"]) + .attr("href", "javascript:void(0)") #TODO + .appendTo($similarPosts) + else + $wrapper.hide() + else + $wrapper.hide() + $title.attr("prev-text", text) - newPost: -> - if not @$(".wmd-panel").length - view = { discussion_id: @model.id } - @$el.children(".discussion-non-content").append Mustache.render DiscussionUtil.getTemplate("_new_post"), view - $newPostBody = @$(".new-post-body") - DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "new-post-body" + newPost: -> + if not @$(".wmd-panel").length + view = { discussion_id: @model.id } + @$el.children(".discussion-non-content").append Mustache.render DiscussionUtil.getTemplate("_new_post"), view + $newPostBody = @$(".new-post-body") + DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "new-post-body" - $input = DiscussionUtil.getWmdInput @$el, $.proxy(@$, @), "new-post-body" - $input.attr("placeholder", "post a new topic...") - if @$el.hasClass("inline-discussion") - $input.bind 'focus', (e) => + $input = DiscussionUtil.getWmdInput @$el, $.proxy(@$, @), "new-post-body" + $input.attr("placeholder", "post a new topic...") + if @$el.hasClass("inline-discussion") + $input.bind 'focus', (e) => + @$(".new-post-form").removeClass('collapsed') + else if @$el.hasClass("forum-discussion") @$(".new-post-form").removeClass('collapsed') - else if @$el.hasClass("forum-discussion") - @$(".new-post-form").removeClass('collapsed') - @$(".new-post-tags").tagsInput DiscussionUtil.tagsInputOptions() + @$(".new-post-tags").tagsInput DiscussionUtil.tagsInputOptions() - @$(".new-post-title").blur $.proxy(@loadSimilarPost, @) + @$(".new-post-title").blur $.proxy(@loadSimilarPost, @) - @$(".hide-similar-posts").click => - @$(".new-post-similar-posts-wrapper").hide() + @$(".hide-similar-posts").click => + @$(".new-post-similar-posts-wrapper").hide() - @$(".discussion-submit-post").click $.proxy(@submitNewPost, @) - @$(".discussion-cancel-post").click $.proxy(@cancelNewPost, @) - - - @$(".new-post-form").show() - - submitNewPost: (event) -> - title = @$(".new-post-title").val() - body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "new-post-body" - tags = @$(".new-post-tags").val() - anonymous = false || @$(".discussion-post-anonymously").is(":checked") - autowatch = false || @$(".discussion-auto-watch").is(":checked") - url = DiscussionUtil.urlFor('create_thread', @model.id) - DiscussionUtil.safeAjax - $elem: $(event.target) - url: url - type: "POST" - dataType: 'json' - data: - title: title - body: body - tags: tags - anonymous: anonymous - auto_subscribe: autowatch - error: DiscussionUtil.formErrorHandler(@$(".new-post-form-errors")) - success: (response, textStatus) => - DiscussionUtil.clearFormErrors(@$(".new-post-form-errors")) - $thread = $(response.html) - @$el.children(".threads").prepend($thread) - - @$(".new-post-title").val("") - DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "new-post-body", "" - @$(".new-post-tags").val("") - @$(".new-post-tags").importTags("") - - thread = @model.addThread response.content - threadView = new ThreadView el: $thread[0], model: thread - thread.updateInfo response.annotated_content_info - @cancelNewPost() + @$(".discussion-submit-post").click $.proxy(@submitNewPost, @) + @$(".discussion-cancel-post").click $.proxy(@cancelNewPost, @) - cancelNewPost: (event) -> - if @$el.hasClass("inline-discussion") - @$(".new-post-form").addClass("collapsed") - else if @$el.hasClass("forum-discussion") - @$(".new-post-form").hide() + @$(".new-post-form").show() - search: (event) -> - event.preventDefault() - $elem = $(event.target) - url = URI($elem.attr("action")).addSearch({text: @$(".search-input").val()}) - @reload($elem, url) + submitNewPost: (event) -> + title = @$(".new-post-title").val() + body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "new-post-body" + tags = @$(".new-post-tags").val() + anonymous = false || @$(".discussion-post-anonymously").is(":checked") + autowatch = false || @$(".discussion-auto-watch").is(":checked") + url = DiscussionUtil.urlFor('create_thread', @model.id) + DiscussionUtil.safeAjax + $elem: $(event.target) + url: url + type: "POST" + dataType: 'json' + data: + title: title + body: body + tags: tags + anonymous: anonymous + auto_subscribe: autowatch + error: DiscussionUtil.formErrorHandler(@$(".new-post-form-errors")) + success: (response, textStatus) => + DiscussionUtil.clearFormErrors(@$(".new-post-form-errors")) + $thread = $(response.html) + @$el.children(".threads").prepend($thread) - sort: -> - $elem = $(event.target) - url = $elem.attr("sort-url") - @reload($elem, url) + @$(".new-post-title").val("") + DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "new-post-body", "" + @$(".new-post-tags").val("") + @$(".new-post-tags").importTags("") - page: (event) -> - $elem = $(event.target) - url = $elem.attr("page-url") - @reload($elem, url) + thread = @model.addThread response.content + threadView = new ThreadView el: $thread[0], model: thread + thread.updateInfo response.annotated_content_info + @cancelNewPost() + - events: - "submit .search-wrapper>.discussion-search-form": "search" - "click .discussion-search-link": "search" - "click .discussion-sort-link": "sort" - "click .discussion-page-link": "page" + cancelNewPost: (event) -> + if @$el.hasClass("inline-discussion") + @$(".new-post-form").addClass("collapsed") + else if @$el.hasClass("forum-discussion") + @$(".new-post-form").hide() + + search: (event) -> + event.preventDefault() + $elem = $(event.target) + url = URI($elem.attr("action")).addSearch({text: @$(".search-input").val()}) + @reload($elem, url) + + sort: -> + $elem = $(event.target) + url = $elem.attr("sort-url") + @reload($elem, url) + + page: (event) -> + $elem = $(event.target) + url = $elem.attr("page-url") + @reload($elem, url) + + events: + "submit .search-wrapper>.discussion-search-form": "search" + "click .discussion-search-link": "search" + "click .discussion-sort-link": "sort" + "click .discussion-page-link": "page" diff --git a/lms/static/coffee/src/discussion/discussion_module.coffee b/lms/static/coffee/src/discussion/discussion_module.coffee index 38f44be1f1..0f3e306379 100644 --- a/lms/static/coffee/src/discussion/discussion_module.coffee +++ b/lms/static/coffee/src/discussion/discussion_module.coffee @@ -1,32 +1,33 @@ -class @DiscussionModuleView extends Backbone.View - events: - "click .discussion-show": "toggleDiscussion" - toggleDiscussion: (event) -> - if @showed - @$("section.discussion").hide() - $(event.target).html("Show Discussion") - @showed = false - else - if @retrieved - @$("section.discussion").show() - $(event.target).html("Hide Discussion") - @showed = true +if Backbone? + class @DiscussionModuleView extends Backbone.View + events: + "click .discussion-show": "toggleDiscussion" + toggleDiscussion: (event) -> + if @showed + @$("section.discussion").hide() + $(event.target).html("Show Discussion") + @showed = false else - $elem = $(event.target) - discussion_id = $elem.attr("discussion_id") - url = DiscussionUtil.urlFor 'retrieve_discussion', discussion_id - Discussion.safeAjax - $elem: $elem - url: url - type: "GET" - dataType: 'json' - success: (response, textStatus) => - @$el.append(response.html) - $discussion = @$el.find("section.discussion") - $(event.target).html("Hide Discussion") - discussion = new Discussion() - discussion.reset(response.discussionData, {silent: false}) - view = new DiscussionView(el: $discussion[0], model: discussion) - DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) - @retrieved = true - @showed = true + if @retrieved + @$("section.discussion").show() + $(event.target).html("Hide Discussion") + @showed = true + else + $elem = $(event.target) + discussion_id = $elem.attr("discussion_id") + url = DiscussionUtil.urlFor 'retrieve_discussion', discussion_id + Discussion.safeAjax + $elem: $elem + url: url + type: "GET" + dataType: 'json' + success: (response, textStatus) => + @$el.append(response.html) + $discussion = @$el.find("section.discussion") + $(event.target).html("Hide Discussion") + discussion = new Discussion() + discussion.reset(response.discussionData, {silent: false}) + view = new DiscussionView(el: $discussion[0], model: discussion) + DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + @retrieved = true + @showed = true diff --git a/lms/static/coffee/src/discussion/main.coffee b/lms/static/coffee/src/discussion/main.coffee index 2266e136ed..2f26211424 100644 --- a/lms/static/coffee/src/discussion/main.coffee +++ b/lms/static/coffee/src/discussion/main.coffee @@ -12,4 +12,5 @@ $ -> discussion.reset(discussionData, {silent: false}) view = new DiscussionView(el: elem, model: discussion) - DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + if window.$$annotated_content_info? + DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) From 007de179e1d6db76541062d98de7ddf738a284c3 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Wed, 22 Aug 2012 23:44:15 -0700 Subject: [PATCH 05/18] add user profile page back --- .../django_comment_client/base/views.py | 2 +- .../django_comment_client/forum/views.py | 7 ++- .../coffee/src/discussion/content.coffee | 2 +- lms/static/coffee/src/discussion/main.coffee | 5 ++ .../coffee/src/discussion/user_profile.coffee | 61 +++++++++---------- .../discussion/_content_renderer.html | 14 ++--- .../discussion/_user_active_threads.html | 8 +-- lms/templates/discussion/_user_profile.html | 6 +- .../discussion/mustache/_content.mustache | 2 +- lms/templates/discussion/user_profile.html | 6 +- 10 files changed, 58 insertions(+), 55 deletions(-) diff --git a/lms/djangoapps/django_comment_client/base/views.py b/lms/djangoapps/django_comment_client/base/views.py index ee293351c0..5b020b7601 100644 --- a/lms/djangoapps/django_comment_client/base/views.py +++ b/lms/djangoapps/django_comment_client/base/views.py @@ -282,7 +282,7 @@ def update_moderator_status(request, course_id, user_id): 'course_id': course_id, 'user': request.user, 'django_user': user, - 'discussion_user': discussion_user.to_dict(), + 'profiled_user': discussion_user.to_dict(), } return JsonResponse({ 'html': render_to_string('discussion/ajax_user_profile.html', context) diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/django_comment_client/forum/views.py index 592cb0a1d2..eda574cb6e 100644 --- a/lms/djangoapps/django_comment_client/forum/views.py +++ b/lms/djangoapps/django_comment_client/forum/views.py @@ -83,7 +83,7 @@ def render_discussion(request, course_id, threads, *args, **kwargs): 'base_url': base_url, 'query_params': strip_blank(strip_none(extract(query_params, ['page', 'sort_key', 'sort_order', 'tags', 'text']))), 'annotated_content_info': json.dumps(annotated_content_info), - 'discussion_data': json.dumps({ discussion_id: threads }), + 'discussion_data': json.dumps({ (discussion_id or user_id): threads }) } context = dict(context.items() + query_params.items()) return render_to_string(template, context) @@ -250,7 +250,10 @@ def user_profile(request, course_id, user_id): content = render_user_discussion(request, course_id, threads, user_id=user_id, query_params=query_params) if request.is_ajax(): - return utils.HtmlResponse(content) + return utils.JsonResponse({ + 'html': content, + 'discussionData': threads, + }) else: context = { 'course': course, diff --git a/lms/static/coffee/src/discussion/content.coffee b/lms/static/coffee/src/discussion/content.coffee index 69073e1890..a8caf3e392 100644 --- a/lms/static/coffee/src/discussion/content.coffee +++ b/lms/static/coffee/src/discussion/content.coffee @@ -257,7 +257,7 @@ if Backbone? else view.body = @$(".comment-raw-body").html() @$discussionContent().append Mustache.render DiscussionUtil.getTemplate("_edit_#{@model.get('type')}"), view - Discussion.makeWmdEditor @$el, $.proxy(@$, @), "#{@model.get('type')}-body-edit" + DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "#{@model.get('type')}-body-edit" @$(".thread-tags-edit").tagsInput DiscussionUtil.tagsInputOptions() @$(".discussion-submit-update").unbind("click").click $.proxy(@submitEdit, @) @$(".discussion-cancel-update").unbind("click").click $.proxy(@cancelEdit, @) diff --git a/lms/static/coffee/src/discussion/main.coffee b/lms/static/coffee/src/discussion/main.coffee index 2f26211424..023345c5da 100644 --- a/lms/static/coffee/src/discussion/main.coffee +++ b/lms/static/coffee/src/discussion/main.coffee @@ -14,3 +14,8 @@ $ -> if window.$$annotated_content_info? DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + + $userProfile = $(".discussion-sidebar>.user-profile") + if $userProfile.length + console.log "initialize user profile" + view = new DiscussionUserProfileView(el: $userProfile[0]) diff --git a/lms/static/coffee/src/discussion/user_profile.coffee b/lms/static/coffee/src/discussion/user_profile.coffee index 0cff708ae6..ed4f6ea988 100644 --- a/lms/static/coffee/src/discussion/user_profile.coffee +++ b/lms/static/coffee/src/discussion/user_profile.coffee @@ -1,34 +1,29 @@ -if not @Discussion? - @Discussion = {} +class @DiscussionUserProfileView extends Backbone.View + toggleModeratorStatus: (event) -> + confirmValue = confirm("Are you sure?") + if not confirmValue then return + $elem = $(event.target) + if $elem.hasClass("sidebar-promote-moderator-button") + isModerator = true + else if $elem.hasClass("sidebar-revoke-moderator-button") + isModerator = false + else + console.error "unrecognized moderator status" + return + url = DiscussionUtil.urlFor('update_moderator_status', $$profiled_user_id) + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" + dataType: 'json' + data: + is_moderator: isModerator + error: (response, textStatus, e) -> + console.log e + success: (response, textStatus) => + parent = @$el.parent() + @$el.replaceWith(response.html) + view = new DiscussionUserProfileView el: parent.children(".user-profile") -Discussion = @Discussion - -@Discussion = $.extend @Discussion, - initializeUserProfile: ($userProfile) -> - $local = Discussion.generateLocal $userProfile - - handleUpdateModeratorStatus = (elem, isModerator) -> - confirmValue = confirm("Are you sure?") - if not confirmValue then return - url = Discussion.urlFor('update_moderator_status', $$profiled_user_id) - Discussion.safeAjax - $elem: $(elem) - url: url - type: "POST" - dataType: 'json' - data: - is_moderator: isModerator - error: (response, textStatus, e) -> - console.log e - success: (response, textStatus) -> - parent = $userProfile.parent() - $userProfile.replaceWith(response.html) - Discussion.initializeUserProfile parent.children(".user-profile") - - Discussion.bindLocalEvents $local, - "click .sidebar-revoke-moderator-button": (event) -> - handleUpdateModeratorStatus(this, false) - "click .sidebar-promote-moderator-button": (event) -> - handleUpdateModeratorStatus(this, true) - - initializeUserActiveDiscussion: ($discussion) -> + events: + "click .sidebar-toggle-moderator-button": "toggleModeratorStatus" diff --git a/lms/templates/discussion/_content_renderer.html b/lms/templates/discussion/_content_renderer.html index f81fdb612c..54371bf4dd 100644 --- a/lms/templates/discussion/_content_renderer.html +++ b/lms/templates/discussion/_content_renderer.html @@ -1,20 +1,20 @@ <%! import django_comment_client.helpers as helpers %> -<%def name="render_content(content)"> - ${helpers.render_content(content)} +<%def name="render_content(content, *args, **kwargs)"> + ${helpers.render_content(content, *args, **kwargs)} -<%def name="render_content_with_comments(content)"> +<%def name="render_content_with_comments(content, *args, **kwargs)">
- ${render_content(content)} - ${render_comments(content.get('children', []))} + ${render_content(content, *args, **kwargs)} + ${render_comments(content.get('children', []), *args, **kwargs)}
-<%def name="render_comments(comments)"> +<%def name="render_comments(comments, *args, **kwargs)">
% for comment in comments: - ${render_content_with_comments(comment)} + ${render_content_with_comments(comment, *args, **kwargs)} % endfor
diff --git a/lms/templates/discussion/_user_active_threads.html b/lms/templates/discussion/_user_active_threads.html index c3f5d0c403..ad72ccdd5e 100644 --- a/lms/templates/discussion/_user_active_threads.html +++ b/lms/templates/discussion/_user_active_threads.html @@ -1,12 +1,12 @@ -<%namespace name="renderer" file="_thread.html"/> +<%namespace name="renderer" file="_content_renderer.html"/> -
+
-
+
% for thread in threads: - ${renderer.render_thread(course_id, thread, show_comments=True)} + ${renderer.render_content_with_comments(thread, {'partial_comments': True})} % endfor
diff --git a/lms/templates/discussion/_user_profile.html b/lms/templates/discussion/_user_profile.html index 6d7bc13e8c..a092a97951 100644 --- a/lms/templates/discussion/_user_profile.html +++ b/lms/templates/discussion/_user_profile.html @@ -1,4 +1,4 @@ -<%! from django_comment_client.utils import pluralize %> +<%! from django_comment_client.helpers import pluralize %> <%! from django_comment_client.permissions import has_permission, check_permissions_by_view %> <%! from operator import attrgetter %> @@ -15,9 +15,9 @@ % if check_permissions_by_view(user, course.id, content=None, name='update_moderator_status'): % if "Moderator" in role_names: -
Revoke Moderator provileges + Revoke Moderator provileges % else: - Promote to Moderator + Promote to Moderator % endif % endif diff --git a/lms/templates/discussion/mustache/_content.mustache b/lms/templates/discussion/mustache/_content.mustache index f65270a967..34926b57b5 100644 --- a/lms/templates/discussion/mustache/_content.mustache +++ b/lms/templates/discussion/mustache/_content.mustache @@ -37,7 +37,7 @@ anonymous {{/content.anonymous}} {{^content.anonymous}} - {{content.username}} + {{content.username}} {{/content.anonymous}}
diff --git a/lms/templates/discussion/user_profile.html b/lms/templates/discussion/user_profile.html index c4d0d85607..e5234abca3 100644 --- a/lms/templates/discussion/user_profile.html +++ b/lms/templates/discussion/user_profile.html @@ -1,5 +1,4 @@ <%! from django.template.defaultfilters import escapejs %> -<%namespace name="renderer" file="_thread.html"/> <%inherit file="../main.html" /> <%namespace name='static' file='../static_content.html'/> @@ -8,13 +7,14 @@ <%block name="headextra"> <%static:css group='course'/> +<%include file="_js_head_dependencies.html" /> <%block name="js_extra"> -<%include file="_js_dependencies.html" /> +<%include file="_js_body_dependencies.html" /> -<%include file="/courseware/course_navigation.html" args="active_page='discussion'" /> +<%include file="../courseware/course_navigation.html" args="active_page='discussion'" />
From 74bc23294665dda64d900d5dd114b405c28e2cc0 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Thu, 23 Aug 2012 00:07:57 -0700 Subject: [PATCH 06/18] fixed discussion title and edit --- lms/templates/discussion/index.html | 2 +- lms/templates/discussion/single_thread.html | 2 +- lms/templates/discussion/user_profile.html | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lms/templates/discussion/index.html b/lms/templates/discussion/index.html index d8a2607944..af564cabe3 100644 --- a/lms/templates/discussion/index.html +++ b/lms/templates/discussion/index.html @@ -1,7 +1,7 @@ <%inherit file="../main.html" /> <%namespace name='static' file='../static_content.html'/> <%block name="bodyclass">discussion -<%block name="title">Discussion – MITx 6.002x +<%block name="title">Discussion – ${course.number} <%block name="headextra"> <%static:css group='course'/> diff --git a/lms/templates/discussion/single_thread.html b/lms/templates/discussion/single_thread.html index 3a03c9174a..111f35cac9 100644 --- a/lms/templates/discussion/single_thread.html +++ b/lms/templates/discussion/single_thread.html @@ -1,7 +1,7 @@ <%inherit file="../main.html" /> <%namespace name='static' file='../static_content.html'/> <%block name="bodyclass">discussion -<%block name="title">Discussion – MITx 6.002x +<%block name="title">Discussion – ${course.number} <%block name="headextra"> <%static:css group='course'/> diff --git a/lms/templates/discussion/user_profile.html b/lms/templates/discussion/user_profile.html index e5234abca3..1bc6addffc 100644 --- a/lms/templates/discussion/user_profile.html +++ b/lms/templates/discussion/user_profile.html @@ -3,7 +3,7 @@ <%inherit file="../main.html" /> <%namespace name='static' file='../static_content.html'/> <%block name="bodyclass">discussion -<%block name="title">Discussion – MITx 6.002x +<%block name="title">Discussion – ${course.number} <%block name="headextra"> <%static:css group='course'/> @@ -12,6 +12,7 @@ <%block name="js_extra"> <%include file="_js_body_dependencies.html" /> +<%static:js group='discussion'/> <%include file="../courseware/course_navigation.html" args="active_page='discussion'" /> From abe12ddd7c284a2f914d48b346e564f92343adea Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Thu, 23 Aug 2012 01:47:47 -0700 Subject: [PATCH 07/18] display loading status --- .../coffee/src/discussion/content.coffee | 78 ++++++++++++------ .../coffee/src/discussion/discussion.coffee | 22 +++-- lms/static/coffee/src/discussion/utils.coffee | 16 +++- lms/static/images/discussion/loading.gif | Bin 0 -> 809 bytes lms/static/sass/_discussion.scss | 8 ++ 5 files changed, 92 insertions(+), 32 deletions(-) create mode 100644 lms/static/images/discussion/loading.gif diff --git a/lms/static/coffee/src/discussion/content.coffee b/lms/static/coffee/src/discussion/content.coffee index a8caf3e392..e691365f83 100644 --- a/lms/static/coffee/src/discussion/content.coffee +++ b/lms/static/coffee/src/discussion/content.coffee @@ -120,14 +120,19 @@ if Backbone? else $elem = $.merge @$(".thread-title"), @$showComments() url = @model.urlFor('retrieve') - DiscussionUtil.get $elem, url, {}, (response, textStatus) => - @showed = true - @updateShowComments() - @$showComments().addClass("retrieved") - @$el.children(".comments").replaceWith response.html - @model.resetComments response.content.children - @initCommentViews() - DiscussionUtil.bulkUpdateContentInfo response.annotated_content_info + DiscussionUtil.safeAjax + $elem: $elem + $loading: $(event.target) if event + type: "GET" + url: url + success: (response, textStatus) => + @showed = true + @updateShowComments() + @$showComments().addClass("retrieved") + @$el.children(".comments").replaceWith response.html + @model.resetComments response.content.children + @initCommentViews() + DiscussionUtil.bulkUpdateContentInfo response.annotated_content_info toggleSingleThread: (event) -> if @showed @@ -169,6 +174,7 @@ if Backbone? DiscussionUtil.safeAjax $elem: $(event.target) + $loading: $(event.target) if event url: url type: "POST" dataType: 'json' @@ -197,16 +203,24 @@ if Backbone? unvote: (event) -> url = @model.urlFor('unvote') $elem = @$(".discussion-vote") - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('voted', '') - @model.set('votes_point', response.votes.point) + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" + success: (response, textStatus) => + @model.set('voted', '') + @model.set('votes_point', response.votes.point) vote: (event, value) -> url = @model.urlFor("#{value}vote") $elem = @$(".discussion-vote") - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('voted', value) - @model.set('votes_point', response.votes.point) + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" + success: (response, textStatus) => + @model.set('voted', value) + @model.set('votes_point', response.votes.point) toggleVote: (event) -> $elem = $(event.target) @@ -221,8 +235,13 @@ if Backbone? url = @model.urlFor('endorse') endorsed = @model.get('endorsed') data = { endorsed: not endorsed } - DiscussionUtil.post $elem, url, data, (response, textStatus) => - @model.set('endorsed', not endorsed) + DiscussionUtil.safeAjax + $elem: $elem + url: url + data: data + type: "POST" + success: (response, textStatus) => + @model.set('endorsed', not endorsed) toggleFollow: (event) -> $elem = $(event.target) @@ -231,16 +250,25 @@ if Backbone? url = @model.urlFor('unfollow') else url = @model.urlFor('follow') - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @model.set('subscribed', not subscribed) + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" + success: (response, textStatus) => + @model.set('subscribed', not subscribed) toggleClosed: (event) -> $elem = $(event.target) url = @model.urlFor('close') closed = @model.get('closed') data = { closed: not closed } - DiscussionUtil.post $elem, url, data, (response, textStatus) => - @model.set('closed', not closed) + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" + data: data + success: (response, textStatus) => + @model.set('closed', not closed) edit: (event) -> @$(".discussion-content-wrapper").hide() @@ -274,6 +302,7 @@ if Backbone? data.body = DiscussionUtil.getWmdContent @$el, $.proxy(@$, @), "comment-body-edit" DiscussionUtil.safeAjax $elem: $(event.target) + $loading: $(event.target) if event url: url type: "POST" dataType: 'json' @@ -298,9 +327,12 @@ if Backbone? if not c return $elem = $(event.target) - DiscussionUtil.post $elem, url, {}, (response, textStatus) => - @$el.remove() - @model.get('thread').removeComment(@model) + DiscussionUtil.safeAjax + $elem: $elem + url: url + success: (response, textStatus) => + @$el.remove() + @model.get('thread').removeComment(@model) events: "click .discussion-follow-thread": "toggleFollow" diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 0b6c59964b..71adf08b40 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -39,14 +39,19 @@ if Backbone? reload: ($elem, url) -> if not url then return - DiscussionUtil.get $elem, url, {}, (response, textStatus) => - $parent = @$el.parent() - @$el.replaceWith(response.html) - $discussion = $parent.find("section.discussion") - @model.reset(response.discussionData, { silent: false }) - view = new DiscussionView el: $discussion[0], model: @model - DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) - $("html, body").animate({ scrollTop: 0 }, 0) + DiscussionUtil.safeAjax + $elem: $elem + $loading: $elem + url: url + type: "GET" + success: (response, textStatus) => + $parent = @$el.parent() + @$el.replaceWith(response.html) + $discussion = $parent.find("section.discussion") + @model.reset(response.discussionData, { silent: false }) + view = new DiscussionView el: $discussion[0], model: @model + DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info) + $("html, body").animate({ scrollTop: 0 }, 0) loadSimilarPost: (event) -> $title = @$(".new-post-title") @@ -114,6 +119,7 @@ if Backbone? url = DiscussionUtil.urlFor('create_thread', @model.id) DiscussionUtil.safeAjax $elem: $(event.target) + $loading: $(event.target) if event url: url type: "POST" dataType: 'json' diff --git a/lms/static/coffee/src/discussion/utils.coffee b/lms/static/coffee/src/discussion/utils.coffee index 0610ade1f8..b05d3d8974 100644 --- a/lms/static/coffee/src/discussion/utils.coffee +++ b/lms/static/coffee/src/discussion/utils.coffee @@ -1,3 +1,10 @@ +$ -> + $.fn.extend + loading: -> + $(this).after("") + loaded: -> + $(this).parent().children(".loading").remove() + class @DiscussionUtil @wmdEditors: {} @@ -62,9 +69,16 @@ class @DiscussionUtil $elem = params.$elem if $elem.attr("disabled") return - $elem.attr("disabled", "disabled") + params["beforeSend"] = -> + $elem.attr("disabled", "disabled") + if params["$loading"] + console.log "loading" + params["$loading"].loading() $.ajax(params).always -> $elem.removeAttr("disabled") + if params["$loading"] + console.log "loaded" + params["$loading"].loaded() @get: ($elem, url, data, success) -> @safeAjax diff --git a/lms/static/images/discussion/loading.gif b/lms/static/images/discussion/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..85638328a4f7e6220d27bf336143d5bef17b81b1 GIT binary patch literal 809 zcmZ?wbhEHbo#un4~{M@tz5ox?W@;sR=@u`q-Vg)$iTp$_>+Z|2WXlOkPW2x85~&L zKAc?HGD}#b!P=s}TShvghx&p_s$Y?k1_W;DyZ zvrSu+fkrpK`3f|e^Fd$Y9Twb1b8^kNEZDwVsA~(4_i+}UX&`e?T$bU*X0*t>vyEGX zfkwBy2?ZL>_~2aP9TVI}?>sikxUt2WyXT33AG-)c8_3+Vi#fQk8O<}#w`of-(CCIY zra+^4AM_>MvB7Qh%Z}N?k}cL64O19AxASmc1DSj3FbfYhqXp*qHf%8l8r}A0E6`~E z2Yv~6L~t8D(_z-;xoy9tx?3bXo(u3T1DSh Date: Thu, 23 Aug 2012 01:51:51 -0700 Subject: [PATCH 08/18] include discussion js group in coursewar & removed unnecessary code --- lms/static/coffee/src/discussion/content.coffee | 12 ------------ .../coffee/src/discussion/discussion_module.coffee | 2 +- lms/templates/courseware/courseware.html | 1 + 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/lms/static/coffee/src/discussion/content.coffee b/lms/static/coffee/src/discussion/content.coffee index a8caf3e392..9f2cec290b 100644 --- a/lms/static/coffee/src/discussion/content.coffee +++ b/lms/static/coffee/src/discussion/content.coffee @@ -333,9 +333,6 @@ if Backbone? initTimeago: -> @$("span.timeago").timeago() - initPermalink: -> - @$(".discussion-permanent-link").attr "href", @model.permalink() - renderPartial: -> for attr, value of @model.changedAttributes() if @partial[attr] @@ -370,10 +367,6 @@ if Backbone? @set('thread', @) super() - permalink: -> - discussion_id = @get('commentable_id') - return Discussion.urlFor("permanent_link_thread", discussion_id, @id) - class @ThreadView extends @ContentView class @Comment extends @Content @@ -386,11 +379,6 @@ if Backbone? 'update': -> DiscussionUtil.urlFor('update_comment', @id) 'delete': -> DiscussionUtil.urlFor('delete_comment', @id) - permalink: -> - thread_id = @get('thread').id - discussion_id = @get('thread').get('commentable_id') - return Discussion.urlFor("permanent_link_comment", discussion_id, thread_id, @id) - getCommentsCount: -> count = 0 @get('comments').each (comment) -> diff --git a/lms/static/coffee/src/discussion/discussion_module.coffee b/lms/static/coffee/src/discussion/discussion_module.coffee index 0f3e306379..6452d065d8 100644 --- a/lms/static/coffee/src/discussion/discussion_module.coffee +++ b/lms/static/coffee/src/discussion/discussion_module.coffee @@ -16,7 +16,7 @@ if Backbone? $elem = $(event.target) discussion_id = $elem.attr("discussion_id") url = DiscussionUtil.urlFor 'retrieve_discussion', discussion_id - Discussion.safeAjax + DiscussionUtil.safeAjax $elem: $elem url: url type: "GET" diff --git a/lms/templates/courseware/courseware.html b/lms/templates/courseware/courseware.html index 141d05352c..2950aa827e 100644 --- a/lms/templates/courseware/courseware.html +++ b/lms/templates/courseware/courseware.html @@ -22,6 +22,7 @@ ## <%static:js group='courseware'/> + <%static:js group='discussion'/> <%include file="../discussion/_js_body_dependencies.html" /> From 2b6a0928ca19b56a96bd52dd535fb6ef63dc9643 Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Thu, 23 Aug 2012 01:55:31 -0700 Subject: [PATCH 09/18] fixed loading for discussion module --- .../src/discussion/discussion_module.coffee | 1 + lms/static/coffee/src/discussion/utils.coffee | 4 ++-- lms/static/sass/_discussion.scss | 18 +++++++----------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lms/static/coffee/src/discussion/discussion_module.coffee b/lms/static/coffee/src/discussion/discussion_module.coffee index 6452d065d8..4bcacc1474 100644 --- a/lms/static/coffee/src/discussion/discussion_module.coffee +++ b/lms/static/coffee/src/discussion/discussion_module.coffee @@ -18,6 +18,7 @@ if Backbone? url = DiscussionUtil.urlFor 'retrieve_discussion', discussion_id DiscussionUtil.safeAjax $elem: $elem + $loading: $elem url: url type: "GET" dataType: 'json' diff --git a/lms/static/coffee/src/discussion/utils.coffee b/lms/static/coffee/src/discussion/utils.coffee index b05d3d8974..e156b09a63 100644 --- a/lms/static/coffee/src/discussion/utils.coffee +++ b/lms/static/coffee/src/discussion/utils.coffee @@ -1,9 +1,9 @@ $ -> $.fn.extend loading: -> - $(this).after("") + $(this).after("") loaded: -> - $(this).parent().children(".loading").remove() + $(this).parent().children(".discussion-loading").remove() class @DiscussionUtil diff --git a/lms/static/sass/_discussion.scss b/lms/static/sass/_discussion.scss index 28466894ad..717770f459 100644 --- a/lms/static/sass/_discussion.scss +++ b/lms/static/sass/_discussion.scss @@ -35,7 +35,13 @@ $tag-text-color: #5b614f; } } - +.discussion-loading { + background-image: url(../images/discussion/loading.gif); + width: 15px; + height: 15px; + margin-left: 2px; + display: inline-block; +} /*** Discussions ***/ @@ -49,16 +55,6 @@ $tag-text-color: #5b614f; margin-top: 0; } - .loading { - background-image: url(../images/discussion/loading.gif); - width: 15px; - height: 15px; - margin-left: 2px; - display: inline-block; - } - - - /*** Sidebar ***/ .sidebar-module { From 5fb2bbbd7f325ffa7823d9862ce68de72501b7bb Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Thu, 23 Aug 2012 02:03:50 -0700 Subject: [PATCH 10/18] make similar posts go away when submitted post --- lms/static/coffee/src/discussion/discussion.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 0b6c59964b..336a440739 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -129,6 +129,8 @@ if Backbone? $thread = $(response.html) @$el.children(".threads").prepend($thread) + @$(".new-post-similar-posts").empty() + @$(".new-post-similar-posts-wrapper").hide() @$(".new-post-title").val("") DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "new-post-body", "" @$(".new-post-tags").val("") From 0b00e3b0991fe37c144d0e8d1796ef21232c963b Mon Sep 17 00:00:00 2001 From: Rocky Duan Date: Thu, 23 Aug 2012 02:17:17 -0700 Subject: [PATCH 11/18] make similar posts url working --- .../django_comment_client/base/views.py | 9 +++++--- .../django_comment_client/helpers.py | 16 +------------- lms/djangoapps/django_comment_client/utils.py | 17 +++++++++++++++ .../coffee/src/discussion/discussion.coffee | 21 +++++++++---------- lms/templates/discussion/_similar_posts.html | 9 ++++++++ .../discussion/mustache/_new_post.mustache | 6 +----- 6 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 lms/templates/discussion/_similar_posts.html diff --git a/lms/djangoapps/django_comment_client/base/views.py b/lms/djangoapps/django_comment_client/base/views.py index 5b020b7601..61ab28df76 100644 --- a/lms/djangoapps/django_comment_client/base/views.py +++ b/lms/djangoapps/django_comment_client/base/views.py @@ -298,10 +298,13 @@ def search_similar_threads(request, course_id, commentable_id): 'text': text, 'commentable_id': commentable_id, } - result = cc.search_similar_threads(course_id, recursive=False, query_params=query_params) - return JsonResponse(result) + threads = cc.search_similar_threads(course_id, recursive=False, query_params=query_params) else: - return JsonResponse([]) + theads = [] + context = { 'threads': map(utils.extend_content, threads) } + return JsonResponse({ + 'html': render_to_string('discussion/_similar_posts.html', context) + }) @require_GET def tags_autocomplete(request, course_id): diff --git a/lms/djangoapps/django_comment_client/helpers.py b/lms/djangoapps/django_comment_client/helpers.py index 779ae3c9ee..e793be27b5 100644 --- a/lms/djangoapps/django_comment_client/helpers.py +++ b/lms/djangoapps/django_comment_client/helpers.py @@ -33,24 +33,10 @@ def include_mustache_templates(): file_contents = map(read_file, filter(valid_file_name, os.listdir(mustache_dir))) return '\n'.join(map(wrap_in_tag, map(strip_file_name, file_contents))) -def permalink(content): - if content['type'] == 'thread': - return reverse('django_comment_client.forum.views.single_thread', - args=[content['course_id'], content['commentable_id'], content['id']]) - else: - return reverse('django_comment_client.forum.views.single_thread', - args=[content['course_id'], content['commentable_id'], content['thread_id']]) + '#' + content['id'] - def render_content(content, additional_context={}): - content_info = { - 'displayed_title': content.get('highlighted_title') or content.get('title', ''), - 'displayed_body': content.get('highlighted_body') or content.get('body', ''), - 'raw_tags': ','.join(content.get('tags', [])), - 'permalink': permalink(content), - } context = { - 'content': merge_dict(content, content_info), + 'content': extend_content(content), content['type']: True, } context = merge_dict(context, additional_context) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 9e2f9c8a03..11403bbaed 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -197,3 +197,20 @@ def url_for_tags(course_id, tags): def render_mustache(template_name, dictionary, *args, **kwargs): template = middleware.lookup['main'].get_template(template_name).source return pystache.render(template, dictionary) + +def permalink(content): + if content['type'] == 'thread': + return reverse('django_comment_client.forum.views.single_thread', + args=[content['course_id'], content['commentable_id'], content['id']]) + else: + return reverse('django_comment_client.forum.views.single_thread', + args=[content['course_id'], content['commentable_id'], content['thread_id']]) + '#' + content['id'] + +def extend_content(content): + content_info = { + 'displayed_title': content.get('highlighted_title') or content.get('title', ''), + 'displayed_body': content.get('highlighted_body') or content.get('body', ''), + 'raw_tags': ','.join(content.get('tags', [])), + 'permalink': permalink(content), + } + return merge_dict(content, content_info) diff --git a/lms/static/coffee/src/discussion/discussion.coffee b/lms/static/coffee/src/discussion/discussion.coffee index 336a440739..364df1d12c 100644 --- a/lms/static/coffee/src/discussion/discussion.coffee +++ b/lms/static/coffee/src/discussion/discussion.coffee @@ -61,17 +61,16 @@ if Backbone? $elem = $(event.target) url = DiscussionUtil.urlFor 'search_similar_threads', @model.id data = { text: @$(".new-post-title").val() } - DiscussionUtil.get $elem, url, data, (response, textStatus) => - $similarPosts.empty() - if $.type(response) == "array" and response.length + DiscussionUtil.safeAjax + $elem: $elem + url: url + data: data + dataType: 'json' + success: (response, textStatus) => + $wrapper.html(response.html) $wrapper.show() - for thread in response - $similarPost = $("").addClass("similar-post") - .html(thread["title"]) - .attr("href", "javascript:void(0)") #TODO - .appendTo($similarPosts) - else - $wrapper.hide() + $wrapper.find(".hide-similar-posts").click => + $wrapper.hide() else $wrapper.hide() $title.attr("prev-text", text) @@ -131,7 +130,7 @@ if Backbone? @$(".new-post-similar-posts").empty() @$(".new-post-similar-posts-wrapper").hide() - @$(".new-post-title").val("") + @$(".new-post-title").val("").attr("prev-text", "") DiscussionUtil.setWmdContent @$el, $.proxy(@$, @), "new-post-body", "" @$(".new-post-tags").val("") @$(".new-post-tags").importTags("") diff --git a/lms/templates/discussion/_similar_posts.html b/lms/templates/discussion/_similar_posts.html new file mode 100644 index 0000000000..f68964acec --- /dev/null +++ b/lms/templates/discussion/_similar_posts.html @@ -0,0 +1,9 @@ +% if len(threads) > 0: + Similar Posts: + Hide +
+ % for thread in threads: + ${thread['title']} + % endfor +
+% endif diff --git a/lms/templates/discussion/mustache/_new_post.mustache b/lms/templates/discussion/mustache/_new_post.mustache index 451d2e3a93..c8229c9d27 100644 --- a/lms/templates/discussion/mustache/_new_post.mustache +++ b/lms/templates/discussion/mustache/_new_post.mustache @@ -1,11 +1,7 @@
- ${content} + ${content.decode('utf-8')}
From d1a8cd3f6536f112b1975c58eac9511a4ed648fb Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Thu, 23 Aug 2012 04:50:03 -0700 Subject: [PATCH 16/18] Limiting depth of comments --- lms/djangoapps/django_comment_client/base/views.py | 9 ++++++++- lms/djangoapps/django_comment_client/helpers.py | 8 ++++++++ lms/djangoapps/django_comment_client/utils.py | 2 ++ lms/envs/common.py | 4 ++++ lms/templates/discussion/mustache/_content.mustache | 4 +++- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/django_comment_client/base/views.py b/lms/djangoapps/django_comment_client/base/views.py index 70396ba064..dd9da857c6 100644 --- a/lms/djangoapps/django_comment_client/base/views.py +++ b/lms/djangoapps/django_comment_client/base/views.py @@ -8,6 +8,8 @@ import functools import comment_client as cc import django_comment_client.utils as utils +import django_comment_client.settings as cc_settings + from django.core import exceptions from django.contrib.auth.decorators import login_required @@ -15,7 +17,6 @@ from django.views.decorators.http import require_POST, require_GET from django.views.decorators import csrf from django.core.files.storage import get_storage_class from django.utils.translation import ugettext as _ -from django.conf import settings from django.contrib.auth.models import User from mitxmako.shortcuts import render_to_response, render_to_string @@ -114,6 +115,9 @@ def _create_comment(request, course_id, thread_id=None, parent_id=None): @login_required @permitted def create_comment(request, course_id, thread_id): + if cc_settings.MAX_COMMENT_DEPTH is not None: + if cc_settings.MAX_COMMENT_DEPTH < 0: + return JsonError("Comment level too deep") return _create_comment(request, course_id, thread_id=thread_id) @require_POST @@ -158,6 +162,9 @@ def openclose_thread(request, course_id, thread_id): @login_required @permitted def create_sub_comment(request, course_id, comment_id): + if cc_settings.MAX_COMMENT_DEPTH is not None: + if cc_settings.MAX_COMMENT_DEPTH <= cc.Comment.find(comment_id).depth: + return JsonError("Comment level too deep") return _create_comment(request, course_id, parent_id=comment_id) @require_POST diff --git a/lms/djangoapps/django_comment_client/helpers.py b/lms/djangoapps/django_comment_client/helpers.py index c35559255d..671659aed8 100644 --- a/lms/djangoapps/django_comment_client/helpers.py +++ b/lms/djangoapps/django_comment_client/helpers.py @@ -6,6 +6,7 @@ from django.core.urlresolvers import reverse from functools import partial from utils import * +import django_comment_client.settings as cc_settings import pystache_custom as pystache import urllib @@ -39,6 +40,13 @@ def render_content(content, additional_context={}): 'content': extend_content(content), content['type']: True, } + if cc_settings.MAX_COMMENT_DEPTH is not None: + if content['type'] == 'thread': + if cc_settings.MAX_COMMENT_DEPTH < 0: + context['max_depth'] = True + elif content['type'] == 'comment': + if cc_settings.MAX_COMMENT_DEPTH <= content['depth']: + context['max_depth'] = True context = merge_dict(context, additional_context) partial_mustache_helpers = {k: partial(v, content) for k, v in mustache_helpers.items()} context = merge_dict(context, partial_mustache_helpers) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 11403bbaed..fded387462 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -21,6 +21,8 @@ import pystache_custom as pystache _FULLMODULES = None _DISCUSSIONINFO = None + + def extract(dic, keys): return {k: dic.get(k) for k in keys} diff --git a/lms/envs/common.py b/lms/envs/common.py index dc1d631046..99c68afbe3 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -38,6 +38,10 @@ ASKBOT_ENABLED = False GENERATE_RANDOM_USER_CREDENTIALS = False PERFSTATS = False +DISCUSSION_SETTINGS = { + 'MAX_COMMENT_DEPTH': 2, +} + # Features MITX_FEATURES = { 'SAMPLE' : False, diff --git a/lms/templates/discussion/mustache/_content.mustache b/lms/templates/discussion/mustache/_content.mustache index 34926b57b5..91330dd0d8 100644 --- a/lms/templates/discussion/mustache/_content.mustache +++ b/lms/templates/discussion/mustache/_content.mustache @@ -51,7 +51,9 @@ {{/thread}}
    -
  • Reply
  • + {{^max_depth}} +
  • Reply
  • + {{/max_depth}} {{#thread}}
  • {{/thread}} From c52dd5faeae3eb9f53a5e568719b55bd68e6def2 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 23 Aug 2012 07:59:53 -0400 Subject: [PATCH 17/18] another unicode fix for forums --- lms/templates/discussion/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/discussion/index.html b/lms/templates/discussion/index.html index af564cabe3..43291b6f9b 100644 --- a/lms/templates/discussion/index.html +++ b/lms/templates/discussion/index.html @@ -32,7 +32,7 @@
- ${content} + ${content.decode('utf-8')}
From ec4858801ec17c386efc25efcce8b422aa0b4734 Mon Sep 17 00:00:00 2001 From: David Ormsbee Date: Thu, 23 Aug 2012 08:02:19 -0400 Subject: [PATCH 18/18] read the comment service shared key from django config --- lms/envs/aws.py | 2 +- lms/envs/dev.py | 2 ++ lms/lib/comment_client/settings.py | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lms/envs/aws.py b/lms/envs/aws.py index bf7d85b91e..75ae712b88 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -68,4 +68,4 @@ if 'COURSE_ID' in ENV_TOKENS: ASKBOT_URL = "courses/{0}/discussions/".format(ENV_TOKENS['COURSE_ID']) COMMENTS_SERVICE_URL = ENV_TOKENS["COMMENTS_SERVICE_URL"] - +COMMENTS_SERVICE_KEY = ENV_TOKENS["COMMENTS_SERVICE_KEY"] diff --git a/lms/envs/dev.py b/lms/envs/dev.py index d798815543..a76e6de262 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -92,6 +92,8 @@ SUBDOMAIN_BRANDING = { 'harvard': 'HarvardX', } +COMMENTS_SERVICE_KEY = "PUT_YOUR_API_KEY_HERE" + ################################ LMS Migration ################################# MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll diff --git a/lms/lib/comment_client/settings.py b/lms/lib/comment_client/settings.py index 75a107d0c9..4ae697adb5 100644 --- a/lms/lib/comment_client/settings.py +++ b/lms/lib/comment_client/settings.py @@ -7,4 +7,7 @@ else: PREFIX = SERVICE_HOST + '/api/v1' -API_KEY = "PUT_YOUR_API_KEY_HERE" +if hasattr(settings, "COMMENTS_SERVICE_KEY"): + API_KEY = settings.COMMENTS_SERVICE_KEY +else: + API_KEY = "PUT_YOUR_API_KEY_HERE"