Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
problem-builder
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
OpenEdx
problem-builder
Commits
0d7b18fa
Unverified
Commit
0d7b18fa
authored
Nov 10, 2017
by
Braden MacDonald
Committed by
GitHub
Nov 10, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #173 from open-craft/uman/fix-pb-swipe
[MCKIN-5975] Make pb-swipe return proper student view data.
parents
1dc9578a
0931ca2c
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
68 additions
and
131 deletions
+68
-131
doc/Native APIs.md
+15
-26
problem_builder/public/css/problem-builder.css
+0
-4
problem_builder/swipe.py
+52
-67
problem_builder/templates/html/swipeblock.html
+0
-33
setup.py
+1
-1
No files found.
doc/Native APIs.md
View file @
0d7b18fa
...
...
@@ -371,40 +371,29 @@ Swipeable Binary Response (`pb-swipe`)
-
`block_id`
: (string) The XBlock's usage ID
-
`display_name`
: (string) The XBlock's display name
-
`type`
: (string): The XBlock's identifier, "pb-swipe"
-
`question`
: (string) The question contents
-
`message`
: (string) Feedback provided when submitting
-
`img_url`
: (string) URL to an associated image
-
`weight`
: (float) Overall value of the question
-
`choices`
: (array) A list of objects providing info about available
choices. See below for more info.
-
`tips`
: (array) A list of objects providing info about tips defined for the
problem. See below for more info.
#### `tips`
Each entry in the
`tips`
array contains these values:
-
`content`
: (string) The text content of the tip.
-
`for_choices`
: (array) A list of string values corresponding to choices to
which this tip applies to.
#### `choices`
Each item in the
`choices`
array contains these fields:
-
`value`
: (string) The value of the choice.
-
`content`
: (string) The description of the choice
-
`text`
: (string) The text to display on the card
-
`img_url`
: (string) URL of the image to display as the background of the card
-
`correct`
: (boolean) Whether the student's swipe is correct or not
### `student_view_user_state`
-
`student_choice`
: (
string
) The value of the last submitted choice.
-
`student_choice`
: (
boolean
) The value of the last submitted choice.
### POST Submit Data
When submitting the problem the data should be a single object containing the
`"value"`
property which has the value of the selected choice.
Example:
`{"value": "blue"}`
`"value"`
property which has a boolean value indicating which swipe the student took:
-
Right -> True
-
Left -> False
Example:
`{"value": true}`
if the student made a
*rightwards*
swipe.
The returned result will contain the following:
-
`submission`
: (boolean) The value just POST'd.
-
`status`
: (string)
`"correct"`
if the swipe is correct,
`"incorrect"`
otherwise.
-
`score`
: (integer) 1 if the swipe is correct, otherwise 0.
Multiple Response Question (`pb-mrq`)
-------------------------------------
...
...
problem_builder/public/css/problem-builder.css
View file @
0d7b18fa
...
...
@@ -260,7 +260,3 @@
.mentoring
.copyright
a
{
color
:
#69C0E8
;
}
.swipe-img
{
max-width
:
100%
;
}
problem_builder/swipe.py
View file @
0d7b18fa
...
...
@@ -19,18 +19,20 @@
#
# Imports ###########################################################
import
logging
from
xblock.fields
import
Scope
,
String
from
xblock.validation
import
ValidationMessage
from
xblock.core
import
XBlock
from
xblock.fields
import
Boolean
,
Scope
,
String
from
xblock.fragment
import
Fragment
from
xblockutils.resources
import
ResourceLoader
from
xblockutils.studio_editable
import
StudioEditableXBlockMixin
,
XBlockWithPreviewMixin
from
.mixins
import
StudentViewUserStateMixin
from
.questionnaire
import
QuestionnaireAbstractBlock
from
.sub_api
import
SubmittingXBlockMixin
from
.mixins
import
QuestionMixin
,
StudentViewUserStateMixin
# Globals ###########################################################
log
=
logging
.
getLogger
(
__name__
)
loader
=
ResourceLoader
(
__name__
)
...
...
@@ -41,53 +43,51 @@ def _(text):
# Classes ###########################################################
class
SwipeBlock
(
SubmittingXBlockMixin
,
StudentViewUserStateMixin
,
QuestionnaireAbstractBlock
):
@XBlock.needs
(
"i18n"
)
class
SwipeBlock
(
QuestionMixin
,
StudioEditableXBlockMixin
,
StudentViewUserStateMixin
,
XBlockWithPreviewMixin
,
XBlock
,
):
"""
An XBlock used to ask binary-choice questions with a swiping interface
"""
CATEGORY
=
'pb-swipe'
STUDIO_LABEL
=
_
(
u"Swipeable Binary Choice Question"
)
USER_STATE_FIELDS
=
[
'num_attempts'
,
'student_choice'
]
message
=
String
(
display_name
=
_
(
"Message"
),
help
=
_
(
"General feedback provided when submitting. "
"(This is not shown if there is a more specific feedback tip for the choice selected by the learner.)"
),
scope
=
Scope
.
content
,
default
=
""
)
USER_STATE_FIELDS
=
[
'student_choice'
]
student_choice
=
String
(
# {Last input submitted by the student
text
=
String
(
display_name
=
_
(
"Text"
),
help
=
_
(
"Text to display on this card. The student must determine if this statement is true or false."
),
scope
=
Scope
.
content
,
default
=
""
,
scope
=
Scope
.
user_stat
e
,
multiline_editor
=
Tru
e
,
)
correct_choice
=
String
(
display_name
=
_
(
"Correct Choice"
),
help
=
_
(
"Specify the value that students may select for this question to be considered correct."
),
scope
=
Scope
.
content
,
values_provider
=
QuestionnaireAbstractBlock
.
choice_values_provider
,
)
img_url
=
String
(
display_name
=
_
(
"Image"
),
help
=
_
(
"Specify the URL of an image associated with this question."
),
help
=
_
(
"Specify the URL of an image associated with this question."
),
scope
=
Scope
.
content
,
default
=
""
)
editable_fields
=
QuestionnaireAbstractBlock
.
editable_fields
+
(
'message'
,
'correct_choice'
,
'img_url'
,)
correct
=
Boolean
(
display_name
=
_
(
"Correct Choice"
),
help
=
_
(
"Specifies whether the card is correct."
),
scope
=
Scope
.
content
,
)
student_choice
=
Boolean
(
scope
=
Scope
.
user_state
,
help
=
_
(
"Last input submitted by the student."
)
)
editable_fields
=
(
'display_name'
,
'text'
,
'img_url'
,
'correct'
)
def
calculate_results
(
self
,
submission
):
correct
=
s
elf
.
correct_choice
==
submission
correct
=
s
ubmission
==
self
.
correct
return
{
'submission'
:
submission
,
'message'
:
self
.
message_formatted
,
'status'
:
'correct'
if
correct
else
'incorrect'
,
'weight'
:
self
.
weight
,
'score'
:
1
if
correct
else
0
,
}
...
...
@@ -99,33 +99,12 @@ class SwipeBlock(SubmittingXBlockMixin, StudentViewUserStateMixin, Questionnaire
def
submit
(
self
,
submission
):
log
.
debug
(
u'Received Swipe submission: "
%
s"'
,
submission
)
result
=
self
.
calculate_results
(
submission
[
'value'
]
)
# We expect to receive a boolean indicating the swipe the student made (left -> false, right -> true
)
self
.
student_choice
=
submission
[
'value'
]
result
=
self
.
calculate_results
(
self
.
student_choice
)
log
.
debug
(
u'Swipe submission result:
%
s'
,
result
)
return
result
def
validate_field_data
(
self
,
validation
,
data
):
"""
Validate this block's field data.
"""
super
(
SwipeBlock
,
self
)
.
validate_field_data
(
validation
,
data
)
def
add_error
(
msg
):
validation
.
add
(
ValidationMessage
(
ValidationMessage
.
ERROR
,
msg
))
if
len
(
self
.
all_choice_values
)
==
0
:
# Let's not set an error until at least one choice is added
return
if
len
(
self
.
all_choice_values
)
!=
2
:
add_error
(
self
.
_
(
u"You must have exactly two choices."
)
)
if
not
data
.
correct_choice
:
add_error
(
self
.
_
(
u"You must indicate the correct answer, or the student will always get this question wrong."
)
)
def
student_view_data
(
self
,
context
=
None
):
"""
Returns a JSON representation of the student_view of this XBlock,
...
...
@@ -136,15 +115,9 @@ class SwipeBlock(SubmittingXBlockMixin, StudentViewUserStateMixin, Questionnaire
'block_id'
:
unicode
(
self
.
scope_ids
.
usage_id
),
'display_name'
:
self
.
display_name_with_default
,
'type'
:
self
.
CATEGORY
,
'question'
:
self
.
question
,
'message'
:
self
.
message
,
'text'
:
self
.
text
,
'img_url'
:
self
.
expand_static_url
(
self
.
img_url
),
'choices'
:
[
{
'value'
:
choice
[
'value'
],
'content'
:
choice
[
'display_name'
]}
for
choice
in
self
.
human_readable_choices
],
'weight'
:
self
.
weight
,
'tips'
:
[
tip
.
student_view_data
()
for
tip
in
self
.
get_tips
()],
'correct'
:
self
.
correct
,
}
def
expand_static_url
(
self
,
url
):
...
...
@@ -166,6 +139,18 @@ class SwipeBlock(SubmittingXBlockMixin, StudentViewUserStateMixin, Questionnaire
pass
return
url
@property
def
expanded_img_url
(
self
):
return
self
.
expand_static_url
(
self
.
img_url
)
def
mentoring_view
(
self
,
context
=
None
):
""" Render the swipe image, text & whether it's correct within a mentoring block question. """
return
Fragment
(
(
u'<img src="{img_url}" style="max-width: 100
%
;" />'
u'<p class="swipe-text">"{text}"</p>'
)
.
format
(
img_url
=
self
.
expand_static_url
(
self
.
img_url
),
text
=
self
.
text
,
)
)
def
student_view
(
self
,
context
=
None
):
""" Normal view of this XBlock, identical to mentoring_view """
return
self
.
mentoring_view
(
context
)
problem_builder/templates/html/swipeblock.html
deleted
100644 → 0
View file @
1dc9578a
{% load i18n %}
{% if not hide_header %}
<h4
class=
"question-title"
id=
"heading_{{ self.html_id }}"
>
{{ self.display_name_with_default }}
</h4>
{% endif %}
{% if self.img_url.strip %}
<img
class=
"swipe-img"
src=
"{{ self.expanded_img_url }}"
alt=
""
/>
{% endif %}
<fieldset
class=
"choices questionnaire"
id=
"{{ self.html_id }}"
>
<legend
class=
"question field-group-hd"
>
{{ self.question|safe }}
</legend>
<div
class=
"choices-list"
>
{% for choice in custom_choices %}
<div
class=
"choice"
aria-live=
"polite"
aria-atomic=
"true"
>
<label
class=
"choice-label"
aria-describedby=
"feedback_{{ self.html_id }} choice_tips_{{ self.html_id }}-{{ forloop.counter }}"
>
<span
class=
"choice-result fa icon-2x"
aria-label=
""
data-label_correct=
"{% trans "
Correct
"
%}"
data-label_incorrect=
"{% trans "
Incorrect
"
%}"
></span>
<span
class=
"choice-selector"
>
<input
type=
"radio"
name=
"{{ self.name }}"
value=
"{{ choice.value }}"
{%
if
self
.
student_choice =
=
choice
.
value
and
not
hide_prev_answer
%}
checked
{%
endif
%}
/>
</span>
<span
class=
"choice-label-text"
>
{{ choice.content|safe }}
</span>
</label>
<div
class=
"choice-tips-container"
>
<div
class=
"choice-tips"
id=
"choice_tips_{{ self.html_id }}-{{ forloop.counter }}"
></div>
</div>
</div>
{% endfor %}
<div
class=
"feedback"
id=
"feedback_{{ self.html_id }}"
></div>
</div>
</fieldset>
setup.py
View file @
0d7b18fa
...
...
@@ -72,7 +72,7 @@ BLOCKS = [
setup
(
name
=
'xblock-problem-builder'
,
version
=
'2.7.
9
'
,
version
=
'2.7.
10
'
,
description
=
'XBlock - Problem Builder'
,
packages
=
find_packages
(),
install_requires
=
[
...
...
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