Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
be04740e
Commit
be04740e
authored
Jul 02, 2014
by
Greg Price
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4291 from edx/forum-sidebar-improvements
Forum sidebar improvements
parents
220a028b
6d87443a
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1119 additions
and
936 deletions
+1119
-936
common/static/coffee/spec/discussion/content_spec.coffee
+1
-4
common/static/coffee/spec/discussion/discussion_spec_helper.coffee
+6
-0
common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee
+1
-2
common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee
+351
-63
common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee
+1
-2
common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee
+1
-1
common/static/coffee/spec/discussion/view/response_comment_show_view_spec.coffee
+1
-0
common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee
+1
-3
common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee
+1
-1
common/static/coffee/src/discussion/content.coffee
+4
-1
common/static/coffee/src/discussion/discussion.coffee
+1
-1
common/static/coffee/src/discussion/main.coffee
+2
-0
common/static/coffee/src/discussion/utils.coffee
+6
-2
common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
+161
-192
common/test/acceptance/pages/lms/discussion.py
+6
-10
common/test/acceptance/tests/test_discussion.py
+4
-4
lms/static/images/comment-icon-bottoms.png
+0
-0
lms/static/sass/application-extend2.scss.mako
+6
-2
lms/static/sass/discussion/_discussion.scss
+3
-560
lms/static/sass/discussion/elements/_navigation.scss
+279
-0
lms/static/sass/discussion/utilities/_developer.scss
+0
-0
lms/static/sass/discussion/utilities/_shame.scss
+151
-0
lms/static/sass/discussion/utilities/_variables.scss
+5
-0
lms/templates/discussion/_filter_dropdown.html
+25
-23
lms/templates/discussion/_thread_list_template.html
+42
-46
lms/templates/discussion/_underscore_templates.html
+59
-18
lms/templates/discussion/index.html
+1
-1
No files found.
common/static/coffee/spec/discussion/content_spec.coffee
View file @
be04740e
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
->
...
...
common/static/coffee/spec/discussion/discussion_spec_helper.coffee
0 → 100644
View file @
be04740e
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
:
[]})
common/static/coffee/spec/discussion/view/discussion_content_view_spec.coffee
View file @
be04740e
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
...
...
common/static/coffee/spec/discussion/view/discussion_thread_list_view_spec.coffee
View file @
be04740e
describe
"DiscussionThreadListView"
,
->
beforeEach
->
DiscussionSpecHelper
.
setUpGlobals
()
setFixtures
"""
<script type="text/template" id="thread-list-item-template">
<a href="<%- id %>" data-id="<%- id %>">
<span class="title"><%- title %></span>
<span class="comments-count">
<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>
<%
var fmt;
var data = {
'span_sr_open': '<span class="sr">',
'span_close': '</span>',
'unread_comments_count': unread_comments_count,
'comments_count': comments_count
};
if (unread_comments_count > 0) {
fmt = '%(comments_count)s %(span_sr_open)scomments (%(unread_comments_count)s unread comments)%(span_close)s';
} else {
fmt = '%(comments_count)s %(span_sr_open)scomments %(span_close)s';
}
print(interpolate(fmt, data, true));
%>
</span>
<span class="votes-count">+<%=
interpolate(
'%(votes_up_count)s%(span_sr_open)s votes %(span_close)s',
{'span_sr_open': '<span class="sr">', 'span_close': '</span>', 'votes_up_count': votes['up_count']},
true
)
%></span>
</a>
var labels = "";
if (pinned) {
labels += '<li class="forum-nav-thread-label-pinned"><i class="icon icon-pushpin"></i>Pinned</li> ';
}
if (typeof(subscribed) != "undefined" && subscribed) {
labels += '<li class="forum-nav-thread-label-following"><i class="icon icon-star"></i>Following</li> ';
}
if (staff_authored) {
labels += '<li class="forum-nav-thread-label-staff"><i class="icon icon-user"></i>By: Staff</li> ';
}
if (community_ta_authored) {
labels += '<li class="forum-nav-thread-label-community-ta"><i class="icon icon-user"></i>By: Community TA</li> ';
}
if (labels != "") {
print('<ul class="forum-nav-thread-labels">' + labels + '</ul>');
}
%>
</div><div class="forum-nav-thread-wrapper-2">
<% if (endorsed) { %>
<span class="forum-nav-thread-endorsed"><i class="icon icon-ok"></i><span class="sr">Endorsed response</span></span>
<% } %>
<span class="forum-nav-thread-votes-count">+<%=
interpolate(
'%(votes_up_count)s%(span_sr_open)s votes %(span_close)s',
{'span_sr_open': '<span class="sr">', 'span_close': '</span>', 'votes_up_count': votes['up_count']},
true
)
%></span>
<span class="forum-nav-thread-comments-count <% if (unread_comments_count > 0) { %>is-unread<% } %>">
<%
var fmt;
var data = {
'span_sr_open': '<span class="sr">',
'span_close': '</span>',
'unread_comments_count': unread_comments_count,
'comments_count': comments_count
};
if (unread_comments_count > 0) {
fmt = '%(comments_count)s %(span_sr_open)scomments (%(unread_comments_count)s unread comments)%(span_close)s';
} else {
fmt = '%(comments_count)s %(span_sr_open)scomments %(span_close)s';
}
print(interpolate(fmt, data, true));
%>
</span>
</div>
</a>
</li>
</script>
<script type="text/template" id="thread-list-template">
<div class="browse-search">
<div class="home"></div>
<div class="browse is-open"></div>
<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 class="forum-nav-header">
<a href="#" class="forum-nav-browse" aria-haspopup="true">
<i class="icon icon-reorder"></i>
<span class="sr">Discussion topics; current selection is: </span>
<span class="forum-nav-browse-current">All Discussions</span>
▾
</a>
<form class="forum-nav-search">
<label>
<span class="sr">Search</span>
<input class="forum-nav-search-input" type="text" placeholder="Search all posts">
</label>
</form>
</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>
<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">
</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>
<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>
<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>
<li class="forum-nav-browse-menu-item">
<a href="#" class="forum-nav-browse-title">Parent</a>
<ul class="forum-nav-browse-submenu">
<li class="forum-nav-browse-menu-item">
<a href="#" class="forum-nav-browse-title">Target</a>
<ul class="forum-nav-browse-submenu">
<li
class="forum-nav-browse-menu-item"
data-discussion-id='{"sort_key": null, "id": "child"}'
data-cohorted="false"
>
<a href="#" class="forum-nav-browse-title">Child</a>
</li>
</ul>
<li
class="forum-nav-browse-menu-item"
data-discussion-id='{"sort_key": null, "id": "sibling"}'
data-cohorted="false"
>
<a href="#" class="forum-nav-browse-title">Sibling</a>
</li>
</ul>
</li>
<li
class="forum-nav-browse-menu-item"
data-discussion-id='{"sort_key": null, "id": "other"}'
data-cohorted="false"
>
<a href="#" class="forum-nav-browse-title">Other Category</a>
</li>
</ul>
</div>
<div class="search-alerts"></div>
<div class="post-list-wrapper">
<ul class="post-list"></ul>
<div class="forum-nav-thread-list-wrapper">
<div class="forum-nav-refine-bar">
<span class="forum-nav-sort">
<select class="forum-nav-sort-control">
<option value="date">by recent activity</option>
<option value="comments">by most activity</option>
<option value="votes">by most votes</option>
</select>
</span>
</div>
</div>
<div class="search-alerts"></div>
<ul class="forum-nav-thread-list"></ul>
</script>
<script aria-hidden="true" type="text/template" id="search-alert-template">
<div class="search-alert" id="search-alert-<%- cid %>">
...
...
@@ -71,12 +150,28 @@ describe "DiscussionThreadListView", ->
<div class="sidebar"></div>
"""
@
threads
=
[
{
id
:
"1"
,
title
:
"Thread1"
,
body
:
"dummy body"
,
votes
:
{
up_count
:
'20'
},
unread_comments_count
:
0
,
comments_count
:
1
,
created_at
:
'2013-04-03T20:08:39Z'
,},
{
id
:
"2"
,
title
:
"Thread2"
,
body
:
"dummy body"
,
votes
:
{
up_count
:
'42'
},
unread_comments_count
:
0
,
comments_count
:
2
,
created_at
:
'2013-04-03T20:07:39Z'
,},
{
id
:
"3"
,
title
:
"Thread3"
,
body
:
"dummy body"
,
votes
:
{
up_count
:
'12'
},
unread_comments_count
:
0
,
comments_count
:
3
,
created_at
:
'2013-04-03T20:06:39Z'
,},
makeThreadWithProps
({
id
:
"1"
,
title
:
"Thread1"
,
votes
:
{
up_count
:
'20'
},
comments_count
:
1
,
created_at
:
'2013-04-03T20:08:39Z'
,
}),
makeThreadWithProps
({
id
:
"2"
,
title
:
"Thread2"
,
votes
:
{
up_count
:
'42'
},
comments_count
:
2
,
created_at
:
'2013-04-03T20:07:39Z'
,
}),
makeThreadWithProps
({
id
:
"3"
,
title
:
"Thread3"
,
votes
:
{
up_count
:
'12'
},
comments_count
:
3
,
created_at
:
'2013-04-03T20:06:39Z'
,
}),
]
window
.
$
$course_id
=
"TestOrg/TestCourse/TestRun"
window
.
user
=
new
DiscussionUser
({
id
:
"567"
,
upvoted_ids
:
[]})
spyOn
(
$
,
"ajax"
)
...
...
@@ -84,6 +179,21 @@ describe "DiscussionThreadListView", ->
@
view
=
new
DiscussionThreadListView
({
collection
:
@
discussion
,
el
:
$
(
".sidebar"
)})
@
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
=
(
discussion
)
->
return
new
DiscussionThreadListView
(
el
:
$
(
".sidebar"
),
...
...
@@ -91,18 +201,20 @@ describe "DiscussionThreadListView", ->
)
checkThreadsOrdering
=
(
view
,
sort_order
,
type
)
->
expect
(
view
.
$el
.
find
(
".
post-list .list-item
"
).
children
().
length
).
toEqual
(
3
)
expect
(
view
.
$el
.
find
(
".
post-list .list-item:nth-child(1) .
title"
).
text
()).
toEqual
(
sort_order
[
0
])
expect
(
view
.
$el
.
find
(
".
post-list .list-item:nth-child(2) .
title"
).
text
()).
toEqual
(
sort_order
[
1
])
expect
(
view
.
$el
.
find
(
".
post-list .list-item:nth-child(3) .
title"
).
text
()).
toEqual
(
sort_order
[
2
])
expect
(
view
.
$el
.
find
(
".
sort-bar a.active"
).
text
()).
toEqual
(
type
)
expect
(
view
.
$el
.
find
(
".
forum-nav-thread
"
).
children
().
length
).
toEqual
(
3
)
expect
(
view
.
$el
.
find
(
".
forum-nav-thread:nth-child(1) .forum-nav-thread-
title"
).
text
()).
toEqual
(
sort_order
[
0
])
expect
(
view
.
$el
.
find
(
".
forum-nav-thread:nth-child(2) .forum-nav-thread-
title"
).
text
()).
toEqual
(
sort_order
[
1
])
expect
(
view
.
$el
.
find
(
".
forum-nav-thread:nth-child(3) .forum-nav-thread-
title"
).
text
()).
toEqual
(
sort_order
[
2
])
expect
(
view
.
$el
.
find
(
".
forum-nav-sort-control"
).
val
()).
toEqual
(
type
)
describe
"thread rendering should be correct"
,
->
checkRender
=
(
threads
,
type
,
sort_order
)
->
discussion
=
new
Discussion
(
threads
,
{
pages
:
1
,
sort
:
type
})
discussion
=
new
Discussion
(
_
.
map
(
threads
,
(
thread
)
->
new
Thread
(
thread
))
,
{
pages
:
1
,
sort
:
type
})
view
=
makeView
(
discussion
)
view
.
render
()
checkThreadsOrdering
(
view
,
sort_order
,
type
)
expect
(
view
.
$el
.
find
(
".forum-nav-thread-comments-count:visible"
).
length
).
toEqual
(
if
type
==
"votes"
then
0
else
3
)
expect
(
view
.
$el
.
find
(
".forum-nav-thread-votes-count:visible"
).
length
).
toEqual
(
if
type
==
"votes"
then
3
else
0
)
it
"with sort preference date"
,
->
checkRender
(
@
threads
,
"date"
,
[
"Thread1"
,
"Thread2"
,
"Thread3"
])
...
...
@@ -113,12 +225,13 @@ describe "DiscussionThreadListView", ->
it
"with sort preference comments"
,
->
checkRender
(
@
threads
,
"comments"
,
[
"Thread3"
,
"Thread2"
,
"Thread1"
])
describe
"Sort c
lick
should be correct"
,
->
describe
"Sort c
hange
should be correct"
,
->
changeSorting
=
(
threads
,
selected_type
,
new_type
,
sort_order
)
->
discussion
=
new
Discussion
(
threads
,
{
pages
:
1
,
sort
:
selected_type
})
discussion
=
new
Discussion
(
_
.
map
(
threads
,
(
thread
)
->
new
Thread
(
thread
))
,
{
pages
:
1
,
sort
:
selected_type
})
view
=
makeView
(
discussion
)
view
.
render
()
expect
(
view
.
$el
.
find
(
".sort-bar a.active"
).
text
()).
toEqual
(
selected_type
)
sortControl
=
view
.
$el
.
find
(
".forum-nav-sort-control"
)
expect
(
sortControl
.
val
()).
toEqual
(
selected_type
)
sorted_threads
=
[]
if
new_type
==
'date'
sorted_threads
=
[
threads
[
0
],
threads
[
1
],
threads
[
2
]]
...
...
@@ -132,9 +245,8 @@ describe "DiscussionThreadListView", ->
)
{
always
:
->
}
)
view
.
$el
.
find
(
".sort-bar a[data-sort='"
+
new_type
+
"']"
).
click
()
sortControl
.
val
(
new_type
).
change
()
expect
(
$
.
ajax
).
toHaveBeenCalled
()
expect
(
view
.
sortBy
).
toEqual
(
new_type
)
checkThreadsOrdering
(
view
,
sort_order
,
new_type
)
it
"with sort preference date"
,
->
...
...
@@ -271,3 +383,179 @@ describe "DiscussionThreadListView", ->
@
view
.
searchForUser
(
"dummy"
)
expect
(
$
.
ajax
).
toHaveBeenCalled
()
expect
(
@
view
.
addSearchAlert
).
not
.
toHaveBeenCalled
()
describe
"endorsed renders correctly"
,
->
it
"when absent"
,
->
renderSingleThreadWithProps
({})
expect
(
$
(
".forum-nav-thread-endorsed"
).
length
).
toEqual
(
0
)
it
"when present"
,
->
renderSingleThreadWithProps
({
endorsed
:
true
})
expect
(
$
(
".forum-nav-thread-endorsed"
).
length
).
toEqual
(
1
)
describe
"post labels render correctly"
,
->
beforeEach
->
@
moderatorId
=
"42"
@
administratorId
=
"43"
@
communityTaId
=
"44"
DiscussionUtil
.
loadRoles
({
"Moderator"
:
[
parseInt
(
@
moderatorId
)],
"Administrator"
:
[
parseInt
(
@
administratorId
)],
"Community TA"
:
[
parseInt
(
@
communityTaId
)],
})
it
"for pinned"
,
->
renderSingleThreadWithProps
({
pinned
:
true
})
expect
(
$
(
".forum-nav-thread-label-pinned"
).
length
).
toEqual
(
1
)
it
"for following"
,
->
renderSingleThreadWithProps
({
subscribed
:
true
})
expect
(
$
(
".forum-nav-thread-label-following"
).
length
).
toEqual
(
1
)
it
"for moderator"
,
->
renderSingleThreadWithProps
({
user_id
:
@
moderatorId
})
expect
(
$
(
".forum-nav-thread-label-staff"
).
length
).
toEqual
(
1
)
it
"for administrator"
,
->
renderSingleThreadWithProps
({
user_id
:
@
administratorId
})
expect
(
$
(
".forum-nav-thread-label-staff"
).
length
).
toEqual
(
1
)
it
"for community TA"
,
->
renderSingleThreadWithProps
({
user_id
:
@
communityTaId
})
expect
(
$
(
".forum-nav-thread-label-community-ta"
).
length
).
toEqual
(
1
)
it
"when none should be present"
,
->
renderSingleThreadWithProps
({})
expect
(
$
(
".forum-nav-thread-labels"
).
length
).
toEqual
(
0
)
describe
"browse menu"
,
->
setupAjax
=
(
callback
)
->
$
.
ajax
.
andCallFake
(
(
params
)
=>
if
callback
callback
(
params
)
params
.
success
({
discussion_data
:
[],
page
:
1
,
num_pages
:
1
})
{
always
:
->
}
)
afterEach
->
# Remove handler added to make browse menu disappear
$
(
"body"
).
unbind
(
"click"
)
expectBrowseMenuVisible
=
(
isVisible
)
->
expect
(
$
(
".forum-nav-browse-menu:visible"
).
length
).
toEqual
(
if
isVisible
then
1
else
0
)
expect
(
$
(
".forum-nav-thread-list-wrapper:visible"
).
length
).
toEqual
(
if
isVisible
then
0
else
1
)
it
"should not be visible by default"
,
->
expectBrowseMenuVisible
(
false
)
it
"should show when header button is clicked"
,
->
$
(
".forum-nav-browse"
).
click
()
expectBrowseMenuVisible
(
true
)
describe
"when shown"
,
->
beforeEach
->
$
(
".forum-nav-browse"
).
click
()
it
"should hide when header button is clicked"
,
->
$
(
".forum-nav-browse"
).
click
()
expectBrowseMenuVisible
(
false
)
it
"should hide when a click outside the menu occurs"
,
->
$
(
".forum-nav-search-input"
).
click
()
expectBrowseMenuVisible
(
false
)
it
"should hide when a search is executed"
,
->
setupAjax
()
$
(
".forum-nav-search-input"
).
trigger
(
$
.
Event
(
"keydown"
,
{
which
:
13
}))
expectBrowseMenuVisible
(
false
)
it
"should hide when a category is clicked"
,
->
$
(
".forum-nav-browse-title"
)[
0
].
click
()
expectBrowseMenuVisible
(
false
)
it
"should still be shown when filter input is clicked"
,
->
$
(
".forum-nav-browse-filter-input"
).
click
()
expectBrowseMenuVisible
(
true
)
describe
"filtering"
,
->
checkFilter
=
(
filterText
,
expectedItems
)
->
$
(
".forum-nav-browse-filter-input"
).
val
(
filterText
).
keyup
()
visibleItems
=
$
(
".forum-nav-browse-title:visible"
).
map
(
(
i
,
elem
)
->
$
(
elem
).
text
()
).
get
()
expect
(
visibleItems
).
toEqual
(
expectedItems
)
it
"should be case-insensitive"
,
->
checkFilter
(
"flagged"
,
[
"Flagged Discussions"
])
it
"should match partial words"
,
->
checkFilter
(
"ateg"
,
[
"Other Category"
])
it
"should show ancestors and descendants of matches"
,
->
checkFilter
(
"Target"
,
[
"Parent"
,
"Target"
,
"Child"
])
it
"should handle multiple words regardless of order"
,
->
checkFilter
(
"Following Posts"
,
[
"Posts I'm Following"
])
it
"should handle multiple words in different depths"
,
->
checkFilter
(
"Parent Child"
,
[
"Parent"
,
"Target"
,
"Child"
])
describe
"selecting an item"
,
->
it
"should clear the search box"
,
->
setupAjax
()
$
(
".forum-nav-search-input"
).
val
(
"foobar"
)
$
(
".forum-nav-browse-menu-following .forum-nav-browse-title"
).
click
()
expect
(
$
(
".forum-nav-search-input"
).
val
()).
toEqual
(
""
)
it
"should change the button text"
,
->
setupAjax
()
$
(
".forum-nav-browse-menu-following .forum-nav-browse-title"
).
click
()
expect
(
$
(
".forum-nav-browse-current"
).
text
()).
toEqual
(
"Posts I'm Following"
)
testSelectionRequest
=
(
callback
,
itemText
)
->
setupAjax
(
callback
)
$
(
".forum-nav-browse-title:contains(
#{
itemText
}
)"
).
click
()
it
"should get all discussions"
,
->
testSelectionRequest
(
(
params
)
->
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
"threads"
)),
"All"
)
it
"should get flagged threads"
,
->
testSelectionRequest
(
(
params
)
->
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
"search"
))
expect
(
params
.
data
.
flagged
).
toEqual
(
true
)
,
"Flagged"
)
it
"should get followed threads"
,
->
testSelectionRequest
(
(
params
)
->
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
"followed_threads"
,
window
.
user
.
id
)
)
,
"Following"
)
it
"should get threads for the selected leaf"
,
->
testSelectionRequest
(
(
params
)
->
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
"search"
))
expect
(
params
.
data
.
commentable_ids
).
toEqual
(
"child"
)
,
"Child"
)
it
"should get threads for children of the selected intermediate node"
,
->
testSelectionRequest
(
(
params
)
->
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
"search"
))
expect
(
params
.
data
.
commentable_ids
).
toEqual
(
"child,sibling"
)
,
"Parent"
)
common/static/coffee/spec/discussion/view/discussion_thread_show_view_spec.coffee
View file @
be04740e
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
,
...
...
common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee
View file @
be04740e
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
)
->
...
...
common/static/coffee/spec/discussion/view/response_comment_show_view_spec.coffee
View file @
be04740e
describe
'ResponseCommentShowView'
,
->
beforeEach
->
DiscussionSpecHelper
.
setUpGlobals
()
# set up the container for the response to go in
setFixtures
"""
<ol class="responses"></ol>
...
...
common/static/coffee/spec/discussion/view/response_comment_view_spec.coffee
View file @
be04740e
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
,
...
...
common/static/coffee/spec/discussion/view/thread_response_show_view_spec.coffee
View file @
be04740e
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
)
...
...
common/static/coffee/src/discussion/content.coffee
View file @
be04740e
...
...
@@ -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
:
->
...
...
common/static/coffee/src/discussion/discussion.coffee
View file @
be04740e
...
...
@@ -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
)
->
...
...
common/static/coffee/src/discussion/main.coffee
View file @
be04740e
...
...
@@ -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"
)
...
...
common/static/coffee/src/discussion/utils.coffee
View file @
be04740e
...
...
@@ -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
()
...
...
common/static/coffee/src/discussion/views/discussion_thread_list_view.coffee
View file @
be04740e
if
Backbone
?
class
@
DiscussionThreadListView
extends
Backbone
.
View
events
:
"click .search"
:
"showSearch"
"click .home"
:
"goHome"
"click .browse"
:
"toggleTopicDrop"
"keydown .post-search-field"
:
"performSearch"
"focus .post-search-field"
:
"showSearch"
"click .sort-bar a"
:
"sortThreads"
"click .browse-topic-drop-menu"
:
"filterTopic"
"click .browse-topic-drop-search-input"
:
"ignoreClick"
"click .post-list .list-item a"
:
"threadSelected"
"click .post-list .more-pages a"
:
"loadMorePages"
"change .cohort-options"
:
"chooseCohort"
'keyup .browse-topic-drop-search-input'
:
DiscussionFilter
.
filterDrop
"click .forum-nav-browse"
:
"toggleBrowseMenu"
"keypress .forum-nav-browse-filter-input"
:
(
event
)
=>
DiscussionUtil
.
ignoreEnterKey
(
event
)
"keyup .forum-nav-browse-filter-input"
:
"filterTopics"
"click .forum-nav-browse-menu-wrapper"
:
"ignoreClick"
"click .forum-nav-browse-title"
:
"selectTopic"
"keydown .forum-nav-search-input"
:
"performSearch"
"change .forum-nav-sort-control"
:
"sortThreads"
"click .forum-nav-thread-link"
:
"threadSelected"
"click .forum-nav-load-more-link"
:
"loadMorePages"
"change .forum-nav-filter-cohort-control"
:
"chooseCohort"
initialize
:
->
@
displayedCollection
=
new
Discussion
(
@
collection
.
models
,
pages
:
@
collection
.
pages
)
@
collection
.
on
"change"
,
@
reloadDisplayedCollection
@
sortBy
=
"date"
@
discussionIds
=
""
@
collection
.
on
"reset"
,
(
discussion
)
=>
board
=
$
(
".current-board"
).
html
()
...
...
@@ -30,7 +27,6 @@ if Backbone?
# @filterTopic($.Event("filter", {'target': target[0]}))
@
collection
.
on
"add"
,
@
addAndSelectThread
@
sidebar_padding
=
10
@
sidebar_header_height
=
87
@
boardName
@
template
=
_
.
template
(
$
(
"#thread-list-template"
).
html
())
@
current_search
=
""
...
...
@@ -68,9 +64,10 @@ if Backbone?
@
clearSearchAlerts
()
thread_id
=
thread
.
get
(
'id'
)
content
=
@
renderThread
(
thread
)
current_el
=
@
$
(
"
a
[data-id=
#{
thread_id
}
]"
)
active
=
current_el
.
has
Class
(
"active"
)
current_el
=
@
$
(
"
.forum-nav-thread
[data-id=
#{
thread_id
}
]"
)
active
=
current_el
.
has
(
".forum-nav-thread-link.is-active"
).
length
!=
0
current_el
.
replaceWith
(
content
)
@
showMetadataAccordingToSort
()
if
active
@
setActiveThread
(
thread_id
)
...
...
@@ -78,8 +75,8 @@ if Backbone?
#TODO fix this entire chain of events
addAndSelectThread
:
(
thread
)
=>
commentable_id
=
thread
.
get
(
"commentable_id"
)
commentable
=
@
$
(
".board-name[data-discussion_id]"
).
filter
(
->
$
(
this
).
data
(
"discussion_
id"
).
id
==
commentable_id
)
@
set
TopicHack
(
commentable
)
menuItem
=
@
$
(
".forum-nav-browse-menu-item[data-discussion-id]"
).
filter
(
->
$
(
this
).
data
(
"discussion-
id"
).
id
==
commentable_id
)
@
set
CurrentTopicDisplay
(
@
getPathText
(
menuItem
)
)
@
retrieveDiscussion
commentable_id
,
=>
@
trigger
"thread:created"
,
thread
.
get
(
'id'
)
...
...
@@ -88,7 +85,7 @@ if Backbone?
scrollTop
=
$
(
window
).
scrollTop
();
windowHeight
=
$
(
window
).
height
();
discussionBody
=
$
(
".discussion-
article
"
)
discussionBody
=
$
(
".discussion-
column
"
)
discussionsBodyTop
=
if
discussionBody
[
0
]
then
discussionBody
.
offset
().
top
discussionsBodyBottom
=
discussionsBodyTop
+
discussionBody
.
outerHeight
()
...
...
@@ -98,9 +95,6 @@ if Backbone?
else
sidebar
.
css
(
'top'
,
'0'
);
sidebarWidth
=
.
31
*
$
(
".discussion-body"
).
width
();
sidebar
.
css
(
'width'
,
sidebarWidth
+
'px'
);
sidebarHeight
=
windowHeight
-
Math
.
max
(
discussionsBodyTop
-
scrollTop
,
@
sidebar_padding
)
topOffset
=
scrollTop
+
windowHeight
...
...
@@ -111,19 +105,22 @@ if Backbone?
sidebarHeight
=
Math
.
min
(
sidebarHeight
+
1
,
discussionBody
.
outerHeight
())
sidebar
.
css
'height'
,
sidebarHeight
postListWrapper
=
@
$
(
'.post-list-wrapper'
)
postListWrapper
.
css
(
'height'
,
(
sidebarHeight
-
@
sidebar_header_height
-
4
)
+
'px'
)
headerHeight
=
@
$
(
".forum-nav-header"
).
outerHeight
()
refineBarHeight
=
@
$
(
".forum-nav-refine-bar"
).
outerHeight
()
@
$
(
'.forum-nav-thread-list'
).
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
refineBarHeight
-
2
)
+
'px'
)
@
$
(
'.forum-nav-browse-menu-wrapper'
).
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
2
)
+
'px'
)
# Because we want the behavior that when the body is clicked the menu is
# closed, we need to
ignore clicks in the search field and stop propagation.
#
Without this, clicking the search field would also close the menu
.
# closed, we need to
stop propagation of a click in any part of the menu
#
that is not a link
.
ignoreClick
:
(
event
)
->
event
.
stopPropagation
()
render
:
->
@
timer
=
0
@
$el
.
html
(
@
template
())
@
$
(
".forum-nav-sort-control"
).
val
(
@
collection
.
sort_preference
)
$
(
window
).
bind
"load"
,
@
updateSidebar
$
(
window
).
bind
"scroll"
,
@
updateSidebar
...
...
@@ -132,36 +129,49 @@ if Backbone?
@
displayedCollection
.
on
"reset"
,
@
renderThreads
@
displayedCollection
.
on
"thread:remove"
,
@
renderThreads
@
renderThreads
()
sort_element
=
@
$
(
'.sort-bar a[data-sort="'
+
this
.
collection
.
sort_preference
+
'"]'
)
sort_element
.
attr
(
'aria-checked'
,
true
)
sort_element
.
addClass
(
'active'
)
@
renderThreads
:
=>
@
$
(
".
post
-list"
).
html
(
""
)
@
$
(
".
forum-nav-thread
-list"
).
html
(
""
)
rendered
=
$
(
"<div></div>"
)
for
thread
in
@
displayedCollection
.
models
content
=
@
renderThread
(
thread
)
rendered
.
append
content
content
.
wrap
(
"<li class='list-item' data-id='
\"
#{
thread
.
get
(
'id'
)
}
\"
' />"
)
@
$
(
".post-list"
).
html
(
rendered
.
html
())
@
$
(
".forum-nav-thread-list"
).
html
(
rendered
.
html
())
@
showMetadataAccordingToSort
()
@
renderMorePages
()
@
updateSidebar
()
@
trigger
"threads:rendered"
showMetadataAccordingToSort
:
()
=>
# Ensure that threads display metadata appropriate for the current sort
voteCounts
=
@
$
(
".forum-nav-thread-votes-count"
)
commentCounts
=
@
$
(
".forum-nav-thread-comments-count"
)
voteCounts
.
hide
()
commentCounts
.
hide
()
switch
@
$
(
".forum-nav-sort-control"
).
val
()
when
"date"
,
"comments"
commentCounts
.
show
()
when
"votes"
voteCounts
.
show
()
renderMorePages
:
->
if
@
displayedCollection
.
hasMorePages
()
@
$
(
".post-list"
).
append
(
"<li class='more-pages'><a href='#'>"
+
gettext
(
"Load more"
)
+
"</a></li>"
)
@
$
(
".forum-nav-thread-list"
).
append
(
"<li class='forum-nav-load-more'><a href='#' class='forum-nav-load-more-link'>"
+
gettext
(
"Load more"
)
+
"</a></li>"
)
getLoadingContent
:
(
srText
)
->
return
'<div class="forum-nav-loading" tabindex="0"><span class="icon-spinner icon-spin"/><span class="sr" role="alert">'
+
srText
+
'</span></div>'
loadMorePages
:
(
event
)
-
>
loadMorePages
:
(
event
)
=
>
if
event
event
.
preventDefault
()
@
$
(
".more-pages"
).
html
(
'<div class="loading-animation" tabindex=0><span class="sr" role="alert">'
+
gettext
(
'Loading more threads'
)
+
'</span></div>'
)
@
$
(
".more-pages"
).
addClass
(
"loading"
)
loading
Div
=
@
$
(
".more-pages .loading-animation
"
)
DiscussionUtil
.
makeFocusTrap
(
loading
Div
)
loading
Div
.
focus
()
loadMoreElem
=
@
$
(
".forum-nav-load-more"
)
loadMoreElem
.
html
(
@
getLoadingContent
(
gettext
(
"Loading more threads"
))
)
loading
Elem
=
loadMoreElem
.
find
(
".forum-nav-loading
"
)
DiscussionUtil
.
makeFocusTrap
(
loading
Elem
)
loading
Elem
.
focus
()
options
=
{}
switch
@
mode
when
'search'
...
...
@@ -184,57 +194,40 @@ if Backbone?
if
lastThread
# Pagination; focus the first thread after what was previously the last thread
@
once
(
"threads:rendered"
,
->
$
(
".
post-list li:has(a[data-id='
#{
lastThread
}
']) + li a
"
).
focus
()
$
(
".
forum-nav-thread[data-id='
#{
lastThread
}
'] + .forum-nav-thread .forum-nav-thread-link
"
).
focus
()
)
else
# Totally refreshing the list (e.g. from clicking a sort button); focus the first thread
@
once
(
"threads:rendered"
,
->
$
(
".
post-list a
"
).
first
()
?
.
focus
()
$
(
".
forum-nav-thread-link
"
).
first
()
?
.
focus
()
)
error
=
=>
@
renderThreads
()
DiscussionUtil
.
discussionAlert
(
gettext
(
"Sorry"
),
gettext
(
"We had some trouble loading more threads. Please try again."
))
@
collection
.
retrieveAnotherPage
(
@
mode
,
options
,
{
sort_key
:
@
sortBy
},
error
)
@
collection
.
retrieveAnotherPage
(
@
mode
,
options
,
{
sort_key
:
@
$
(
".forum-nav-sort-control"
).
val
()
},
error
)
renderThread
:
(
thread
)
=>
content
=
$
(
_
.
template
(
$
(
"#thread-list-item-template"
).
html
())(
thread
.
toJSON
()))
if
thread
.
get
(
'subscribed'
)
content
.
addClass
(
"followed"
)
if
thread
.
get
(
'endorsed'
)
content
.
addClass
(
"resolved"
)
if
thread
.
get
(
'read'
)
content
.
addClass
(
"read"
)
unreadCount
=
thread
.
get
(
'unread_comments_count'
)
unreadCount
=
thread
.
get
(
'unread_comments_count'
)
+
(
if
thread
.
get
(
"read"
)
then
0
else
1
)
if
unreadCount
>
0
content
.
find
(
'.
comments-count'
).
addClass
(
"unread"
).
attr
(
content
.
find
(
'.
forum-nav-thread-comments-count'
).
attr
(
"data-tooltip"
,
interpolate
(
ngettext
(
'%(unread_count)s new comment'
,
'%(unread_count)s new comments'
,
unreadCount
),
{
unread_count
:
thread
.
get
(
'unread_comments_count'
)
},
{
unread_count
:
unreadCount
},
true
)
)
@
highlight
(
content
)
highlight
:
(
el
)
->
el
.
html
(
el
.
html
().
replace
(
/<mark>/g
,
"<mark>"
).
replace
(
/<\/mark>/g
,
"</mark>"
))
renderThreadListItem
:
(
thread
)
=>
view
=
new
ThreadListItemView
(
model
:
thread
)
view
.
on
"thread:selected"
,
@
threadSelected
view
.
on
"thread:removed"
,
@
threadRemoved
view
.
render
()
@
$
(
".post-list"
).
append
(
view
.
el
)
content
threadSelected
:
(
e
)
=>
# Use .attr('data-id') rather than .data('id') because .data does type
# coercion. Usually, this is fine, but when Mongo gives an object id with
# no letters, it casts it to a Number.
thread_id
=
$
(
e
.
target
).
closest
(
"
a
"
).
attr
(
"data-id"
)
thread_id
=
$
(
e
.
target
).
closest
(
"
.forum-nav-thread
"
).
attr
(
"data-id"
)
@
setActiveThread
(
thread_id
)
@
trigger
(
"thread:selected"
,
thread_id
)
# This triggers a callback in the DiscussionRouter which calls the line above...
false
...
...
@@ -243,21 +236,13 @@ if Backbone?
@
trigger
(
"thread:removed"
,
thread_id
)
setActiveThread
:
(
thread_id
)
->
@
$
(
".post-list a[data-id!='
#{
thread_id
}
']"
).
removeClass
(
"active"
)
@
$
(
".post-list a[data-id='
#{
thread_id
}
']"
).
addClass
(
"active"
)
showSearch
:
->
@
$
(
".browse"
).
removeClass
(
'is-dropped'
)
@
hideTopicDrop
()
@
$
(
".search"
).
addClass
(
'is-open'
)
@
$
(
".browse"
).
removeClass
(
'is-open'
)
setTimeout
(
->
@
$
(
".post-search-field"
).
focus
()),
200
unless
@
$
(
".post-search-field"
).
is
(
":focus"
)
@
$
(
".forum-nav-thread[data-id!='
#{
thread_id
}
'] .forum-nav-thread-link"
).
removeClass
(
"is-active"
)
@
$
(
".forum-nav-thread[data-id='
#{
thread_id
}
'] .forum-nav-thread-link"
).
addClass
(
"is-active"
)
goHome
:
->
@
template
=
_
.
template
(
$
(
"#discussion-home"
).
html
())
$
(
".discussion-column"
).
html
(
@
template
)
$
(
".
post-list a"
).
removeClass
(
"
active"
)
$
(
".
forum-nav-thread-list a"
).
removeClass
(
"is-
active"
)
$
(
"input.email-setting"
).
bind
"click"
,
@
updateEmailNotifications
url
=
DiscussionUtil
.
urlFor
(
"notifications_status"
,
window
.
user
.
get
(
"id"
))
DiscussionUtil
.
safeAjax
...
...
@@ -272,51 +257,64 @@ if Backbone?
@
trigger
(
"thread:removed"
)
#select all threads
toggleTopicDrop
:
(
event
)
=>
isBrowseMenuVisible
:
=>
@
$
(
".forum-nav-browse-menu-wrapper"
).
is
(
":visible"
)
showBrowseMenu
:
=>
if
not
@
isBrowseMenuVisible
()
@
$
(
".forum-nav-browse"
).
addClass
(
"is-active"
)
@
$
(
".forum-nav-browse-menu-wrapper"
).
show
()
@
$
(
".forum-nav-thread-list-wrapper"
).
hide
()
$
(
".forum-nav-browse-filter-input"
).
focus
()
$
(
"body"
).
bind
"click"
,
@
hideBrowseMenu
hideBrowseMenu
:
=>
if
@
isBrowseMenuVisible
()
@
$
(
".forum-nav-browse"
).
removeClass
(
"is-active"
)
@
$
(
".forum-nav-browse-menu-wrapper"
).
hide
()
@
$
(
".forum-nav-thread-list-wrapper"
).
show
()
$
(
"body"
).
unbind
"click"
,
@
hideBrowseMenu
toggleBrowseMenu
:
(
event
)
=>
event
.
preventDefault
()
event
.
stopPropagation
()
if
@
current_search
!=
""
@
clearSearch
()
@
$
(
".search"
).
removeClass
(
'is-open'
)
@
$
(
".browse"
).
addClass
(
'is-open'
)
@
$
(
".browse"
).
toggleClass
(
'is-dropped'
)
if
@
$
(
".browse"
).
hasClass
(
'is-dropped'
)
@
$
(
".browse-topic-drop-menu-wrapper"
).
show
()
$
(
".browse-topic-drop-search-input"
).
focus
()
$
(
"body"
).
bind
"click"
,
@
toggleTopicDrop
$
(
"body"
).
bind
"keydown"
,
@
setActiveItem
if
@
isBrowseMenuVisible
()
@
hideBrowseMenu
()
else
@
hideTopicDrop
()
hideTopicDrop
:
->
@
$
(
".browse-topic-drop-menu-wrapper"
).
hide
()
$
(
"body"
).
unbind
"click"
,
@
toggleTopicDrop
$
(
"body"
).
unbind
"keydown"
,
@
setActiveItem
# TODO get rid of this asap
setTopicHack
:
(
boardNameContainer
)
->
item
=
$
(
boardNameContainer
).
closest
(
'a'
)
boardName
=
item
.
find
(
".board-name"
).
html
()
_
.
each
item
.
parents
(
'ul'
).
not
(
'.browse-topic-drop-menu'
),
(
parent
)
->
boardName
=
$
(
parent
).
siblings
(
'a'
).
find
(
'.board-name'
).
html
()
+
' / '
+
boardName
@
$
(
".current-board"
).
html
(
@
fitName
(
boardName
))
setTopic
:
(
event
)
->
item
=
$
(
event
.
target
).
closest
(
'a'
)
boardName
=
item
.
find
(
".board-name"
).
html
()
_
.
each
item
.
parents
(
'ul'
).
not
(
'.browse-topic-drop-menu'
),
(
parent
)
->
boardName
=
$
(
parent
).
siblings
(
'a'
).
find
(
'.board-name'
).
html
()
+
' / '
+
boardName
@
$
(
".current-board"
).
html
(
@
fitName
(
boardName
))
setSelectedTopic
:
(
name
)
->
@
$
(
".current-board"
).
html
(
@
fitName
(
name
))
@
showBrowseMenu
()
# Given a menu item, get the text for it and its ancestors
# (starting from the root, separated by " / ")
getPathText
:
(
item
)
->
path
=
item
.
parents
(
".forum-nav-browse-menu-item"
).
andSelf
()
pathTitles
=
path
.
children
(
".forum-nav-browse-title"
).
map
((
i
,
elem
)
->
$
(
elem
).
text
()).
get
()
pathText
=
pathTitles
.
join
(
" / "
)
filterTopics
:
(
event
)
=>
query
=
$
(
event
.
target
).
val
()
items
=
@
$
(
".forum-nav-browse-menu-item"
)
if
query
.
length
==
0
items
.
show
()
else
# If all filter terms occur in the path to an item then that item and
# all its descendants are displayed
items
.
hide
()
items
.
each
(
i
,
item
)
=>
item
=
$
(
item
)
if
not
item
.
is
(
":visible"
)
pathText
=
@
getPathText
(
item
).
toLowerCase
()
if
query
.
split
(
" "
).
every
((
term
)
->
pathText
.
search
(
term
.
toLowerCase
())
!=
-
1
)
path
=
item
.
parents
(
".forum-nav-browse-menu-item"
).
andSelf
()
path
.
add
(
item
.
find
(
".forum-nav-browse-menu-item"
)).
show
()
setCurrentTopicDisplay
:
(
text
)
->
@
$
(
".forum-nav-browse-current"
).
text
(
@
fitName
(
text
))
getNameWidth
:
(
name
)
->
test
=
$
(
"<div>"
)
test
.
css
"font-size"
:
@
$
(
".
current-board
"
).
css
(
'font-size'
)
"font-size"
:
@
$
(
".
forum-nav-browse-current
"
).
css
(
'font-size'
)
opacity
:
0
position
:
'absolute'
left
:
-
1000
...
...
@@ -328,54 +326,57 @@ if Backbone?
return
width
fitName
:
(
name
)
->
@
maxNameWidth
=
(
@
$el
.
width
()
*
.
8
)
-
50
@
maxNameWidth
=
@
$
(
".forum-nav-browse"
).
width
()
-
parseInt
(
@
$
(
".forum-nav-browse"
).
css
(
"padding-left"
))
-
parseInt
(
@
$
(
".forum-nav-browse"
).
css
(
"padding-right"
))
-
@
$
(
".forum-nav-browse .icon"
).
outerWidth
(
true
)
-
@
$
(
".forum-nav-browse-drop-arrow"
).
outerWidth
(
true
)
width
=
@
getNameWidth
(
name
)
if
width
<
@
maxNameWidth
return
name
path
=
(
x
.
replace
/^\s+|\s+$/g
,
""
for
x
in
name
.
split
(
"/"
))
prefix
=
""
while
path
.
length
>
1
prefix
=
gettext
(
"…"
)
+
"/"
path
.
shift
()
partialName
=
gettext
(
"…"
)
+
"/"
+
path
.
join
(
"/"
)
partialName
=
prefix
+
path
.
join
(
"/"
)
if
@
getNameWidth
(
partialName
)
<
@
maxNameWidth
return
partialName
rawName
=
path
[
0
]
name
=
gettext
(
"…"
)
+
"/"
+
rawName
name
=
prefix
+
rawName
while
@
getNameWidth
(
name
)
>
@
maxNameWidth
rawName
=
rawName
[
0
...
rawName
.
length
-
1
]
name
=
gettext
(
"…"
)
+
"/"
+
rawName
+
gettext
(
"…"
)
name
=
prefix
+
rawName
+
gettext
(
"…"
)
return
name
filterTopic
:
(
event
)
->
if
@
current_search
!=
""
@
setTopic
(
event
)
@
clearSearch
@
filterTopic
,
event
selectTopic
:
(
event
)
->
event
.
preventDefault
()
@
hideBrowseMenu
()
@
clearSearch
()
item
=
$
(
event
.
target
).
closest
(
'.forum-nav-browse-menu-item'
)
@
setCurrentTopicDisplay
(
@
getPathText
(
item
))
if
item
.
hasClass
(
"forum-nav-browse-menu-all"
)
@
discussionIds
=
""
@
$
(
'.forum-nav-filter-cohort'
).
show
()
@
retrieveAllThreads
()
else
if
item
.
hasClass
(
"forum-nav-browse-menu-flagged"
)
@
discussionIds
=
""
@
$
(
'.forum-nav-filter-cohort'
).
hide
()
@
retrieveFlaggedThreads
()
else
if
item
.
hasClass
(
"forum-nav-browse-menu-following"
)
@
retrieveFollowed
()
@
$
(
'.forum-nav-filter-cohort'
).
hide
()
else
@
setTopic
(
event
)
# just sets the title for the dropdown
item
=
$
(
event
.
target
).
closest
(
'li'
)
discussionId
=
item
.
find
(
"span.board-name"
).
data
(
"discussion_id"
)
if
discussionId
==
"#all"
@
discussionIds
=
""
@
$
(
".post-search-field"
).
val
(
""
)
@
$
(
'.cohort'
).
show
()
@
retrieveAllThreads
()
else
if
discussionId
==
"#flagged"
@
discussionIds
=
""
@
$
(
".post-search-field"
).
val
(
""
)
@
$
(
'.cohort'
).
hide
()
@
retrieveFlaggedThreads
()
else
if
discussionId
==
"#following"
@
retrieveFollowed
(
event
)
@
$
(
'.cohort'
).
hide
()
else
discussionIds
=
_
.
map
item
.
find
(
".board-name[data-discussion_id]"
),
(
board
)
->
$
(
board
).
data
(
"discussion_id"
).
id
if
$
(
event
.
target
).
attr
(
'cohorted'
)
==
"True"
@
retrieveDiscussions
(
discussionIds
,
"function(){$('.cohort').show();}"
)
else
@
retrieveDiscussions
(
discussionIds
,
"function(){$('.cohort').hide();}"
)
allItems
=
item
.
find
(
".forum-nav-browse-menu-item"
).
andSelf
()
discussionIds
=
allItems
.
filter
(
"[data-discussion-id]"
).
map
(
(
i
,
elem
)
->
$
(
elem
).
data
(
"discussion-id"
).
id
).
get
()
@
retrieveDiscussions
(
discussionIds
)
@
$
(
".forum-nav-filter-cohort"
).
toggle
(
item
.
data
(
'cohorted'
)
==
true
)
chooseCohort
:
(
event
)
->
@
group_id
=
@
$
(
'.
cohort-options
:selected'
).
val
()
@
group_id
=
@
$
(
'.
forum-nav-filter-cohort-control
:selected'
).
val
()
@
collection
.
current_page
=
0
@
collection
.
reset
()
@
loadMorePages
(
event
)
...
...
@@ -416,23 +417,19 @@ if Backbone?
@
loadMorePages
(
event
)
sortThreads
:
(
event
)
->
activeSort
=
@
$
(
".sort-bar a.active"
)
activeSort
.
removeClass
(
"active"
)
activeSort
.
attr
(
"aria-checked"
,
"false"
)
newSort
=
$
(
event
.
target
)
newSort
.
addClass
(
"active"
)
newSort
.
attr
(
"aria-checked"
,
"true"
)
@
sortBy
=
newSort
.
data
(
"sort"
)
@
displayedCollection
.
setSortComparator
(
@
sortBy
)
@
displayedCollection
.
setSortComparator
(
@
$
(
".forum-nav-sort-control"
).
val
())
@
retrieveFirstPage
(
event
)
performSearch
:
(
event
)
->
if
event
.
which
==
13
event
.
preventDefault
()
text
=
@
$
(
".post-search-field"
).
val
()
@
hideBrowseMenu
()
@
setCurrentTopicDisplay
(
gettext
(
"Search Results"
))
text
=
@
$
(
".forum-nav-search-input"
).
val
()
@
searchFor
(
text
)
searchFor
:
(
text
,
callback
,
value
)
->
searchFor
:
(
text
)
->
@
clearSearchAlerts
()
@
mode
=
'search'
@
current_search
=
text
...
...
@@ -441,17 +438,16 @@ if Backbone?
# Mainly because this currently does not reset any pagination variables which could cause problems.
# This doesn't use pagination either.
DiscussionUtil
.
safeAjax
$elem
:
@
$
(
".
post-search-field
"
)
$elem
:
@
$
(
".
forum-nav-search-input
"
)
data
:
{
text
:
text
}
url
:
url
type
:
"GET"
dataType
:
'json'
$loading
:
$
loadingCallback
:
=>
@
$
(
".
post-list"
).
html
(
'<li class="loading"><div class="loading-animation"><span class="sr">'
+
gettext
(
'Loading thread list'
)
+
'</span></div></li>'
)
@
$
(
".
forum-nav-thread-list"
).
html
(
"<li class='forum-nav-load-more'>"
+
@
getLoadingContent
(
gettext
(
"Loading thread list"
))
+
"</li>"
)
loadedCallback
:
=>
if
callback
callback
.
apply
@
,
[
value
]
@
$
(
".forum-nav-thread-list .forum-nav-load-more"
).
remove
()
success
:
(
response
,
textStatus
)
=>
if
textStatus
==
'success'
# TODO: Augment existing collection?
...
...
@@ -497,40 +493,13 @@ if Backbone?
)
@
addSearchAlert
(
message
)
clearSearch
:
(
callback
,
value
)
->
@
$
(
".post-search-field"
).
val
(
""
)
@
searchFor
(
""
,
callback
,
value
)
setActiveItem
:
(
event
)
->
if
event
.
which
==
13
$
(
".browse-topic-drop-menu-wrapper .focused"
).
click
()
return
if
event
.
which
!=
40
&&
event
.
which
!=
38
return
event
.
preventDefault
()
items
=
$
.
makeArray
(
$
(
".browse-topic-drop-menu-wrapper a"
).
not
(
".hidden"
))
index
=
items
.
indexOf
(
$
(
'.browse-topic-drop-menu-wrapper .focused'
)[
0
])
if
event
.
which
==
40
index
=
Math
.
min
(
index
+
1
,
items
.
length
-
1
)
if
event
.
which
==
38
index
=
Math
.
max
(
index
-
1
,
0
)
$
(
".browse-topic-drop-menu-wrapper .focused"
).
removeClass
(
"focused"
)
$
(
items
[
index
]).
addClass
(
"focused"
)
itemTop
=
$
(
items
[
index
]).
parent
().
offset
().
top
scrollTop
=
$
(
".browse-topic-drop-menu"
).
scrollTop
()
itemFromTop
=
$
(
".browse-topic-drop-menu"
).
offset
().
top
-
itemTop
scrollTarget
=
Math
.
min
(
scrollTop
-
itemFromTop
,
scrollTop
)
scrollTarget
=
Math
.
max
(
scrollTop
-
itemFromTop
-
$
(
".browse-topic-drop-menu"
).
height
()
+
$
(
items
[
index
]).
height
(),
scrollTarget
)
$
(
".browse-topic-drop-menu"
).
scrollTop
(
scrollTarget
)
clearSearch
:
->
@
$
(
".forum-nav-search-input"
).
val
(
""
)
@
current_search
=
""
retrieveFollowed
:
(
event
)
=>
retrieveFollowed
:
(
)
=>
@
mode
=
'followed'
@
retrieveFirstPage
(
event
)
@
retrieveFirstPage
()
updateEmailNotifications
:
()
=>
if
$
(
'input.email-setting'
).
attr
(
'checked'
)
...
...
common/test/acceptance/pages/lms/discussion.py
View file @
be04740e
...
...
@@ -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"
...
...
common/test/acceptance/tests/test_discussion.py
View file @
be04740e
...
...
@@ -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
)
lms/static/images/comment-icon-bottoms.png
deleted
100644 → 0
View file @
220a028b
960 Bytes
lms/static/sass/application-extend2.scss.mako
View file @
be04740e
...
...
@@ -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
...
...
lms/static/sass/discussion/_discussion.scss
View file @
be04740e
...
...
@@ -595,563 +595,6 @@ body.discussion {
box-shadow
:
none
;
line-height
:
1
.4
;
.sidebar
{
@include
box-sizing
(
border-box
);
float
:
left
;
border
:
1px
solid
#aaa
;
border-right
:
1px
solid
#bcbcbc
;
border-radius
:
3px
;
width
:
31%
;
height
:
550px
;
background
:
#f6f6f6
;
box-shadow
:
0
1px
2px
rgba
(
0
,
0
,
0
,
.05
);
}
.browse-search
{
position
:
relative
;
display
:
block
;
border-bottom
:
1px
solid
#a3a3a3
;
border-radius
:
3px
0
0
0
;
height
:
60px
;
.home
,
.browse
,
.search
{
@include
linear-gradient
(
top
,
rgba
(
255
,
255
,
255
,
.5
)
,
rgba
(
255
,
255
,
255
,
0
));
@include
transition
(
all
.2s
ease-out
);
position
:
relative
;
float
:
left
;
width
:
20%
;
height
:
100%
;
background-color
:
#dedede
;
&
:hover
,
&
:focus
{
background-color
:
$white
;
}
}
.icon
{
@include
transition
(
all
.2s
ease-out
);
z-index
:
100
;
display
:
inline-block
;
width
:
100%
;
color
:
#aeaeae
;
text-align
:
center
;
font-size
:
28px
;
line-height
:
60px
;
opacity
:
1
;
}
.home
{
border-radius
:
3px
0
0
0
;
box-shadow
:
-1px
0
0
#aaa
inset
;
cursor
:
pointer
;
}
.home-icon
{
width
:
100%
;
height
:
100%
;
display
:
block
;
}
.browse
{
border-radius
:
3px
0
0
0
;
box-shadow
:
-1px
0
0
#aaa
inset
;
&
.is-open
{
width
:
60%
;
.browse-topic-drop-btn
{
visibility
:
visible
;
}
.browse-topic-drop-icon
{
visibility
:
hidden
;
}
&
.is-dropped
{
.browse-topic-drop-btn
{
span
{
color
:
$white
;
text-shadow
:
none
;
}
border-color
:
#4b4b4b
;
}
}
}
&
.is-dropped
{
.browse-topic-drop-btn
{
background-color
:
#616161
;
}
}
}
.search
{
cursor
:
pointer
;
border-radius
:
0
3px
0
0
;
&
.is-open
{
cursor
:
auto
;
width
:
60%
;
.home
{
width
:
0%
;
}
.post-search
{
padding
:
0
$baseline
/
2
;
max-width
:
1000px
;
}
.post-search-field
{
cursor
:
text
;
pointer-events
:
auto
;
&
:
:-
webkit-input-placeholder
,
&:-
moz-placeholder
,
&:-
ms-input-placeholder
{
opacity
:
1
.0
;
}
}
}
}
.browse-topic-drop-btn
{
@include
transition
(
none
);
position
:
absolute
;
top
:
-1px
;
left
:
-1px
;
display
:
block
;
visibility
:
hidden
;
overflow
:
hidden
;
width
:
100%
;
height
:
100%
;
border
:
1px
solid
transparent
;
text-align
:
center
;
span
{
font-size
:
14px
;
font-weight
:
700
;
line-height
:
58px
;
color
:
#333
;
text-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
.8
);
}
.drop-arrow
{
font-size
:
16px
;
}
}
.browse-topic-drop-icon
{
display
:
block
;
visibility
:
visible
;
@include
transition
(
none
);
}
.browse-topic-drop-menu-wrapper
{
display
:
none
;
position
:
absolute
;
top
:
60px
;
left
:
-1px
;
z-index
:
9999
;
width
:
100%
;
background
:
#797979
;
border
:
1px
solid
#4b4b4b
;
border-left
:
none
;
border-radius
:
0
0
3px
3px
;
box-shadow
:
1px
0
0
#4b4b4b
inset
;
.browse-topic-drop-menu
{
max-height
:
400px
;
overflow-y
:
scroll
;
}
ul
{
position
:
inline
;
}
>
li
:first-child
a
{
border-top
:
none
;
}
a
{
display
:
block
;
padding
:
0
$baseline
;
border-top
:
1px
solid
#5f5f5f
;
font-size
:
12px
;
font-weight
:
700
;
line-height
:
22px
;
color
:
$white
;
@include
clearfix
;
@include
transition
(
none
);
&
.hidden
{
display
:
none
;
}
&
:hover
,
&
:focus
{
background-color
:
#636363
;
}
.board-name
{
float
:
left
;
width
:
80%
;
margin
:
13px
0
;
color
:
$white
;
}
.unread
{
float
:
right
;
padding
:
0
5px
;
margin-top
:
13px
;
font-size
:
11px
;
line-height
:
22px
;
border-radius
:
2px
;
@include
linear-gradient
(
top
,
#4c4c4c
,
#5a5a5a
);
}
}
li
li
{
a
{
padding-left
:
44px
;
background
:
url(../images/nested-icon.png)
no-repeat
22px
14px
;
}
}
li
li
li
{
a
{
padding-left
:
68px
;
background
:
url(../images/nested-icon.png)
no-repeat
46px
14px
;
}
}
}
.browse-topic-drop-search
{
padding
:
$baseline
/
2
;
}
.browse-topic-drop-search-input
{
width
:
100%
;
height
:
30px
;
padding
:
0
15px
;
@include
box-sizing
(
border-box
);
border-radius
:
30px
;
border
:
1px
solid
#333
;
box-shadow
:
0
1px
3px
rgba
(
0
,
0
,
0
,
.25
)
inset
;
background
:
-webkit-linear-gradient
(
top
,
#eee
,
$white
);
font-size
:
11px
;
line-height
:
16px
;
color
:
#333
;
}
.post-search
{
width
:
100%
;
max-width
:
30px
;
margin
:
auto
;
@include
box-sizing
(
border-box
);
@include
transition
(
all
.2s
linear
0s
);
}
.post-search-field
{
display
:
block
;
width
:
100%
;
height
:
30px
;
padding
:
0
0
0
30px
;
margin
:
14px
auto
;
@include
box-sizing
(
border-box
);
border
:
1px
solid
#acacac
;
border-radius
:
30px
;
box-shadow
:
0
1px
3px
rgba
(
0
,
0
,
0
,
.1
)
inset
,
0
1px
0
rgba
(
255
,
255
,
255
,
.5
);
background
:
url(../images/search-icon.png)
no-repeat
7px
center
#fff
;
font-family
:
'Open Sans'
,
sans-serif
;
font-weight
:
400
;
font-size
:
13px
;
line-height
:
20px
;
color
:
#333
;
cursor
:
pointer
;
pointer-events
:
none
;
@include
transition
(
all
.2s
ease-out
0s
);
&
:
:-
webkit-input-placeholder
,
&:-
moz-placeholder
,
&:-
ms-input-placeholder
{
opacity
:
0
.0
;
@include
transition
(
opacity
.2s
linear
0s
);
}
&
:focus
{
border-color
:
#4697c1
;
}
}
}
.sort-bar
{
height
:
auto
;
min-height
:
27px
;
border-bottom
:
1px
solid
#a3a3a3
;
@include
linear-gradient
(
top
,
rgba
(
255
,
255
,
255
,
.3
)
,
rgba
(
255
,
255
,
255
,
0
));
background-color
:
#aeaeae
;
box-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
.2
)
inset
;
span
,
a
{
font-size
:
9px
;
font-weight
:
bold
;
line-height
:
25px
;
color
:
#333
;
text-transform
:
uppercase
;
text-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
.4
);
}
.sort-label
{
display
:
block
;
float
:
left
;
margin
:
0
$baseline
/
2
;
}
li
{
float
:
left
;
margin
:
4px
4px
0
0
;
}
a
{
display
:
block
;
height
:
18px
;
padding
:
0
9px
;
border-radius
:
19px
;
color
:
#333
;
line-height
:
17px
;
&
:hover
,
&
:focus
{
@include
linear-gradient
(
top
,
rgba
(
255
,
255
,
255
,
.4
)
,
rgba
(
255
,
255
,
255
,
.2
));
color
:
#333
;
}
&
.active
{
@include
linear-gradient
(
top
,
rgba
(
0
,
0
,
0
,
.3
)
,
rgba
(
0
,
0
,
0
,
0
));
background-color
:
#999
;
color
:
$white
;
text-shadow
:
0
-1px
0
rgba
(
0
,
0
,
0
,
.3
);
box-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
0
.2
)
,
0
1px
1px
rgba
(
0
,
0
,
0
,
.2
)
inset
;
}
}
.group-filter-label
{
width
:
40px
;
margin-left
:
$baseline
/
2
;
}
.group-filter-select
{
margin
:
5px
0px
5px
5px
;
width
:
80px
;
font-size
:
10px
;
background
:
transparent
;
border-color
:
#ccc
;
}
}
.post-list-wrapper
{
overflow-y
:
scroll
;
overflow-x
:
hidden
;
//border-right: 1px solid transparent;
}
.post-list
{
background-color
:
#ddd
;
.loading
{
padding
:
(
$baseline
*.
75
)
0
;
background
:
$gray-l6
;
.loading-animation
{
background-image
:
url(../images/spinner-on-grey.gif)
;
}
}
.more-pages
a
{
background
:
#eee
;
font-size
:
12px
;
line-height
:
33px
;
text-align
:
center
;
&
:hover
,
&
:focus
{
background-image
:
none
;
background-color
:
#e6e6e6
;
}
}
a
{
display
:
block
;
position
:
relative
;
float
:
left
;
clear
:
both
;
width
:
100%
;
padding
:
0
(
$baseline
/
2
)
0
18px
;
margin-bottom
:
1px
;
margin-right
:
-1px
;
@include
linear-gradient
(
top
,
rgba
(
255
,
255
,
255
,
.7
)
,
rgba
(
255
,
255
,
255
,
0
));
background-color
:
$white
;
@include
clearfix
;
&
:hover
,
&
:focus
{
@include
linear-gradient
(
top
,
rgba
(
255
,
255
,
255
,
.7
)
,
rgba
(
255
,
255
,
255
,
0
));
background-color
:
#eee
;
}
&
.staff-post.staff-response
{
.staff-post-icon
{
top
:
5px
;
}
.staff-response-icon
{
top
:
18px
;
}
}
.staff-post-icon
,
.staff-response-icon
{
position
:
absolute
;
top
:
11px
;
left
:
3px
;
width
:
13px
;
height
:
13px
;
background
:
url(../images/staff-icons.png)
no-repeat
;
}
.staff-post-icon
{
left
:
2px
;
background-position
:
0
0
;
}
.staff-response-icon
{
background-position
:
-13px
0
;
}
.title
{
display
:
block
;
float
:
left
;
width
:
70%
;
margin
:
(
$baseline
/
2
)
0
(
$baseline
/
2
);
font-size
:
13px
;
font-weight
:
700
;
line-height
:
1
.4
;
color
:
$dark-gray
;
}
&
.read
{
background
:
#f2f2f2
;
.title
{
font-weight
:
400
;
color
:
#737373
;
}
}
&
.resolved
:before
{
content
:
''
;
position
:
absolute
;
top
:
12px
;
right
:
75px
;
width
:
9px
;
height
:
8px
;
background
:
url(../images/sidebar-resolved-icons.png)
no-repeat
;
}
&
.followed
:after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
right
:
0
;
width
:
12px
;
height
:
12px
;
background
:
url(../images/following-flag.png)
no-repeat
;
}
&
.active
{
@include
linear-gradient
(
top
,
#96e0fd
,
#61c7fc
);
border-color
:
#4697c1
;
box-shadow
:
0
1px
0
#4697c1
,
0
-1px
0
#4697c1
;
.title
{
color
:
#333
;
}
.staff-post-icon
{
background-position
:
0
-13px
;
}
.staff-response-icon
{
background-position
:
-13px
-13px
;
}
.comments-count
{
@include
linear-gradient
(
top
,
#3994c7
,
#4da7d3
);
color
:
$white
;
&
:after
{
background-position
:
0
0
;
}
}
&
.followed
:after
{
background-position
:
0
-12px
;
}
&
.resolved
:before
{
background-position
:
0
-8px
;
}
}
}
.votes-count
,
.comments-count
{
display
:
block
;
float
:
right
;
margin-top
:
8px
;
border-radius
:
2px
;
width
:
36px
;
height
:
20px
;
color
:
#767676
;
text-align
:
center
;
font-size
:
11px
;
line-height
:
20px
;
}
.comments-count
{
@include
linear-gradient
(
top
,
#d4d4d4
,
#dfdfdf
);
position
:
relative
;
margin-left
:
(
$baseline
/
4
);
margin-right
:(
$baseline
/
4
);
width
:
28px
;
font-weight
:
700
;
&
:after
{
content
:
''
;
display
:
block
;
position
:
absolute
;
top
:
20px
;
right
:
3px
;
width
:
5px
;
height
:
5px
;
background
:
url(../images/comment-icon-bottoms.png)
no-repeat
;
background-position
:
0
-5px
;
}
&
.unread
{
@include
linear-gradient
(
top
,
#84d7fe
,
#60a8d6
);
color
:
#333
;
&
:after
{
color
:
#99e0fe
;
background-position
:
0
0px
;
}
}
}
}
.bottom-post-status
{
padding
:
30px
;
font-size
:
20px
;
...
...
@@ -1440,7 +883,7 @@ body.discussion {
&
.community-ta
{
padding-top
:
38px
;
border-color
:
#449944
;
border-color
:
$forum-color-community-ta
;
}
.staff-banner
{
...
...
@@ -1468,7 +911,7 @@ body.discussion {
padding
:
1px
5px
;
@include
box-sizing
(
border-box
);
border-radius
:
2px
2px
0
0
;
background
:
#449944
;
background
:
$forum-color-community-ta
;
font-size
:
9px
;
font-weight
:
700
;
color
:
$white
;
...
...
@@ -1672,7 +1115,7 @@ body.discussion {
margin-left
:
(
$baseline
/
10
);
padding
:
0
(
$baseline
/
5
);
border-radius
:
2px
;
background
:
#449944
;
background
:
$forum-color-community-ta
;
font-size
:
9px
;
font-weight
:
700
;
font-style
:
normal
;
...
...
lms/static/sass/discussion/elements/_navigation.scss
0 → 100644
View file @
be04740e
.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
;
}
lms/static/sass/discussion/
_discussion-
developer.scss
→
lms/static/sass/discussion/
utilities/_
developer.scss
View file @
be04740e
File moved
lms/static/sass/discussion/utilities/_shame.scss
0 → 100644
View file @
be04740e
// -------------------
// 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
;
}
}
lms/static/sass/discussion/utilities/_variables.scss
0 → 100644
View file @
be04740e
$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
;
lms/templates/discussion/_filter_dropdown.html
View file @
be04740e
...
...
@@ -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>
...
...
lms/templates/discussion/_thread_list_template.html
View file @
be04740e
<
%!
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
>
<
/a
>
<
/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
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
>
<
/form
>
<
/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
=
"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 {cohort_name}"
).
format
(
cohort_name
=
c
[
'name'
])}
<
/option
>
%
endfor
<
/select
>
<
/span
>
%
endif
%
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
>
%
for
c
in
cohorts
:
<
option
value
=
"${c['id']}"
>
$
{
_
(
"View as {name}"
).
format
(
name
=
c
[
'name'
])}
<
/option
>
%
endfor
<
/select
>
%
endif
<
/div
>
<
div
class
=
"search-alerts"
><
/div
>
<
div
class
=
"post-list-wrapper"
>
<
ul
class
=
"post-list"
>
<
/ul
>
<
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
>
<
ul
class
=
"forum-nav-thread-list"
><
/ul
>
<
/div
>
</script>
lms/templates/discussion/_underscore_templates.html
View file @
be04740e
...
...
@@ -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"
>
...
...
lms/templates/discussion/index.html
View file @
be04740e
...
...
@@ -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>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment