From 8506cbcd1573bdae0b7c46e040d89fdeb7dea300 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Fri, 14 Sep 2012 00:11:32 -0700 Subject: [PATCH] Response editing --- .../views/discussion_thread_edit_view.coffee | 39 +-- .../views/discussion_thread_show_view.coffee | 240 +++++++++--------- .../views/response_comment_show_view.coffee | 35 +++ .../views/thread_response_edit_view.coffee | 25 ++ .../views/thread_response_show_view.coffee | 91 +++++++ .../views/thread_response_view.coffee | 159 +++++++----- .../discussion/_underscore_templates.html | 30 ++- 7 files changed, 407 insertions(+), 212 deletions(-) create mode 100644 lms/static/coffee/src/discussion/views/response_comment_show_view.coffee create mode 100644 lms/static/coffee/src/discussion/views/thread_response_edit_view.coffee create mode 100644 lms/static/coffee/src/discussion/views/thread_response_show_view.coffee diff --git a/lms/static/coffee/src/discussion/views/discussion_thread_edit_view.coffee b/lms/static/coffee/src/discussion/views/discussion_thread_edit_view.coffee index 18c1701e50..6e9be30b6e 100644 --- a/lms/static/coffee/src/discussion/views/discussion_thread_edit_view.coffee +++ b/lms/static/coffee/src/discussion/views/discussion_thread_edit_view.coffee @@ -1,25 +1,26 @@ -class @DiscussionThreadEditView extends Backbone.View +if Backbone? + class @DiscussionThreadEditView extends Backbone.View - events: - "click .post-update": "update" - "click .post-cancel": "cancel_edit" + events: + "click .post-update": "update" + "click .post-cancel": "cancel_edit" - $: (selector) -> - @$el.find(selector) + $: (selector) -> + @$el.find(selector) - initialize: -> - super() + initialize: -> + super() - render: -> - @template = _.template($("#thread-edit-template").html()) - @$el.html(@template(@model.toJSON())) - @delegateEvents() - DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "edit-post-body" - @$(".edit-post-tags").tagsInput DiscussionUtil.tagsInputOptions() - @ + render: -> + @template = _.template($("#thread-edit-template").html()) + @$el.html(@template(@model.toJSON())) + @delegateEvents() + DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "edit-post-body" + @$(".edit-post-tags").tagsInput DiscussionUtil.tagsInputOptions() + @ - update: (event) -> - @trigger "thread:update", event + update: (event) -> + @trigger "thread:update", event - cancel_edit: (event) -> - @trigger "thread:cancel_edit", event + cancel_edit: (event) -> + @trigger "thread:cancel_edit", event diff --git a/lms/static/coffee/src/discussion/views/discussion_thread_show_view.coffee b/lms/static/coffee/src/discussion/views/discussion_thread_show_view.coffee index 8bb01196d0..79ff3116de 100644 --- a/lms/static/coffee/src/discussion/views/discussion_thread_show_view.coffee +++ b/lms/static/coffee/src/discussion/views/discussion_thread_show_view.coffee @@ -1,137 +1,139 @@ -class @DiscussionThreadShowView extends DiscussionContentView +if Backbone? + class @DiscussionThreadShowView extends DiscussionContentView - events: - "click .discussion-vote": "toggleVote" - "click .action-follow": "toggleFollowing" - "click .action-edit": "edit" - "click .action-delete": "delete" - "click .action-openclose": "toggleClosed" + events: + "click .discussion-vote": "toggleVote" + "click .action-follow": "toggleFollowing" + "click .action-edit": "edit" + "click .action-delete": "delete" + "click .action-openclose": "toggleClosed" - $: (selector) -> - @$el.find(selector) + $: (selector) -> + @$el.find(selector) - initialize: -> - super() - @model.on "change", @updateModelDetails + initialize: -> + super() + @model.on "change", @updateModelDetails - renderTemplate: -> - @template = _.template($("#thread-show-template").html()) - @template(@model.toJSON()) - render: -> - @$el.html(@renderTemplate()) - @delegateEvents() - @renderDogear() - @renderVoted() - @renderAttrs() - @$("span.timeago").timeago() - @convertMath() - @highlight @$(".post-body") - @highlight @$("h1,h3") - @ + renderTemplate: -> + @template = _.template($("#thread-show-template").html()) + @template(@model.toJSON()) - renderDogear: -> - if window.user.following(@model) - @$(".dogear").addClass("is-followed") + render: -> + @$el.html(@renderTemplate()) + @delegateEvents() + @renderDogear() + @renderVoted() + @renderAttrs() + @$("span.timeago").timeago() + @convertMath() + @highlight @$(".post-body") + @highlight @$("h1,h3") + @ - renderVoted: => - if window.user.voted(@model) - @$("[data-role=discussion-vote]").addClass("is-cast") - else - @$("[data-role=discussion-vote]").removeClass("is-cast") + renderDogear: -> + if window.user.following(@model) + @$(".dogear").addClass("is-followed") - updateModelDetails: => - @renderVoted() - @$("[data-role=discussion-vote] .votes-count-number").html(@model.get("votes")["up_count"]) + renderVoted: => + if window.user.voted(@model) + @$("[data-role=discussion-vote]").addClass("is-cast") + else + @$("[data-role=discussion-vote]").removeClass("is-cast") - convertMath: -> - element = @$(".post-body") - element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() - MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] + updateModelDetails: => + @renderVoted() + @$("[data-role=discussion-vote] .votes-count-number").html(@model.get("votes")["up_count"]) - toggleVote: (event) -> - event.preventDefault() - if window.user.voted(@model) - @unvote() - else - @vote() + convertMath: -> + element = @$(".post-body") + element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() + MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] - toggleFollowing: (event) -> - $elem = $(event.target) - url = null - if not @model.get('subscribed') - @model.follow() - url = @model.urlFor("follow") - else - @model.unfollow() - url = @model.urlFor("unfollow") - DiscussionUtil.safeAjax - $elem: $elem - url: url - type: "POST" + 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}) + toggleFollowing: (event) -> + $elem = $(event.target) + url = null + if not @model.get('subscribed') + @model.follow() + url = @model.urlFor("follow") + else + @model.unfollow() + url = @model.urlFor("unfollow") + DiscussionUtil.safeAjax + $elem: $elem + url: url + type: "POST" - 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}) + 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}) - edit: (event) -> - @trigger "thread:edit", event + 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}) - delete: (event) -> - @trigger "thread:delete", event + edit: (event) -> + @trigger "thread:edit", event - toggleClosed: (event) -> - $elem = $(event.target) - url = @model.urlFor('close') - closed = @model.get('closed') - data = { closed: not closed } - DiscussionUtil.safeAjax - $elem: $elem - url: url - data: data - type: "POST" - success: (response, textStatus) => - @model.set('closed', not closed) - @model.set('ability', response.ability) + delete: (event) -> + @trigger "thread:delete", event - toggleEndorse: (event) -> - $elem = $(event.target) - url = @model.urlFor('endorse') - endorsed = @model.get('endorsed') - data = { endorsed: not endorsed } - DiscussionUtil.safeAjax - $elem: $elem - url: url - data: data - type: "POST" - success: (response, textStatus) => - @model.set('endorsed', not endorsed) + toggleClosed: (event) -> + $elem = $(event.target) + url = @model.urlFor('close') + closed = @model.get('closed') + data = { closed: not closed } + DiscussionUtil.safeAjax + $elem: $elem + url: url + data: data + type: "POST" + success: (response, textStatus) => + @model.set('closed', not closed) + @model.set('ability', response.ability) - highlight: (el) -> - if el.html() - el.html(el.html().replace(/<mark>/g, "").replace(/<\/mark>/g, "")) + toggleEndorse: (event) -> + $elem = $(event.target) + url = @model.urlFor('endorse') + endorsed = @model.get('endorsed') + data = { endorsed: not endorsed } + DiscussionUtil.safeAjax + $elem: $elem + url: url + data: data + type: "POST" + success: (response, textStatus) => + @model.set('endorsed', not endorsed) -class @DiscussionThreadInlineShowView extends DiscussionThreadShowView - renderTemplate: -> - @template = DiscussionUtil.getTemplate('_inline_thread_show') - params = @model.toJSON() - if not @model.get('anonymous') - params = $.extend(params, user:{username: @model.username, user_url: @model.user_url}) - Mustache.render(@template, params) + highlight: (el) -> + if el.html() + el.html(el.html().replace(/<mark>/g, "").replace(/<\/mark>/g, "")) + + class @DiscussionThreadInlineShowView extends DiscussionThreadShowView + renderTemplate: -> + @template = DiscussionUtil.getTemplate('_inline_thread_show') + params = @model.toJSON() + if not @model.get('anonymous') + params = $.extend(params, user:{username: @model.username, user_url: @model.user_url}) + Mustache.render(@template, params) diff --git a/lms/static/coffee/src/discussion/views/response_comment_show_view.coffee b/lms/static/coffee/src/discussion/views/response_comment_show_view.coffee new file mode 100644 index 0000000000..2fb85f8f96 --- /dev/null +++ b/lms/static/coffee/src/discussion/views/response_comment_show_view.coffee @@ -0,0 +1,35 @@ +if Backbone? + class @ResponseCommentShowView extends DiscussionContentView + + tagName: "li" + + render: -> + @template = _.template($("#response-comment-show-template").html()) + params = @model.toJSON() + + # Only things that are nested under comments get parents + params['deep'] = @model.hasOwnProperty('parent') + if @model.hasOwnProperty('parent') + params['parent_id'] = @model.parent.id + params['parent_username'] = @model.parent.get('username') + + @$el.html(@template(params)) + @initLocal() + @delegateEvents() + @renderAttrs() + @markAsStaff() + @$el.find(".timeago").timeago() + @convertMath() + @ + + convertMath: -> + body = @$el.find(".response-body") + body.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight body.html() + # This removes paragraphs so that comments are more compact + body.children("p").each (index, elem) -> + $(elem).replaceWith($(elem).html()) + MathJax.Hub.Queue ["Typeset", MathJax.Hub, body[0]] + + markAsStaff: -> + if DiscussionUtil.isStaff(@model.get("user_id")) + @$el.find("a.profile-link").after('staff') diff --git a/lms/static/coffee/src/discussion/views/thread_response_edit_view.coffee b/lms/static/coffee/src/discussion/views/thread_response_edit_view.coffee new file mode 100644 index 0000000000..82f2c7d2f1 --- /dev/null +++ b/lms/static/coffee/src/discussion/views/thread_response_edit_view.coffee @@ -0,0 +1,25 @@ +if Backbone? + class @ThreadResponseEditView extends Backbone.View + + events: + "click .post-update": "update" + "click .post-cancel": "cancel_edit" + + $: (selector) -> + @$el.find(selector) + + initialize: -> + super() + + render: -> + @template = _.template($("#thread-response-edit-template").html()) + @$el.html(@template(@model.toJSON())) + @delegateEvents() + DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "edit-post-body" + @ + + update: (event) -> + @trigger "response:update", event + + cancel_edit: (event) -> + @trigger "response:cancel_edit", event diff --git a/lms/static/coffee/src/discussion/views/thread_response_show_view.coffee b/lms/static/coffee/src/discussion/views/thread_response_show_view.coffee new file mode 100644 index 0000000000..6da57c845d --- /dev/null +++ b/lms/static/coffee/src/discussion/views/thread_response_show_view.coffee @@ -0,0 +1,91 @@ +if Backbone? + class @ThreadResponseShowView extends DiscussionContentView + events: + "click .vote-btn": "toggleVote" + "click .action-endorse": "toggleEndorse" + "click .action-delete": "delete" + "click .action-edit": "edit" + + $: (selector) -> + @$el.find(selector) + + initialize: -> + super() + @model.on "change", @updateModelDetails + + renderTemplate: -> + @template = _.template($("#thread-response-show-template").html()) + @template(@model.toJSON()) + + render: -> + @$el.html(@renderTemplate()) + @delegateEvents() + if window.user.voted(@model) + @$(".vote-btn").addClass("is-cast") + @renderAttrs() + @$el.find(".posted-details").timeago() + @convertMath() + @markAsStaff() + @ + + convertMath: -> + element = @$(".response-body") + element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() + MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] + + markAsStaff: -> + if DiscussionUtil.isStaff(@model.get("user_id")) + @$el.addClass("staff") + @$el.prepend('
staff
') + + toggleVote: (event) -> + event.preventDefault() + @$(".vote-btn").toggleClass("is-cast") + if @$(".vote-btn").hasClass("is-cast") + @vote() + else + @unvote() + + 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 + + delete: (event) -> + @trigger "response:delete", event + + toggleEndorse: (event) -> + event.preventDefault() + if not @model.can('can_endorse') + return + $elem = $(event.target) + url = @model.urlFor('endorse') + endorsed = @model.get('endorsed') + data = { endorsed: not endorsed } + @model.set('endorsed', not endorsed) + @trigger "comment:endorse", not endorsed + DiscussionUtil.safeAjax + $elem: $elem + url: url + data: data + type: "POST" diff --git a/lms/static/coffee/src/discussion/views/thread_response_view.coffee b/lms/static/coffee/src/discussion/views/thread_response_view.coffee index c6f0643de6..7ff1b1a157 100644 --- a/lms/static/coffee/src/discussion/views/thread_response_view.coffee +++ b/lms/static/coffee/src/discussion/views/thread_response_view.coffee @@ -3,35 +3,28 @@ if Backbone? tagName: "li" events: - "click .vote-btn": "toggleVote" "submit .comment-form": "submitComment" - "click .action-endorse": "toggleEndorse" - "click .action-delete": "delete" + + $: (selector) -> + @$el.find(selector) + + initialize: -> + @createShowView() + + renderTemplate: -> + @template = _.template($("#thread-response-template").html()) + @template(@model.toJSON()) render: -> - @template = _.template($("#thread-response-template").html()) - @$el.html(@template(@model.toJSON())) - @initLocal() + @$el.html(@renderTemplate()) @delegateEvents() - if window.user.voted(@model) - @$(".vote-btn").addClass("is-cast") + + @renderShowView() @renderAttrs() - @$el.find(".posted-details").timeago() - @convertMath() - @markAsStaff() + @renderComments() @ - convertMath: -> - element = @$(".response-body") - element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() - MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] - - markAsStaff: -> - if DiscussionUtil.isStaff(@model.get("user_id")) - @$el.addClass("staff") - @$el.prepend('
staff
') - renderComments: -> comments = new Comments() comments.comparator = (comment) -> @@ -52,36 +45,6 @@ if Backbone? @$el.find(".comments li:last").before(view.el) view - toggleVote: (event) -> - event.preventDefault() - @$(".vote-btn").toggleClass("is-cast") - if @$(".vote-btn").hasClass("is-cast") - @vote() - else - @unvote() - - 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) - submitComment: (event) -> event.preventDefault() url = @model.urlFor('reply') @@ -103,14 +66,14 @@ if Backbone? success: (response, textStatus) -> comment.set(response.content) view.render() # This is just to update the id for the most part, but might be useful in general - delete: (event) -> + + delete: (event) => event.preventDefault() if not @model.can('can_delete') return - console.log $(event.target) - url = @model.urlFor('delete') if not confirm "Are you sure to delete this response? " return + url = @model.urlFor('delete') @model.remove() @$el.remove() $elem = $(event.target) @@ -120,18 +83,80 @@ if Backbone? type: "POST" success: (response, textStatus) => - toggleEndorse: (event) -> + createEditView: () -> + if @showView? + @showView.undelegateEvents() + @showView.$el.empty() + @showView = null + + @editView = new ThreadResponseEditView(model: @model) + @editView.bind "response:update", @update + @editView.bind "response:cancel_edit", @cancelEdit + + renderSubView: (view) -> + view.setElement(@$('.discussion-response')) + view.render() + view.delegateEvents() + + renderEditView: () -> + @renderSubView(@editView) + + hideCommentForm: () -> + @$('.comment-form').closest('li').hide() + + showCommentForm: () -> + @$('.comment-form').closest('li').show() + + createShowView: () -> + + if @editView? + @editView.undelegateEvents() + @editView.$el.empty() + @editView = null + + @showView = new ThreadResponseShowView(model: @model) + @showView.bind "response:delete", @delete + @showView.bind "response:edit", @edit + + renderShowView: () -> + @renderSubView(@showView) + + cancelEdit: (event) => event.preventDefault() - if not @model.can('can_endorse') - return - $elem = $(event.target) - url = @model.urlFor('endorse') - endorsed = @model.get('endorsed') - data = { endorsed: not endorsed } - @model.set('endorsed', not endorsed) - @trigger "comment:endorse", not endorsed + @createShowView() + @renderShowView() + @showCommentForm() + + edit: (event) => + @createEditView() + @renderEditView() + @hideCommentForm() + + update: (event) => + + newBody = @editView.$(".edit-post-body textarea").val() + + url = DiscussionUtil.urlFor('update_comment', @model.id) + DiscussionUtil.safeAjax - $elem: $elem - url: url - data: data - type: "POST" + $elem: $(event.target) + $loading: $(event.target) if event + url: url + type: "POST" + dataType: 'json' + async: false # TODO when the rest of the stuff below is made to work properly.. + data: + body: newBody + error: DiscussionUtil.formErrorHandler(@$(".edit-post-form-errors")) + success: (response, textStatus) => + # TODO: Move this out of the callback, this makes it feel sluggish + @editView.$(".edit-post-body textarea").val("").attr("prev-text", "") + @editView.$(".wmd-preview p").html("") + + @model.set + body: newBody + + @createShowView() + @renderShowView() + @showCommentForm() + diff --git a/lms/templates/discussion/_underscore_templates.html b/lms/templates/discussion/_underscore_templates.html index 5fc84c6676..24780cb4dd 100644 --- a/lms/templates/discussion/_underscore_templates.html +++ b/lms/templates/discussion/_underscore_templates.html @@ -72,6 +72,17 @@ + + + +