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
0e59038c
Commit
0e59038c
authored
Apr 16, 2014
by
Greg Price
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add pagination to forum user profile page
parent
643069c6
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
360 additions
and
64 deletions
+360
-64
common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee
+274
-0
common/static/coffee/src/discussion/discussion_module_view.coffee
+3
-14
common/static/coffee/src/discussion/main.coffee
+3
-1
common/static/coffee/src/discussion/utils.coffee
+15
-0
common/static/coffee/src/discussion/views/discussion_user_profile_view.coffee
+39
-18
lms/djangoapps/django_comment_client/forum/tests.py
+2
-2
lms/djangoapps/django_comment_client/forum/views.py
+2
-0
lms/static/sass/_discussion.scss
+12
-12
lms/templates/discussion/mustache/_pagination.mustache
+1
-1
lms/templates/discussion/mustache/_user_profile.mustache
+8
-9
lms/templates/discussion/user_profile.html
+1
-7
No files found.
common/static/coffee/spec/discussion/view/discussion_user_profile_view_spec.coffee
0 → 100644
View file @
0e59038c
describe
"DiscussionUserProfileView"
,
->
beforeEach
->
setFixtures
(
"""
<script type="text/template" id="_user_profile">
<section class="discussion">
{{#threads}}
<article class="discussion-thread" id="thread_{{id}}"/>
{{/threads}}
</section>
<section class="pagination"/>
</script>
<script type="text/template" id="_profile_thread">
<div class="profile-thread" id="thread_{{id}}"/>
</script>
<script type="text/template" id="_pagination">
<div class="discussion-paginator">
<a href="#different-page"/>
</div>
<div
class="pagination-params"
data-leftdots="{{leftdots}}"
data-page="{{page}}"
data-rightdots="{{rightdots}}"
>
{{#previous}}
<div class="previous" data-url="{{url}}" data-number="{{number}}"/>
{{/previous}}
{{#first}}
<div class="first" data-url="{{url}}" data-number="{{number}}"/>
{{/first}}
{{#lowPages}}
<div class="lowPages" data-url="{{url}}" data-number="{{number}}"/>
{{/lowPages}}
{{#highPages}}
<div class="highPages" data-url="{{url}}" data-number="{{number}}"/>
{{/highPages}}
{{#last}}
<div class="last" data-url="{{url}}" data-number="{{number}}"/>
{{/last}}
{{#next}}
<div class="next" data-url="{{url}}" data-number="{{number}}"/>
{{/next}}
</div>
</script>
<div class="user-profile-fixture"/>
"""
)
window
.
$
$course_id
=
"dummy_course_id"
spyOn
(
DiscussionThreadProfileView
.
prototype
,
"render"
)
makeView
=
(
threads
,
page
,
numPages
)
->
return
new
DiscussionUserProfileView
(
el
:
$
(
".user-profile-fixture"
)
collection
:
threads
page
:
page
numPages
:
numPages
)
describe
"thread rendering should be correct"
,
->
checkRender
=
(
numThreads
)
->
threads
=
_
.
map
(
_
.
range
(
numThreads
),
(
i
)
->
{
id
:
i
.
toString
(),
body
:
"dummy body"
})
view
=
makeView
(
threads
,
1
,
1
)
expect
(
view
.
$
(
".discussion"
).
children
().
length
).
toEqual
(
numThreads
)
_
.
each
(
threads
,
(
thread
)
->
expect
(
view
.
$
(
"#thread_
#{
thread
.
id
}
"
).
length
).
toEqual
(
1
))
it
"with no threads"
,
->
checkRender
(
0
)
it
"with one thread"
,
->
checkRender
(
1
)
it
"with several threads"
,
->
checkRender
(
5
)
describe
"pagination rendering should be correct"
,
->
baseUri
=
URI
(
window
.
location
)
pageInfo
=
(
page
)
->
{
url
:
baseUri
.
clone
().
addSearch
(
"page"
,
page
).
toString
(),
number
:
page
}
checkRender
=
(
params
)
->
view
=
makeView
([],
params
.
page
,
params
.
numPages
)
paramsQuery
=
view
.
$
(
".pagination-params"
)
expect
(
paramsQuery
.
length
).
toEqual
(
1
)
_
.
each
(
[
"page"
,
"leftdots"
,
"rightdots"
],
(
param
)
->
expect
(
paramsQuery
.
data
(
param
)).
toEqual
(
params
[
param
])
)
_
.
each
(
[
"previous"
,
"first"
,
"last"
,
"next"
],
(
param
)
->
expected
=
params
[
param
]
expect
(
paramsQuery
.
find
(
"."
+
param
).
data
()).
toEqual
(
if
expected
then
pageInfo
(
expected
)
else
null
)
)
_
.
each
(
[
"lowPages"
,
"highPages"
]
(
param
)
->
expect
(
paramsQuery
.
find
(
"."
+
param
).
map
(
->
$
(
this
).
data
()).
get
()).
toEqual
(
_
.
map
(
params
[
param
],
pageInfo
)
)
)
it
"for one page"
,
->
checkRender
(
page
:
1
numPages
:
1
previous
:
null
first
:
null
leftdots
:
false
lowPages
:
[]
highPages
:
[]
rightdots
:
false
last
:
null
next
:
null
)
it
"for first page of three (max with no last)"
,
->
checkRender
(
page
:
1
numPages
:
3
previous
:
null
first
:
null
leftdots
:
false
lowPages
:
[]
highPages
:
[
2
,
3
]
rightdots
:
false
last
:
null
next
:
2
)
it
"for first page of four (has last but no dots)"
,
->
checkRender
(
page
:
1
numPages
:
4
previous
:
null
first
:
null
leftdots
:
false
lowPages
:
[]
highPages
:
[
2
,
3
]
rightdots
:
false
last
:
4
next
:
2
)
it
"for first page of five (has dots)"
,
->
checkRender
(
page
:
1
numPages
:
5
previous
:
null
first
:
null
leftdots
:
false
lowPages
:
[]
highPages
:
[
2
,
3
]
rightdots
:
true
last
:
5
next
:
2
)
it
"for last page of three (max with no first)"
,
->
checkRender
(
page
:
3
numPages
:
3
previous
:
2
first
:
null
leftdots
:
false
lowPages
:
[
1
,
2
]
highPages
:
[]
rightdots
:
false
last
:
null
next
:
null
)
it
"for last page of four (has first but no dots)"
,
->
checkRender
(
page
:
4
numPages
:
4
previous
:
3
first
:
1
leftdots
:
false
lowPages
:
[
2
,
3
]
highPages
:
[]
rightdots
:
false
last
:
null
next
:
null
)
it
"for last page of five (has dots)"
,
->
checkRender
(
page
:
5
numPages
:
5
previous
:
4
first
:
1
leftdots
:
true
lowPages
:
[
3
,
4
]
highPages
:
[]
rightdots
:
false
last
:
null
next
:
null
)
it
"for middle page of five (max with no first/last)"
,
->
checkRender
(
page
:
3
numPages
:
5
previous
:
2
first
:
null
leftdots
:
false
lowPages
:
[
1
,
2
]
highPages
:
[
4
,
5
]
rightdots
:
false
last
:
null
next
:
4
)
it
"for middle page of seven (has first/last but no dots)"
,
->
checkRender
(
page
:
4
numPages
:
7
previous
:
3
first
:
1
leftdots
:
false
lowPages
:
[
2
,
3
]
highPages
:
[
5
,
6
]
rightdots
:
false
last
:
7
next
:
5
)
it
"for middle page of nine (has dots)"
,
->
checkRender
(
page
:
5
numPages
:
9
previous
:
4
first
:
1
leftdots
:
true
lowPages
:
[
3
,
4
]
highPages
:
[
6
,
7
]
rightdots
:
true
last
:
9
next
:
6
)
describe
"pagination interaction"
,
->
beforeEach
->
@
view
=
makeView
([],
1
,
1
)
spyOn
(
$
,
"ajax"
)
it
"causes updated rendering"
,
->
$
.
ajax
.
andCallFake
(
(
params
)
=>
params
.
success
(
discussion_data
:
[{
id
:
"on_page_42"
,
body
:
"dummy body"
}]
page
:
42
num_pages
:
99
)
{
always
:
->
}
)
@
view
.
$
(
".pagination a"
).
first
().
click
()
expect
(
@
view
.
$
(
"#thread_on_page_42"
).
length
).
toEqual
(
1
)
expect
(
@
view
.
$
(
".pagination-params"
).
data
(
"page"
)).
toEqual
(
42
)
expect
(
@
view
.
$
(
".pagination-params .last"
).
data
(
"number"
)).
toEqual
(
99
)
it
"handles AJAX errors"
,
->
spyOn
(
DiscussionUtil
,
"discussionAlert"
)
$
.
ajax
.
andCallFake
(
(
params
)
=>
params
.
error
()
{
always
:
->
}
)
@
view
.
$
(
".pagination a"
).
first
().
click
()
expect
(
DiscussionUtil
.
discussionAlert
).
toHaveBeenCalled
()
common/static/coffee/src/discussion/discussion_module_view.coffee
View file @
0e59038c
...
...
@@ -116,7 +116,7 @@ if Backbone?
@
discussion
.
on
"add"
,
@
addThread
@
retrieved
=
true
@
showed
=
true
@
renderPagination
(
2
,
response
.
num_pages
)
@
renderPagination
(
response
.
num_pages
)
if
@
isWaitingOnNewPost
@
newPostForm
.
show
()
...
...
@@ -128,21 +128,10 @@ if Backbone?
threadView
.
render
()
@
threadviews
.
unshift
threadView
renderPagination
:
(
delta
,
numPages
)
=>
minPage
=
Math
.
max
(
@
page
-
delta
,
1
)
maxPage
=
Math
.
min
(
@
page
+
delta
,
numPages
)
renderPagination
:
(
numPages
)
=>
pageUrl
=
(
number
)
->
"?discussion_page=
#{
number
}
"
params
=
page
:
@
page
lowPages
:
_
.
range
(
minPage
,
@
page
).
map
(
n
)
->
{
number
:
n
,
url
:
pageUrl
(
n
)}
highPages
:
_
.
range
(
@
page
+
1
,
maxPage
+
1
).
map
(
n
)
->
{
number
:
n
,
url
:
pageUrl
(
n
)}
previous
:
if
@
page
-
1
>=
1
then
{
url
:
pageUrl
(
@
page
-
1
),
number
:
@
page
-
1
}
else
false
next
:
if
@
page
+
1
<=
numPages
then
{
url
:
pageUrl
(
@
page
+
1
),
number
:
@
page
+
1
}
else
false
leftdots
:
minPage
>
2
rightdots
:
maxPage
<
numPages
-
1
first
:
if
minPage
>
1
then
{
url
:
pageUrl
(
1
)}
else
false
last
:
if
maxPage
<
numPages
then
{
number
:
numPages
,
url
:
pageUrl
(
numPages
)}
else
false
params
=
DiscussionUtil
.
getPaginationParams
(
@
page
,
numPages
,
pageUrl
)
thing
=
Mustache
.
render
@
paginationTemplate
(),
params
@
$
(
'section.pagination'
).
html
(
thing
)
...
...
common/static/coffee/src/discussion/main.coffee
View file @
0e59038c
...
...
@@ -21,7 +21,9 @@ if Backbone?
threads
=
element
.
data
(
"threads"
)
user_info
=
element
.
data
(
"user-info"
)
window
.
user
=
new
DiscussionUser
(
user_info
)
new
DiscussionUserProfileView
(
el
:
element
,
collection
:
threads
)
page
=
element
.
data
(
"page"
)
numPages
=
element
.
data
(
"num-pages"
)
new
DiscussionUserProfileView
(
el
:
element
,
collection
:
threads
,
page
:
page
,
numPages
:
numPages
)
$
->
$
(
"section.discussion"
).
each
(
index
,
elem
)
->
DiscussionApp
.
start
(
elem
)
...
...
common/static/coffee/src/discussion/utils.coffee
View file @
0e59038c
...
...
@@ -299,3 +299,18 @@ class @DiscussionUtil
minLength
++
return
text
.
substr
(
0
,
minLength
)
+
gettext
(
'…'
)
@
getPaginationParams
:
(
curPage
,
numPages
,
pageUrlFunc
)
=>
delta
=
2
minPage
=
Math
.
max
(
curPage
-
delta
,
1
)
maxPage
=
Math
.
min
(
curPage
+
delta
,
numPages
)
pageInfo
=
(
pageNum
)
->
{
number
:
pageNum
,
url
:
pageUrlFunc
(
pageNum
)}
params
=
page
:
curPage
lowPages
:
_
.
range
(
minPage
,
curPage
).
map
(
pageInfo
)
highPages
:
_
.
range
(
curPage
+
1
,
maxPage
+
1
).
map
(
pageInfo
)
previous
:
if
curPage
>
1
then
pageInfo
(
curPage
-
1
)
else
null
next
:
if
curPage
<
numPages
then
pageInfo
(
curPage
+
1
)
else
null
leftdots
:
minPage
>
2
rightdots
:
maxPage
<
numPages
-
1
first
:
if
minPage
>
1
then
pageInfo
(
1
)
else
null
last
:
if
maxPage
<
numPages
then
pageInfo
(
numPages
)
else
null
common/static/coffee/src/discussion/views/discussion_user_profile_view.coffee
View file @
0e59038c
if
Backbone
?
class
@
DiscussionUserProfileView
extends
Backbone
.
View
# events:
# "":""
events
:
"click .discussion-paginator a"
:
"changePage"
initialize
:
(
options
)
->
@
renderThreads
@
$el
,
@
collection
renderThreads
:
(
$elem
,
threads
)
=>
#Content.loadContentInfos(response.annotated_content_info)
super
()
@
page
=
options
.
page
@
numPages
=
options
.
numPages
@
discussion
=
new
Discussion
()
@
discussion
.
reset
(
threads
,
{
silent
:
false
})
$discussion
=
$
(
Mustache
.
render
$
(
"script#_user_profile"
).
html
(),
{
'threads'
:
threads
})
$elem
.
append
(
$discussion
)
@
threadviews
=
@
discussion
.
map
(
thread
)
->
new
DiscussionThreadProfileView
el
:
@
$
(
"article#thread_
#{
thread
.
id
}
"
),
model
:
thread
_
.
each
@
threadviews
,
(
dtv
)
->
dtv
.
render
()
@
discussion
.
on
(
"reset"
,
@
render
)
@
discussion
.
reset
(
@
collection
,
{
silent
:
false
})
render
:
()
=>
profileTemplate
=
$
(
"script#_user_profile"
).
html
()
@
$el
.
html
(
Mustache
.
render
(
profileTemplate
,
{
threads
:
@
discussion
.
models
}))
@
discussion
.
map
(
thread
)
->
new
DiscussionThreadProfileView
(
el
:
@
$
(
"article#thread_
#{
thread
.
id
}
"
),
model
:
thread
).
render
()
baseUri
=
URI
(
window
.
location
).
removeSearch
(
"page"
)
pageUrlFunc
=
(
page
)
->
baseUri
.
clone
().
addSearch
(
"page"
,
page
)
paginationParams
=
DiscussionUtil
.
getPaginationParams
(
@
page
,
@
numPages
,
pageUrlFunc
)
paginationTemplate
=
$
(
"script#_pagination"
).
html
()
@
$el
.
find
(
".pagination"
).
html
(
Mustache
.
render
(
paginationTemplate
,
paginationParams
))
addThread
:
(
thread
,
collection
,
options
)
=>
# TODO: When doing pagination, this will need to repaginate. Perhaps just reload page 1?
article
=
$
(
"<article class='discussion-thread' id='thread_
#{
thread
.
id
}
'></article>"
)
@
$
(
'section.discussion > .threads'
).
prepend
(
article
)
threadView
=
new
DiscussionThreadInlineView
el
:
article
,
model
:
thread
threadView
.
render
()
@
threadviews
.
unshift
threadView
changePage
:
(
event
)
->
event
.
preventDefault
()
url
=
$
(
event
.
target
).
attr
(
"href"
)
DiscussionUtil
.
safeAjax
$elem
:
@
$el
$loading
:
$
(
event
.
target
)
takeFocus
:
true
url
:
url
type
:
"GET"
dataType
:
"json"
success
:
(
response
,
textStatus
,
xhr
)
=>
@
page
=
response
.
page
@
numPages
=
response
.
num_pages
@
discussion
.
reset
(
response
.
discussion_data
,
{
silent
:
false
})
history
.
pushState
({},
""
,
url
)
error
:
=>
DiscussionUtil
.
discussionAlert
(
gettext
(
"Sorry"
),
gettext
(
"We had some trouble loading the page you requested. Please try again."
)
)
lms/djangoapps/django_comment_client/forum/tests.py
View file @
0e59038c
...
...
@@ -299,8 +299,8 @@ class UserProfileTestCase(ModuleStoreTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
[
'Content-Type'
],
'text/html; charset=utf-8'
)
html
=
response
.
content
self
.
assertRegexpMatches
(
html
,
r'
var \$\$course_id = \"{}\"'
.
format
(
self
.
course
.
id
)
)
self
.
assertRegexpMatches
(
html
,
r'
var \$\$profiled_user_id = \"{}\"'
.
format
(
self
.
profiled_user
.
id
)
)
self
.
assertRegexpMatches
(
html
,
r'
data-page="1"'
)
self
.
assertRegexpMatches
(
html
,
r'
data-num-pages="1"'
)
self
.
assertRegexpMatches
(
html
,
r'<span>1</span> discussion started'
)
self
.
assertRegexpMatches
(
html
,
r'<span>2</span> comments'
)
self
.
assertRegexpMatches
(
html
,
r'"id": "{}"'
.
format
(
self
.
TEST_THREAD_ID
))
...
...
lms/djangoapps/django_comment_client/forum/views.py
View file @
0e59038c
...
...
@@ -353,6 +353,8 @@ def user_profile(request, course_id, user_id):
'threads'
:
saxutils
.
escape
(
json
.
dumps
(
threads
),
escapedict
),
'user_info'
:
saxutils
.
escape
(
json
.
dumps
(
user_info
),
escapedict
),
'annotated_content_info'
:
saxutils
.
escape
(
json
.
dumps
(
annotated_content_info
),
escapedict
),
'page'
:
query_params
[
'page'
],
'num_pages'
:
query_params
[
'num_pages'
],
# 'content': content,
}
...
...
lms/static/sass/_discussion.scss
View file @
0e59038c
...
...
@@ -2226,18 +2226,18 @@ body.discussion {
a
{
@include
white-button
;
}
}
li
.current-page
{
height
:
3
5px
;
padding
:
0
15px
;
border
:
1px
solid
#ccc
;
border-radius
:
3px
;
font-size
:
13px
;
font-weight
:
700
;
line-height
:
32px
;
color
:
#333
;
text-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
0
.6
);
&
.current-page
span
{
display
:
inline-block
;
height
:
35px
;
padding
:
0
1
5px
;
border
:
1px
solid
#ccc
;
border-radius
:
3px
;
font-size
:
1
3px
;
font-weight
:
700
;
line-height
:
32px
;
color
:
#333
;
text-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
0
.6
)
;
}
}
}
}
...
...
lms/templates/discussion/mustache/_pagination.mustache
View file @
0e59038c
...
...
@@ -15,7 +15,7 @@
{{#
lowPages
}}
<li><a
class=
"discussion-pagination"
href=
"
{{
url
}}
"
data-page-number=
"
{{
number
}}
"
>
{{
number
}}
</a></li>
{{/
lowPages
}}
<li
class=
"current-page"
>
{{
page
}}
</li>
<li
class=
"current-page"
>
<span>
{{
page
}}
</span>
</li>
{{#
highPages
}}
<li><a
class=
"discussion-pagination"
href=
"
{{
url
}}
"
data-page-number=
"
{{
number
}}
"
>
{{
number
}}
</a></li>
{{/
highPages
}}
...
...
lms/templates/discussion/mustache/_user_profile.mustache
View file @
0e59038c
<section
class=
"discussion-user-threads"
>
<section
class=
"discussion"
>
{{#
threads
}}
<article
class=
"discussion-thread"
id=
"thread_
{{
id
}}
"
>
</article>
{{/
threads
}}
</div>
<section
class=
"pagination"
>
</section>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<h2>
${_("Active Threads")}
</h2>
<section
class=
"discussion"
>
{{#
threads
}}
<article
class=
"discussion-thread"
id=
"thread_
{{
id
}}
"
/>
{{/
threads
}}
</section>
<section
class=
"pagination"
/>
lms/templates/discussion/user_profile.html
View file @
0e59038c
...
...
@@ -32,14 +32,8 @@
</nav>
</section>
<section
class=
"course-content container discussion-user-threads"
data-user-id=
"${django_user.id | h}"
data-course-id=
"${course.id | h}"
data-threads=
"${threads}"
data-user-info=
"${user_info}"
>
<h2>
${_("Active Threads")}
</h2>
</section>
<section
class=
"course-content container discussion-user-threads"
data-course-id=
"${course.id | h}"
data-threads=
"${threads}"
data-user-info=
"${user_info}"
data-page=
"${page}"
data-num-pages=
"${num_pages}"
/>
</div>
</section>
<script
type=
"text/javascript"
>
var
$$profiled_user_id
=
"${django_user.id | escapejs}"
;
var
$$course_id
=
"${course.id | escapejs}"
;
</script>
<
%
include
file=
"_underscore_templates.html"
/>
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