Commit be04740e by Greg Price

Merge pull request #4291 from edx/forum-sidebar-improvements

Forum sidebar improvements
parents 220a028b 6d87443a
describe 'All Content', ->
beforeEach ->
# TODO: figure out a better way of handling this
# It is set up in main.coffee DiscussionApp.start
window.$$course_id = 'edX/999/test'
window.user = new DiscussionUser {id: '567'}
DiscussionSpecHelper.setUpGlobals()
describe 'Content', ->
beforeEach ->
......
class @DiscussionSpecHelper
# This is sad. We should avoid dependence on global vars.
@setUpGlobals = ->
DiscussionUtil.loadRoles({"Moderator": [], "Administrator": [], "Community TA": []})
window.$$course_id = "edX/999/test"
window.user = new DiscussionUser({id: "567", upvoted_ids: []})
describe "DiscussionContentView", ->
beforeEach ->
DiscussionSpecHelper.setUpGlobals()
setFixtures(
"""
<div class="discussion-post">
......@@ -36,7 +36,6 @@ describe "DiscussionContentView", ->
@thread = new Thread(@threadData)
@view = new DiscussionContentView({ model: @thread })
@view.setElement($('.discussion-post'))
window.user = new DiscussionUser({id: '567', upvoted_ids: []})
it 'defines the tag', ->
expect($('#jasmine-fixtures')).toExist
......
describe "DiscussionThreadShowView", ->
beforeEach ->
DiscussionSpecHelper.setUpGlobals()
setFixtures(
"""
<div class="discussion-post">
......@@ -14,8 +15,6 @@ describe "DiscussionThreadShowView", ->
"""
)
window.$$course_id = "TestOrg/TestCourse/TestRun"
window.user = new DiscussionUser({id: "567", upvoted_ids: []})
@threadData = {
id: "dummy",
user_id: user.id,
......
describe "DiscussionUserProfileView", ->
beforeEach ->
DiscussionSpecHelper.setUpGlobals()
setFixtures(
"""
<script type="text/template" id="_user_profile">
......@@ -46,7 +47,6 @@ describe "DiscussionUserProfileView", ->
<div class="user-profile-fixture"/>
"""
)
window.$$course_id = "dummy_course_id"
spyOn(DiscussionThreadProfileView.prototype, "render")
makeView = (threads, page, numPages) ->
......
describe 'ResponseCommentShowView', ->
beforeEach ->
DiscussionSpecHelper.setUpGlobals()
# set up the container for the response to go in
setFixtures """
<ol class="responses"></ol>
......
describe 'ResponseCommentView', ->
beforeEach ->
window.$$course_id = 'edX/999/test'
window.user = new DiscussionUser {id: '567'}
DiscussionUtil.loadRoles []
DiscussionSpecHelper.setUpGlobals()
@comment = new Comment {
id: '01234567',
user_id: user.id,
......
describe "ThreadResponseShowView", ->
beforeEach ->
DiscussionSpecHelper.setUpGlobals()
setFixtures(
"""
<div class="discussion-post">
......@@ -22,7 +23,6 @@ describe "ThreadResponseShowView", ->
@comment = new Comment(@commentData)
@view = new ThreadResponseShowView({ model: @comment })
@view.setElement($(".discussion-post"))
window.user = new DiscussionUser({id: "567", upvoted_ids: []})
it "renders the vote correctly", ->
DiscussionViewSpecHelper.checkRenderVote(@view, @comment)
......
......@@ -53,9 +53,12 @@ if Backbone?
initialize: ->
Content.addContent @id, @
userId = @get('user_id')
@set('staff_authored', DiscussionUtil.isStaff(userId))
@set('community_ta_authored', DiscussionUtil.isTA(userId))
if Content.getInfo(@id)
@updateInfo(Content.getInfo(@id))
@set 'user_url', DiscussionUtil.urlFor('user_profile', @get('user_id'))
@set 'user_url', DiscussionUtil.urlFor('user_profile', userId)
@resetComments(@get('children'))
remove: ->
......
......@@ -62,9 +62,9 @@ if Backbone?
new_threads = [new Thread(data) for data in response.discussion_data][0]
new_collection = _.union(models, new_threads)
Content.loadContentInfos(response.annotated_content_info)
@reset new_collection
@pages = response.num_pages
@current_page = response.page
@reset new_collection
error: error
sortByDate: (thread) ->
......
......@@ -20,6 +20,8 @@ if Backbone?
Backbone.history.start({pushState: true, root: "/courses/#{$$course_id}/discussion/forum/"})
DiscussionProfileApp =
start: (elem) ->
# Roles are not included in user profile page, but they are not used for anything
DiscussionUtil.loadRoles({"Moderator": [], "Administrator": [], "Community TA": []})
element = $(elem)
window.$$course_id = element.data("course-id")
threads = element.data("threads")
......
......@@ -32,12 +32,12 @@ class @DiscussionUtil
@loadFlagModerator($("#discussion-container").data("flag-moderator"))
@isStaff: (user_id) ->
user_id ?= @user.id
user_id ?= @user?.id
staff = _.union(@roleIds['Moderator'], @roleIds['Administrator'])
_.include(staff, parseInt(user_id))
@isTA: (user_id) ->
user_id ?= @user.id
user_id ?= @user?.id
ta = _.union(@roleIds['Community TA'])
_.include(ta, parseInt(user_id))
......@@ -93,6 +93,10 @@ class @DiscussionUtil
"notifications_status" : "/notification_prefs/status/"
}[name]
@ignoreEnterKey: (event) =>
if event.which == 13
event.preventDefault()
@activateOnSpace: (event, func) ->
if event.which == 32
event.preventDefault()
......
......@@ -179,19 +179,20 @@ class DiscussionSortPreferencePage(CoursePage):
"""
Return true if the browser is on the right page else false.
"""
return self.q(css="body.discussion .sort-bar").present
return self.q(css="body.discussion .forum-nav-sort-control").present
def get_selected_sort_preference_text(self):
def get_selected_sort_preference(self):
"""
Return the text of option that is selected for sorting.
"""
return self.q(css="body.discussion .sort-bar a.active").text[0].lower()
options = self.q(css="body.discussion .forum-nav-sort-control option")
return options.filter(lambda el: el.is_selected())[0].get_attribute("value")
def change_sort_preference(self, sort_by):
"""
Change the option of sorting by clicking on new option.
"""
self.q(css="body.discussion .sort-bar a[data-sort='{0}']".format(sort_by)).click()
self.q(css="body.discussion .forum-nav-sort-control option[value='{0}']".format(sort_by)).click()
def refresh_page(self):
"""
......@@ -352,12 +353,7 @@ class DiscussionTabHomePage(CoursePage, DiscussionPageMixin):
return self.q(css=".discussion-body section.home-header").present
def perform_search(self, text="dummy"):
self.q(css=".discussion-body .sidebar .search").first.click()
EmptyPromise(
lambda: self.q(css=".discussion-body .sidebar .search.is-open").present,
"waiting for search input to be available"
).fulfill()
self.q(css="#search-discussions").fill(text + chr(10))
self.q(css=".forum-nav-search-input").fill(text + chr(10))
EmptyPromise(
self.is_ajax_finished,
"waiting for server to return result"
......
......@@ -509,7 +509,7 @@ class DiscussionSortPreferenceTest(UniqueCourseTest):
"""
Test to check the default sorting preference of user. (Default = date )
"""
selected_sort = self.sort_page.get_selected_sort_preference_text()
selected_sort = self.sort_page.get_selected_sort_preference()
self.assertEqual(selected_sort, "date")
def test_change_sort_preference(self):
......@@ -520,7 +520,7 @@ class DiscussionSortPreferenceTest(UniqueCourseTest):
for sort_type in ["votes", "comments", "date"]:
self.assertNotEqual(selected_sort, sort_type)
self.sort_page.change_sort_preference(sort_type)
selected_sort = self.sort_page.get_selected_sort_preference_text()
selected_sort = self.sort_page.get_selected_sort_preference()
self.assertEqual(selected_sort, sort_type)
def test_last_preference_saved(self):
......@@ -531,8 +531,8 @@ class DiscussionSortPreferenceTest(UniqueCourseTest):
for sort_type in ["votes", "comments", "date"]:
self.assertNotEqual(selected_sort, sort_type)
self.sort_page.change_sort_preference(sort_type)
selected_sort = self.sort_page.get_selected_sort_preference_text()
selected_sort = self.sort_page.get_selected_sort_preference()
self.assertEqual(selected_sort, sort_type)
self.sort_page.refresh_page()
selected_sort = self.sort_page.get_selected_sort_preference_text()
selected_sort = self.sort_page.get_selected_sort_preference()
self.assertEqual(selected_sort, sort_type)
......@@ -48,8 +48,12 @@
@import 'views/shoppingcart';
// applications
@import 'discussion/discussion';
@import 'discussion/discussion-developer';
@import "discussion/utilities/variables";
@import 'discussion/discussion'; // Process old file after definitions but before everything else
@import "discussion/elements/navigation";
@import 'discussion/utilities/developer';
@import 'discussion/utilities/shame';
@import 'news';
// temp - shame and developer
......
.forum-nav {
@include box-sizing(border-box);
float: left;
border: 1px solid #aaa;
border-radius: 3px;
}
// ------
// Header
// ------
.forum-nav-header {
@include box-sizing(border-box);
display: table;
border-bottom: 1px solid $gray-l2;
background-color: $gray-l3;
}
.forum-nav-browse {
@include box-sizing(border-box);
display: table-cell;
vertical-align: middle;
width: 50%;
padding: ($baseline/4);
&:hover, &:focus, &.is-active {
background-color: $gray-l5;
}
.icon {
margin-right: ($baseline/4);
}
}
.forum-nav-browse-current {
@include font-size(12);
}
.forum-nav-browse-drop-arrow {
margin-left: ($baseline/4);
}
.forum-nav-search {
@include box-sizing(border-box);
display: table-cell;
position: relative;
vertical-align: middle;
width: 50%;
padding: ($baseline/4);
}
.forum-nav-search .icon {
@include font-size(12);
position: absolute;
margin-top: -6px;
top: 50%;
right: ($baseline/4 + 1px + $baseline / 4); // Wrapper padding + border + input padding
}
.forum-nav-search-input {
width: 100%;
}
// -----------
// Browse menu
// -----------
.forum-nav-browse-menu-wrapper {
overflow-y: scroll;
border-bottom: 1px solid $gray-l3;
background: $gray-l5;
}
.forum-nav-browse-filter {
position: relative;
border-bottom: 1px solid $gray-l2;
padding: ($baseline/4);
}
.forum-nav-browse-filter .icon {
@include font-size(12);
position: absolute;
margin-top: -6px;
top: 50%;
right: ($baseline/4 + 1px + $baseline / 4); // Wrapper padding + border + input padding
}
.forum-nav-browse-filter-input {
width: 100%;
}
.forum-nav-browse-title .icon {
margin-right: ($baseline/2);
}
// -------------------
// Sort and filter bar
// -------------------
.forum-nav-refine-bar {
@include clearfix();
@include font-size(11);
border-bottom: 1px solid $gray-l3;
background-color: $gray-l5;
padding: ($baseline/4) ($baseline/2);
color: $black;
}
%forum-nav-select {
border: none;
max-width: 100%;
background-color: transparent;
font: inherit;
}
.forum-nav-filter-cohort-control {
@extend %forum-nav-select;
}
.forum-nav-sort {
float: right;
}
.forum-nav-sort-control {
@extend %forum-nav-select;
}
// -----------
// Thread list
// -----------
.forum-nav-thread-list {
overflow-y: scroll;
}
.forum-nav-thread {
border-bottom: 1px solid $gray-l3;
}
.forum-nav-thread-link {
@include clearfix();
}
%forum-nav-thread-wrapper {
display: inline-block;
vertical-align: middle;
}
.forum-nav-thread-wrapper-1 {
@extend %forum-nav-thread-wrapper;
width: 70%;
}
.forum-nav-thread-wrapper-2 {
@extend %forum-nav-thread-wrapper;
width: 30%;
text-align: right;
}
.forum-nav-thread-title {
@extend %t-title7;
display: block;
}
%forum-nav-thread-label {
@extend %t-weight4;
@include font-size(9);
display: inline;
border: 1px solid;
border-radius: 3px;
text-transform: uppercase;
white-space: nowrap;
&:last-child {
margin-right: 0;
}
.icon {
margin-right: ($baseline/5);
}
}
.forum-nav-thread-label-pinned {
@extend %forum-nav-thread-label;
border-color: $forum-color-pinned;
color: $forum-color-pinned;
}
.forum-nav-thread-label-following {
@extend %forum-nav-thread-label;
border-color: $forum-color-following;
color: $forum-color-following;
}
.forum-nav-thread-label-staff {
@extend %forum-nav-thread-label;
border-color: $forum-color-staff;
color: $forum-color-staff;
}
.forum-nav-thread-label-community-ta {
@extend %forum-nav-thread-label;
border-color: $forum-color-community-ta;
color: $forum-color-community-ta;
}
%forum-nav-thread-wrapper-2-content {
@include font-size(11);
display: inline-block;
margin-right: ($baseline/4);
text-align: center;
color: $black;
&:last-child {
margin-right: 0;
}
}
.forum-nav-thread-endorsed {
@extend %forum-nav-thread-wrapper-2-content;
color: $green-d1;
}
.forum-nav-thread-votes-count {
@extend %forum-nav-thread-wrapper-2-content;
}
.forum-nav-thread-comments-count {
@extend %forum-nav-thread-wrapper-2-content;
@extend %t-weight4;
position: relative;
margin-left: ($baseline/4);
margin-bottom: ($baseline/4); // Because tail is position: absolute
border-radius: 2px;
padding: ($baseline/10) ($baseline/5);
min-width: 2em; // Fit most comment counts but allow expansion if necessary
background-color: $gray-l3;
// Speech bubble tail
&:after {
content: '';
display: block;
position: absolute;
bottom: (-$baseline/4);
right: ($baseline/4);
width: 0;
height: 0;
border-style: solid;
border-width: 0 ($baseline/4) ($baseline/4) 0;
border-color: transparent $gray-l3 transparent transparent;
}
&.is-unread {
background-color: $white;
&:after {
border-right-color: $white
}
}
}
.forum-nav-thread.is-unread .forum-nav-thread-comments-count {
background-color: $blue;
color: $white;
&:after {
border-right-color: $blue;
}
}
%forum-nav-load-more-content {
text-align: center;
}
.forum-nav-load-more-link {
@extend %forum-nav-load-more-content;
color: $link-color;
}
.forum-nav-loading {
@extend %forum-nav-load-more-content;
}
// -------------------
// navigation - header
// -------------------
// Override global a rules
.forum-nav-browse {
color: $black !important;
}
// Override global label rules
.forum-nav-search label {
margin-bottom: 0;
}
// Override global input rules
.forum-nav-search-input {
box-shadow: none !important;
border: 1px solid $gray-l2 !important;
border-radius: 3px !important;
height: auto !important;
padding-left: ($baseline/4) !important;
padding-right: ($baseline/2 + 12px) !important; // Leave room for icon
font-size: 12px !important;
}
// Firefox does not compute the correct containing box for absolute positioning
// of .forum-nav-search .icon, so there's an extra div to make it happy
.forum-nav-search-ff-position-fix {
position: relative;
}
// The sidebar class does a lot of things that we don't want in the thread list;
// the following rules contain styling that is necessary and would otherwise
// reside in elements/_navigation.scss if the sidebar styling did not make the
// !important directive necessary.
.forum-nav {
width: 31% !important;
}
// ------------------------
// navigation - browse menu
// ------------------------
// Override global a rules
.forum-nav-browse-title {
color: inherit !important;
}
// Override global label rules
.forum-nav-browse-filter label {
margin-bottom: 0;
}
// Override global input rules
.forum-nav-browse-filter-input {
box-shadow: none !important;
border-radius: 3px !important;
height: auto !important;
padding-left: ($baseline/4) !important;
padding-right: ($baseline/2 + 12px) !important; // Leave room for icon
font-size: 12px !important;
}
// The sidebar class does a lot of things that we don't want in the thread list;
// the following rules contain styling that is necessary and would otherwise
// reside in elements/_navigation.scss if the sidebar styling did not make the
// !important directive necessary.
.forum-nav-browse-title {
border-bottom: 1px solid $gray-l3 !important;
padding: ($baseline/2) ($baseline/2) !important;
&:hover, &:focus {
background: $forum-color-active-thread !important;
}
}
.forum-nav-browse-submenu {
padding-left: $baseline !important;
}
// --------------------------------
// navigation - sort and filter bar
// --------------------------------
// Override global span rules
.forum-nav-sort-label {
color: inherit;
}
// --------------------------------
// navigation - thread list
// --------------------------------
// The sidebar class does a lot of things that we don't want in the thread list;
// the following rules contain styling that is necessary and would otherwise
// reside in elements/_navigation.scss if the sidebar styling did not make the
// !important directive necessary.
.forum-nav-thread {
background-color: $gray-l5 !important;
&.is-unread {
background-color: $white !important;
}
}
.forum-nav-thread-link {
padding: ($baseline/4) ($baseline/2) !important;
&.is-active, &:hover, &:focus {
background-color: $forum-color-active-thread !important;
}
}
li[class*=forum-nav-thread-label-] {
margin-top: ($baseline/4) !important;
padding: 1px 6px !important;
}
.forum-nav-load-more {
border-bottom: 1px solid $gray-l3 !important;
background-color: $gray-l5 !important;
}
.forum-nav-load-more-link {
&:hover, &:focus {
color: $link-color !important;
background-color: $forum-color-active-thread !important;
}
}
.forum-nav-load-more-link, .forum-nav-loading {
padding: $baseline 0 !important;
}
// The following rules would be unnecessary but for broadly scoped rules defined
// elsewhere in our CSS.
li[class*=forum-nav-thread-label-] {
// Override global span rules
span {
color: inherit;
}
// Override clearfix stuff in .sidebar ul li rules
&:before, &:after {
display: none !important;
}
}
$forum-color-active-thread: tint($blue, 85%);
$forum-color-pinned: $pink;
$forum-color-following: $blue;
$forum-color-staff: $blue;
$forum-color-community-ta: $green-d1;
......@@ -12,41 +12,43 @@
</%def>
<%def name="render_entry(entries, entry)">
<li><a href="#" class="drop-menu-entry"><span class="board-name" data-discussion_id='${json.dumps(entries[entry])}' cohorted = "${str(entries[entry]['is_cohorted']).lower()}">${entry}</span></a></li>
<li
class="forum-nav-browse-menu-item"
data-discussion-id='${json.dumps(entries[entry])}'
data-cohorted="${str(entries[entry]['is_cohorted']).lower()}"
>
<a href="#" class="forum-nav-browse-title">${entry}</a>
</li>
</%def>
<%def name="render_category(categories, category)">
<li>
<a href="#" class="drop-menu-parent-category"><span class="board-name">${category}</span></a>
<ul>
<li class="forum-nav-browse-menu-item">
<a href="#" class="forum-nav-browse-title">${category}</a>
<ul class="forum-nav-browse-submenu">
${render_dropdown(categories[category])}
</ul>
</li>
</%def>
<div class="browse-topic-drop-menu-wrapper">
<div class="browse-topic-drop-search">
<label class="sr" for="browse-topic">${_("Filter Topics")}</label>
<input type="text" id="browse-topic" class="browse-topic-drop-search-input" placeholder="${_('filter topics')}">
</div>
<ul class="browse-topic-drop-menu">
<li>
<a href="#" class="drop-menu-meta-category">
<span class="board-name" data-discussion_id='#all'>${_("Show All Discussions")}</span>
</a>
<div class="forum-nav-browse-menu-wrapper" style="display: none">
<form class="forum-nav-browse-filter">
<label>
<span class="sr">${_("Filter Topics")}</span>
<input type="text" class="forum-nav-browse-filter-input" placeholder="${_("filter topics")}">
<i class="icon icon-filter"></i>
</label>
</form>
<ul class="forum-nav-browse-menu">
<li class="forum-nav-browse-menu-item forum-nav-browse-menu-all">
<a href="#" class="forum-nav-browse-title">${_("All Discussions")}</a>
</li>
%if flag_moderator:
<li>
<a href="#">
<span class="board-name" data-discussion_id='#flagged'><i class="icon-flag" style="padding-right:5px;"></i>${_("Show Flagged Discussions")}</span>
</a>
<li class="forum-nav-browse-menu-item forum-nav-browse-menu-flagged">
<a href="#" class="forum-nav-browse-title"><i class="icon icon-flag"></i>${_("Flagged Discussions")}</a>
</li>
%endif
<li>
<a href="#" class="drop-menu-meta-category">
<span class="board-name" data-discussion_id='#following'><i class="icon-star" style="padding-right:5px;"></i>${_("Posts I'm Following")}</span>
</a>
<li class="forum-nav-browse-menu-item forum-nav-browse-menu-following">
<a href="#" class="forum-nav-browse-title"><i class="icon icon-star"></i>${_("Posts I'm Following")}</a>
</li>
${render_dropdown(category_map)}
</ul>
......
<%! from django.utils.translation import ugettext as _ %>
<script type="text/template" id="thread-list-template">
<div class="browse-search">
<div class="home">
<a href="#" class="home-icon">
<i class="icon icon-home"></i>
<span class="sr">${_("Discussion Home")}</span>
<div class="forum-nav-header">
<a href="#" class="forum-nav-browse" aria-haspopup="true">
## There is no whitespace between these because the front-end JS code
## needs to precisely compute the available width for forum-nav-
## browse-current in order to do truncation of topic names.
<i class="icon icon-reorder"></i><span class="sr">${_("Discussion topics; current selection is: ")}</span><span class="forum-nav-browse-current">${_("All Discussions")}</span><span class="forum-nav-browse-drop-arrow">▾</span>
</a>
<form class="forum-nav-search">
<div class="forum-nav-search-ff-position-fix">
<label>
<span class="sr">${_("Search")}</span>
<input class="forum-nav-search-input" type="text" placeholder="${_("Search all posts")}">
<i class="icon icon-search"></i>
</label>
</div>
<div class="browse is-open">
<a href="#" class="browse-topic-drop-icon">
<i class="icon icon-reorder"></i>
<span class="sr">${_("Discussion Topics")}</span>
</a>
<a href="#" class="browse-topic-drop-btn" aria-haspopup="true" aria-owns="browse-topic-drop-menu">
<span class="sr">${_("Discussion topics; current selection is: ")}</span>
<span class="current-board">${_("Show All Discussions")}</span>
<span class="drop-arrow" aria-hidden="true"></span>
</a>
</div>
<%include file="_filter_dropdown.html" />
<div class="search">
<form class="post-search">
<label class="sr" for="search-discussions">${_("Search")}</label>
<input type="text" id="search-discussions" placeholder="${_("Search all discussions")}" class="post-search-field">
</form>
</div>
</div>
<div class="sort-bar">
<span class="sort-label" id="sort-label">${_("Sort by:")}</span>
<ul role="radiogroup" aria-labelledby="sort-label">
<li><a href="#" role="radio" aria-checked="false" data-sort="date">${_("date")}</a></li>
<li><a href="#" role="radio" aria-checked="false" data-sort="votes">${_("votes")}</a></li>
<li><a href="#" role="radio" aria-checked="false" data-sort="comments">${_("comments")}</a></li>
</ul>
<%include file="_filter_dropdown.html" />
<div class="forum-nav-thread-list-wrapper">
<div class="forum-nav-refine-bar">
%if is_course_cohorted and is_moderator:
<span class="group-filter-label cohort">${_("Show:")}</span>
<select class="group-filter-select cohort-options cohort">
<option value="all">${_("View All")}</option>
<span class="forum-nav-filter-cohort">
<select class="forum-nav-filter-cohort-control">
<option value="all">${_("View all cohorts")}</option>
%for c in cohorts:
<option value="${c['id']}">${_("View as {name}").format(name=c['name'])}</option>
<option value="${c['id']}">${_("View as {cohort_name}").format(cohort_name=c['name'])}</option>
%endfor
</select>
</span>
%endif
<span class="forum-nav-sort">
<select class="forum-nav-sort-control">
## Translators: This is a menu option for sorting forum threads
<option value="date">${_("by recent activity")}</option>
## Translators: This is a menu option for sorting forum threads
<option value="comments">${_("by most activity")}</option>
## Translators: This is a menu option for sorting forum threads
<option value="votes">${_("by most votes")}</option>
</select>
</span>
</div>
<div class="search-alerts"></div>
<div class="post-list-wrapper">
<ul class="post-list">
</ul>
<ul class="forum-nav-thread-list"></ul>
</div>
</script>
......@@ -205,16 +205,67 @@
</script>
<script aria-hidden="true" type="text/template" id="thread-list-item-template">
<a href="${'<%- id %>'}" data-id="${'<%- id %>'}">
<span class="title">${"<%- title %>"}</span>
<li data-id="${'<%- id %>'}" class="forum-nav-thread${'<% if (typeof(read) != "undefined" && !read) { %> is-unread<% } %>'}">
<a href="#" class="forum-nav-thread-link">
<div class="forum-nav-thread-wrapper-1">
<span class="forum-nav-thread-title">${"<%- title %>"}</span>
<%
js_block = u"""
var labels = "";
if (pinned) {{
labels += '<li class="forum-nav-thread-label-pinned"><i class="icon icon-pushpin"></i>{pinned_text}</li> ';
}}
if (typeof(subscribed) != "undefined" && subscribed) {{
labels += '<li class="forum-nav-thread-label-following"><i class="icon icon-star"></i>{following_text}</li> ';
}}
if (staff_authored) {{
labels += '<li class="forum-nav-thread-label-staff"><i class="icon icon-user"></i>{staff_text}</li> ';
}}
if (community_ta_authored) {{
labels += '<li class="forum-nav-thread-label-community-ta"><i class="icon icon-user"></i>{community_ta_text}</li> ';
}}
if (labels != "") {{
print('<ul class="forum-nav-thread-labels">' + labels + '</ul>');
}}
""".format(
## Translators: This is a label for a forum thread that has been pinned
pinned_text=escapejs(_("Pinned")),
## Translators: This is a label for a forum thread that the user is subscribed to
following_text=escapejs(_("Following")),
## Translators: This is a label for a forum thread that was authored by a member of the course staff
staff_text=escapejs(_("By: Staff")),
## Translators: This is a label for a forum thread that was authored by a community TA
community_ta_text=escapejs(_("By: Community TA"))
)
%>
${"<%"}${js_block}${"%>"}
</div><div class="forum-nav-thread-wrapper-2">
${"<% if (endorsed) { %>"}
## Translators: This is a label for a forum thread with a response that was endorsed by the course staff
<span class="forum-nav-thread-endorsed"><i class="icon icon-ok"></i><span class="sr">${_("Endorsed response")}</span></span>
${"<% } %>"}
<%
js_block = u"""
interpolate(
'{}',
{{'span_sr_open': '<span class=\"sr\">', 'span_close': '</span>', 'votes_up_count': votes['up_count']}},
true
)
""".format(
## Translators: 'votes_up_count' is a numerical placeholder for a specific discussion thread; 'span_*' placeholders refer to HTML markup. Please translate the word 'votes'.
escapejs( _('%(votes_up_count)s%(span_sr_open)s votes %(span_close)s'))
)
%>
<span class="forum-nav-thread-votes-count">+${'<%='}${js_block}${'%>'}</span>
<%
js_block = u"""
var fmt;
// Counts in data do not include the post itself, but the UI should
var data = {{
'span_sr_open': '<span class=\"sr\">',
'span_close': '</span>',
'unread_comments_count': unread_comments_count,
'comments_count': comments_count
'unread_comments_count': unread_comments_count + (read ? 0 : 1),
'comments_count': comments_count + 1
}};
if (unread_comments_count > 0) {{
fmt = '{markup_with_unread}';
......@@ -229,24 +280,14 @@
markup_none_unread=escapejs(_('%(comments_count)s %(span_sr_open)scomments %(span_close)s'))
)
%>
<span class="comments-count">
<span class="forum-nav-thread-comments-count ${'<% if (unread_comments_count > 0) { %>is-unread<% } %>'}">
${'<%'}${js_block}${'%>'}
</span>
<%
js_block = u"""
interpolate(
'{}',
{{'span_sr_open': '<span class=\"sr\">', 'span_close': '</span>', 'votes_up_count': votes['up_count']}},
true
)
""".format(
## Translators: 'votes_up_count' is a numerical placeholder for a specific discussion thread; 'span_*' placeholders refer to HTML markup. Please translate the word 'votes'.
escapejs( _('%(votes_up_count)s%(span_sr_open)s votes %(span_close)s'))
)
%>
<span class="votes-count">+${'<%='}${js_block}${'%>'}</span>
</div>
</a>
</li>
</script>
<script aria-hidden="true" type="text/template" id="discussion-home">
<div class="discussion-article blank-slate">
<section class="home-header">
......
......@@ -37,7 +37,7 @@
data-user-cohort-id="${user_cohort}"
data-course-settings="${course_settings}">
<div class="discussion-body">
<div class="sidebar"></div>
<div class="sidebar forum-nav"></div>
<div class="discussion-column">
</div>
</div>
......
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