Commit 07f818da by Rocky Duan

got reply working under backbone framework

parent 9dedd532
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template.defaultfilters import escapejs
from django.conf import settings from django.conf import settings
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
from mustache_helpers import mustache_helpers from mustache_helpers import mustache_helpers
...@@ -24,11 +23,11 @@ def show_if(text, condition): ...@@ -24,11 +23,11 @@ def show_if(text, condition):
# TODO there should be a better way to handle this # TODO there should be a better way to handle this
def include_mustache_templates(): def include_mustache_templates():
mustache_dir = settings.PROJECT_ROOT / 'templates' / 'discussion' mustache_dir = settings.PROJECT_ROOT / 'templates' / 'discussion' / 'mustache'
valid_file_name = lambda file_name: file_name.endswith('.mustache') valid_file_name = lambda file_name: file_name.endswith('.mustache')
read_file = lambda file_name: (file_name, open(mustache_dir / file_name, "r").read()) read_file = lambda file_name: (file_name, open(mustache_dir / file_name, "r").read())
strip_file_name = lambda x: (x[0].rpartition('.')[0], x[1]) strip_file_name = lambda x: (x[0].rpartition('.')[0], x[1])
wrap_in_tag = lambda x: "<script type='text/template' id='{0}'>{1}</script>".format(x[0], escapejs(x[1])) wrap_in_tag = lambda x: "<script type='text/template' id='{0}'>{1}</script>".format(x[0], x[1])
file_contents = map(read_file, filter(valid_file_name, os.listdir(mustache_dir))) 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))) return '\n'.join(map(wrap_in_tag, map(strip_file_name, file_contents)))
...@@ -48,4 +47,4 @@ def render_content(content, additional_context={}): ...@@ -48,4 +47,4 @@ def render_content(content, additional_context={}):
context = merge_dict(context, additional_context) context = merge_dict(context, additional_context)
partial_mustache_helpers = {k: partial(v, content) for k, v in mustache_helpers.items()} partial_mustache_helpers = {k: partial(v, content) for k, v in mustache_helpers.items()}
context = merge_dict(context, partial_mustache_helpers) context = merge_dict(context, partial_mustache_helpers)
return render_mustache('discussion/_content.mustache', context) return render_mustache('discussion/mustache/_content.mustache', context)
...@@ -4,7 +4,6 @@ import json ...@@ -4,7 +4,6 @@ import json
class AjaxExceptionMiddleware(object): class AjaxExceptionMiddleware(object):
def process_exception(self, request, exception): def process_exception(self, request, exception):
import pdb; pdb.set_trace()
if isinstance(exception, CommentClientError) and request.is_ajax(): if isinstance(exception, CommentClientError) and request.is_ajax():
return JsonError(json.loads(exception.message)) return JsonError(json.loads(exception.message))
return None return None
...@@ -18,6 +18,9 @@ class @Content extends Backbone.Model ...@@ -18,6 +18,9 @@ class @Content extends Backbone.Model
can: (action) -> can: (action) ->
DiscussionUtil.getContentInfo @id, action DiscussionUtil.getContentInfo @id, action
thread_id: ->
if @get('type') == "comment" then @get('thread_id') else @id
initialize: -> initialize: ->
@set('comments', new Comments()) @set('comments', new Comments())
if @get('children') if @get('children')
...@@ -28,99 +31,110 @@ class @ContentView extends Backbone.View ...@@ -28,99 +31,110 @@ class @ContentView extends Backbone.View
$: (selector) -> $: (selector) ->
@$local.find(selector) @$local.find(selector)
showSingleThread: (event) -> discussionContent: ->
if @showed @_discussionContent ||= @$el.children(".discussion-content")
@$el.children(".comments").hide()
@showed = false
$showComments = @$(".discussion-show-comments")
prevHtml = $showComments.html()
$showComments.html prevHtml.replace "Hide", "Show"
else
if @retrieved
@$el.children(".comments").show()
@showed = true
else
discussion_id = @model.discussion.id
url = DiscussionUtil.urlFor('retrieve_single_thread', discussion_id, @model.id)
DiscussionUtil.safeAjax
$elem: $.merge @$(".thread-title"), @$(".discussion-show-comments")
url: url
type: "GET"
dataType: 'json'
success: (response, textStatus) =>
DiscussionUtil.bulkExtendContentInfo response['annotated_content_info']
@retrieved = true
@showed = true
@$el.append(response['html'])
@model.get('comments').reset response.content.children, {silent: false}
@initCommentViews()
return
$threadTitle = @$(".thread-title")
$showComments = @$(".discussion-show-comments")
if not $showComments.hasClass("first-time") and (not $showComments.length or not $threadTitle.length)
return
rebindHideEvents = -> hideSingleThread: (event) ->
$threadTitle.unbind('click').click @hideSingleThread $showComments = @$(".discussion-show-comments")
$showComments.unbind('click').click @hideSingleThread @$el.children(".comments").hide()
$showComments.removeClass("discussion-show-comments") @showed = false
.addClass("discussion-hide-comments") $showComments.html $showComments.html().replace "Hide", "Show"
prevHtml = $showComments.html()
$showComments.html prevHtml.replace "Show", "Hide"
if not $showComments.hasClass("first-time") and @$el.children(".comments").length showSingleThread: (event) ->
$showComments = @$(".discussion-show-comments")
retrieved = not $showComments.hasClass("first-time") and @model.get("children") != undefined
if retrieved
@$el.children(".comments").show() @$el.children(".comments").show()
rebindHideEvents() $showComments.html $showComments.html().replace "Show", "Hide"
@showed = true
else else
discussion_id = @model.discussion.id discussion_id = @model.discussion.id
url = DiscussionUtil.urlFor('retrieve_single_thread', discussion_id, @model.id) url = DiscussionUtil.urlFor('retrieve_single_thread', discussion_id, @model.id)
DiscussionUtil.safeAjax DiscussionUtil.safeAjax
$elem: $.merge($threadTitle, $showComments) $elem: $.merge @$(".thread-title"), @$(".discussion-show-comments")
url: url url: url
type: "GET" type: "GET"
dataType: 'json' dataType: 'json'
success: (response, textStatus) => success: (response, textStatus) =>
DiscussionUtil.bulkExtendContentInfo response['annotated_content_info'] DiscussionUtil.bulkExtendContentInfo response['annotated_content_info']
@showed = true
$showComments.html $showComments.html().replace "Show", "Hide"
@$el.append(response['html']) @$el.append(response['html'])
@model.set('children', response.content.children)
@model.get('comments').reset response.content.children, {silent: false} @model.get('comments').reset response.content.children, {silent: false}
@initCommentViews() @initCommentViews()
$showComments.removeClass("first-time")
rebindHideEvents()
toggleSingleThread: (event) ->
if @showed
@hideSingleThread(event)
else
@showSingleThread(event)
initCommentViews: -> initCommentViews: ->
@$el.children(".comments").children(".comment").each (index, elem) => @$el.children(".comments").children(".comment").each (index, elem) =>
model = @model.get('comments').find $(elem).attr("_id") model = @model.get('comments').find $(elem).attr("_id")
if not model.view if not model.view
commentView = new CommentView el: elem, model: model commentView = new CommentView el: elem, model: model
hideSingleThread: ->
$threadTitle = @$(".thread-title")
$hideComments = @$(".discussion-hide-comments")
$hideComments.removeClass("discussion-hide-comments")
.addClass("discussion-show-comments")
@$el.children(".comments").hide()
$threadTitle.unbind('click').click @showSingleThread
$hideComments.unbind('click').click @showSingleThread
prevHtml = $hideComments.html()
$hideComments.html prevHtml.replace "Hide", "Show"
reply: -> reply: ->
if @model.get('type') == 'thread'
@showSingleThread()
$replyView = @$(".discussion-reply-new") $replyView = @$(".discussion-reply-new")
if $replyView.length if $replyView.length
$replyView.show() $replyView.show()
else else
thread_id = if @model.get('type') == "comment" then @model.get('thread_id') else @model.id thread_id = @model.thread_id()
view = view =
id: @model.id id: @model.id
showWatchCheckbox: not DiscussionUtil.isSubscribed(thread_id, "thread") showWatchCheckbox: not DiscussionUtil.isSubscribed(thread_id, "thread")
@$discussionContent.append Mustache.render DiscussionUtil.replyTemplate, view html = Mustache.render DiscussionUtil.getTemplate('_reply'), view
DiscussionUtil.makeWmdEditor @$el, @$local, "reply-body" @discussionContent().append html
@$(".discussion-submit-post").click @submitReply DiscussionUtil.makeWmdEditor @$el, $.proxy(@$, @), "reply-body"
@$(".discussion-cancel-post").click @cancelReply @$(".discussion-submit-post").click $.proxy(@submitReply, @)
@$(".discussion-cancel-post").click $.proxy(@cancelReply, @)
@$(".discussion-reply").hide() @$(".discussion-reply").hide()
@$(".discussion-edit").hide() @$(".discussion-edit").hide()
submitReply: (event) ->
if @model.get('type') == 'thread'
url = DiscussionUtil.urlFor('create_comment', @model.id)
else if @model.get('type') == 'comment'
url = DiscussionUtil.urlFor('create_sub_comment', @model.id)
else
console.error "unrecognized model type #{@model.get('type')}"
return
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
autowatch: 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", ""
#DiscussionUtil.setContentInfo response.content['id'], 'can_reply', true
#DiscussionUtil.setContentInfo response.content['id'], 'editable', true
comment = new Comment(response.content)
DiscussionUtil.extendContentInfo comment.id, response['annotated_content_info']
@model.get('children').push(response.content)
@model.get('comments').add(comment)
commentView = new CommentView el: $comment[0], model: comment
@$(".discussion-reply-new").hide()
@$(".discussion-reply").show()
@$(".discussion-edit").show()
@discussionContent().attr("status", "normal")
cancelReply: -> cancelReply: ->
$replyView = @$(".discussion-reply-new") $replyView = @$(".discussion-reply-new")
if $replyView.length if $replyView.length
...@@ -213,7 +227,7 @@ class @ContentView extends Backbone.View ...@@ -213,7 +227,7 @@ class @ContentView extends Backbone.View
body: $local(".thread-raw-body").html() body: $local(".thread-raw-body").html()
tags: $local(".thread-raw-tags").html() tags: $local(".thread-raw-tags").html()
} }
$discussionContent.append Mustache.render Discussion.editThreadTemplate, view @discussionContent().append Mustache.render Discussion.editThreadTemplate, view
Discussion.makeWmdEditor $content, $local, "thread-body-edit" Discussion.makeWmdEditor $content, $local, "thread-body-edit"
$local(".thread-tags-edit").tagsInput Discussion.tagsInputOptions() $local(".thread-tags-edit").tagsInput Discussion.tagsInputOptions()
$local(".discussion-submit-update").unbind("click").click -> handleSubmitEditThread(this) $local(".discussion-submit-update").unbind("click").click -> handleSubmitEditThread(this)
...@@ -233,7 +247,7 @@ class @ContentView extends Backbone.View ...@@ -233,7 +247,7 @@ class @ContentView extends Backbone.View
error: Discussion.formErrorHandler($local(".discussion-update-errors")) error: Discussion.formErrorHandler($local(".discussion-update-errors"))
success: (response, textStatus) -> success: (response, textStatus) ->
Discussion.clearFormErrors($local(".discussion-update-errors")) Discussion.clearFormErrors($local(".discussion-update-errors"))
$discussionContent.replaceWith(response.html) @discussionContent().replaceWith(response.html)
Discussion.extendContentInfo response.content['id'], response['annotated_content_info'] Discussion.extendContentInfo response.content['id'], response['annotated_content_info']
Discussion.initializeContent($content) Discussion.initializeContent($content)
Discussion.bindContentEvents($content) Discussion.bindContentEvents($content)
...@@ -262,7 +276,6 @@ class @ContentView extends Backbone.View ...@@ -262,7 +276,6 @@ class @ContentView extends Backbone.View
events: events:
"click .thread-title": "showSingleThread" "click .thread-title": "showSingleThread"
"click .discussion-show-comments": "showSingleThread" "click .discussion-show-comments": "showSingleThread"
"click .discussion-hide-comments": "hideSingleThread"
"click .discussion-reply-thread": "reply" "click .discussion-reply-thread": "reply"
"click .discussion-reply-comment": "reply" "click .discussion-reply-comment": "reply"
"click .discussion-cancel-reply": "cancelReply" "click .discussion-cancel-reply": "cancelReply"
......
if not @Discussion?
@Discussion = {}
Discussion = @Discussion
@Discussion = $.extend @Discussion,
newPostTemplate: """
<form class="new-post-form collapsed" id="new-post-form" style="display: block; ">
<ul class="new-post-form-errors discussion-errors"></ul>
<input type="text" class="new-post-title title-input" placeholder="Title" />
<div class="new-post-similar-posts-wrapper" style="display: none">
Similar Posts:
<a class="hide-similar-posts" href="javascript:void(0)">Hide</a>
<div class="new-post-similar-posts"></div>
</div>
<div class="new-post-body reply-body"></div>
<input class="new-post-tags" placeholder="Tags" />
<div class="post-options">
<input type="checkbox" class="discussion-post-anonymously" id="discussion-post-anonymously-${discussion_id}">
<label for="discussion-post-anonymously-${discussion_id}">post anonymously</label>
<input type="checkbox" class="discussion-auto-watch" id="discussion-autowatch-${discussion_id}" checked="">
<label for="discussion-auto-watch-${discussion_id}">follow this thread</label>
</div>
<div class="new-post-control post-control">
<a class="discussion-cancel-post" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-post control-button" href="javascript:void(0)">Submit</a>
</div>
</form>
"""
replyTemplate: """
<form class="discussion-reply-new">
<ul class="discussion-errors"></ul>
<div class="reply-body"></div>
<input type="checkbox" class="discussion-post-anonymously" id="discussion-post-anonymously-{{id}}" />
<label for="discussion-post-anonymously-{{id}}">post anonymously</label>
{{#showWatchCheckbox}}
<input type="checkbox" class="discussion-auto-watch" id="discussion-autowatch-{{id}}" checked />
<label for="discussion-auto-watch-{{id}}">follow this thread</label>
{{/showWatchCheckbox}}
<br />
<div class = "reply-post-control">
<a class="discussion-cancel-post" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-post control-button" href="javascript:void(0)">Submit</a>
</div>
</form>
"""
editThreadTemplate: """
<form class="discussion-content-edit discussion-thread-edit" _id="{{id}}">
<ul class="discussion-errors discussion-update-errors"></ul>
<input type="text" class="thread-title-edit title-input" placeholder="Title" value="{{title}}"/>
<div class="thread-body-edit body-input">{{body}}</div>
<input class="thread-tags-edit" placeholder="Tags" value="{{tags}}" />
<div class = "edit-post-control">
<a class="discussion-cancel-update" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-update control-button" href="javascript:void(0)">Update</a>
</div>
</form>
"""
editCommentTemplate: """
<form class="discussion-content-edit discussion-comment-edit" _id="{{id}}">
<ul class="discussion-errors discussion-update-errors"></ul>
<div class="comment-body-edit body-input">{{body}}</div>
<div class = "edit-post-control">
<a class="discussion-cancel-update" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-update control-button" href="javascript:void(0)">Update</a>
</div>
</form>
"""
...@@ -143,7 +143,9 @@ class @DiscussionUtil ...@@ -143,7 +143,9 @@ class @DiscussionUtil
id = $content.attr("_id") id = $content.attr("_id")
appended_id = "-#{cls_identifier}-#{id}" appended_id = "-#{cls_identifier}-#{id}"
imageUploadUrl = @urlFor('upload') imageUploadUrl = @urlFor('upload')
editor = Markdown.makeWmdEditor elem, appended_id, imageUploadUrl, @postMathJaxProcessor _processor = (_this) ->
(text) -> _this.postMathJaxProcessor(text)
editor = Markdown.makeWmdEditor elem, appended_id, imageUploadUrl, _processor(@)
@wmdEditors["#{cls_identifier}-#{id}"] = editor @wmdEditors["#{cls_identifier}-#{id}"] = editor
editor editor
......
<form class="discussion-content-edit discussion-comment-edit" _id="{{id}}">
<ul class="discussion-errors discussion-update-errors"></ul>
<div class="comment-body-edit body-input">{{body}}</div>
<div class = "edit-post-control">
<a class="discussion-cancel-update" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-update control-button" href="javascript:void(0)">Update</a>
</div>
</form>
<form class="discussion-content-edit discussion-thread-edit" _id="{{id}}">
<ul class="discussion-errors discussion-update-errors"></ul>
<input type="text" class="thread-title-edit title-input" placeholder="Title" value="{{title}}"/>
<div class="thread-body-edit body-input">{{body}}</div>
<input class="thread-tags-edit" placeholder="Tags" value="{{tags}}" />
<div class = "edit-post-control">
<a class="discussion-cancel-update" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-update control-button" href="javascript:void(0)">Update</a>
</div>
</form>
<form class="new-post-form collapsed" id="new-post-form" style="display: block; ">
<ul class="new-post-form-errors discussion-errors"></ul>
<input type="text" class="new-post-title title-input" placeholder="Title" />
<div class="new-post-similar-posts-wrapper" style="display: none">
Similar Posts:
<a class="hide-similar-posts" href="javascript:void(0)">Hide</a>
<div class="new-post-similar-posts"></div>
</div>
<div class="new-post-body reply-body"></div>
<input class="new-post-tags" placeholder="Tags" />
<div class="post-options">
<input type="checkbox" class="discussion-post-anonymously" id="discussion-post-anonymously-${discussion_id}">
<label for="discussion-post-anonymously-${discussion_id}">post anonymously</label>
<input type="checkbox" class="discussion-auto-watch" id="discussion-autowatch-${discussion_id}" checked="">
<label for="discussion-auto-watch-${discussion_id}">follow this thread</label>
</div>
<div class="new-post-control post-control">
<a class="discussion-cancel-post" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-post control-button" href="javascript:void(0)">Submit</a>
</div>
</form>
<form class="discussion-reply-new">
<ul class="discussion-errors"></ul>
<div class="reply-body"></div>
<input type="checkbox" class="discussion-post-anonymously" id="discussion-post-anonymously-{{id}}" />
<label for="discussion-post-anonymously-{{id}}">post anonymously</label>
{{#showWatchCheckbox}}
<input type="checkbox" class="discussion-auto-watch" id="discussion-autowatch-{{id}}" checked />
<label for="discussion-auto-watch-{{id}}">follow this thread</label>
{{/showWatchCheckbox}}
<br />
<div class="reply-post-control">
<a class="discussion-cancel-post" href="javascript:void(0)">Cancel</a>
<a class="discussion-submit-post control-button" href="javascript:void(0)">Submit</a>
</div>
</form>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment