Unify forum thread views (and templates)
This commit is contained in:
@@ -150,21 +150,21 @@ describe "DiscussionThreadListView", ->
|
||||
<div class="forum-nav"></div>
|
||||
"""
|
||||
@threads = [
|
||||
makeThreadWithProps({
|
||||
DiscussionViewSpecHelper.makeThreadWithProps({
|
||||
id: "1",
|
||||
title: "Thread1",
|
||||
votes: {up_count: '20'},
|
||||
comments_count: 1,
|
||||
created_at: '2013-04-03T20:08:39Z',
|
||||
}),
|
||||
makeThreadWithProps({
|
||||
DiscussionViewSpecHelper.makeThreadWithProps({
|
||||
id: "2",
|
||||
title: "Thread2",
|
||||
votes: {up_count: '42'},
|
||||
comments_count: 2,
|
||||
created_at: '2013-04-03T20:07:39Z',
|
||||
}),
|
||||
makeThreadWithProps({
|
||||
DiscussionViewSpecHelper.makeThreadWithProps({
|
||||
id: "3",
|
||||
title: "Thread3",
|
||||
votes: {up_count: '12'},
|
||||
@@ -179,20 +179,8 @@ describe "DiscussionThreadListView", ->
|
||||
@view = new DiscussionThreadListView({collection: @discussion, el: $(".forum-nav")})
|
||||
@view.render()
|
||||
|
||||
makeThreadWithProps = (props) ->
|
||||
# Minimal set of properties necessary for rendering
|
||||
thread = {
|
||||
id: "dummy_id",
|
||||
pinned: false,
|
||||
endorsed: false,
|
||||
votes: {up_count: '0'},
|
||||
unread_comments_count: 0,
|
||||
comments_count: 0,
|
||||
}
|
||||
$.extend(thread, props)
|
||||
|
||||
renderSingleThreadWithProps = (props) ->
|
||||
makeView(new Discussion([new Thread(makeThreadWithProps(props))])).render()
|
||||
makeView(new Discussion([new Thread(DiscussionViewSpecHelper.makeThreadWithProps(props))])).render()
|
||||
|
||||
makeView = (discussion) ->
|
||||
return new DiscussionThreadListView(
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
describe "DiscussionThreadInlineView", ->
|
||||
beforeEach ->
|
||||
setFixtures(
|
||||
"""
|
||||
<script type="text/template" id="_inline_thread">
|
||||
<article class="discussion-article">
|
||||
<div class="non-cohorted-indicator"/>
|
||||
<div class="post-body"/>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"/>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
</div>
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="expand-post">Expand</a>
|
||||
<a href="javascript:void(0)" class="collapse-post">Collapse</a>
|
||||
</div>
|
||||
</article>
|
||||
</script>
|
||||
<script type="text/template" id="_inline_thread_cohorted">
|
||||
<article class="discussion-article">
|
||||
<div class="cohorted-indicator"/>
|
||||
<div class="post-body"/>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"/>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
</div>
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="expand-post">Expand</a>
|
||||
<a href="javascript:void(0)" class="collapse-post">Collapse</a>
|
||||
</div>
|
||||
</article>
|
||||
</script>
|
||||
<div class="thread-fixture"/>
|
||||
"""
|
||||
)
|
||||
|
||||
@threadData = {
|
||||
id: "dummy",
|
||||
body: "dummy body",
|
||||
abuse_flaggers: [],
|
||||
votes: {up_count: "42"}
|
||||
}
|
||||
@thread = new Thread(@threadData)
|
||||
@view = new DiscussionThreadInlineView({ model: @thread })
|
||||
@view.setElement($(".thread-fixture"))
|
||||
spyOn($, "ajax")
|
||||
# Avoid unnecessary boilerplate
|
||||
spyOn(@view.showView, "render")
|
||||
spyOn(@view.showView, "convertMath")
|
||||
spyOn(@view, "makeWmdEditor")
|
||||
spyOn(DiscussionThreadView.prototype, "renderResponse")
|
||||
|
||||
assertContentVisible = (view, selector, visible) ->
|
||||
content = view.$el.find(selector)
|
||||
expect(content.length).toEqual(1)
|
||||
expect(content.is(":visible")).toEqual(visible)
|
||||
|
||||
assertExpandedContentVisible = (view, expanded) ->
|
||||
expect(view.$el.hasClass("expanded")).toEqual(expanded)
|
||||
assertContentVisible(view, ".post-extended-content", expanded)
|
||||
assertContentVisible(view, ".expand-post", not expanded)
|
||||
assertContentVisible(view, ".collapse-post", expanded)
|
||||
|
||||
describe "render", ->
|
||||
it "uses the cohorted template if cohorted", ->
|
||||
@view.model.set({group_id: 1})
|
||||
@view.render()
|
||||
expect(@view.$el.find(".cohorted-indicator").length).toEqual(1)
|
||||
|
||||
it "uses the non-cohorted template if not cohorted", ->
|
||||
@view.render()
|
||||
expect(@view.$el.find(".non-cohorted-indicator").length).toEqual(1)
|
||||
|
||||
it "shows content that should be visible when collapsed", ->
|
||||
@view.render()
|
||||
assertExpandedContentVisible(@view, false)
|
||||
|
||||
it "does not render any responses by default", ->
|
||||
@view.render()
|
||||
expect($.ajax).not.toHaveBeenCalled()
|
||||
expect(@view.$el.find(".responses li").length).toEqual(0)
|
||||
|
||||
describe "expand/collapse", ->
|
||||
it "shows/hides appropriate content", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 0, children: []})
|
||||
@view.render()
|
||||
@view.expandPost()
|
||||
assertExpandedContentVisible(@view, true)
|
||||
@view.collapsePost()
|
||||
assertExpandedContentVisible(@view, false)
|
||||
|
||||
it "switches between the abbreviated and full body", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 0, children: []})
|
||||
@thread.set("body", new Array(100).join("test "))
|
||||
@view.abbreviateBody()
|
||||
expect(@thread.get("body")).not.toEqual(@thread.get("abbreviatedBody"))
|
||||
@view.render()
|
||||
@view.expandPost()
|
||||
expect(@view.$el.find(".post-body").text()).toEqual(@thread.get("body"))
|
||||
expect(@view.showView.convertMath).toHaveBeenCalled()
|
||||
@view.showView.convertMath.reset()
|
||||
@view.collapsePost()
|
||||
expect(@view.$el.find(".post-body").text()).toEqual(@thread.get("abbreviatedBody"))
|
||||
expect(@view.showView.convertMath).toHaveBeenCalled()
|
||||
@@ -4,77 +4,144 @@ describe "DiscussionThreadView", ->
|
||||
"""
|
||||
<script type="text/template" id="thread-template">
|
||||
<article class="discussion-article">
|
||||
<div class="response-count"/>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
<div class="thread-content-wrapper"></div>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"></div>
|
||||
<ol class="responses"></ol>
|
||||
<div class="response-pagination"></div>
|
||||
</div>
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="forum-thread-expand">Expand</a>
|
||||
<a href="javascript:void(0)" class="forum-thread-collapse">Collapse</a>
|
||||
</div>
|
||||
</article>
|
||||
</script>
|
||||
<script type="text/template" id="thread-show-template">
|
||||
<div class="discussion-post">
|
||||
<div class="post-body"><%- body %></div>
|
||||
</div>
|
||||
</script>
|
||||
<div class="thread-fixture"/>
|
||||
"""
|
||||
)
|
||||
|
||||
jasmine.Clock.useMock()
|
||||
@threadData = {
|
||||
id: "dummy"
|
||||
}
|
||||
@threadData = DiscussionViewSpecHelper.makeThreadWithProps({})
|
||||
@thread = new Thread(@threadData)
|
||||
@view = new DiscussionThreadView({ model: @thread })
|
||||
@view.setElement($(".thread-fixture"))
|
||||
spyOn($, "ajax")
|
||||
# Avoid unnecessary boilerplate
|
||||
spyOn(@view.showView, "render")
|
||||
spyOn(@view, "makeWmdEditor")
|
||||
spyOn(DiscussionThreadShowView.prototype, "convertMath")
|
||||
spyOn(DiscussionContentView.prototype, "makeWmdEditor")
|
||||
spyOn(DiscussionThreadView.prototype, "renderResponse")
|
||||
|
||||
describe "response count and pagination", ->
|
||||
renderWithContent = (view, content) ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent(content)
|
||||
view.render()
|
||||
jasmine.Clock.tick(100)
|
||||
assertContentVisible = (view, selector, visible) ->
|
||||
content = view.$el.find(selector)
|
||||
expect(content.length).toBeGreaterThan(0)
|
||||
content.each (i, elem) ->
|
||||
expect($(elem).is(":visible")).toEqual(visible)
|
||||
|
||||
assertRenderedCorrectly = (view, countText, displayCountText, buttonText) ->
|
||||
expect(view.$el.find(".response-count").text()).toEqual(countText)
|
||||
if displayCountText
|
||||
expect(view.$el.find(".response-display-count").text()).toEqual(displayCountText)
|
||||
else
|
||||
expect(view.$el.find(".response-display-count").length).toEqual(0)
|
||||
if buttonText
|
||||
expect(view.$el.find(".load-response-button").text()).toEqual(buttonText)
|
||||
else
|
||||
expect(view.$el.find(".load-response-button").length).toEqual(0)
|
||||
assertExpandedContentVisible = (view, expanded) ->
|
||||
expect(view.$el.hasClass("expanded")).toEqual(expanded)
|
||||
assertContentVisible(view, ".post-extended-content", expanded)
|
||||
assertContentVisible(view, ".forum-thread-expand", not expanded)
|
||||
assertContentVisible(view, ".forum-thread-collapse", expanded)
|
||||
|
||||
it "correctly render for a thread with no responses", ->
|
||||
renderWithContent(@view, {resp_total: 0, children: []})
|
||||
assertRenderedCorrectly(@view, "0 responses", null, null)
|
||||
describe "tab mode", ->
|
||||
beforeEach ->
|
||||
@view = new DiscussionThreadView({ model: @thread, el: $(".thread-fixture"), mode: "tab"})
|
||||
|
||||
it "correctly render for a thread with one response", ->
|
||||
renderWithContent(@view, {resp_total: 1, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "1 response", "Showing all responses", null)
|
||||
describe "response count and pagination", ->
|
||||
renderWithContent = (view, content) ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent(content)
|
||||
view.render()
|
||||
jasmine.Clock.tick(100)
|
||||
|
||||
it "correctly render for a thread with one additional page", ->
|
||||
renderWithContent(@view, {resp_total: 2, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "2 responses", "Showing first response", "Load all responses")
|
||||
assertRenderedCorrectly = (view, countText, displayCountText, buttonText) ->
|
||||
expect(view.$el.find(".response-count").text()).toEqual(countText)
|
||||
if displayCountText
|
||||
expect(view.$el.find(".response-display-count").text()).toEqual(displayCountText)
|
||||
else
|
||||
expect(view.$el.find(".response-display-count").length).toEqual(0)
|
||||
if buttonText
|
||||
expect(view.$el.find(".load-response-button").text()).toEqual(buttonText)
|
||||
else
|
||||
expect(view.$el.find(".load-response-button").length).toEqual(0)
|
||||
|
||||
it "correctly render for a thread with multiple additional pages", ->
|
||||
renderWithContent(@view, {resp_total: 111, children: [{}, {}]})
|
||||
assertRenderedCorrectly(@view, "111 responses", "Showing first 2 responses", "Load next 100 responses")
|
||||
it "correctly render for a thread with no responses", ->
|
||||
renderWithContent(@view, {resp_total: 0, children: []})
|
||||
assertRenderedCorrectly(@view, "0 responses", null, null)
|
||||
|
||||
describe "on clicking the load more button", ->
|
||||
beforeEach ->
|
||||
renderWithContent(@view, {resp_total: 5, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "5 responses", "Showing first response", "Load all responses")
|
||||
|
||||
it "correctly re-render when all threads have loaded", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 5, children: [{}, {}, {}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "5 responses", "Showing all responses", null)
|
||||
it "correctly render for a thread with one response", ->
|
||||
renderWithContent(@view, {resp_total: 1, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "1 response", "Showing all responses", null)
|
||||
|
||||
it "correctly re-render when one page remains", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 42, children: [{}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "42 responses", "Showing first 3 responses", "Load all responses")
|
||||
it "correctly render for a thread with one additional page", ->
|
||||
renderWithContent(@view, {resp_total: 2, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "2 responses", "Showing first response", "Load all responses")
|
||||
|
||||
it "correctly re-render when multiple pages remain", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 111, children: [{}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "111 responses", "Showing first 3 responses", "Load next 100 responses")
|
||||
it "correctly render for a thread with multiple additional pages", ->
|
||||
renderWithContent(@view, {resp_total: 111, children: [{}, {}]})
|
||||
assertRenderedCorrectly(@view, "111 responses", "Showing first 2 responses", "Load next 100 responses")
|
||||
|
||||
describe "on clicking the load more button", ->
|
||||
beforeEach ->
|
||||
renderWithContent(@view, {resp_total: 5, children: [{}]})
|
||||
assertRenderedCorrectly(@view, "5 responses", "Showing first response", "Load all responses")
|
||||
|
||||
it "correctly re-render when all threads have loaded", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 5, children: [{}, {}, {}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "5 responses", "Showing all responses", null)
|
||||
|
||||
it "correctly re-render when one page remains", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 42, children: [{}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "42 responses", "Showing first 3 responses", "Load all responses")
|
||||
|
||||
it "correctly re-render when multiple pages remain", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 111, children: [{}, {}]})
|
||||
@view.$el.find(".load-response-button").click()
|
||||
assertRenderedCorrectly(@view, "111 responses", "Showing first 3 responses", "Load next 100 responses")
|
||||
|
||||
describe "inline mode", ->
|
||||
beforeEach ->
|
||||
@view = new DiscussionThreadView({ model: @thread, el: $(".thread-fixture"), mode: "inline"})
|
||||
|
||||
describe "render", ->
|
||||
it "shows content that should be visible when collapsed", ->
|
||||
@view.render()
|
||||
assertExpandedContentVisible(@view, false)
|
||||
|
||||
it "does not render any responses by default", ->
|
||||
@view.render()
|
||||
expect($.ajax).not.toHaveBeenCalled()
|
||||
expect(@view.$el.find(".responses li").length).toEqual(0)
|
||||
|
||||
describe "expand/collapse", ->
|
||||
it "shows/hides appropriate content", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 0, children: []})
|
||||
@view.render()
|
||||
@view.expand()
|
||||
assertExpandedContentVisible(@view, true)
|
||||
@view.collapse()
|
||||
assertExpandedContentVisible(@view, false)
|
||||
|
||||
it "switches between the abbreviated and full body", ->
|
||||
DiscussionViewSpecHelper.setNextResponseContent({resp_total: 0, children: []})
|
||||
longBody = new Array(100).join("test ")
|
||||
expectedAbbreviation = DiscussionUtil.abbreviateString(longBody, 140)
|
||||
@thread.set("body", longBody)
|
||||
|
||||
@view.render()
|
||||
expect($(".post-body").text()).toEqual(expectedAbbreviation)
|
||||
expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled()
|
||||
DiscussionThreadShowView.prototype.convertMath.reset()
|
||||
|
||||
@view.expand()
|
||||
expect($(".post-body").text()).toEqual(longBody)
|
||||
expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled()
|
||||
DiscussionThreadShowView.prototype.convertMath.reset()
|
||||
|
||||
@view.collapse()
|
||||
expect($(".post-body").text()).toEqual(expectedAbbreviation)
|
||||
expect(DiscussionThreadShowView.prototype.convertMath).toHaveBeenCalled()
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
class @DiscussionViewSpecHelper
|
||||
@makeThreadWithProps = (props) ->
|
||||
# Minimal set of properties necessary for rendering
|
||||
thread = {
|
||||
id: "dummy_id",
|
||||
pinned: false,
|
||||
endorsed: false,
|
||||
votes: {up_count: '0'},
|
||||
unread_comments_count: 0,
|
||||
comments_count: 0,
|
||||
abuse_flaggers: [],
|
||||
body: ""
|
||||
}
|
||||
$.extend(thread, props)
|
||||
|
||||
@expectVoteRendered = (view, voted) ->
|
||||
button = view.$el.find(".vote-btn")
|
||||
if voted
|
||||
|
||||
@@ -101,7 +101,7 @@ if Backbone?
|
||||
|
||||
@newPostForm = $('.new-post-article')
|
||||
@threadviews = @discussion.map (thread) ->
|
||||
new DiscussionThreadInlineView el: @$("article#thread_#{thread.id}"), model: thread
|
||||
new DiscussionThreadView el: @$("article#thread_#{thread.id}"), model: thread, mode: "inline"
|
||||
_.each @threadviews, (dtv) -> dtv.render()
|
||||
DiscussionUtil.bulkUpdateContentInfo(window.$$annotated_content_info)
|
||||
@newPostView = new NewPostView(
|
||||
@@ -124,7 +124,7 @@ if Backbone?
|
||||
# TODO: When doing pagination, this will need to repaginate. Perhaps just reload page 1?
|
||||
article = $("<article class='discussion-thread' id='thread_#{thread.id}'></article>")
|
||||
@$('section.discussion > .threads').prepend(article)
|
||||
threadView = new DiscussionThreadInlineView el: article, model: thread
|
||||
threadView = new DiscussionThreadView el: article, model: thread, mode: "inline"
|
||||
threadView.render()
|
||||
@threadviews.unshift threadView
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ if Backbone?
|
||||
if(@newPost.is(":visible"))
|
||||
@newPost.fadeOut()
|
||||
|
||||
@main = new DiscussionThreadView(el: $(".forum-content"), model: @thread)
|
||||
@main = new DiscussionThreadView(el: $(".forum-content"), model: @thread, mode: "tab")
|
||||
@main.render()
|
||||
@main.on "thread:responses:rendered", =>
|
||||
@nav.updateSidebar()
|
||||
|
||||
@@ -23,13 +23,18 @@ if Backbone?
|
||||
$: (selector) ->
|
||||
@$el.find(selector)
|
||||
|
||||
initialize: ->
|
||||
initialize: (options) ->
|
||||
super()
|
||||
@mode = options.mode or "inline" # allowed values are "tab" or "inline"
|
||||
if @mode not in ["tab", "inline"]
|
||||
throw new Error("invalid mode: " + @mode)
|
||||
@model.on "change", @updateModelDetails
|
||||
|
||||
renderTemplate: ->
|
||||
@template = _.template($("#thread-show-template").html())
|
||||
@template(@model.toJSON())
|
||||
context = @model.toJSON()
|
||||
context.mode = @mode
|
||||
@template(context)
|
||||
|
||||
render: ->
|
||||
@$el.html(@renderTemplate())
|
||||
@@ -170,13 +175,3 @@ if Backbone?
|
||||
highlight: (el) ->
|
||||
if el.html()
|
||||
el.html(el.html().replace(/<mark>/g, "<mark>").replace(/<\/mark>/g, "</mark>"))
|
||||
|
||||
class @DiscussionThreadInlineShowView extends DiscussionThreadShowView
|
||||
renderTemplate: ->
|
||||
@template = DiscussionUtil.getTemplate('_inline_thread_show')
|
||||
params = @model.toJSON()
|
||||
if @model.get('username')?
|
||||
params = $.extend(params, user:{username: @model.username, user_url: @model.user_url})
|
||||
Mustache.render(@template, params)
|
||||
|
||||
|
||||
|
||||
@@ -7,14 +7,20 @@ if Backbone?
|
||||
events:
|
||||
"click .discussion-submit-post": "submitComment"
|
||||
"click .add-response-btn": "scrollToAddResponse"
|
||||
"click .forum-thread-expand": "expand"
|
||||
"click .forum-thread-collapse": "collapse"
|
||||
|
||||
$: (selector) ->
|
||||
@$el.find(selector)
|
||||
|
||||
initialize: ->
|
||||
initialize: (options) ->
|
||||
super()
|
||||
@mode = options.mode or "inline" # allowed values are "tab" or "inline"
|
||||
if @mode not in ["tab", "inline"]
|
||||
throw new Error("invalid mode: " + @mode)
|
||||
@createShowView()
|
||||
@responses = new Comments()
|
||||
@loadedResponses = false
|
||||
|
||||
renderTemplate: ->
|
||||
@template = _.template($("#thread-template").html())
|
||||
@@ -31,10 +37,44 @@ if Backbone?
|
||||
@makeWmdEditor "reply-body"
|
||||
@renderAddResponseButton()
|
||||
@responses.on("add", @renderResponse)
|
||||
# Without a delay, jQuery doesn't add the loading extension defined in
|
||||
# utils.coffee before safeAjax is invoked, which results in an error
|
||||
setTimeout((=> @loadInitialResponses()), 100)
|
||||
@
|
||||
if @mode == "tab"
|
||||
# Without a delay, jQuery doesn't add the loading extension defined in
|
||||
# utils.coffee before safeAjax is invoked, which results in an error
|
||||
setTimeout((=> @loadInitialResponses()), 100)
|
||||
@$(".post-tools").hide()
|
||||
else # mode == "inline"
|
||||
@collapse()
|
||||
|
||||
expand: (event) ->
|
||||
if event
|
||||
event.preventDefault()
|
||||
@$el.addClass("expanded")
|
||||
@$el.find(".post-body").html(@model.get("body"))
|
||||
@showView.convertMath()
|
||||
@$el.find(".forum-thread-expand").hide()
|
||||
@$el.find(".forum-thread-collapse").show()
|
||||
@$el.find(".post-extended-content").show()
|
||||
if not @loadedResponses
|
||||
@loadInitialResponses()
|
||||
|
||||
collapse: (event) ->
|
||||
if event
|
||||
event.preventDefault()
|
||||
@$el.removeClass("expanded")
|
||||
@$el.find(".post-body").html(@getAbbreviatedBody())
|
||||
@showView.convertMath()
|
||||
@$el.find(".forum-thread-expand").show()
|
||||
@$el.find(".forum-thread-collapse").hide()
|
||||
@$el.find(".post-extended-content").hide()
|
||||
|
||||
getAbbreviatedBody: ->
|
||||
cached = @model.get("abbreviatedBody")
|
||||
if cached
|
||||
cached
|
||||
else
|
||||
abbreviated = DiscussionUtil.abbreviateString @model.get("body"), 140
|
||||
@model.set("abbreviatedBody", abbreviated)
|
||||
abbreviated
|
||||
|
||||
cleanup: ->
|
||||
if @responsesRequest?
|
||||
@@ -56,6 +96,7 @@ if Backbone?
|
||||
@responses.add(data['content']['children'])
|
||||
@renderResponseCountAndPagination(data['content']['resp_total'])
|
||||
@trigger "thread:responses:rendered"
|
||||
@loadedResponses = true
|
||||
error: (xhr) =>
|
||||
if xhr.status == 404
|
||||
DiscussionUtil.discussionAlert(
|
||||
@@ -208,6 +249,7 @@ if Backbone?
|
||||
@model.set
|
||||
title: newTitle
|
||||
body: newBody
|
||||
@model.unset("abbreviatedBody")
|
||||
|
||||
@createShowView()
|
||||
@renderShowView()
|
||||
@@ -231,9 +273,6 @@ if Backbone?
|
||||
renderEditView: () ->
|
||||
@renderSubView(@editView)
|
||||
|
||||
getShowViewClass: () ->
|
||||
return DiscussionThreadShowView
|
||||
|
||||
createShowView: () ->
|
||||
|
||||
if @editView?
|
||||
@@ -241,8 +280,7 @@ if Backbone?
|
||||
@editView.$el.empty()
|
||||
@editView = null
|
||||
|
||||
showViewClass = @getShowViewClass()
|
||||
@showView = new showViewClass(model: @model)
|
||||
@showView = new DiscussionThreadShowView({model: @model, mode: @mode})
|
||||
@showView.bind "thread:_delete", @_delete
|
||||
@showView.bind "thread:edit", @edit
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
if Backbone?
|
||||
class @DiscussionThreadInlineView extends DiscussionThreadView
|
||||
expanded = false
|
||||
events:
|
||||
"click .discussion-submit-post": "submitComment"
|
||||
"click .expand-post": "expandPost"
|
||||
"click .collapse-post": "collapsePost"
|
||||
"click .add-response-btn": "scrollToAddResponse"
|
||||
|
||||
initialize: ->
|
||||
super()
|
||||
|
||||
renderTemplate: () ->
|
||||
if @model.has('group_id')
|
||||
@template = DiscussionUtil.getTemplate("_inline_thread_cohorted")
|
||||
else
|
||||
@template = DiscussionUtil.getTemplate("_inline_thread")
|
||||
|
||||
if not @model.has('abbreviatedBody')
|
||||
@abbreviateBody()
|
||||
params = @model.toJSON()
|
||||
Mustache.render(@template, params)
|
||||
|
||||
render: () ->
|
||||
super()
|
||||
@$el.find('.post-extended-content').hide()
|
||||
@$el.find('.collapse-post').hide()
|
||||
|
||||
getShowViewClass: () ->
|
||||
return DiscussionThreadInlineShowView
|
||||
|
||||
loadInitialResponses: () ->
|
||||
if @expanded
|
||||
super()
|
||||
|
||||
abbreviateBody: ->
|
||||
abbreviated = DiscussionUtil.abbreviateString @model.get('body'), 140
|
||||
@model.set('abbreviatedBody', abbreviated)
|
||||
|
||||
expandPost: (event) =>
|
||||
@$el.addClass('expanded')
|
||||
@$el.find('.post-body').html(@model.get('body'))
|
||||
@showView.convertMath()
|
||||
@$el.find('.expand-post').css('display', 'none')
|
||||
@$el.find('.collapse-post').css('display', 'block')
|
||||
@$el.find('.post-extended-content').show()
|
||||
if not @expanded
|
||||
@expanded = true
|
||||
@loadInitialResponses()
|
||||
|
||||
collapsePost: (event) ->
|
||||
curScroll = $(window).scrollTop()
|
||||
postTop = @$el.offset().top
|
||||
if postTop < curScroll
|
||||
$('html, body').animate({scrollTop: postTop})
|
||||
@$el.removeClass('expanded')
|
||||
@$el.find('.post-body').html(@model.get('abbreviatedBody'))
|
||||
@showView.convertMath()
|
||||
@$el.find('.expand-post').css('display', 'block')
|
||||
@$el.find('.collapse-post').css('display', 'none')
|
||||
@$el.find('.post-extended-content').hide()
|
||||
|
||||
createEditView: () ->
|
||||
super()
|
||||
@editView.bind "thread:update", @abbreviateBody
|
||||
@@ -269,7 +269,7 @@ class InlineDiscussionThreadPage(DiscussionThreadPage):
|
||||
|
||||
def expand(self):
|
||||
"""Clicks the link to expand the thread"""
|
||||
self._find_within(".expand-post").first.click()
|
||||
self._find_within(".forum-thread-expand").first.click()
|
||||
EmptyPromise(
|
||||
lambda: bool(self.get_response_total_text()),
|
||||
"Thread expanded"
|
||||
|
||||
@@ -1007,7 +1007,8 @@ body.discussion {
|
||||
max-height: 600px;
|
||||
|
||||
.group-visibility-label {
|
||||
margin: $baseline ($baseline*1.5) ($baseline*-0.5);
|
||||
font-weight: 400;
|
||||
margin-bottom: ($baseline*0.5);
|
||||
}
|
||||
|
||||
.discussion-post {
|
||||
@@ -1043,10 +1044,10 @@ body.discussion {
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
h1 {
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0px;
|
||||
margin-bottom: 0px !important; // Override courseware CSS
|
||||
}
|
||||
|
||||
h4 {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
// CASE: inline styling
|
||||
// TO-DO: additional styling cleanup here necessary, for now this case was ported over from _discussion.scss
|
||||
.discussion-module .forum-new-post-form {
|
||||
.discussion-module {
|
||||
|
||||
.wmd-panel {
|
||||
width: 100%;
|
||||
|
||||
@@ -4,29 +4,37 @@
|
||||
|
||||
<script aria-hidden="true" type="text/template" id="thread-template">
|
||||
<article class="discussion-article" data-id="${'<%- id %>'}">
|
||||
<div class="thread-content-wrapper"></div>
|
||||
<div class="response-count"/>
|
||||
<div class="add-response">
|
||||
<button class="button add-response-btn">
|
||||
<i class="icon icon-reply"></i>
|
||||
<span class="add-response-btn-text">${_('Add A Response')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
<div class="post-status-closed bottom-post-status" style="display: none">
|
||||
${_("This thread is closed.")}
|
||||
</div>
|
||||
% if course is UNDEFINED or has_permission(user, 'create_comment', course.id):
|
||||
<form class="discussion-reply-new" data-id="${'<%- id %>'}">
|
||||
<h4>${_("Post a response:")}</h4>
|
||||
<ul class="discussion-errors"></ul>
|
||||
<div class="reply-body" data-id="${'<%- id %>'}"></div>
|
||||
<div class="reply-post-control">
|
||||
<a class="discussion-submit-post control-button" href="#">${_("Submit")}</a>
|
||||
<div class="thread-wrapper">
|
||||
<div class="thread-content-wrapper"></div>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"/>
|
||||
<div class="add-response">
|
||||
<button class="button add-response-btn">
|
||||
<i class="icon icon-reply"></i>
|
||||
<span class="add-response-btn-text">${_('Add A Response')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
<div class="post-status-closed bottom-post-status" style="display: none">
|
||||
${_("This thread is closed.")}
|
||||
</div>
|
||||
% if course is UNDEFINED or has_permission(user, 'create_comment', course.id):
|
||||
<form class="discussion-reply-new" data-id="${'<%- id %>'}">
|
||||
<h4>${_("Post a response:")}</h4>
|
||||
<ul class="discussion-errors"></ul>
|
||||
<div class="reply-body" data-id="${'<%- id %>'}"></div>
|
||||
<div class="reply-post-control">
|
||||
<a class="discussion-submit-post control-button" href="#">${_("Submit")}</a>
|
||||
</div>
|
||||
</form>
|
||||
% endif
|
||||
</div>
|
||||
</form>
|
||||
% endif
|
||||
</div>
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="forum-thread-expand"><span class="icon icon-plus"/> ${_("Expand discussion")}</a>
|
||||
<a href="javascript:void(0)" class="forum-thread-collapse"><span class="icon icon-minus"/> ${_("Collapse discussion")}</a>
|
||||
</div>
|
||||
</article>
|
||||
</script>
|
||||
|
||||
@@ -80,15 +88,17 @@
|
||||
escapejs(_("(this post is about %(courseware_title_linked)s)"))
|
||||
)
|
||||
%>
|
||||
${'<% if (obj.courseware_url) { %>'}
|
||||
${'<% if (mode == "tab" && obj.courseware_url) { %>'}
|
||||
<div class="post-context">${'<%'}${js_block}${'%>'}</div>
|
||||
${'<% } %>'}
|
||||
|
||||
<ul class="moderator-actions">
|
||||
<li style="display: none"><a class="action-edit" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Edit")}</a></li>
|
||||
<li style="display: none"><a class="action-delete" href="javascript:void(0)"><span class="delete-icon"></span> ${_("Delete")}</a></li>
|
||||
<li style="display: none"><a class="action-openclose" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Close")}</a></li>
|
||||
</ul>
|
||||
<div class="post-extended-content">
|
||||
<ul class="moderator-actions">
|
||||
<li style="display: none"><a class="action-edit" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Edit")}</a></li>
|
||||
<li style="display: none"><a class="action-delete" href="javascript:void(0)"><span class="delete-icon"></span> ${_("Delete")}</a></li>
|
||||
<li style="display: none"><a class="action-openclose" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Close")}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
<article class="discussion-article" data-id="{{id}}">
|
||||
<div class="thread-wrapper">
|
||||
<div class="thread-content-wrapper"></div>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"/>
|
||||
<div class="add-response">
|
||||
<button class="button add-response-btn">
|
||||
<i class="icon icon-reply"></i>
|
||||
<span class="add-response-btn-text">${_('Add A Response')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
{{#ability.can_reply}}
|
||||
<form class="discussion-reply-new" data-id="{{id}}">
|
||||
<h4>${_("Post a response:")}</h4>
|
||||
<ul class="discussion-errors"></ul>
|
||||
<div class="reply-body" data-id="{{id}}"></div>
|
||||
<div class="reply-post-control">
|
||||
<a class="discussion-submit-post control-button" href="#">${_("Submit")}</a>
|
||||
</div>
|
||||
</form>
|
||||
{{/ability.can_reply}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="expand-post"><span class="icon icon-plus"/> ${_("Expand discussion")}</a>
|
||||
<a href="javascript:void(0)" class="collapse-post"><span class="icon icon-minus"/> ${_("Collapse discussion")}</a>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -1,33 +0,0 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
<article class="discussion-article" data-id="{{id}}">
|
||||
<div class="thread-wrapper">
|
||||
<div class="group-visibility-label">{{group_string}}</div>
|
||||
<div class="thread-content-wrapper"></div>
|
||||
<div class="post-extended-content">
|
||||
<div class="response-count"/>
|
||||
<div class="add-response">
|
||||
<button class="button add-response-btn">
|
||||
<i class="icon icon-reply"></i>
|
||||
<span class="add-response-btn-text">${_('Add A Response')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ol class="responses"/>
|
||||
<div class="response-pagination"/>
|
||||
<form class="discussion-reply-new" data-id="{{id}}">
|
||||
<h4>${_("Post a response:")}</h4>
|
||||
<ul class="discussion-errors"></ul>
|
||||
<div class="reply-body" data-id="{{id}}"></div>
|
||||
<div class="reply-post-control">
|
||||
<a class="discussion-submit-post control-button" href="#">${_("Submit")}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-tools">
|
||||
<a href="javascript:void(0)" class="expand-post"><span class="icon icon-plus"/> ${_("Expand discussion")}</a>
|
||||
<a href="javascript:void(0)" class="collapse-post"><span class="icon icon-minus"/> ${_("Collapse discussion")}</a>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -1,36 +0,0 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
|
||||
<div class="discussion-post">
|
||||
<div><a href="javascript:void(0)" class="dogear action-follow" data-tooltip="follow"></a></div>
|
||||
<header>
|
||||
<a href="#" class="vote-btn" role="button" aria-pressed="false"/>
|
||||
<h3>{{title}}</h3>
|
||||
<div class="discussion-flag-abuse notflagged" data-role="thread-flag">
|
||||
<i class="icon icon-flag"></i><span class="flag-label"/></div>
|
||||
|
||||
<div class="discussion-pin-inline pinned pinned-{{pinned}}" data-tooltip="${_("This thread has been pinned by course staff.")}">
|
||||
<i class="icon icon-pushpin"></i><span class="pin-label">${_("Pinned")}</span></div>
|
||||
|
||||
<p class="posted-details">
|
||||
{{#user}}
|
||||
<a href="{{user_url}}" class="username">{{username}}</a>
|
||||
{{/user}}
|
||||
{{^user}}
|
||||
${_("anonymous")}
|
||||
{{/user}}
|
||||
|
||||
<span class="timeago" title="{{created_at}}">{{created_at}}</span>
|
||||
|
||||
<span class="post-status-closed top-post-status" style="display: none">
|
||||
• ${_("This thread is closed.")}
|
||||
</span>
|
||||
</p>
|
||||
</header>
|
||||
<div class="post-body">{{abbreviatedBody}}</div>
|
||||
|
||||
<ul class="moderator-actions post-extended-content">
|
||||
<li style="display: none"><a class="action-edit" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Edit")}</a></li>
|
||||
<li style="display: none"><a class="action-delete" href="javascript:void(0)"><span class="delete-icon"></span> ${_("Delete")}</a></li>
|
||||
<li style="display: none"><a class="action-openclose" href="javascript:void(0)"><span class="edit-icon"></span> ${_("Close")}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
Reference in New Issue
Block a user