diff --git a/common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee index 85ab5ec254..71495ad9c6 100644 --- a/common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee +++ b/common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee @@ -1,13 +1,12 @@ describe "DiscussionContentView", -> beforeEach -> - setFixtures - ( + setFixtures( """
- - + 0 + + 0 votes (click to vote)

Post Title

robot @@ -23,16 +22,21 @@ describe "DiscussionContentView", -> """ ) - @thread = new Thread { - id: '01234567', - user_id: '567', - course_id: 'mitX/999/test', - body: 'this is a thread', - created_at: '2013-04-03T20:08:39Z', - abuse_flaggers: ['123'] - roles: [] + @threadData = { + id: '01234567', + user_id: '567', + course_id: 'mitX/999/test', + body: 'this is a thread', + created_at: '2013-04-03T20:08:39Z', + abuse_flaggers: ['123'], + votes: {up_count: '42'}, + type: "thread", + roles: [] } + @thread = new Thread(@threadData) @view = new DiscussionContentView({ model: @thread }) + @view.setElement($('.discussion-post')) + window.user = new DiscussionUser({id: '567', upvoted_ids: []}) it 'defines the tag', -> expect($('#jasmine-fixtures')).toExist @@ -56,3 +60,15 @@ describe "DiscussionContentView", -> @thread.set("abuse_flaggers",temp_array) @thread.unflagAbuse() expect(@thread.get 'abuse_flaggers').toEqual [] + + it 'renders the vote button properly', -> + DiscussionViewSpecHelper.checkRenderVote(@view, @thread) + + it 'votes correctly', -> + DiscussionViewSpecHelper.checkVote(@view, @thread, @threadData, false) + + it 'unvotes correctly', -> + DiscussionViewSpecHelper.checkUnvote(@view, @thread, @threadData, false) + + it 'toggles the vote correctly', -> + DiscussionViewSpecHelper.checkToggleVote(@view, @thread) diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee new file mode 100644 index 0000000000..f10d30d0af --- /dev/null +++ b/common/static/coffee/spec/discussion/view/discussion_thread_profile_view_spec.coffee @@ -0,0 +1,40 @@ +describe "DiscussionThreadProfileView", -> + beforeEach -> + setFixtures( + """ +

+ + 0 votes (click to vote) + +
+ """ + ) + + @threadData = { + id: "dummy", + user_id: "567", + course_id: "TestOrg/TestCourse/TestRun", + body: "this is a thread", + created_at: "2013-04-03T20:08:39Z", + abuse_flaggers: [], + votes: {up_count: "42"} + } + @thread = new Thread(@threadData) + @view = new DiscussionThreadProfileView({ model: @thread }) + @view.setElement($(".discussion-post")) + window.user = new DiscussionUser({id: "567", upvoted_ids: []}) + + it "renders the vote correctly", -> + DiscussionViewSpecHelper.checkRenderVote(@view, @thread) + + it "votes correctly", -> + DiscussionViewSpecHelper.checkVote(@view, @thread, @threadData, true) + + it "unvotes correctly", -> + DiscussionViewSpecHelper.checkUnvote(@view, @thread, @threadData, true) + + it "toggles the vote correctly", -> + DiscussionViewSpecHelper.checkToggleVote(@view, @thread) + + it "vote button activates on appropriate events", -> + DiscussionViewSpecHelper.checkVoteButtonEvents(@view) diff --git a/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee b/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee new file mode 100644 index 0000000000..69e4b231a2 --- /dev/null +++ b/common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee @@ -0,0 +1,40 @@ +describe "DiscussionThreadShowView", -> + beforeEach -> + setFixtures( + """ +
+ + 0 votes (click to vote) + +
+ """ + ) + + @threadData = { + id: "dummy", + user_id: "567", + course_id: "TestOrg/TestCourse/TestRun", + body: "this is a thread", + created_at: "2013-04-03T20:08:39Z", + abuse_flaggers: [], + votes: {up_count: "42"} + } + @thread = new Thread(@threadData) + @view = new DiscussionThreadShowView({ model: @thread }) + @view.setElement($(".discussion-post")) + window.user = new DiscussionUser({id: "567", upvoted_ids: []}) + + it "renders the vote correctly", -> + DiscussionViewSpecHelper.checkRenderVote(@view, @thread) + + it "votes correctly", -> + DiscussionViewSpecHelper.checkVote(@view, @thread, @threadData, true) + + it "unvotes correctly", -> + DiscussionViewSpecHelper.checkUnvote(@view, @thread, @threadData, true) + + it 'toggles the vote correctly', -> + DiscussionViewSpecHelper.checkToggleVote(@view, @thread) + + it "vote button activates on appropriate events", -> + DiscussionViewSpecHelper.checkVoteButtonEvents(@view) diff --git a/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee b/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee new file mode 100644 index 0000000000..d5c25aa5e2 --- /dev/null +++ b/common/static/coffee/spec/discussion/view/discussion_view_spec_helper.coffee @@ -0,0 +1,113 @@ +class @DiscussionViewSpecHelper + @expectVoteRendered = (view, voted) -> + button = view.$el.find(".vote-btn") + if voted + expect(button.hasClass("is-cast")).toBe(true) + expect(button.attr("aria-pressed")).toEqual("true") + expect(button.attr("data-tooltip")).toEqual("remove vote") + expect(button.find(".votes-count-number").html()).toEqual("43") + expect(button.find(".sr").html()).toEqual("votes (click to remove your vote)") + else + expect(button.hasClass("is-cast")).toBe(false) + expect(button.attr("aria-pressed")).toEqual("false") + expect(button.attr("data-tooltip")).toEqual("vote") + expect(button.find(".votes-count-number").html()).toEqual("42") + expect(button.find(".sr").html()).toEqual("votes (click to vote)") + + @checkRenderVote = (view, model) -> + view.renderVote() + DiscussionViewSpecHelper.expectVoteRendered(view, false) + window.user.vote(model) + view.renderVote() + DiscussionViewSpecHelper.expectVoteRendered(view, true) + window.user.unvote(model) + view.renderVote() + DiscussionViewSpecHelper.expectVoteRendered(view, false) + + @checkVote = (view, model, modelData, checkRendering) -> + view.renderVote() + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, false) + + spyOn($, "ajax").andCallFake((params) => + newModelData = {} + $.extend(newModelData, modelData, {votes: {up_count: "43"}}) + params.success(newModelData, "success") + # Caller invokes always function on return value but it doesn't matter here + {always: ->} + ) + + view.vote() + expect(window.user.voted(model)).toBe(true) + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, true) + expect($.ajax).toHaveBeenCalled() + $.ajax.reset() + + # Check idempotence + view.vote() + expect(window.user.voted(model)).toBe(true) + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, true) + expect($.ajax).toHaveBeenCalled() + + @checkUnvote = (view, model, modelData, checkRendering) -> + window.user.vote(model) + expect(window.user.voted(model)).toBe(true) + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, true) + + spyOn($, "ajax").andCallFake((params) => + newModelData = {} + $.extend(newModelData, modelData, {votes: {up_count: "42"}}) + params.success(newModelData, "success") + # Caller invokes always function on return value but it doesn't matter here + {always: ->} + ) + + view.unvote() + expect(window.user.voted(model)).toBe(false) + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, false) + expect($.ajax).toHaveBeenCalled() + $.ajax.reset() + + # Check idempotence + view.unvote() + expect(window.user.voted(model)).toBe(false) + if checkRendering + DiscussionViewSpecHelper.expectVoteRendered(view, false) + expect($.ajax).toHaveBeenCalled() + + @checkToggleVote = (view, model) -> + event = {preventDefault: ->} + spyOn(event, "preventDefault") + spyOn(view, "vote").andCallFake(() -> window.user.vote(model)) + spyOn(view, "unvote").andCallFake(() -> window.user.unvote(model)) + + expect(window.user.voted(model)).toBe(false) + view.toggleVote(event) + expect(view.vote).toHaveBeenCalled() + expect(view.unvote).not.toHaveBeenCalled() + expect(event.preventDefault.callCount).toEqual(1) + + view.vote.reset() + view.unvote.reset() + expect(window.user.voted(model)).toBe(true) + view.toggleVote(event) + expect(view.vote).not.toHaveBeenCalled() + expect(view.unvote).toHaveBeenCalled() + expect(event.preventDefault.callCount).toEqual(2) + + @checkVoteButtonEvents = (view) -> + spyOn(view, "toggleVote") + button = view.$el.find(".vote-btn") + + button.click() + expect(view.toggleVote).toHaveBeenCalled() + view.toggleVote.reset() + button.trigger($.Event("keydown", {which: 13})) + expect(view.toggleVote).toHaveBeenCalled() + view.toggleVote.reset() + button.trigger($.Event("keydown", {which: 32})) + expect(view.toggleVote).not.toHaveBeenCalled() diff --git a/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee new file mode 100644 index 0000000000..7ba00c66d1 --- /dev/null +++ b/common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee @@ -0,0 +1,40 @@ +describe "ThreadResponseShowView", -> + beforeEach -> + setFixtures( + """ +
+ + 0 votes (click to vote) + +
+ """ + ) + + @commentData = { + id: "dummy", + user_id: "567", + course_id: "TestOrg/TestCourse/TestRun", + body: "this is a comment", + created_at: "2013-04-03T20:08:39Z", + abuse_flaggers: [], + votes: {up_count: "42"} + } + @comment = new Comment(@commentData) + @view = new ThreadResponseShowView({ model: @comment }) + @view.setElement($(".discussion-post")) + window.user = new DiscussionUser({id: "567", upvoted_ids: []}) + + it "renders the vote correctly", -> + DiscussionViewSpecHelper.checkRenderVote(@view, @comment) + + it "votes correctly", -> + DiscussionViewSpecHelper.checkVote(@view, @comment, @commentData, true) + + it "unvotes correctly", -> + DiscussionViewSpecHelper.checkUnvote(@view, @comment, @commentData, true) + + it 'toggles the vote correctly', -> + DiscussionViewSpecHelper.checkToggleVote(@view, @comment) + + it "vote button activates on appropriate events", -> + DiscussionViewSpecHelper.checkVoteButtonEvents(@view) diff --git a/common/static/coffee/src/discussion/content.coffee b/common/static/coffee/src/discussion/content.coffee index 23a31ae7e6..5e3d4ce20b 100644 --- a/common/static/coffee/src/discussion/content.coffee +++ b/common/static/coffee/src/discussion/content.coffee @@ -99,6 +99,13 @@ if Backbone? @get("abuse_flaggers").pop(window.user.get('id')) @trigger "change", @ + vote: -> + @get("votes")["up_count"] = parseInt(@get("votes")["up_count"]) + 1 + @trigger "change", @ + + unvote: -> + @get("votes")["up_count"] = parseInt(@get("votes")["up_count"]) - 1 + @trigger "change", @ class @Thread extends @Content urlMappers: @@ -130,14 +137,6 @@ if Backbone? unfollow: -> @set('subscribed', false) - vote: -> - @get("votes")["up_count"] = parseInt(@get("votes")["up_count"]) + 1 - @trigger "change", @ - - unvote: -> - @get("votes")["up_count"] = parseInt(@get("votes")["up_count"]) - 1 - @trigger "change", @ - display_body: -> if @has("highlighted_body") String(@get("highlighted_body")).replace(//g, '').replace(/<\/highlight>/g, '') diff --git a/common/static/coffee/src/discussion/utils.coffee b/common/static/coffee/src/discussion/utils.coffee index a85e4f0eaa..0e8362472a 100644 --- a/common/static/coffee/src/discussion/utils.coffee +++ b/common/static/coffee/src/discussion/utils.coffee @@ -91,7 +91,7 @@ class @DiscussionUtil @activateOnEnter: (event, func) -> if event.which == 13 - e.preventDefault() + event.preventDefault() func(event) @makeFocusTrap: (elem) -> diff --git a/common/static/coffee/src/discussion/views/discussion_content_view.coffee b/common/static/coffee/src/discussion/views/discussion_content_view.coffee index 9c3c4a01f5..96d74df4ef 100644 --- a/common/static/coffee/src/discussion/views/discussion_content_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_content_view.coffee @@ -159,3 +159,42 @@ if Backbone? temp_array = [] @model.set('abuse_flaggers', temp_array) + + renderVote: => + button = @$el.find(".vote-btn") + voted = window.user.voted(@model) + voteNum = @model.get("votes")["up_count"] + button.toggleClass("is-cast", voted) + button.attr("aria-pressed", voted) + button.attr("data-tooltip", if voted then "remove vote" else "vote") + button.find(".votes-count-number").html(voteNum) + button.find(".sr").html(if voted then "votes (click to remove your vote)" else "votes (click to vote)") + + toggleVote: (event) => + event.preventDefault() + if window.user.voted(@model) + @unvote() + else + @vote() + + vote: => + window.user.vote(@model) + url = @model.urlFor("upvote") + DiscussionUtil.safeAjax + $elem: @$el.find(".vote-btn") + url: url + type: "POST" + success: (response, textStatus) => + if textStatus == 'success' + @model.set(response) + + unvote: => + window.user.unvote(@model) + url = @model.urlFor("unvote") + DiscussionUtil.safeAjax + $elem: @$el.find(".vote-btn") + url: url + type: "POST" + success: (response, textStatus) => + if textStatus == 'success' + @model.set(response) diff --git a/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee b/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee index 7130ac555c..f6a6ea8eb6 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee @@ -2,7 +2,10 @@ if Backbone? class @DiscussionThreadProfileView extends DiscussionContentView expanded = false events: - "click .discussion-vote": "toggleVote" + "click .vote-btn": + (event) -> @toggleVote(event) + "keydown .vote-btn": + (event) -> DiscussionUtil.activateOnEnter(event, @toggleVote) "click .action-follow": "toggleFollowing" "keypress .action-follow": (event) -> DiscussionUtil.activateOnEnter(event, toggleFollowing) @@ -27,7 +30,7 @@ if Backbone? @$el.html(Mustache.render(@template, params)) @initLocal() @delegateEvents() - @renderVoted() + @renderVote() @renderAttrs() @$("span.timeago").timeago() @convertMath() @@ -35,15 +38,8 @@ if Backbone? @renderResponses() @ - renderVoted: => - if window.user.voted(@model) - @$("[data-role=discussion-vote]").addClass("is-cast") - else - @$("[data-role=discussion-vote]").removeClass("is-cast") - updateModelDetails: => - @renderVoted() - @$("[data-role=discussion-vote] .votes-count-number").html(@model.get("votes")["up_count"]) + @renderVote() convertMath: -> element = @$(".post-body") @@ -71,35 +67,6 @@ if Backbone? addComment: => @model.comment() - toggleVote: (event) -> - event.preventDefault() - if window.user.voted(@model) - @unvote() - else - @vote() - - vote: -> - window.user.vote(@model) - url = @model.urlFor("upvote") - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response) - - unvote: -> - window.user.unvote(@model) - url = @model.urlFor("unvote") - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response) - edit: -> abbreviateBody: -> diff --git a/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee b/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee index 1a3f8929e1..14dd01e3fa 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee @@ -2,7 +2,10 @@ if Backbone? class @DiscussionThreadShowView extends DiscussionContentView events: - "click .discussion-vote": "toggleVote" + "click .vote-btn": + (event) -> @toggleVote(event) + "keydown .vote-btn": + (event) -> DiscussionUtil.activateOnEnter(event, @toggleVote) "click .discussion-flag-abuse": "toggleFlagAbuse" "keypress .discussion-flag-abuse": (event) -> DiscussionUtil.activateOnEnter(event, toggleFlagAbuse) @@ -28,7 +31,7 @@ if Backbone? render: -> @$el.html(@renderTemplate()) @delegateEvents() - @renderVoted() + @renderVote() @renderFlagged() @renderPinned() @renderAttrs() @@ -38,14 +41,6 @@ if Backbone? @highlight @$("h1,h3") @ - renderVoted: => - if window.user.voted(@model) - @$("[data-role=discussion-vote]").addClass("is-cast") - @$("[data-role=discussion-vote] span.sr").html("votes (click to remove your vote)") - else - @$("[data-role=discussion-vote]").removeClass("is-cast") - @$("[data-role=discussion-vote] span.sr").html("votes (click to vote)") - renderFlagged: => if window.user.id in @model.get("abuse_flaggers") or (DiscussionUtil.isFlagModerator and @model.get("abuse_flaggers").length > 0) @$("[data-role=thread-flag]").addClass("flagged") @@ -70,52 +65,15 @@ if Backbone? updateModelDetails: => - @renderVoted() + @renderVote() @renderFlagged() @renderPinned() - @$("[data-role=discussion-vote] .votes-count-number").html(@model.get("votes")["up_count"] + '') - if window.user.voted(@model) - @$("[data-role=discussion-vote] .votes-count-number span.sr").html("votes (click to remove your vote)") - else - @$("[data-role=discussion-vote] .votes-count-number span.sr").html("votes (click to vote)") - convertMath: -> element = @$(".post-body") element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.text() MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] - toggleVote: (event) -> - event.preventDefault() - if window.user.voted(@model) - @unvote() - else - @vote() - - vote: -> - window.user.vote(@model) - url = @model.urlFor("upvote") - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response, {silent: true}) - - - unvote: -> - window.user.unvote(@model) - url = @model.urlFor("unvote") - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response, {silent: true}) - - edit: (event) -> @trigger "thread:edit", event diff --git a/common/static/coffee/src/discussion/views/thread_response_show_view.coffee b/common/static/coffee/src/discussion/views/thread_response_show_view.coffee index eaed0568c2..57736e789d 100644 --- a/common/static/coffee/src/discussion/views/thread_response_show_view.coffee +++ b/common/static/coffee/src/discussion/views/thread_response_show_view.coffee @@ -1,7 +1,10 @@ if Backbone? class @ThreadResponseShowView extends DiscussionContentView events: - "click .vote-btn": "toggleVote" + "click .vote-btn": + (event) -> @toggleVote(event) + "keydown .vote-btn": + (event) -> DiscussionUtil.activateOnEnter(event, @toggleVote) "click .action-endorse": "toggleEndorse" "click .action-delete": "_delete" "click .action-edit": "edit" @@ -23,9 +26,7 @@ if Backbone? render: -> @$el.html(@renderTemplate()) @delegateEvents() - if window.user.voted(@model) - @$(".vote-btn").addClass("is-cast") - @$(".vote-btn span.sr").html("votes (click to remove your vote)") + @renderVote() @renderAttrs() @renderFlagged() @$el.find(".posted-details").timeago() @@ -46,39 +47,6 @@ if Backbone? @$el.addClass("community-ta") @$el.prepend('
Community TA
') - toggleVote: (event) -> - event.preventDefault() - @$(".vote-btn").toggleClass("is-cast") - if @$(".vote-btn").hasClass("is-cast") - @vote() - @$(".vote-btn span.sr").html("votes (click to remove your vote)") - else - @unvote() - @$(".vote-btn span.sr").html("votes (click to vote)") - - vote: -> - url = @model.urlFor("upvote") - @$(".votes-count-number").html((parseInt(@$(".votes-count-number").html()) + 1) + '') - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response) - - unvote: -> - url = @model.urlFor("unvote") - @$(".votes-count-number").html((parseInt(@$(".votes-count-number").html()) - 1)+'') - DiscussionUtil.safeAjax - $elem: @$(".discussion-vote") - url: url - type: "POST" - success: (response, textStatus) => - if textStatus == 'success' - @model.set(response) - - edit: (event) -> @trigger "response:edit", event @@ -115,4 +83,5 @@ if Backbone? @$(".discussion-flag-abuse .flag-label").html("Report Misuse") updateModelDetails: => + @renderVote() @renderFlagged() diff --git a/common/static/js_test.yml b/common/static/js_test.yml index 31929401f0..c56e3f4a90 100644 --- a/common/static/js_test.yml +++ b/common/static/js_test.yml @@ -34,6 +34,7 @@ lib_paths: - js/vendor/underscore-min.js - js/vendor/backbone-min.js - js/vendor/jquery.timeago.js + - js/vendor/URI.min.js - coffee/src/ajax_prefix.js - js/test/add_ajax_prefix.js - coffee/src/jquery.immediateDescendents.js diff --git a/lms/djangoapps/django_comment_client/base/views.py b/lms/djangoapps/django_comment_client/base/views.py index 4e3331e592..4d8bffdd73 100644 --- a/lms/djangoapps/django_comment_client/base/views.py +++ b/lms/djangoapps/django_comment_client/base/views.py @@ -50,16 +50,14 @@ def permitted(fn): return wrapper -def ajax_content_response(request, course_id, content, template_name): +def ajax_content_response(request, course_id, content): context = { 'course_id': course_id, 'content': content, } - html = render_to_string(template_name, context) user_info = cc.User.from_django_user(request.user).to_dict() annotated_content_info = utils.get_annotated_content_info(course_id, content, request.user, user_info) return JsonResponse({ - 'html': html, 'content': utils.safe_content(content), 'annotated_content_info': annotated_content_info, }) @@ -131,7 +129,7 @@ def create_thread(request, course_id, commentable_id): data = thread.to_dict() add_courseware_context([data], course) if request.is_ajax(): - return ajax_content_response(request, course_id, data, 'discussion/ajax_create_thread.html') + return ajax_content_response(request, course_id, data) else: return JsonResponse(utils.safe_content(data)) @@ -147,7 +145,7 @@ def update_thread(request, course_id, thread_id): thread.update_attributes(**extract(request.POST, ['body', 'title', 'tags'])) thread.save() if request.is_ajax(): - return ajax_content_response(request, course_id, thread.to_dict(), 'discussion/ajax_update_thread.html') + return ajax_content_response(request, course_id, thread.to_dict()) else: return JsonResponse(utils.safe_content(thread.to_dict())) @@ -184,7 +182,7 @@ def _create_comment(request, course_id, thread_id=None, parent_id=None): user = cc.User.from_django_user(request.user) user.follow(comment.thread) if request.is_ajax(): - return ajax_content_response(request, course_id, comment.to_dict(), 'discussion/ajax_create_comment.html') + return ajax_content_response(request, course_id, comment.to_dict()) else: return JsonResponse(utils.safe_content(comment.to_dict())) @@ -228,7 +226,7 @@ def update_comment(request, course_id, comment_id): comment.update_attributes(**extract(request.POST, ['body'])) comment.save() if request.is_ajax(): - return ajax_content_response(request, course_id, comment.to_dict(), 'discussion/ajax_update_comment.html') + return ajax_content_response(request, course_id, comment.to_dict()) else: return JsonResponse(utils.safe_content(comment.to_dict())) diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/django_comment_client/forum/views.py index 83516fc3ac..4bbcd5acd4 100644 --- a/lms/djangoapps/django_comment_client/forum/views.py +++ b/lms/djangoapps/django_comment_client/forum/views.py @@ -248,13 +248,10 @@ def single_thread(request, course_id, discussion_id, thread_id): with newrelic.agent.FunctionTrace(nr_transaction, "get_annotated_content_infos"): annotated_content_info = utils.get_annotated_content_infos(course_id, thread, request.user, user_info=user_info) context = {'thread': thread.to_dict(), 'course_id': course_id} - # TODO: Remove completely or switch back to server side rendering - # html = render_to_string('discussion/_ajax_single_thread.html', context) content = utils.safe_content(thread.to_dict()) with newrelic.agent.FunctionTrace(nr_transaction, "add_courseware_context"): add_courseware_context([content], course) return utils.JsonResponse({ - #'html': html, 'content': content, 'annotated_content_info': annotated_content_info, }) diff --git a/lms/djangoapps/django_comment_client/helpers.py b/lms/djangoapps/django_comment_client/helpers.py index 1310c4e0c1..b9f144e76c 100644 --- a/lms/djangoapps/django_comment_client/helpers.py +++ b/lms/djangoapps/django_comment_client/helpers.py @@ -31,22 +31,3 @@ 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 render_content(content, additional_context={}): - - 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) - return render_mustache('discussion/mustache/_content.mustache', context) diff --git a/lms/static/js/URI.min.js b/lms/static/js/URI.min.js deleted file mode 100644 index 2663ddccd6..0000000000 --- a/lms/static/js/URI.min.js +++ /dev/null @@ -1,58 +0,0 @@ -/*! URI.js v1.6.3 http://medialize.github.com/URI.js/ */ -(function(){("undefined"!==typeof module&&module.exports?module.exports:window).IPv6={best:function(e){var e=e.toLowerCase().split(":"),h=e.length,j=8;""===e[0]&&""===e[1]&&""===e[2]?(e.shift(),e.shift()):""===e[0]&&""===e[1]?e.shift():""===e[h-1]&&""===e[h-2]&&e.pop();h=e.length;-1!==e[h-1].indexOf(".")&&(j=7);var f;for(f=0;fl;l++)if("0"===h[0]&&1l&&(h=p,l=r)):"0"==e[f]&&(d=!0,p=f,r=1);r>l&&(h=p,l=r);1>>10&1023|55296),a=56320|a&1023);return b+=x(a)}).join("")}function r(g, -d,e){for(var f=0,g=e?t(g/c):g>>1,g=g+t(g/d);g>B*a>>1;f+=s)g=t(g/B);return t(f+(B+1)*g/(g+b))}function p(b){var c=[],d=b.length,e,f=0,j=C,k=g,m,u,n,o,i;m=b.lastIndexOf(D);0>m&&(m=0);for(u=0;u=d&&h("invalid-input");o=b.charCodeAt(m++);o=10>o-48?o-22:26>o-65?o-65:26>o-97?o-97:s;(o>=s||o>t((v-f)/e))&&h("overflow");f+=o*e;i=n<=k?y:n>=k+a?a:n-k;if(ot(v/o)&&h("overflow");e*= -o}e=c.length+1;k=r(f-u,e,0==u);t(f/e)>v-j&&h("overflow");j+=t(f/e);f%=e;c.splice(f++,0,j)}return l(c)}function d(b){var c,d,e,j,k,i,m,l,n,o=[],w,p,q,b=f(b);w=b.length;c=C;d=0;k=g;for(i=0;in&&o.push(x(n));for((e=j=o.length)&&o.push(D);e=c&&nt((v-d)/p)&&h("overflow");d+=(m-c)*p;c=m;for(i=0;iv&&h("overflow"),n==c){l=d;for(m=s;;m+=s){n=m<=k?y:m>=k+a?a:m-k;if(l -n+q%l)-0));l=t(q/l)}o.push(x(l+22+75*(26>l)-0));k=r(d,p,e==j);d=0;++e}++d;++c}return o.join("")}var k,i="function"==typeof define&&"object"==typeof define.amd&&define.amd&&define,q="object"==typeof exports&&exports,z="object"==typeof module&&module,v=2147483647,s=36,y=1,a=26,b=38,c=700,g=72,C=128,D="-",w=/[^ -~]/,F=/^xn--/,E={overflow:"Overflow: input needs wider integers to process.",ucs2decode:"UCS-2(decode): illegal sequence",ucs2encode:"UCS-2(encode): illegal value","not-basic":"Illegal input >= 0x80 (not a basic code point)", -"invalid-input":"Invalid input"},B=s-y,t=Math.floor,x=String.fromCharCode,A;k={version:"0.3.0",ucs2:{decode:f,encode:l},decode:p,encode:d,toASCII:function(a){return j(a.split("."),function(a){return w.test(a)?"xn--"+d(a):a}).join(".")},toUnicode:function(a){return j(a.split("."),function(a){return F.test(a)?p(a.slice(4).toLowerCase()):a}).join(".")}};if(q)if(z&&z.exports==q)z.exports=k;else for(A in k)k.hasOwnProperty(A)&&(q[A]=k[A]);else i?define("punycode",k):e.punycode=k})(this); -(function(){var e={list:{ac:"com|gov|mil|net|org",ae:"ac|co|gov|mil|name|net|org|pro|sch",af:"com|edu|gov|net|org",al:"com|edu|gov|mil|net|org",ao:"co|ed|gv|it|og|pb",ar:"com|edu|gob|gov|int|mil|net|org|tur",at:"ac|co|gv|or",au:"asn|com|csiro|edu|gov|id|net|org",ba:"co|com|edu|gov|mil|net|org|rs|unbi|unmo|unsa|untz|unze",bb:"biz|co|com|edu|gov|info|net|org|store|tv",bh:"biz|cc|com|edu|gov|info|net|org",bn:"com|edu|gov|net|org",bo:"com|edu|gob|gov|int|mil|net|org|tv",br:"adm|adv|agr|am|arq|art|ato|b|bio|blog|bmd|cim|cng|cnt|com|coop|ecn|edu|eng|esp|etc|eti|far|flog|fm|fnd|fot|fst|g12|ggf|gov|imb|ind|inf|jor|jus|lel|mat|med|mil|mus|net|nom|not|ntr|odo|org|ppg|pro|psc|psi|qsl|rec|slg|srv|tmp|trd|tur|tv|vet|vlog|wiki|zlg", -bs:"com|edu|gov|net|org",bz:"du|et|om|ov|rg",ca:"ab|bc|mb|nb|nf|nl|ns|nt|nu|on|pe|qc|sk|yk",ck:"biz|co|edu|gen|gov|info|net|org",cn:"ac|ah|bj|com|cq|edu|fj|gd|gov|gs|gx|gz|ha|hb|he|hi|hl|hn|jl|js|jx|ln|mil|net|nm|nx|org|qh|sc|sd|sh|sn|sx|tj|tw|xj|xz|yn|zj",co:"com|edu|gov|mil|net|nom|org",cr:"ac|c|co|ed|fi|go|or|sa",cy:"ac|biz|com|ekloges|gov|ltd|name|net|org|parliament|press|pro|tm","do":"art|com|edu|gob|gov|mil|net|org|sld|web",dz:"art|asso|com|edu|gov|net|org|pol",ec:"com|edu|fin|gov|info|med|mil|net|org|pro", -eg:"com|edu|eun|gov|mil|name|net|org|sci",er:"com|edu|gov|ind|mil|net|org|rochest|w",es:"com|edu|gob|nom|org",et:"biz|com|edu|gov|info|name|net|org",fj:"ac|biz|com|info|mil|name|net|org|pro",fk:"ac|co|gov|net|nom|org",fr:"asso|com|f|gouv|nom|prd|presse|tm",gg:"co|net|org",gh:"com|edu|gov|mil|org",gn:"ac|com|gov|net|org",gr:"com|edu|gov|mil|net|org",gt:"com|edu|gob|ind|mil|net|org",gu:"com|edu|gov|net|org",hk:"com|edu|gov|idv|net|org",id:"ac|co|go|mil|net|or|sch|web",il:"ac|co|gov|idf|k12|muni|net|org", -"in":"ac|co|edu|ernet|firm|gen|gov|i|ind|mil|net|nic|org|res",iq:"com|edu|gov|i|mil|net|org",ir:"ac|co|dnssec|gov|i|id|net|org|sch",it:"edu|gov",je:"co|net|org",jo:"com|edu|gov|mil|name|net|org|sch",jp:"ac|ad|co|ed|go|gr|lg|ne|or",ke:"ac|co|go|info|me|mobi|ne|or|sc",kh:"com|edu|gov|mil|net|org|per",ki:"biz|com|de|edu|gov|info|mob|net|org|tel",km:"asso|com|coop|edu|gouv|k|medecin|mil|nom|notaires|pharmaciens|presse|tm|veterinaire",kn:"edu|gov|net|org",kr:"ac|busan|chungbuk|chungnam|co|daegu|daejeon|es|gangwon|go|gwangju|gyeongbuk|gyeonggi|gyeongnam|hs|incheon|jeju|jeonbuk|jeonnam|k|kg|mil|ms|ne|or|pe|re|sc|seoul|ulsan", -kw:"com|edu|gov|net|org",ky:"com|edu|gov|net|org",kz:"com|edu|gov|mil|net|org",lb:"com|edu|gov|net|org",lk:"assn|com|edu|gov|grp|hotel|int|ltd|net|ngo|org|sch|soc|web",lr:"com|edu|gov|net|org",lv:"asn|com|conf|edu|gov|id|mil|net|org",ly:"com|edu|gov|id|med|net|org|plc|sch",ma:"ac|co|gov|m|net|org|press",mc:"asso|tm",me:"ac|co|edu|gov|its|net|org|priv",mg:"com|edu|gov|mil|nom|org|prd|tm",mk:"com|edu|gov|inf|name|net|org|pro",ml:"com|edu|gov|net|org|presse",mn:"edu|gov|org",mo:"com|edu|gov|net|org", -mt:"com|edu|gov|net|org",mv:"aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro",mw:"ac|co|com|coop|edu|gov|int|museum|net|org",mx:"com|edu|gob|net|org",my:"com|edu|gov|mil|name|net|org|sch",nf:"arts|com|firm|info|net|other|per|rec|store|web",ng:"biz|com|edu|gov|mil|mobi|name|net|org|sch",ni:"ac|co|com|edu|gob|mil|net|nom|org",np:"com|edu|gov|mil|net|org",nr:"biz|com|edu|gov|info|net|org",om:"ac|biz|co|com|edu|gov|med|mil|museum|net|org|pro|sch",pe:"com|edu|gob|mil|net|nom|org|sld",ph:"com|edu|gov|i|mil|net|ngo|org", -pk:"biz|com|edu|fam|gob|gok|gon|gop|gos|gov|net|org|web",pl:"art|bialystok|biz|com|edu|gda|gdansk|gorzow|gov|info|katowice|krakow|lodz|lublin|mil|net|ngo|olsztyn|org|poznan|pwr|radom|slupsk|szczecin|torun|warszawa|waw|wroc|wroclaw|zgora",pr:"ac|biz|com|edu|est|gov|info|isla|name|net|org|pro|prof",ps:"com|edu|gov|net|org|plo|sec",pw:"belau|co|ed|go|ne|or",ro:"arts|com|firm|info|nom|nt|org|rec|store|tm|www",rs:"ac|co|edu|gov|in|org",sb:"com|edu|gov|net|org",sc:"com|edu|gov|net|org",sh:"co|com|edu|gov|net|nom|org", -sl:"com|edu|gov|net|org",st:"co|com|consulado|edu|embaixada|gov|mil|net|org|principe|saotome|store",sv:"com|edu|gob|org|red",sz:"ac|co|org",tr:"av|bbs|bel|biz|com|dr|edu|gen|gov|info|k12|name|net|org|pol|tel|tsk|tv|web",tt:"aero|biz|cat|co|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel",tw:"club|com|ebiz|edu|game|gov|idv|mil|net|org",mu:"ac|co|com|gov|net|or|org",mz:"ac|co|edu|gov|org",na:"co|com",nz:"ac|co|cri|geek|gen|govt|health|iwi|maori|mil|net|org|parliament|school", -pa:"abo|ac|com|edu|gob|ing|med|net|nom|org|sld",pt:"com|edu|gov|int|net|nome|org|publ",py:"com|edu|gov|mil|net|org",qa:"com|edu|gov|mil|net|org",re:"asso|com|nom",ru:"ac|adygeya|altai|amur|arkhangelsk|astrakhan|bashkiria|belgorod|bir|bryansk|buryatia|cbg|chel|chelyabinsk|chita|chukotka|chuvashia|com|dagestan|e-burg|edu|gov|grozny|int|irkutsk|ivanovo|izhevsk|jar|joshkar-ola|kalmykia|kaluga|kamchatka|karelia|kazan|kchr|kemerovo|khabarovsk|khakassia|khv|kirov|koenig|komi|kostroma|kranoyarsk|kuban|kurgan|kursk|lipetsk|magadan|mari|mari-el|marine|mil|mordovia|mosreg|msk|murmansk|nalchik|net|nnov|nov|novosibirsk|nsk|omsk|orenburg|org|oryol|penza|perm|pp|pskov|ptz|rnd|ryazan|sakhalin|samara|saratov|simbirsk|smolensk|spb|stavropol|stv|surgut|tambov|tatarstan|tom|tomsk|tsaritsyn|tsk|tula|tuva|tver|tyumen|udm|udmurtia|ulan-ude|vladikavkaz|vladimir|vladivostok|volgograd|vologda|voronezh|vrn|vyatka|yakutia|yamal|yekaterinburg|yuzhno-sakhalinsk", -rw:"ac|co|com|edu|gouv|gov|int|mil|net",sa:"com|edu|gov|med|net|org|pub|sch",sd:"com|edu|gov|info|med|net|org|tv",se:"a|ac|b|bd|c|d|e|f|g|h|i|k|l|m|n|o|org|p|parti|pp|press|r|s|t|tm|u|w|x|y|z",sg:"com|edu|gov|idn|net|org|per",sn:"art|com|edu|gouv|org|perso|univ",sy:"com|edu|gov|mil|net|news|org",th:"ac|co|go|in|mi|net|or",tj:"ac|biz|co|com|edu|go|gov|info|int|mil|name|net|nic|org|test|web",tn:"agrinet|com|defense|edunet|ens|fin|gov|ind|info|intl|mincom|nat|net|org|perso|rnrt|rns|rnu|tourism",tz:"ac|co|go|ne|or", -ua:"biz|cherkassy|chernigov|chernovtsy|ck|cn|co|com|crimea|cv|dn|dnepropetrovsk|donetsk|dp|edu|gov|if|in|ivano-frankivsk|kh|kharkov|kherson|khmelnitskiy|kiev|kirovograd|km|kr|ks|kv|lg|lugansk|lutsk|lviv|me|mk|net|nikolaev|od|odessa|org|pl|poltava|pp|rovno|rv|sebastopol|sumy|te|ternopil|uzhgorod|vinnica|vn|zaporizhzhe|zhitomir|zp|zt",ug:"ac|co|go|ne|or|org|sc",uk:"ac|bl|british-library|co|cym|gov|govt|icnet|jet|lea|ltd|me|mil|mod|national-library-scotland|nel|net|nhs|nic|nls|org|orgn|parliament|plc|police|sch|scot|soc", -us:"dni|fed|isa|kids|nsn",uy:"com|edu|gub|mil|net|org",ve:"co|com|edu|gob|info|mil|net|org|web",vi:"co|com|k12|net|org",vn:"ac|biz|com|edu|gov|health|info|int|name|net|org|pro",ye:"co|com|gov|ltd|me|net|org|plc",yu:"ac|co|edu|gov|org",za:"ac|agric|alt|bourse|city|co|cybernet|db|edu|gov|grondar|iaccess|imt|inca|landesign|law|mil|net|ngo|nis|nom|olivetti|org|pix|school|tm|web",zm:"ac|co|com|edu|gov|net|org|sch"},has_expression:null,is_expression:null,has:function(h){return!!h.match(e.has_expression)}, -is:function(h){return!!h.match(e.is_expression)},get:function(h){return(h=h.match(e.has_expression))&&h[1]||null},init:function(){var h="",j;for(j in e.list)Object.prototype.hasOwnProperty.call(e.list,j)&&(h+="|("+("("+e.list[j]+")."+j)+")");e.has_expression=RegExp(".("+h.substr(1)+")$","i");e.is_expression=RegExp("^("+h.substr(1)+")$","i")}};e.init();"undefined"!==typeof module&&module.exports?module.exports=e:window.SecondLevelDomains=e})(); -(function(e){function h(a){return a.replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function j(a){return"[object Array]"===""+Object.prototype.toString.call(a)}var f="undefined"!==typeof module&&module.exports,l=f?require("./punycode"):window.punycode,r=f?require("./IPv6"):window.IPv6,p=f?require("./SecondLevelDomains"):window.SecondLevelDomains,d=function(a,b){if(!(this instanceof d))return new d(a);a===e&&(a=location.href+"");this.href(a);return b!==e?this.absoluteTo(b):this},f=d.prototype;d.idn_expression= -/[^a-z0-9\.-]/i;d.punycode_expression=/(xn--)/i;d.ip4_expression=/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;d.ip6_expression=/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; -d.find_uri_expression=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u2018\u2019]))/ig;d.defaultPorts={http:"80",https:"443",ftp:"21"};d.invalid_hostname_characters=/[^a-zA-Z0-9\.-]/;d.encode=encodeURIComponent;d.decode=decodeURIComponent;d.iso8859=function(){d.encode=escape;d.decode=unescape};d.unicode=function(){d.encode=encodeURIComponent; -d.decode=decodeURIComponent};d.characters={pathname:{encode:{expression:/%(24|26|2B|2C|3B|3D|3A|40)/ig,map:{"%24":"$","%26":"&","%2B":"+","%2C":",","%3B":";","%3D":"=","%3A":":","%40":"@"}},decode:{expression:/[\/\?#]/g,map:{"/":"%2F","?":"%3F","#":"%23"}}}};d.encodeQuery=function(a){return d.encode(a+"").replace(/%20/g,"+")};d.decodeQuery=function(a){return d.decode((a+"").replace(/\+/g,"%20"))};d.recodePath=function(a){for(var a=(a+"").split("/"),b=0,c=a.length;bd)return a[0]===b[0]&&"/"===a[0]?"/":"";"/"!==a[d]&&(d=a.substring(0,d).lastIndexOf("/")); -return a.substring(0,d+1)};d.withinString=function(a,b){return a.replace(d.find_uri_expression,b)};d.ensureValidHostname=function(a){if(a.match(d.invalid_hostname_characters)){if(!l)throw new TypeError("Hostname '"+a+"' contains characters other than [A-Z0-9.-] and Punycode.js is not available");if(l.toASCII(a).match(d.invalid_hostname_characters))throw new TypeError("Hostname '"+a+"' contains characters other than [A-Z0-9.-]");}};f.build=function(a){if(!0===a)this._deferred_build=!0;else if(a=== -e||this._deferred_build)this._string=d.build(this._parts),this._deferred_build=!1;return this};f.clone=function(){return new d(this)};f.toString=function(){return this.build(!1)._string};f.valueOf=function(){return this.toString()};k={protocol:"protocol",username:"username",password:"password",hostname:"hostname",port:"port"};q=function(a){return function(b,c){if(b===e)return this._parts[a]||"";this._parts[a]=b;this.build(!c);return this}};for(i in k)f[i]=q(k[i]);k={query:"?",fragment:"#"};q=function(a, -b){return function(c,d){if(c===e)return this._parts[a]||"";null!==c&&(c+="",c[0]===b&&(c=c.substring(1)));this._parts[a]=c;this.build(!d);return this}};for(i in k)f[i]=q(i,k[i]);k={search:["?","query"],hash:["#","fragment"]};q=function(a,b){return function(c,d){var e=this[a](c,d);return"string"===typeof e&&e.length?b+e:e}};for(i in k)f[i]=q(k[i][1],k[i][0]);f.pathname=function(a,b){if(a===e||!0===a){var c=this._parts.path||(this._parts.urn?"":"/");return a?d.decodePath(c):c}this._parts.path=a?d.recodePath(a): -"/";this.build(!b);return this};f.path=f.pathname;f.href=function(a,b){if(a===e)return this.toString();this._string="";this._parts={protocol:null,username:null,password:null,hostname:null,urn:null,port:null,path:null,query:null,fragment:null};var c=a instanceof d,g="object"===typeof a&&(a.hostname||a.path),f;if("string"===typeof a)this._parts=d.parse(a);else if(c||g)for(f in c=c?a._parts:a,c)Object.hasOwnProperty.call(this._parts,f)&&(this._parts[f]=c[f]);else throw new TypeError("invalid input"); -this.build(!b);return this};f.is=function(a){var b=!1,c=!1,g=!1,e=!1,f=!1,h=!1,i=!1,j=!this._parts.urn;this._parts.hostname&&(j=!1,c=d.ip4_expression.test(this._parts.hostname),g=d.ip6_expression.test(this._parts.hostname),b=c||g,f=(e=!b)&&p&&p.has(this._parts.hostname),h=e&&d.idn_expression.test(this._parts.hostname),i=e&&d.punycode_expression.test(this._parts.hostname));switch(a.toLowerCase()){case "relative":return j;case "absolute":return!j;case "domain":case "name":return e;case "sld":return f; -case "ip":return b;case "ip4":case "ipv4":case "inet4":return c;case "ip6":case "ipv6":case "inet6":return g;case "idn":return h;case "url":return!this._parts.urn;case "urn":return!!this._parts.urn;case "punycode":return i}return null};var z=f.protocol,v=f.port,s=f.hostname;f.protocol=function(a,b){if(a!==e&&a&&(a=a.replace(/:(\/\/)?$/,""),a.match(/[^a-zA-z0-9\.+-]/)))throw new TypeError("Protocol '"+a+"' contains characters other than [A-Z0-9.+-]");return z.call(this,a,b)};f.scheme=f.protocol;f.port= -function(a,b){if(this._parts.urn)return a===e?"":this;if(a!==e&&(0===a&&(a=null),a&&(a+="",":"===a[0]&&(a=a.substring(1)),a.match(/[^0-9]/))))throw new TypeError("Port '"+a+"' contains characters other than [0-9]");return v.call(this,a,b)};f.hostname=function(a,b){if(this._parts.urn)return a===e?"":this;if(a!==e){var c={};d.parseHost(a,c);a=c.hostname}return s.call(this,a,b)};f.host=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e)return this._parts.hostname?d.buildHost(this._parts): -"";d.parseHost(a,this._parts);this.build(!b);return this};f.authority=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e)return this._parts.hostname?d.buildAuthority(this._parts):"";d.parseAuthority(a,this._parts);this.build(!b);return this};f.userinfo=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e){if(!this._parts.username)return"";var c=d.buildUserinfo(this._parts);return c.substring(0,c.length-1)}"@"!==a[a.length-1]&&(a+="@");d.parseUserinfo(a,this._parts);this.build(!b); -return this};f.subdomain=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e)return!this._parts.hostname||this.is("IP")?"":this._parts.hostname.substring(0,this._parts.hostname.length-this.domain().length-1)||"";var c=this._parts.hostname.substring(0,this._parts.hostname.length-this.domain().length),c=RegExp("^"+h(c));a&&"."!==a[a.length-1]&&(a+=".");a&&d.ensureValidHostname(a);this._parts.hostname=this._parts.hostname.replace(c,a);this.build(!b);return this};f.domain=function(a,b){if(this._parts.urn)return a=== -e?"":this;"boolean"==typeof a&&(b=a,a=e);if(a===e){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.match(/\./g);if(c&&2>c.length)return this._parts.hostname;c=this._parts.hostname.length-this.tld(b).length-1;c=this._parts.hostname.lastIndexOf(".",c-1)+1;return this._parts.hostname.substring(c)||""}if(!a)throw new TypeError("cannot set domain empty");d.ensureValidHostname(a);this._parts.hostname=!this._parts.hostname||this.is("IP")?a:this._parts.hostname.replace(RegExp(h(this.domain())+ -"$"),a);this.build(!b);return this};f.tld=function(a,b){if(this._parts.urn)return a===e?"":this;"boolean"==typeof a&&(b=a,a=e);if(a===e){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.substring(this._parts.hostname.lastIndexOf(".")+1);return!0!==b&&p&&p.list[c.toLowerCase()]?p.get(this._parts.hostname)||c:c}if(a)if(a.match(/[^a-zA-Z0-9-]/))if(p&&p.is(a))c=RegExp(h(this.tld())+"$"),this._parts.hostname=this._parts.hostname.replace(c,a);else throw new TypeError("TLD '"+ -a+"' contains characters other than [A-Z0-9]");else{if(!this._parts.hostname||this.is("IP"))throw new ReferenceError("cannot set TLD on non-domain host");c=RegExp(h(this.tld())+"$");this._parts.hostname=this._parts.hostname.replace(c,a)}else throw new TypeError("cannot set TLD empty");this.build(!b);return this};f.directory=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e||!0===a){if(!this._parts.path&&!this._parts.hostname)return"";if("/"===this._parts.path)return"/";var c=this._parts.path.substring(0, -this._parts.path.length-this.filename().length-1)||(this._parts.hostname?"/":"");return a?d.decodePath(c):c}c=this._parts.path.substring(0,this._parts.path.length-this.filename().length);c=RegExp("^"+h(c));this.is("relative")||(a||(a="/"),"/"!==a[0]&&(a="/"+a));a&&"/"!==a[a.length-1]&&(a+="/");a=d.recodePath(a);this._parts.path=this._parts.path.replace(c,a);this.build(!b);return this};f.filename=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e||!0===a){if(!this._parts.path||"/"===this._parts.path)return""; -var c=this._parts.path.substring(this._parts.path.lastIndexOf("/")+1);return a?d.decodePathSegment(c):c}c=!1;"/"===a[0]&&(a=a.substring(1));a.match(/\.?\//)&&(c=!0);var g=RegExp(h(this.filename())+"$"),a=d.recodePath(a);this._parts.path=this._parts.path.replace(g,a);c?this.normalizePath(b):this.build(!b);return this};f.suffix=function(a,b){if(this._parts.urn)return a===e?"":this;if(a===e||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";var c=this.filename(),g=c.lastIndexOf(".");if(-1=== -g)return"";c=c.substring(g+1);c=/^[a-z0-9%]+$/i.test(c)?c:"";return a?d.decodePathSegment(c):c}"."===a[0]&&(a=a.substring(1));if(c=this.suffix())g=a?RegExp(h(c)+"$"):RegExp(h("."+c)+"$");else{if(!a)return this;this._parts.path+="."+d.recodePath(a)}g&&(a=d.recodePath(a),this._parts.path=this._parts.path.replace(g,a));this.build(!b);return this};var y=f.query;f.query=function(a,b){return!0===a?d.parseQuery(this._parts.query):a!==e&&"string"!==typeof a?(this._parts.query=d.buildQuery(a),this.build(!b), -this):y.call(this,a,b)};f.addQuery=function(a,b,c){var g=d.parseQuery(this._parts.query);d.addQuery(g,a,b);this._parts.query=d.buildQuery(g);"string"!==typeof a&&(c=b);this.build(!c);return this};f.removeQuery=function(a,b,c){var g=d.parseQuery(this._parts.query);d.removeQuery(g,a,b);this._parts.query=d.buildQuery(g);"string"!==typeof a&&(c=b);this.build(!c);return this};f.addSearch=f.addQuery;f.removeSearch=f.removeQuery;f.normalize=function(){return this._parts.urn?this.normalizeProtocol(!1).normalizeQuery(!1).normalizeFragment(!1).build(): -this.normalizeProtocol(!1).normalizeHostname(!1).normalizePort(!1).normalizePath(!1).normalizeQuery(!1).normalizeFragment(!1).build()};f.normalizeProtocol=function(a){"string"===typeof this._parts.protocol&&(this._parts.protocol=this._parts.protocol.toLowerCase(),this.build(!a));return this};f.normalizeHostname=function(a){this._parts.hostname&&(this.is("IDN")&&l?this._parts.hostname=l.toASCII(this._parts.hostname):this.is("IPv6")&&r&&(this._parts.hostname=r.best(this._parts.hostname)),this._parts.hostname= -this._parts.hostname.toLowerCase(),this.build(!a));return this};f.normalizePort=function(a){"string"===typeof this._parts.protocol&&this._parts.port===d.defaultPorts[this._parts.protocol]&&(this._parts.port=null,this.build(!a));return this};f.normalizePath=function(a){if(this._parts.urn||!this._parts.path||"/"===this._parts.path)return this;var b,c,g=this._parts.path,e,f;"/"!==g[0]&&("."===g[0]&&(c=g.substring(0,g.indexOf("/"))),b=!0,g="/"+g);for(g=g.replace(/(\/(\.\/)+)|\/{2,}/g,"/");;){e=g.indexOf("/../"); -if(-1===e)break;else if(0===e){g=g.substring(3);break}f=g.substring(0,e).lastIndexOf("/");-1===f&&(f=e);g=g.substring(0,f)+g.substring(e+3)}b&&this.is("relative")&&(g=c?c+g:g.substring(1));g=d.recodePath(g);this._parts.path=g;this.build(!a);return this};f.normalizePathname=f.normalizePath;f.normalizeQuery=function(a){"string"===typeof this._parts.query&&(this._parts.query.length?this.query(d.parseQuery(this._parts.query)):this._parts.query=null,this.build(!a));return this};f.normalizeFragment=function(a){this._parts.fragment|| -(this._parts.fragment=null,this.build(!a));return this};f.normalizeSearch=f.normalizeQuery;f.normalizeHash=f.normalizeFragment;f.iso8859=function(){var a=d.encode,b=d.decode;d.encode=escape;d.decode=decodeURIComponent;this.normalize();d.encode=a;d.decode=b;return this};f.unicode=function(){var a=d.encode,b=d.decode;d.encode=encodeURIComponent;d.decode=unescape;this.normalize();d.encode=a;d.decode=b;return this};f.readable=function(){var a=this.clone();a.username("").password("").normalize();var b= -"";a._parts.protocol&&(b+=a._parts.protocol+"://");a._parts.hostname&&(a.is("punycode")&&l?(b+=l.toUnicode(a._parts.hostname),a._parts.port&&(b+=":"+a._parts.port)):b+=a.host());a._parts.hostname&&(a._parts.path&&"/"!==a._parts.path[0])&&(b+="/");b+=a.path(!0);if(a._parts.query){for(var c="",g=0,f=a._parts.query.split("&"),h=f.length;g -${renderer.render_comments(thread.get('children'))} diff --git a/lms/templates/discussion/_content_renderer.html b/lms/templates/discussion/_content_renderer.html deleted file mode 100644 index 1de687cb19..0000000000 --- a/lms/templates/discussion/_content_renderer.html +++ /dev/null @@ -1,20 +0,0 @@ -<%! import django_comment_client.helpers as helpers %> - -<%def name="render_content(content, *args, **kwargs)"> - ${helpers.render_content(content, *args, **kwargs)} - - -<%def name="render_content_with_comments(content, *args, **kwargs)"> -
- ${render_content(content, *args, **kwargs)} - ${render_comments(content.get('children', []), *args, **kwargs)} -
- - -<%def name="render_comments(comments, *args, **kwargs)"> -
- % for comment in comments: - ${render_content_with_comments(comment, *args, **kwargs)} - % endfor -
- diff --git a/lms/templates/discussion/_forum.html b/lms/templates/discussion/_forum.html deleted file mode 100644 index b43efae666..0000000000 --- a/lms/templates/discussion/_forum.html +++ /dev/null @@ -1,26 +0,0 @@ -<%namespace name="renderer" file="_content_renderer.html"/> - -
- -
-
- <%include file="_search_bar.html" /> -
-
- % if len(threads) == 0: -
- <%include file="_blank_slate.html" /> -
-
- % else: - <%include file="_sort.html" /> -
- % for thread in threads: - ${renderer.render_content_with_comments(thread)} - % endfor -
- <%include file="_paginator.html" /> - % endif -
- -<%include file="_js_data.html" /> diff --git a/lms/templates/discussion/_inline.html b/lms/templates/discussion/_inline.html deleted file mode 100644 index abef7f39e8..0000000000 --- a/lms/templates/discussion/_inline.html +++ /dev/null @@ -1,16 +0,0 @@ -<%namespace name="renderer" file="_content_renderer.html"/> - -
- -
- -
- % for thread in threads: - ${renderer.render_content_with_comments(thread)} - % endfor -
- - <%include file="_paginator.html" /> -
- -<%include file="_js_data.html" /> diff --git a/lms/templates/discussion/_js_dependencies.html b/lms/templates/discussion/_js_dependencies.html index bde873fee1..961f254efe 100644 --- a/lms/templates/discussion/_js_dependencies.html +++ b/lms/templates/discussion/_js_dependencies.html @@ -9,7 +9,7 @@ - + diff --git a/lms/templates/discussion/_js_head_dependencies.html b/lms/templates/discussion/_js_head_dependencies.html index bde873fee1..961f254efe 100644 --- a/lms/templates/discussion/_js_head_dependencies.html +++ b/lms/templates/discussion/_js_head_dependencies.html @@ -9,7 +9,7 @@ - + diff --git a/lms/templates/discussion/_single_thread.html b/lms/templates/discussion/_single_thread.html deleted file mode 100644 index a14e03d10f..0000000000 --- a/lms/templates/discussion/_single_thread.html +++ /dev/null @@ -1,39 +0,0 @@ -<%! from django.utils.translation import ugettext as _ %> -<%namespace name="renderer" file="_content_renderer.html"/> -<%! from django_comment_client.mustache_helpers import url_for_user %> - -
- -
- -
- %if thread['group_id']: -
${_("This post visible only to group {group}.").format(group=cohort_dictionary[thread['group_id']])}
- %endif - - + ${thread['votes']['up_count']}votes (click to vote) -

${thread['title']}

-

- sometime by - ${thread['username']} -

-
-
- ${thread['body']} -
-
-
    - % for reply in thread.get("children", []): -
  1. -
    ${reply['body']}
    -
      - % for comment in reply.get("children", []): -
    1. ${comment['body']}
    2. - % endfor -
    -
  2. - % endfor -
-
- -<%include file="_js_data.html" /> diff --git a/lms/templates/discussion/_underscore_templates.html b/lms/templates/discussion/_underscore_templates.html index e331a779a5..2ebd1465e1 100644 --- a/lms/templates/discussion/_underscore_templates.html +++ b/lms/templates/discussion/_underscore_templates.html @@ -31,8 +31,8 @@
${"<%- obj.group_string%>"}
${"<% } %>"} - - + ${'<%- votes["up_count"] %>'}votes (click to vote) + + ${'<%- votes["up_count"] %>'} votes (click to vote)

${'<%- title %>'}

${"<% if (obj.username) { %>"} @@ -123,7 +123,7 @@