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)