Merge pull request #516 from MITx/feature/fix_backbone_js
Feature/fix backbone js
This commit is contained in:
@@ -420,6 +420,8 @@ main_vendor_js = [
|
||||
'js/vendor/jquery.qtip.min.js',
|
||||
]
|
||||
|
||||
discussion_js = glob2.glob(PROJECT_ROOT / 'static/coffee/src/discussion/*.coffee')
|
||||
|
||||
# Load javascript from all of the available xmodules, and
|
||||
# prep it for use in pipeline js
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
@@ -490,7 +492,7 @@ PIPELINE_JS = {
|
||||
] + [
|
||||
pth.replace(PROJECT_ROOT / 'static/', '')
|
||||
for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')\
|
||||
if pth not in courseware_only_js
|
||||
if pth not in courseware_only_js and pth not in discussion_js
|
||||
] + [
|
||||
'js/form.ext.js',
|
||||
'js/my_courses_dropdown.js',
|
||||
@@ -514,6 +516,10 @@ PIPELINE_JS = {
|
||||
'spec': {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
|
||||
'output_filename': 'js/lms-spec.js'
|
||||
},
|
||||
'discussion' : {
|
||||
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in discussion_js],
|
||||
'output_filename': 'js/discussion.js'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
if not @Discussion?
|
||||
@Discussion = {}
|
||||
|
||||
Discussion = @Discussion
|
||||
|
||||
initializeVote = (content) ->
|
||||
$content = $(content)
|
||||
$local = Discussion.generateLocal($content.children(".discussion-content"))
|
||||
id = $content.attr("_id")
|
||||
if Discussion.isUpvoted id
|
||||
$local(".discussion-vote-up").addClass("voted")
|
||||
else if Discussion.isDownvoted id
|
||||
$local(".discussion-vote-down").addClass("voted")
|
||||
|
||||
initializeFollowThread = (thread) ->
|
||||
$thread = $(thread)
|
||||
id = $thread.attr("_id")
|
||||
$thread.children(".discussion-content")
|
||||
.find(".follow-wrapper")
|
||||
.append(Discussion.subscriptionLink('thread', id))
|
||||
|
||||
@Discussion = $.extend @Discussion,
|
||||
|
||||
bindContentEvents: (content) ->
|
||||
|
||||
$content = $(content)
|
||||
$discussionContent = $content.children(".discussion-content")
|
||||
$local = Discussion.generateLocal($discussionContent)
|
||||
|
||||
id = $content.attr("_id")
|
||||
|
||||
handleReply = (elem) ->
|
||||
$replyView = $local(".discussion-reply-new")
|
||||
if $replyView.length
|
||||
$replyView.show()
|
||||
else
|
||||
thread_id = $discussionContent.parents(".thread").attr("_id")
|
||||
view =
|
||||
id: id
|
||||
showWatchCheckbox: not Discussion.isSubscribed(thread_id, "thread")
|
||||
$discussionContent.append Mustache.render Discussion.replyTemplate, view
|
||||
Discussion.makeWmdEditor $content, $local, "reply-body"
|
||||
$local(".discussion-submit-post").click -> handleSubmitReply(this)
|
||||
$local(".discussion-cancel-post").click -> handleCancelReply(this)
|
||||
$local(".discussion-reply").hide()
|
||||
$local(".discussion-edit").hide()
|
||||
|
||||
handleCancelReply = (elem) ->
|
||||
$replyView = $local(".discussion-reply-new")
|
||||
if $replyView.length
|
||||
$replyView.hide()
|
||||
$local(".discussion-reply").show()
|
||||
$local(".discussion-edit").show()
|
||||
|
||||
handleSubmitReply = (elem) ->
|
||||
if $content.hasClass("thread")
|
||||
url = Discussion.urlFor('create_comment', id)
|
||||
else if $content.hasClass("comment")
|
||||
url = Discussion.urlFor('create_sub_comment', id)
|
||||
else
|
||||
return
|
||||
|
||||
body = Discussion.getWmdContent $content, $local, "reply-body"
|
||||
|
||||
anonymous = false || $local(".discussion-post-anonymously").is(":checked")
|
||||
autowatch = false || $local(".discussion-auto-watch").is(":checked")
|
||||
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: 'json'
|
||||
data:
|
||||
body: body
|
||||
anonymous: anonymous
|
||||
autowatch: autowatch
|
||||
error: Discussion.formErrorHandler($local(".discussion-errors"))
|
||||
success: (response, textStatus) ->
|
||||
Discussion.clearFormErrors($local(".discussion-errors"))
|
||||
$comment = $(response.html)
|
||||
$content.children(".comments").prepend($comment)
|
||||
Discussion.setWmdContent $content, $local, "reply-body", ""
|
||||
Discussion.setContentInfo response.content['id'], 'can_reply', true
|
||||
Discussion.setContentInfo response.content['id'], 'editable', true
|
||||
Discussion.extendContentInfo response.content['id'], response['annotated_content_info']
|
||||
Discussion.initializeContent($comment)
|
||||
Discussion.bindContentEvents($comment)
|
||||
@cancelReply()
|
||||
$local(".discussion-reply-new").hide()
|
||||
$local(".discussion-reply").show()
|
||||
$local(".discussion-edit").show()
|
||||
$discussionContent.attr("status", "normal")
|
||||
|
||||
handleVote = (elem, value) ->
|
||||
contentType = if $content.hasClass("thread") then "thread" else "comment"
|
||||
url = Discussion.urlFor("#{value}vote_#{contentType}", id)
|
||||
Discussion.safeAjax
|
||||
$elem: $local(".discussion-vote")
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
success: (response, textStatus) ->
|
||||
if textStatus == "success"
|
||||
$local(".discussion-vote").removeClass("voted")
|
||||
$local(".discussion-vote-#{value}").addClass("voted")
|
||||
$local(".discussion-votes-point").html response.votes.point
|
||||
|
||||
handleUnvote = (elem, value) ->
|
||||
contentType = if $content.hasClass("thread") then "thread" else "comment"
|
||||
url = Discussion.urlFor("undo_vote_for_#{contentType}", id)
|
||||
Discussion.safeAjax
|
||||
$elem: $local(".discussion-vote")
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
success: (response, textStatus) ->
|
||||
if textStatus == "success"
|
||||
$local(".discussion-vote").removeClass("voted")
|
||||
$local(".discussion-votes-point").html response.votes.point
|
||||
|
||||
handleCancelEdit = (elem) ->
|
||||
$local(".discussion-content-edit").hide()
|
||||
$local(".discussion-content-wrapper").show()
|
||||
|
||||
handleEditThread = (elem) ->
|
||||
$local(".discussion-content-wrapper").hide()
|
||||
$editView = $local(".discussion-content-edit")
|
||||
if $editView.length
|
||||
$editView.show()
|
||||
else
|
||||
view = {
|
||||
id: id
|
||||
title: $local(".thread-raw-title").html()
|
||||
body: $local(".thread-raw-body").html()
|
||||
tags: $local(".thread-raw-tags").html()
|
||||
}
|
||||
$discussionContent.append Mustache.render Discussion.editThreadTemplate, view
|
||||
Discussion.makeWmdEditor $content, $local, "thread-body-edit"
|
||||
$local(".thread-tags-edit").tagsInput Discussion.tagsInputOptions()
|
||||
$local(".discussion-submit-update").unbind("click").click -> handleSubmitEditThread(this)
|
||||
$local(".discussion-cancel-update").unbind("click").click -> handleCancelEdit(this)
|
||||
|
||||
handleSubmitEditThread = (elem) ->
|
||||
url = Discussion.urlFor('update_thread', id)
|
||||
title = $local(".thread-title-edit").val()
|
||||
body = Discussion.getWmdContent $content, $local, "thread-body-edit"
|
||||
tags = $local(".thread-tags-edit").val()
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: 'json'
|
||||
data: {title: title, body: body, tags: tags},
|
||||
error: Discussion.formErrorHandler($local(".discussion-update-errors"))
|
||||
success: (response, textStatus) ->
|
||||
Discussion.clearFormErrors($local(".discussion-update-errors"))
|
||||
$discussionContent.replaceWith(response.html)
|
||||
Discussion.extendContentInfo response.content['id'], response['annotated_content_info']
|
||||
Discussion.initializeContent($content)
|
||||
Discussion.bindContentEvents($content)
|
||||
|
||||
handleEditComment = (elem) ->
|
||||
$local(".discussion-content-wrapper").hide()
|
||||
$editView = $local(".discussion-content-edit")
|
||||
if $editView.length
|
||||
$editView.show()
|
||||
else
|
||||
view = { id: id, body: $local(".comment-raw-body").html() }
|
||||
$discussionContent.append Mustache.render Discussion.editCommentTemplate, view
|
||||
Discussion.makeWmdEditor $content, $local, "comment-body-edit"
|
||||
$local(".discussion-submit-update").unbind("click").click -> handleSubmitEditComment(this)
|
||||
$local(".discussion-cancel-update").unbind("click").click -> handleCancelEdit(this)
|
||||
|
||||
handleSubmitEditComment= (elem) ->
|
||||
url = Discussion.urlFor('update_comment', id)
|
||||
body = Discussion.getWmdContent $content, $local, "comment-body-edit"
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
data: {body: body}
|
||||
error: Discussion.formErrorHandler($local(".discussion-update-errors"))
|
||||
success: (response, textStatus) ->
|
||||
Discussion.clearFormErrors($local(".discussion-update-errors"))
|
||||
$discussionContent.replaceWith(response.html)
|
||||
Discussion.extendContentInfo response.content['id'], response['annotated_content_info']
|
||||
Discussion.initializeContent($content)
|
||||
Discussion.bindContentEvents($content)
|
||||
|
||||
handleEndorse = (elem, endorsed) ->
|
||||
url = Discussion.urlFor('endorse_comment', id)
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
data: {endorsed: endorsed}
|
||||
success: (response, textStatus) ->
|
||||
if textStatus == "success"
|
||||
if endorsed
|
||||
$(content).addClass("endorsed")
|
||||
else
|
||||
$(content).removeClass("endorsed")
|
||||
|
||||
$(elem).unbind('click').click ->
|
||||
handleEndorse(elem, !endorsed)
|
||||
|
||||
handleOpenClose = (elem, text) ->
|
||||
url = Discussion.urlFor('openclose_thread', id)
|
||||
closed = undefined
|
||||
if text.match(/Close/)
|
||||
closed = true
|
||||
else if text.match(/[Oo]pen/)
|
||||
closed = false
|
||||
else
|
||||
console.log "Unexpected text " + text + "for open/close thread."
|
||||
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
data: {closed: closed}
|
||||
success: (response, textStatus) =>
|
||||
if textStatus == "success"
|
||||
if closed
|
||||
$(content).addClass("closed")
|
||||
$(elem).text "Re-open Thread"
|
||||
else
|
||||
$(content).removeClass("closed")
|
||||
$(elem).text "Close Thread"
|
||||
error: (response, textStatus, e) ->
|
||||
console.log e
|
||||
|
||||
handleDelete = (elem) ->
|
||||
if $content.hasClass("thread")
|
||||
url = Discussion.urlFor('delete_thread', id)
|
||||
c = confirm "Are you sure to delete thread \"" + $content.find("a.thread-title").text() + "\"?"
|
||||
else
|
||||
url = Discussion.urlFor('delete_comment', id)
|
||||
c = confirm "Are you sure to delete this comment? "
|
||||
if c != true
|
||||
return
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: "json"
|
||||
data: {}
|
||||
success: (response, textStatus) =>
|
||||
if textStatus == "success"
|
||||
$(content).remove()
|
||||
error: (response, textStatus, e) ->
|
||||
console.log e
|
||||
|
||||
handleHideSingleThread = (elem) ->
|
||||
$threadTitle = $local(".thread-title")
|
||||
$hideComments = $local(".discussion-hide-comments")
|
||||
$hideComments.removeClass("discussion-hide-comments")
|
||||
.addClass("discussion-show-comments")
|
||||
$content.children(".comments").hide()
|
||||
$threadTitle.unbind('click').click handleShowSingleThread
|
||||
$hideComments.unbind('click').click handleShowSingleThread
|
||||
prevHtml = $hideComments.html()
|
||||
$hideComments.html prevHtml.replace "Hide", "Show"
|
||||
|
||||
handleShowSingleThread = ->
|
||||
$threadTitle = $local(".thread-title")
|
||||
$showComments = $local(".discussion-show-comments")
|
||||
|
||||
if not $showComments.hasClass("first-time") and (not $showComments.length or not $threadTitle.length)
|
||||
return
|
||||
|
||||
rebindHideEvents = ->
|
||||
$threadTitle.unbind('click').click handleHideSingleThread
|
||||
$showComments.unbind('click').click handleHideSingleThread
|
||||
$showComments.removeClass("discussion-show-comments")
|
||||
.addClass("discussion-hide-comments")
|
||||
prevHtml = $showComments.html()
|
||||
$showComments.html prevHtml.replace "Show", "Hide"
|
||||
|
||||
|
||||
if not $showComments.hasClass("first-time") and $content.children(".comments").length
|
||||
$content.children(".comments").show()
|
||||
rebindHideEvents()
|
||||
else
|
||||
discussion_id = $threadTitle.parents(".discussion").attr("_id")
|
||||
url = Discussion.urlFor('retrieve_single_thread', discussion_id, id)
|
||||
Discussion.safeAjax
|
||||
$elem: $.merge($threadTitle, $showComments)
|
||||
url: url
|
||||
type: "GET"
|
||||
dataType: 'json'
|
||||
success: (response, textStatus) ->
|
||||
Discussion.bulkExtendContentInfo response['annotated_content_info']
|
||||
$content.append(response['html'])
|
||||
$content.find(".comment").each (index, comment) ->
|
||||
Discussion.initializeContent(comment)
|
||||
Discussion.bindContentEvents(comment)
|
||||
$showComments.removeClass("first-time")
|
||||
rebindHideEvents()
|
||||
|
||||
Discussion.bindLocalEvents $local,
|
||||
|
||||
"click .thread-title": ->
|
||||
handleShowSingleThread(this)
|
||||
|
||||
"click .discussion-show-comments": ->
|
||||
handleShowSingleThread(this)
|
||||
|
||||
"click .discussion-hide-comments": ->
|
||||
handleHideSingleThread(this)
|
||||
|
||||
"click .discussion-reply-thread": ->
|
||||
handleShowSingleThread($local(".thread-title"))
|
||||
handleReply(this)
|
||||
|
||||
"click .discussion-reply-comment": ->
|
||||
handleReply(this)
|
||||
|
||||
"click .discussion-cancel-reply": ->
|
||||
handleCancelReply(this)
|
||||
|
||||
"click .discussion-vote-up": ->
|
||||
$elem = $(this)
|
||||
if $elem.hasClass("voted")
|
||||
handleUnvote($elem)
|
||||
else
|
||||
handleVote($elem, "up")
|
||||
|
||||
"click .discussion-vote-down": ->
|
||||
$elem = $(this)
|
||||
if $elem.hasClass("voted")
|
||||
handleUnvote($elem)
|
||||
else
|
||||
handleVote($elem, "down")
|
||||
|
||||
"click .admin-endorse": ->
|
||||
handleEndorse(this, not $content.hasClass("endorsed"))
|
||||
|
||||
"click .admin-openclose": ->
|
||||
handleOpenClose(this, $(this).text())
|
||||
|
||||
"click .admin-edit": ->
|
||||
if $content.hasClass("thread")
|
||||
handleEditThread(this)
|
||||
else
|
||||
handleEditComment(this)
|
||||
|
||||
"click .admin-delete": ->
|
||||
handleDelete(this)
|
||||
|
||||
initializeContent: (content) ->
|
||||
|
||||
unescapeHighlightTag = (text) ->
|
||||
text.replace(/\<\;highlight\>\;/g, "<span class='search-highlight'>")
|
||||
.replace(/\<\;\/highlight\>\;/g, "</span>")
|
||||
|
||||
stripHighlight = (text, type) ->
|
||||
text.replace(/\&(amp\;)?lt\;highlight\&(amp\;)?gt\;/g, "")
|
||||
.replace(/\&(amp\;)?lt\;\/highlight\&(amp\;)?gt\;/g, "")
|
||||
|
||||
|
||||
stripLatexHighlight = (text) ->
|
||||
Discussion.processEachMathAndCode text, stripHighlight
|
||||
|
||||
markdownWithHighlight = (text) ->
|
||||
converter = Markdown.getMathCompatibleConverter()
|
||||
unescapeHighlightTag stripLatexHighlight converter.makeHtml text
|
||||
|
||||
$content = $(content)
|
||||
initializeVote $content
|
||||
if $content.hasClass("thread")
|
||||
initializeFollowThread $content
|
||||
$local = Discussion.generateLocal($content.children(".discussion-content"))
|
||||
|
||||
$local("span.timeago").timeago()
|
||||
|
||||
$contentTitle = $local(".thread-title")
|
||||
|
||||
if $contentTitle.length
|
||||
$contentTitle.html unescapeHighlightTag stripLatexHighlight $contentTitle.html()
|
||||
|
||||
$contentBody = $local(".content-body")
|
||||
|
||||
$contentBody.html Discussion.postMathJaxProcessor markdownWithHighlight $contentBody.html()
|
||||
|
||||
MathJax.Hub.Queue ["Typeset", MathJax.Hub, $contentBody.attr("id")]
|
||||
id = $content.attr("_id")
|
||||
|
||||
if $content.hasClass("thread")
|
||||
discussion_id = $content.attr("_discussion_id")
|
||||
permalink = Discussion.urlFor("permanent_link_thread", discussion_id, id)
|
||||
else
|
||||
thread_id = $content.parents(".thread").attr("_id")
|
||||
discussion_id = $content.parents(".thread").attr("_discussion_id")
|
||||
permalink = Discussion.urlFor("permanent_link_comment", discussion_id, thread_id, id)
|
||||
$local(".discussion-permanent-link").attr "href", permalink
|
||||
|
||||
if not Discussion.getContentInfo id, 'editable'
|
||||
$local(".admin-edit").remove()
|
||||
if not Discussion.getContentInfo id, 'can_reply'
|
||||
$local(".discussion-reply").remove()
|
||||
if not Discussion.getContentInfo id, 'can_endorse'
|
||||
$local(".admin-endorse").remove()
|
||||
if not Discussion.getContentInfo id, 'can_delete'
|
||||
$local(".admin-delete").remove()
|
||||
if not Discussion.getContentInfo id, 'can_openclose'
|
||||
$local(".admin-openclose").remove()
|
||||
#if not Discussion.getContentInfo id, 'can_vote'
|
||||
# $local(".discussion-vote").css "visibility", "hidden"
|
||||
@@ -1,190 +0,0 @@
|
||||
if not @Discussion?
|
||||
@Discussion = {}
|
||||
|
||||
Discussion = @Discussion
|
||||
|
||||
initializeFollowDiscussion = (discussion) ->
|
||||
$discussion = $(discussion)
|
||||
id = $following.attr("_id")
|
||||
$local = Discussion.generateLocal()
|
||||
$discussion.children(".discussion-non-content")
|
||||
.find(".discussion-title-wrapper")
|
||||
.append(Discussion.subscriptionLink('discussion', id))
|
||||
|
||||
@Discussion = $.extend @Discussion,
|
||||
|
||||
initializeDiscussion: (discussion) ->
|
||||
$discussion = $(discussion)
|
||||
$discussion.find(".thread").each (index, thread) ->
|
||||
Discussion.initializeContent(thread)
|
||||
Discussion.bindContentEvents(thread)
|
||||
$discussion.find(".comment").each (index, comment) ->
|
||||
Discussion.initializeContent(comment)
|
||||
Discussion.bindContentEvents(comment)
|
||||
|
||||
#initializeFollowDiscussion(discussion) TODO move this somewhere else
|
||||
|
||||
bindDiscussionEvents: (discussion) ->
|
||||
|
||||
$discussion = $(discussion)
|
||||
$discussionNonContent = $discussion.children(".discussion-non-content")
|
||||
$local = Discussion.generateLocal($discussion.children(".discussion-local"))
|
||||
|
||||
id = $discussion.attr("_id")
|
||||
|
||||
handleSubmitNewPost = (elem) ->
|
||||
title = $local(".new-post-title").val()
|
||||
body = Discussion.getWmdContent $discussion, $local, "new-post-body"
|
||||
tags = $local(".new-post-tags").val()
|
||||
url = Discussion.urlFor('create_thread', id)
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: 'json'
|
||||
data:
|
||||
title: title
|
||||
body: body
|
||||
tags: tags
|
||||
error: Discussion.formErrorHandler($local(".new-post-form-errors"))
|
||||
success: (response, textStatus) ->
|
||||
Discussion.clearFormErrors($local(".new-post-form-errors"))
|
||||
$thread = $(response.html)
|
||||
$discussion.children(".threads").prepend($thread)
|
||||
$local(".new-post-title").val("")
|
||||
Discussion.setWmdContent $discussion, $local, "new-post-body", ""
|
||||
$local(".new-post-tags").val("")
|
||||
if $discussion.hasClass("inline-discussion")
|
||||
$local(".new-post-form").addClass("collapsed")
|
||||
else if $discussion.hasClass("forum-discussion")
|
||||
$local(".new-post-form").hide()
|
||||
|
||||
handleCancelNewPost = (elem) ->
|
||||
if $discussion.hasClass("inline-discussion")
|
||||
$local(".new-post-form").addClass("collapsed")
|
||||
else if $discussion.hasClass("forum-discussion")
|
||||
$local(".new-post-form").hide()
|
||||
|
||||
handleSimilarPost = (elem) ->
|
||||
$title = $local(".new-post-title")
|
||||
$wrapper = $local(".new-post-similar-posts-wrapper")
|
||||
$similarPosts = $local(".new-post-similar-posts")
|
||||
prevText = $title.attr("prev-text")
|
||||
text = $title.val()
|
||||
if text == prevText
|
||||
if $local(".similar-post").length
|
||||
$wrapper.show()
|
||||
else if $.trim(text).length
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: Discussion.urlFor 'search_similar_threads', id
|
||||
type: "GET"
|
||||
dateType: 'json'
|
||||
data:
|
||||
text: $local(".new-post-title").val()
|
||||
success: (response, textStatus) ->
|
||||
$similarPosts.empty()
|
||||
console.log response
|
||||
if $.type(response) == "array" and response.length
|
||||
$wrapper.show()
|
||||
for thread in response
|
||||
#singleThreadUrl = Discussion.urlFor 'retrieve_single_thread
|
||||
$similarPost = $("<a>").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)
|
||||
|
||||
initializeNewPost = ->
|
||||
view = { discussion_id: id }
|
||||
$discussionNonContent = $discussion.children(".discussion-non-content")
|
||||
|
||||
if not $local(".wmd-panel").length
|
||||
$discussionNonContent.append Mustache.render Discussion.newPostTemplate, view
|
||||
$newPostBody = $local(".new-post-body")
|
||||
Discussion.makeWmdEditor $discussion, $local, "new-post-body"
|
||||
|
||||
$input = Discussion.getWmdInput($discussion, $local, "new-post-body")
|
||||
$input.attr("placeholder", "post a new topic...")
|
||||
if $discussion.hasClass("inline-discussion")
|
||||
$input.bind 'focus', (e) ->
|
||||
$local(".new-post-form").removeClass('collapsed')
|
||||
else if $discussion.hasClass("forum-discussion")
|
||||
$local(".new-post-form").removeClass('collapsed')
|
||||
|
||||
$local(".new-post-tags").tagsInput Discussion.tagsInputOptions()
|
||||
|
||||
$local(".new-post-title").blur ->
|
||||
handleSimilarPost(this)
|
||||
|
||||
$local(".hide-similar-posts").click ->
|
||||
$local(".new-post-similar-posts-wrapper").hide()
|
||||
|
||||
$local(".discussion-submit-post").click ->
|
||||
handleSubmitNewPost(this)
|
||||
$local(".discussion-cancel-post").click ->
|
||||
handleCancelNewPost(this)
|
||||
|
||||
$local(".new-post-form").show()
|
||||
|
||||
handleAjaxReloadDiscussion = (elem, url) ->
|
||||
if not url then return
|
||||
$elem = $(elem)
|
||||
$discussion = $elem.parents("section.discussion")
|
||||
Discussion.safeAjax
|
||||
$elem: $elem
|
||||
url: url
|
||||
type: "GET"
|
||||
dataType: 'html'
|
||||
success: (data, textStatus) ->
|
||||
$data = $(data)
|
||||
$parent = $discussion.parent()
|
||||
$discussion.replaceWith($data)
|
||||
$discussion = $parent.children(".discussion")
|
||||
Discussion.initializeDiscussion($discussion)
|
||||
Discussion.bindDiscussionEvents($discussion)
|
||||
|
||||
handleAjaxSearch = (elem) ->
|
||||
$elem = $(elem)
|
||||
url = URI($elem.attr("action")).addSearch({text: $local(".search-input").val()})
|
||||
handleAjaxReloadDiscussion($elem, url)
|
||||
|
||||
handleAjaxSort = (elem) ->
|
||||
$elem = $(elem)
|
||||
url = $elem.attr("sort-url")
|
||||
handleAjaxReloadDiscussion($elem, url)
|
||||
|
||||
handleAjaxPage = (elem) ->
|
||||
$elem = $(elem)
|
||||
url = $elem.attr("page-url")
|
||||
handleAjaxReloadDiscussion($elem, url)
|
||||
|
||||
if $discussion.hasClass("inline-discussion")
|
||||
initializeNewPost()
|
||||
|
||||
if $discussion.hasClass("forum-discussion")
|
||||
$discussionSidebar = $(".discussion-sidebar")
|
||||
if $discussionSidebar.length
|
||||
$sidebarLocal = Discussion.generateLocal($discussionSidebar)
|
||||
Discussion.bindLocalEvents $sidebarLocal,
|
||||
"click .sidebar-new-post-button": (event) ->
|
||||
initializeNewPost()
|
||||
|
||||
Discussion.bindLocalEvents $local,
|
||||
|
||||
"submit .search-wrapper>.discussion-search-form": (event) ->
|
||||
event.preventDefault()
|
||||
handleAjaxSearch(this)
|
||||
|
||||
"click .discussion-search-link": ->
|
||||
handleAjaxSearch($local(".search-wrapper>.discussion-search-form"))
|
||||
|
||||
"click .discussion-sort-link": ->
|
||||
handleAjaxSort(this)
|
||||
|
||||
$discussion.children(".discussion-paginator").find(".discussion-page-link").unbind('click').click ->
|
||||
handleAjaxPage(this)
|
||||
@@ -1,42 +0,0 @@
|
||||
if not @Discussion?
|
||||
@Discussion = {}
|
||||
|
||||
Discussion = @Discussion
|
||||
|
||||
@Discussion = $.extend @Discussion,
|
||||
initializeDiscussionModule: (elem) ->
|
||||
$discussionModule = $(elem)
|
||||
$local = Discussion.generateLocal($discussionModule)
|
||||
handleShowDiscussion = (elem) ->
|
||||
$elem = $(elem)
|
||||
if not $local("section.discussion").length
|
||||
discussion_id = $elem.attr("discussion_id")
|
||||
url = Discussion.urlFor 'retrieve_discussion', discussion_id
|
||||
Discussion.safeAjax
|
||||
$elem: $elem
|
||||
url: url
|
||||
type: "GET"
|
||||
success: (data, textStatus, xhr) ->
|
||||
$discussionModule.append(data)
|
||||
discussion = $local("section.discussion")
|
||||
Discussion.initializeDiscussion(discussion)
|
||||
Discussion.bindDiscussionEvents(discussion)
|
||||
$elem.html("Hide Discussion")
|
||||
$elem.unbind('click').click ->
|
||||
handleHideDiscussion(this)
|
||||
dataType: 'html'
|
||||
else
|
||||
$local("section.discussion").show()
|
||||
$elem.html("Hide Discussion")
|
||||
$elem.unbind('click').click ->
|
||||
handleHideDiscussion(this)
|
||||
|
||||
handleHideDiscussion = (elem) ->
|
||||
$local("section.discussion").hide()
|
||||
$elem = $(elem)
|
||||
$elem.html("Show Discussion")
|
||||
$elem.unbind('click').click ->
|
||||
handleShowDiscussion(this)
|
||||
|
||||
$local(".discussion-show").click ->
|
||||
handleShowDiscussion(this)
|
||||
@@ -1,23 +0,0 @@
|
||||
$ ->
|
||||
|
||||
#toggle = ->
|
||||
# $('.course-wrapper').toggleClass('closed')
|
||||
|
||||
#Discussion = window.Discussion
|
||||
#if $('#accordion').length
|
||||
# active = $('#accordion ul:has(li.active)').index('#accordion ul')
|
||||
# $('#accordion').bind('accordionchange', @log).accordion
|
||||
# active: if active >= 0 then active else 1
|
||||
# header: 'h3'
|
||||
# autoHeight: false
|
||||
# $('#open_close_accordion a').click toggle
|
||||
# $('#accordion').show()
|
||||
|
||||
#$(".discussion-module").each (index, elem) ->
|
||||
# Discussion.initializeDiscussionModule(elem)
|
||||
|
||||
#$("section.discussion").each (index, discussion) ->
|
||||
# Discussion.initializeDiscussion(discussion)
|
||||
# Discussion.bindDiscussionEvents(discussion)
|
||||
|
||||
#Discussion.initializeUserProfile($(".discussion-sidebar>.user-profile"))
|
||||
@@ -1,73 +0,0 @@
|
||||
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>
|
||||
"""
|
||||
@@ -1,34 +0,0 @@
|
||||
if not @Discussion?
|
||||
@Discussion = {}
|
||||
|
||||
Discussion = @Discussion
|
||||
|
||||
@Discussion = $.extend @Discussion,
|
||||
initializeUserProfile: ($userProfile) ->
|
||||
$local = Discussion.generateLocal $userProfile
|
||||
|
||||
handleUpdateModeratorStatus = (elem, isModerator) ->
|
||||
confirmValue = confirm("Are you sure?")
|
||||
if not confirmValue then return
|
||||
url = Discussion.urlFor('update_moderator_status', $$profiled_user_id)
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: url
|
||||
type: "POST"
|
||||
dataType: 'json'
|
||||
data:
|
||||
is_moderator: isModerator
|
||||
error: (response, textStatus, e) ->
|
||||
console.log e
|
||||
success: (response, textStatus) ->
|
||||
parent = $userProfile.parent()
|
||||
$userProfile.replaceWith(response.html)
|
||||
Discussion.initializeUserProfile parent.children(".user-profile")
|
||||
|
||||
Discussion.bindLocalEvents $local,
|
||||
"click .sidebar-revoke-moderator-button": (event) ->
|
||||
handleUpdateModeratorStatus(this, false)
|
||||
"click .sidebar-promote-moderator-button": (event) ->
|
||||
handleUpdateModeratorStatus(this, true)
|
||||
|
||||
initializeUserActiveDiscussion: ($discussion) ->
|
||||
@@ -1,244 +0,0 @@
|
||||
if not @Discussion?
|
||||
@Discussion = {}
|
||||
|
||||
Discussion = @Discussion
|
||||
|
||||
wmdEditors = {}
|
||||
|
||||
@Discussion = $.extend @Discussion,
|
||||
|
||||
generateLocal: (elem) ->
|
||||
(selector) -> $(elem).find(selector)
|
||||
|
||||
generateDiscussionLink: (cls, txt, handler) ->
|
||||
$("<a>").addClass("discussion-link")
|
||||
.attr("href", "javascript:void(0)")
|
||||
.addClass(cls).html(txt)
|
||||
.click -> handler(this)
|
||||
|
||||
urlFor: (name, param, param1, param2) ->
|
||||
{
|
||||
follow_discussion : "/courses/#{$$course_id}/discussion/#{param}/follow"
|
||||
unfollow_discussion : "/courses/#{$$course_id}/discussion/#{param}/unfollow"
|
||||
create_thread : "/courses/#{$$course_id}/discussion/#{param}/threads/create"
|
||||
search_similar_threads : "/courses/#{$$course_id}/discussion/#{param}/threads/search_similar"
|
||||
update_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/update"
|
||||
create_comment : "/courses/#{$$course_id}/discussion/threads/#{param}/reply"
|
||||
delete_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/delete"
|
||||
upvote_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/upvote"
|
||||
downvote_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/downvote"
|
||||
undo_vote_for_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/unvote"
|
||||
follow_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/follow"
|
||||
unfollow_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/unfollow"
|
||||
update_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/update"
|
||||
endorse_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/endorse"
|
||||
create_sub_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/reply"
|
||||
delete_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/delete"
|
||||
upvote_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/upvote"
|
||||
downvote_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/downvote"
|
||||
undo_vote_for_comment : "/courses/#{$$course_id}/discussion/comments/#{param}/unvote"
|
||||
upload : "/courses/#{$$course_id}/discussion/upload"
|
||||
search : "/courses/#{$$course_id}/discussion/forum/search"
|
||||
tags_autocomplete : "/courses/#{$$course_id}/discussion/threads/tags/autocomplete"
|
||||
retrieve_discussion : "/courses/#{$$course_id}/discussion/forum/#{param}/inline"
|
||||
retrieve_single_thread : "/courses/#{$$course_id}/discussion/forum/#{param}/threads/#{param1}"
|
||||
update_moderator_status : "/courses/#{$$course_id}/discussion/users/#{param}/update_moderator_status"
|
||||
openclose_thread : "/courses/#{$$course_id}/discussion/threads/#{param}/close"
|
||||
permanent_link_thread : "/courses/#{$$course_id}/discussion/forum/#{param}/threads/#{param1}"
|
||||
permanent_link_comment : "/courses/#{$$course_id}/discussion/forum/#{param}/threads/#{param1}##{param2}"
|
||||
}[name]
|
||||
|
||||
safeAjax: (params) ->
|
||||
$elem = params.$elem
|
||||
if $elem.attr("disabled")
|
||||
return
|
||||
$elem.attr("disabled", "disabled")
|
||||
$.ajax(params).always ->
|
||||
$elem.removeAttr("disabled")
|
||||
|
||||
handleAnchorAndReload: (response) ->
|
||||
#window.location = window.location.pathname + "#" + response['id']
|
||||
window.location.reload()
|
||||
|
||||
bindLocalEvents: ($local, eventsHandler) ->
|
||||
for eventSelector, handler of eventsHandler
|
||||
[event, selector] = eventSelector.split(' ')
|
||||
$local(selector).unbind(event)[event] handler
|
||||
|
||||
tagsInputOptions: ->
|
||||
autocomplete_url: Discussion.urlFor('tags_autocomplete')
|
||||
autocomplete:
|
||||
remoteDataType: 'json'
|
||||
interactive: true
|
||||
height: '30px'
|
||||
width: '100%'
|
||||
defaultText: "Tag your post: press enter after each tag"
|
||||
removeWithBackspace: true
|
||||
|
||||
isSubscribed: (id, type) ->
|
||||
$$user_info? and (
|
||||
if type == "thread"
|
||||
id in $$user_info.subscribed_thread_ids
|
||||
else if type == "commentable" or type == "discussion"
|
||||
id in $$user_info.subscribed_commentable_ids
|
||||
else
|
||||
id in $$user_info.subscribed_user_ids
|
||||
)
|
||||
|
||||
isUpvoted: (id) ->
|
||||
$$user_info? and (id in $$user_info.upvoted_ids)
|
||||
|
||||
isDownvoted: (id) ->
|
||||
$$user_info? and (id in $$user_info.downvoted_ids)
|
||||
|
||||
formErrorHandler: (errorsField) ->
|
||||
(xhr, textStatus, error) ->
|
||||
response = JSON.parse(xhr.responseText)
|
||||
if response.errors? and response.errors.length > 0
|
||||
errorsField.empty()
|
||||
for error in response.errors
|
||||
errorsField.append($("<li>").addClass("new-post-form-error").html(error))
|
||||
|
||||
clearFormErrors: (errorsField) ->
|
||||
errorsField.empty()
|
||||
|
||||
postMathJaxProcessor: (text) ->
|
||||
RE_INLINEMATH = /^\$([^\$]*)\$/g
|
||||
RE_DISPLAYMATH = /^\$\$([^\$]*)\$\$/g
|
||||
Discussion.processEachMathAndCode text, (s, type) ->
|
||||
if type == 'display'
|
||||
s.replace RE_DISPLAYMATH, ($0, $1) ->
|
||||
"\\[" + $1 + "\\]"
|
||||
else if type == 'inline'
|
||||
s.replace RE_INLINEMATH, ($0, $1) ->
|
||||
"\\(" + $1 + "\\)"
|
||||
else
|
||||
s
|
||||
|
||||
makeWmdEditor: ($content, $local, cls_identifier) ->
|
||||
elem = $local(".#{cls_identifier}")
|
||||
id = $content.attr("_id")
|
||||
appended_id = "-#{cls_identifier}-#{id}"
|
||||
imageUploadUrl = Discussion.urlFor('upload')
|
||||
editor = Markdown.makeWmdEditor elem, appended_id, imageUploadUrl, Discussion.postMathJaxProcessor
|
||||
wmdEditors["#{cls_identifier}-#{id}"] = editor
|
||||
editor
|
||||
|
||||
getWmdEditor: ($content, $local, cls_identifier) ->
|
||||
id = $content.attr("_id")
|
||||
wmdEditors["#{cls_identifier}-#{id}"]
|
||||
|
||||
getWmdInput: ($content, $local, cls_identifier) ->
|
||||
id = $content.attr("_id")
|
||||
$local("#wmd-input-#{cls_identifier}-#{id}")
|
||||
|
||||
getWmdContent: ($content, $local, cls_identifier) ->
|
||||
Discussion.getWmdInput($content, $local, cls_identifier).val()
|
||||
|
||||
setWmdContent: ($content, $local, cls_identifier, text) ->
|
||||
Discussion.getWmdInput($content, $local, cls_identifier).val(text)
|
||||
Discussion.getWmdEditor($content, $local, cls_identifier).refreshPreview()
|
||||
|
||||
getContentInfo: (id, attr) ->
|
||||
if not window.$$annotated_content_info?
|
||||
window.$$annotated_content_info = {}
|
||||
(window.$$annotated_content_info[id] || {})[attr]
|
||||
|
||||
setContentInfo: (id, attr, value) ->
|
||||
if not window.$$annotated_content_info?
|
||||
window.$$annotated_content_info = {}
|
||||
window.$$annotated_content_info[id] ||= {}
|
||||
window.$$annotated_content_info[id][attr] = value
|
||||
|
||||
extendContentInfo: (id, newInfo) ->
|
||||
if not window.$$annotated_content_info?
|
||||
window.$$annotated_content_info = {}
|
||||
window.$$annotated_content_info[id] = newInfo
|
||||
bulkExtendContentInfo: (newInfos) ->
|
||||
if not window.$$annotated_content_info?
|
||||
window.$$annotated_content_info = {}
|
||||
window.$$annotated_content_info = $.extend window.$$annotated_content_info, newInfos
|
||||
|
||||
subscriptionLink: (type, id) ->
|
||||
followLink = ->
|
||||
Discussion.generateDiscussionLink("discussion-follow-#{type}", "Follow", handleFollow)
|
||||
|
||||
unfollowLink = ->
|
||||
Discussion.generateDiscussionLink("discussion-unfollow-#{type}", "Unfollow", handleUnfollow)
|
||||
|
||||
handleFollow = (elem) ->
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: Discussion.urlFor("follow_#{type}", id)
|
||||
type: "POST"
|
||||
success: (response, textStatus) ->
|
||||
if textStatus == "success"
|
||||
$(elem).replaceWith unfollowLink()
|
||||
dataType: 'json'
|
||||
|
||||
handleUnfollow = (elem) ->
|
||||
Discussion.safeAjax
|
||||
$elem: $(elem)
|
||||
url: Discussion.urlFor("unfollow_#{type}", id)
|
||||
type: "POST"
|
||||
success: (response, textStatus) ->
|
||||
if textStatus == "success"
|
||||
$(elem).replaceWith followLink()
|
||||
dataType: 'json'
|
||||
|
||||
if Discussion.isSubscribed(id, type)
|
||||
unfollowLink()
|
||||
else
|
||||
followLink()
|
||||
|
||||
processEachMathAndCode: (text, processor) ->
|
||||
|
||||
codeArchive = []
|
||||
|
||||
RE_DISPLAYMATH = /^([^\$]*?)\$\$([^\$]*?)\$\$(.*)$/m
|
||||
RE_INLINEMATH = /^([^\$]*?)\$([^\$]+?)\$(.*)$/m
|
||||
|
||||
ESCAPED_DOLLAR = '@@ESCAPED_D@@'
|
||||
ESCAPED_BACKSLASH = '@@ESCAPED_B@@'
|
||||
|
||||
processedText = ""
|
||||
|
||||
$div = $("<div>").html(text)
|
||||
|
||||
$div.find("code").each (index, code) ->
|
||||
codeArchive.push $(code).html()
|
||||
$(code).html(codeArchive.length - 1)
|
||||
|
||||
text = $div.html()
|
||||
text = text.replace /\\\$/g, ESCAPED_DOLLAR
|
||||
|
||||
while true
|
||||
if RE_INLINEMATH.test(text)
|
||||
text = text.replace RE_INLINEMATH, ($0, $1, $2, $3) ->
|
||||
processedText += $1 + processor("$" + $2 + "$", 'inline')
|
||||
$3
|
||||
else if RE_DISPLAYMATH.test(text)
|
||||
text = text.replace RE_DISPLAYMATH, ($0, $1, $2, $3) ->
|
||||
processedText += $1 + processor("$$" + $2 + "$$", 'display')
|
||||
$3
|
||||
else
|
||||
processedText += text
|
||||
break
|
||||
|
||||
text = processedText
|
||||
text = text.replace(new RegExp(ESCAPED_DOLLAR, 'g'), '\\$')
|
||||
|
||||
text = text.replace /\\\\\\\\/g, ESCAPED_BACKSLASH
|
||||
text = text.replace /\\begin\{([a-z]*\*?)\}([\s\S]*?)\\end\{\1\}/img, ($0, $1, $2) ->
|
||||
processor("\\begin{#{$1}}" + $2 + "\\end{#{$1}}")
|
||||
text = text.replace(new RegExp(ESCAPED_BACKSLASH, 'g'), '\\\\\\\\')
|
||||
|
||||
$div = $("<div>").html(text)
|
||||
cnt = 0
|
||||
$div.find("code").each (index, code) ->
|
||||
$(code).html(processor(codeArchive[cnt], 'code'))
|
||||
cnt += 1
|
||||
|
||||
text = $div.html()
|
||||
|
||||
text
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<%block name="js_extra">
|
||||
<%include file="_js_body_dependencies.html" />
|
||||
<%static:js group='discussion'/>
|
||||
</%block>
|
||||
|
||||
<%include file="../courseware/course_navigation.html" args="active_page='discussion'" />
|
||||
|
||||
Reference in New Issue
Block a user