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
111f7533
Commit
111f7533
authored
Sep 13, 2012
by
Victor Shnayder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Display (unstyled) progress in problems inside sequences
* verticals not-in-sequences next
parent
53d0a6ad
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
87 additions
and
34 deletions
+87
-34
common/lib/capa/capa/capa_problem.py
+3
-1
common/lib/xmodule/xmodule/capa_module.py
+22
-19
common/lib/xmodule/xmodule/css/sequence/display.scss
+5
-1
common/lib/xmodule/xmodule/js/src/capa/display.coffee
+2
-2
common/lib/xmodule/xmodule/js/src/sequence/display.coffee
+40
-9
common/lib/xmodule/xmodule/vertical_module.py
+3
-1
lms/templates/problem_ajax.html
+1
-1
lms/templates/seq_module.html
+11
-0
No files found.
common/lib/capa/capa/capa_problem.py
View file @
111f7533
...
@@ -157,6 +157,8 @@ class LoncapaProblem(object):
...
@@ -157,6 +157,8 @@ class LoncapaProblem(object):
def
get_max_score
(
self
):
def
get_max_score
(
self
):
'''
'''
Return maximum score for this problem.
Return maximum score for this problem.
TODO (vshnayder): Is this fixed once the problem is instantiated? Can we compute it only once?
'''
'''
maxscore
=
0
maxscore
=
0
for
response
,
responder
in
self
.
responders
.
iteritems
():
for
response
,
responder
in
self
.
responders
.
iteritems
():
...
@@ -217,7 +219,7 @@ class LoncapaProblem(object):
...
@@ -217,7 +219,7 @@ class LoncapaProblem(object):
# Get a list of timestamps of all queueing requests, then convert it to a DateTime object
# Get a list of timestamps of all queueing requests, then convert it to a DateTime object
queuetime_strs
=
[
self
.
correct_map
.
get_queuetime_str
(
answer_id
)
queuetime_strs
=
[
self
.
correct_map
.
get_queuetime_str
(
answer_id
)
for
answer_id
in
self
.
correct_map
for
answer_id
in
self
.
correct_map
if
self
.
correct_map
.
is_queued
(
answer_id
)]
if
self
.
correct_map
.
is_queued
(
answer_id
)]
queuetimes
=
[
datetime
.
strptime
(
qt_str
,
xqueue_interface
.
dateformat
)
for
qt_str
in
queuetime_strs
]
queuetimes
=
[
datetime
.
strptime
(
qt_str
,
xqueue_interface
.
dateformat
)
for
qt_str
in
queuetime_strs
]
...
...
common/lib/xmodule/xmodule/capa_module.py
View file @
111f7533
...
@@ -207,15 +207,21 @@ class CapaModule(XModule):
...
@@ -207,15 +207,21 @@ class CapaModule(XModule):
return
None
return
None
def
get_html
(
self
):
def
get_html
(
self
):
progress
=
self
.
get_progress
()
return
self
.
system
.
render_template
(
'problem_ajax.html'
,
{
return
self
.
system
.
render_template
(
'problem_ajax.html'
,
{
'element_id'
:
self
.
location
.
html_id
(),
'element_id'
:
self
.
location
.
html_id
(),
'id'
:
self
.
id
,
'id'
:
self
.
id
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'progress_status'
:
Progress
.
to_js_status_str
(
progress
),
'progress_detail'
:
Progress
.
to_js_detail_str
(
progress
),
})
})
def
get_problem_html
(
self
,
encapsulate
=
True
):
def
get_problem_html
(
self
):
'''Return html for the problem. Adds check, reset, save buttons
"""
as necessary based on the problem config and state.'''
Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.
"""
try
:
try
:
html
=
self
.
lcp
.
get_html
()
html
=
self
.
lcp
.
get_html
()
...
@@ -242,11 +248,11 @@ class CapaModule(XModule):
...
@@ -242,11 +248,11 @@ class CapaModule(XModule):
# check button is context-specific.
# check button is context-specific.
# Put a "Check" button if unlimited attempts or still some left
# Put a "Check" button if unlimited attempts or still some left
if
self
.
max_attempts
is
None
or
self
.
attempts
<
self
.
max_attempts
-
1
:
if
self
.
max_attempts
is
None
or
self
.
attempts
<
self
.
max_attempts
-
1
:
check_button
=
"Check"
check_button
=
"Check"
else
:
else
:
# Will be final check so let user know that
# Will be final check so let user know that
check_button
=
"Final Check"
check_button
=
"Final Check"
reset_button
=
True
reset_button
=
True
save_button
=
True
save_button
=
True
...
@@ -286,33 +292,29 @@ class CapaModule(XModule):
...
@@ -286,33 +292,29 @@ class CapaModule(XModule):
'ajax_url'
:
self
.
system
.
ajax_url
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'attempts_used'
:
self
.
attempts
,
'attempts_used'
:
self
.
attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'progress'
:
self
.
get_progress
(),
}
}
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
if
encapsulate
:
html
=
'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'
.
format
(
id
=
self
.
location
.
html_id
(),
ajax_url
=
self
.
system
.
ajax_url
)
+
html
+
"</div>"
return
self
.
system
.
replace_urls
(
html
,
self
.
metadata
[
'data_dir'
])
return
self
.
system
.
replace_urls
(
html
,
self
.
metadata
[
'data_dir'
])
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
get
):
'''
"""
This is called by courseware.module_render, to handle an AJAX call.
This is called by courseware.module_render, to handle an AJAX call.
"get" is request.POST.
"get" is request.POST.
Returns a json dictionary:
Returns a json dictionary:
{ 'progress_changed' : True/False,
{ 'progress_changed' : True/False,
'progress' : 'none'/'in_progress'/'done',
'progress_status' : 'none'/'in_progress'/'done',
'progress_detail' : 'NA' / '0/3' / '3/8' / '21/20'
<other request-specific values here > }
<other request-specific values here > }
'''
"""
handlers
=
{
handlers
=
{
'problem_get'
:
self
.
get_problem
,
'problem_get'
:
self
.
get_problem
,
'problem_check'
:
self
.
check_problem
,
'problem_check'
:
self
.
check_problem
,
'problem_reset'
:
self
.
reset_problem
,
'problem_reset'
:
self
.
reset_problem
,
'problem_save'
:
self
.
save_problem
,
'problem_save'
:
self
.
save_problem
,
'problem_show'
:
self
.
get_answer
,
'problem_show'
:
self
.
get_answer
,
'score_update'
:
self
.
update_score
,
'score_update'
:
self
.
update_score
,
# Callback for xqueue/grader, not the user's browser.
}
}
if
dispatch
not
in
handlers
:
if
dispatch
not
in
handlers
:
...
@@ -324,6 +326,7 @@ class CapaModule(XModule):
...
@@ -324,6 +326,7 @@ class CapaModule(XModule):
d
.
update
({
d
.
update
({
'progress_changed'
:
after
!=
before
,
'progress_changed'
:
after
!=
before
,
'progress_status'
:
Progress
.
to_js_status_str
(
after
),
'progress_status'
:
Progress
.
to_js_status_str
(
after
),
'progress_detail'
:
Progress
.
to_js_detail_str
(
after
),
})
})
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
...
@@ -414,7 +417,7 @@ class CapaModule(XModule):
...
@@ -414,7 +417,7 @@ class CapaModule(XModule):
Used if we want to reconfirm we have the right thing e.g. after
Used if we want to reconfirm we have the right thing e.g. after
several AJAX calls.
several AJAX calls.
'''
'''
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
return
{
'html'
:
self
.
get_problem_html
()}
@staticmethod
@staticmethod
def
make_dict_of_responses
(
get
):
def
make_dict_of_responses
(
get
):
...
@@ -467,11 +470,11 @@ class CapaModule(XModule):
...
@@ -467,11 +470,11 @@ class CapaModule(XModule):
# Problem queued. Students must wait a specified waittime before they are allowed to submit
# Problem queued. Students must wait a specified waittime before they are allowed to submit
if
self
.
lcp
.
is_queued
():
if
self
.
lcp
.
is_queued
():
current_time
=
datetime
.
datetime
.
now
()
current_time
=
datetime
.
datetime
.
now
()
prev_submit_time
=
self
.
lcp
.
get_recentmost_queuetime
()
prev_submit_time
=
self
.
lcp
.
get_recentmost_queuetime
()
waittime_between_requests
=
self
.
system
.
xqueue
[
'waittime'
]
waittime_between_requests
=
self
.
system
.
xqueue
[
'waittime'
]
if
(
current_time
-
prev_submit_time
)
.
total_seconds
()
<
waittime_between_requests
:
if
(
current_time
-
prev_submit_time
)
.
total_seconds
()
<
waittime_between_requests
:
msg
=
'You must wait at least
%
d seconds between submissions'
%
waittime_between_requests
msg
=
'You must wait at least
%
d seconds between submissions'
%
waittime_between_requests
return
{
'success'
:
msg
,
'html'
:
''
}
# Prompts a modal dialog in ajax callback
return
{
'success'
:
msg
,
'html'
:
''
}
# Prompts a modal dialog in ajax callback
try
:
try
:
old_state
=
self
.
lcp
.
get_state
()
old_state
=
self
.
lcp
.
get_state
()
...
@@ -514,7 +517,7 @@ class CapaModule(XModule):
...
@@ -514,7 +517,7 @@ class CapaModule(XModule):
self
.
system
.
psychometrics_handler
(
self
.
get_instance_state
())
self
.
system
.
psychometrics_handler
(
self
.
get_instance_state
())
# render problem into HTML
# render problem into HTML
html
=
self
.
get_problem_html
(
encapsulate
=
False
)
html
=
self
.
get_problem_html
()
return
{
'success'
:
success
,
return
{
'success'
:
success
,
'contents'
:
html
,
'contents'
:
html
,
...
@@ -587,7 +590,7 @@ class CapaModule(XModule):
...
@@ -587,7 +590,7 @@ class CapaModule(XModule):
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
self
.
system
.
track_function
(
'reset_problem'
,
event_info
)
self
.
system
.
track_function
(
'reset_problem'
,
event_info
)
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
return
{
'html'
:
self
.
get_problem_html
()}
class
CapaDescriptor
(
RawDescriptor
):
class
CapaDescriptor
(
RawDescriptor
):
...
...
common/lib/xmodule/xmodule/css/sequence/display.scss
View file @
111f7533
...
@@ -30,6 +30,10 @@ nav.sequence-nav {
...
@@ -30,6 +30,10 @@ nav.sequence-nav {
pointer-events
:
none
;
pointer-events
:
none
;
}
}
.student-progress
{
display
:
block
;
}
.sequence-list-wrapper
{
.sequence-list-wrapper
{
position
:
relative
;
position
:
relative
;
z-index
:
99
;
z-index
:
99
;
...
@@ -154,7 +158,7 @@ nav.sequence-nav {
...
@@ -154,7 +158,7 @@ nav.sequence-nav {
background-image
:
url('../images/sequence-nav/list-unstarted.png')
;
background-image
:
url('../images/sequence-nav/list-unstarted.png')
;
}
}
&
.progress-
some
,
&
.progress-
in_progress
{
&
.progress-in_progress
{
background-image
:
url('../images/sequence-nav/list-unfinished.png')
;
background-image
:
url('../images/sequence-nav/list-unfinished.png')
;
}
}
...
...
common/lib/xmodule/xmodule/js/src/capa/display.coffee
View file @
111f7533
...
@@ -19,7 +19,6 @@ class @Problem
...
@@ -19,7 +19,6 @@ class @Problem
@
$
(
'section.action input:button'
).
click
@
refreshAnswers
@
$
(
'section.action input:button'
).
click
@
refreshAnswers
@
$
(
'section.action input.check'
).
click
@
check_fd
@
$
(
'section.action input.check'
).
click
@
check_fd
#@$('section.action input.check').click @check
@
$
(
'section.action input.reset'
).
click
@
reset
@
$
(
'section.action input.reset'
).
click
@
reset
@
$
(
'section.action input.show'
).
click
@
show
@
$
(
'section.action input.show'
).
click
@
show
@
$
(
'section.action input.save'
).
click
@
save
@
$
(
'section.action input.save'
).
click
@
save
...
@@ -27,7 +26,8 @@ class @Problem
...
@@ -27,7 +26,8 @@ class @Problem
updateProgress
:
(
response
)
=>
updateProgress
:
(
response
)
=>
if
response
.
progress_changed
if
response
.
progress_changed
@
el
.
attr
progress
:
response
.
progress_status
@
el
.
data
(
'progress_status'
,
response
.
progress_status
)
@
el
.
data
(
'progress_detail'
,
response
.
progress_detail
)
@
el
.
trigger
(
'progressChanged'
)
@
el
.
trigger
(
'progressChanged'
)
queueing
:
=>
queueing
:
=>
...
...
common/lib/xmodule/xmodule/js/src/sequence/display.coffee
View file @
111f7533
...
@@ -18,11 +18,10 @@ class @Sequence
...
@@ -18,11 +18,10 @@ class @Sequence
initProgress
:
->
initProgress
:
->
@
progressTable
=
{}
# "#problem_#{id}" -> progress
@
progressTable
=
{}
# "#problem_#{id}" -> progress
hookUpProgressEvent
:
->
hookUpProgressEvent
:
->
$
(
'.problems-wrapper'
).
bind
'progressChanged'
,
@
updateProgress
$
(
'.problems-wrapper'
).
bind
'progressChanged'
,
@
updateProgress
mergeProgress
:
(
p1
,
p2
)
->
mergeProgress
Status
:
(
p1
,
p2
)
->
# if either is "NA", return the other one
# if either is "NA", return the other one
if
p1
==
"NA"
if
p1
==
"NA"
return
p2
return
p2
...
@@ -41,25 +40,55 @@ class @Sequence
...
@@ -41,25 +40,55 @@ class @Sequence
return
"none"
return
"none"
updateOverallScore
:
(
details
)
=>
# Given a list of "a/b" strings, compute the sum(a)/sum(b), and the corresponding percentage
gotten
=
0
possible
=
0
for
d
in
details
if
d
?
and
d
.
indexOf
(
'/'
)
>
0
a
=
d
.
split
(
'/'
)
got
=
parseInt
(
a
[
0
])
pos
=
parseInt
(
a
[
1
])
gotten
+=
got
possible
+=
pos
if
possible
>
0
s
=
(
gotten
/
possible
*
100
).
toFixed
(
1
)
+
"%"
else
s
=
"0%"
s
+=
" ("
+
gotten
+
'/'
+
possible
+
")"
@
el
.
find
(
'.overall-progress'
).
html
(
s
)
updateProgress
:
=>
updateProgress
:
=>
new_progress
=
"NA"
new_progress_status
=
"NA"
scores_list
=
@
el
.
find
(
'.progress-score-list'
)
scores_list
.
empty
()
details
=
[]
_this
=
this
_this
=
this
$
(
'.problems-wrapper'
).
each
(
index
)
->
$
(
'.problems-wrapper'
).
each
(
index
)
->
progress
=
$
(
this
).
attr
'progress'
progress_status
=
$
(
this
).
data
(
'progress_status'
)
new_progress
=
_this
.
mergeProgress
progress
,
new_progress
new_progress_status
=
_this
.
mergeProgressStatus
progress_status
,
new_progress_status
progress_detail
=
$
(
this
).
data
(
'progress_detail'
)
scores_list
.
append
(
"<li>"
+
progress_detail
+
"</li>"
)
details
.
push
(
progress_detail
)
@
progressTable
[
@
position
]
=
new_progress
@
progressTable
[
@
position
]
=
new_progress_status
@
setProgress
(
new_progress
,
@
link_for
(
@
position
))
@
setProgress
(
new_progress_status
,
@
link_for
(
@
position
))
@
updateOverallScore
(
details
)
setProgress
:
(
progress
,
element
)
->
setProgress
:
(
progress
,
element
)
->
# If progress is "NA", don't add any css class
# If progress is "NA", don't add any css class
element
.
removeClass
(
'progress-none'
)
element
.
removeClass
(
'progress-none'
)
.
removeClass
(
'progress-
some
'
)
.
removeClass
(
'progress-
in_progress
'
)
.
removeClass
(
'progress-done'
)
.
removeClass
(
'progress-done'
)
switch
progress
switch
progress
when
'none'
then
element
.
addClass
(
'progress-none'
)
when
'none'
then
element
.
addClass
(
'progress-none'
)
when
'in_progress'
then
element
.
addClass
(
'progress-
some
'
)
when
'in_progress'
then
element
.
addClass
(
'progress-
in_progress
'
)
when
'done'
then
element
.
addClass
(
'progress-done'
)
when
'done'
then
element
.
addClass
(
'progress-done'
)
toggleArrows
:
=>
toggleArrows
:
=>
...
@@ -95,6 +124,8 @@ class @Sequence
...
@@ -95,6 +124,8 @@ class @Sequence
sequence_links
=
@
$
(
'#seq_content a.seqnav'
)
sequence_links
=
@
$
(
'#seq_content a.seqnav'
)
sequence_links
.
click
@
goto
sequence_links
.
click
@
goto
# update score lists
@
updateProgress
()
goto
:
(
event
)
=>
goto
:
(
event
)
=>
event
.
preventDefault
()
event
.
preventDefault
()
...
...
common/lib/xmodule/xmodule/vertical_module.py
View file @
111f7533
...
@@ -23,7 +23,9 @@ class VerticalModule(XModule):
...
@@ -23,7 +23,9 @@ class VerticalModule(XModule):
})
})
def
get_progress
(
self
):
def
get_progress
(
self
):
# TODO: Cache progress or children array?
"""
Combine the progress of all the children.
"""
children
=
self
.
get_children
()
children
=
self
.
get_children
()
progresses
=
[
child
.
get_progress
()
for
child
in
children
]
progresses
=
[
child
.
get_progress
()
for
child
in
children
]
progress
=
reduce
(
Progress
.
add_counts
,
progresses
,
None
)
progress
=
reduce
(
Progress
.
add_counts
,
progresses
,
None
)
...
...
lms/templates/problem_ajax.html
View file @
111f7533
<section
id=
"problem_${element_id}"
class=
"problems-wrapper"
data-problem-id=
"${id}"
data-url=
"${ajax_url}"
></section>
<section
id=
"problem_${element_id}"
class=
"problems-wrapper"
data-problem-id=
"${id}"
data-url=
"${ajax_url}"
data-progress_status=
"${progress_status}"
data-progress_detail=
"${progress_detail}"
></section>
lms/templates/seq_module.html
View file @
111f7533
<div
id=
"sequence_${element_id}"
class=
"sequence"
data-id=
"${item_id}"
data-position=
"${position}"
data-course_modx_root=
"/course/modx"
>
<div
id=
"sequence_${element_id}"
class=
"sequence"
data-id=
"${item_id}"
data-position=
"${position}"
data-course_modx_root=
"/course/modx"
>
<div
class=
"student-progress"
>
<div
class=
"summary"
>
Overall:
<span
class=
"overall-progress"
>
</span>
</div>
<div
class=
"details"
>
Scores:
<ul
class=
"progress-score-list"
>
</ul>
</div>
</div>
<nav
aria-label=
"Section Navigation"
class=
"sequence-nav"
>
<nav
aria-label=
"Section Navigation"
class=
"sequence-nav"
>
<div
class=
"sequence-list-wrapper"
>
<div
class=
"sequence-list-wrapper"
>
<ol
id=
"sequence-list"
>
<ol
id=
"sequence-list"
>
...
...
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