Commit cd689891 by Braden MacDonald Committed by GitHub

Merge pull request #81 from edx-solutions/tim/max-attempts

Add option for limiting number of attempts in assessment mode to Studio editor
parents 3849de48 40037b19
...@@ -97,10 +97,10 @@ and Drop component to a lesson, then click the `EDIT` button. ...@@ -97,10 +97,10 @@ and Drop component to a lesson, then click the `EDIT` button.
![Edit view](/doc/img/edit-view.png) ![Edit view](/doc/img/edit-view.png)
In the first step, you can set some basic properties of the component, In the first step, you can set some basic properties of the component,
such as the title, the maximum score, the problem text to render such as the title, the mode, the maximum number of attempts, the maximum score,
above the background image, the introductory feedback (shown the problem text to render above the background image, the introductory feedback
initially), and the final feedback (shown after the learner (shown initially), and the final feedback (shown after the learner successfully
successfully completes the drag and drop problem). completes the drag and drop problem).
![Drop zone edit](/doc/img/edit-view-zones.png) ![Drop zone edit](/doc/img/edit-view-zones.png)
......
doc/img/edit-view.png

32.2 KB | W: | H:

doc/img/edit-view.png

29.4 KB | W: | H:

doc/img/edit-view.png
doc/img/edit-view.png
doc/img/edit-view.png
doc/img/edit-view.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -10,7 +10,7 @@ import urllib ...@@ -10,7 +10,7 @@ import urllib
from xblock.core import XBlock from xblock.core import XBlock
from xblock.exceptions import JsonHandlerError from xblock.exceptions import JsonHandlerError
from xblock.fields import Scope, String, Dict, Float, Boolean from xblock.fields import Scope, String, Dict, Float, Boolean, Integer
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader from xblockutils.resources import ResourceLoader
from xblockutils.settings import XBlockWithSettingsMixin, ThemableXBlockMixin from xblockutils.settings import XBlockWithSettingsMixin, ThemableXBlockMixin
...@@ -58,6 +58,16 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin): ...@@ -58,6 +58,16 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
default=STANDARD_MODE default=STANDARD_MODE
) )
max_attempts = Integer(
display_name=_("Maximum attempts"),
help=_(
"Defines the number of times a student can try to answer this problem. "
"If the value is not set, infinite attempts are allowed."
),
scope=Scope.settings,
default=None,
)
show_title = Boolean( show_title = Boolean(
display_name=_("Show title"), display_name=_("Show title"),
help=_("Display the title to the learner?"), help=_("Display the title to the learner?"),
...@@ -262,6 +272,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin): ...@@ -262,6 +272,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
def studio_submit(self, submissions, suffix=''): def studio_submit(self, submissions, suffix=''):
self.display_name = submissions['display_name'] self.display_name = submissions['display_name']
self.mode = submissions['mode'] self.mode = submissions['mode']
self.max_attempts = submissions['max_attempts']
self.show_title = submissions['show_title'] self.show_title = submissions['show_title']
self.question_text = submissions['problem_text'] self.question_text = submissions['problem_text']
self.show_question_header = submissions['show_problem_header'] self.show_question_header = submissions['show_problem_header']
......
...@@ -79,6 +79,11 @@ ...@@ -79,6 +79,11 @@
font-size: 100%; font-size: 100%;
} }
.xblock--drag-and-drop--editor .tab .nested-input {
display: block;
margin-top: 8px;
}
.xblock--drag-and-drop--editor .tab-header, .xblock--drag-and-drop--editor .tab-header,
.xblock--drag-and-drop--editor .tab-content, .xblock--drag-and-drop--editor .tab-content,
.xblock--drag-and-drop--editor .tab-footer { .xblock--drag-and-drop--editor .tab-footer {
......
...@@ -64,6 +64,9 @@ function DragAndDropEditBlock(runtime, element, params) { ...@@ -64,6 +64,9 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn.build.$el.targetImage.show(); _fn.build.$el.targetImage.show();
_fn.build.clickHandlers(); _fn.build.clickHandlers();
// Hide settings that are specific to assessment mode
_fn.build.$el.feedback.form.find('#problem-mode').trigger('change');
}, },
validate: function() { validate: function() {
...@@ -171,6 +174,9 @@ function DragAndDropEditBlock(runtime, element, params) { ...@@ -171,6 +174,9 @@ function DragAndDropEditBlock(runtime, element, params) {
}); });
}); });
$fbkTab
.on('change', '#problem-mode', _fn.build.form.problem.toggleAssessmentSettings);
$zoneTab $zoneTab
.on('click', '.add-zone', function(e) { .on('click', '.add-zone', function(e) {
e.preventDefault(); e.preventDefault();
...@@ -220,6 +226,19 @@ function DragAndDropEditBlock(runtime, element, params) { ...@@ -220,6 +226,19 @@ function DragAndDropEditBlock(runtime, element, params) {
.on('input', '.item-image-url', _fn.build.form.item.imageURLChanged); .on('input', '.item-image-url', _fn.build.form.item.imageURLChanged);
}, },
form: { form: {
problem: {
toggleAssessmentSettings: function(e) {
e.preventDefault();
var $modeSetting = $(e.currentTarget),
$problemForm = $modeSetting.parent('form'),
$assessmentSettings = $problemForm.find('.setting.assessment');
if ($modeSetting.val() === 'assessment') {
$assessmentSettings.show();
} else {
$assessmentSettings.hide();
}
}
},
zone: { zone: {
totalZonesCreated: 0, // This counter is used for HTML IDs. Never decremented. totalZonesCreated: 0, // This counter is used for HTML IDs. Never decremented.
zoneObjects: [], zoneObjects: [],
...@@ -488,6 +507,7 @@ function DragAndDropEditBlock(runtime, element, params) { ...@@ -488,6 +507,7 @@ function DragAndDropEditBlock(runtime, element, params) {
var data = { var data = {
'display_name': $element.find('#display-name').val(), 'display_name': $element.find('#display-name').val(),
'mode': $element.find("#problem-mode").val(), 'mode': $element.find("#problem-mode").val(),
'max_attempts': $element.find(".max-attempts").val(),
'show_title': $element.find('.show-title').is(':checked'), 'show_title': $element.find('.show-title').is(':checked'),
'weight': $element.find('#weight').val(), 'weight': $element.find('#weight').val(),
'problem_text': $element.find('#problem-text').val(), 'problem_text': $element.find('#problem-text').val(),
......
...@@ -31,6 +31,15 @@ ...@@ -31,6 +31,15 @@
</select> </select>
<span class="sr">{{ help_texts.mode }}</span> <span class="sr">{{ help_texts.mode }}</span>
<label class="h3 setting assessment" title="{{ help_texts.max_attempts }}">
{% trans "Maximum attempts" %}
<input class="nested-input max-attempts"
type="number"
min="1"
step="1"
{% if self.max_attempts %}value="{{ self.max_attempts }}"{% endif %} />
</label>
<label class="h3" for="weight">{% trans "Maximum score" %}</label> <label class="h3" for="weight">{% trans "Maximum score" %}</label>
<input id="weight" type="number" step="0.1" value="{{ self.weight|unlocalize }}" /> <input id="weight" type="number" step="0.1" value="{{ self.weight|unlocalize }}" />
......
...@@ -103,6 +103,35 @@ msgid "Drag and Drop" ...@@ -103,6 +103,35 @@ msgid "Drag and Drop"
msgstr "" msgstr ""
#: drag_and_drop_v2.py #: drag_and_drop_v2.py
msgid "Mode"
msgstr ""
#: drag_and_drop_v2.py
msgid ""
"Standard mode: the problem provides immediate feedback each time a learner drops an item on a target zone. "
"Assessment mode: the problem provides feedback only after a learner drops all available items on target zones."
msgstr ""
#: drag_and_drop_v2.py
msgid "Standard"
msgstr ""
#: drag_and_drop_v2.py
msgid "Assessment"
msgstr ""
#: drag_and_drop_v2.py
#: templates/html/drag_and_drop_edit.html
msgid "Maximum attempts"
msgstr ""
#: drag_and_drop_v2.py
msgid ""
"Defines the number of times a student can try to answer this problem. "
"If the value is not set, infinite attempts are allowed."
msgstr ""
#: drag_and_drop_v2.py
#: templates/html/drag_and_drop_edit.html #: templates/html/drag_and_drop_edit.html
msgid "Show title" msgid "Show title"
msgstr "" msgstr ""
...@@ -279,6 +308,10 @@ msgid "Problem title" ...@@ -279,6 +308,10 @@ msgid "Problem title"
msgstr "" msgstr ""
#: templates/html/drag_and_drop_edit.html #: templates/html/drag_and_drop_edit.html
msgid "Problem mode"
msgstr ""
#: templates/html/drag_and_drop_edit.html
msgid "Maximum score" msgid "Maximum score"
msgstr "" msgstr ""
......
...@@ -128,6 +128,42 @@ msgid "Drag and Drop" ...@@ -128,6 +128,42 @@ msgid "Drag and Drop"
msgstr "Dräg änd Dröp Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" msgstr "Dräg änd Dröp Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: drag_and_drop_v2.py #: drag_and_drop_v2.py
msgid "Mode"
msgstr "Mödé Ⱡ'σяєм ι#"
#: drag_and_drop_v2.py
msgid ""
"Standard mode: the problem provides immediate feedback each time a learner drops an item on a target zone. "
"Assessment mode: the problem provides feedback only after a learner drops all available items on target zones."
msgstr ""
"Ständärd mödé: thé prößlém prövïdés ïmmédïäté féédßäçk éäçh tïmé ä léärnér dröps än ïtém ön ä tärgét zöné. "
"Àsséssmént mödé: thé prößlém prövïdés féédßäçk önlý äftér ä léärnér dröps äll äväïläßlé ïtéms ön tärgét zönés. "
"Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє "
"мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαт#"
#: drag_and_drop_v2.py
msgid "Standard"
msgstr "Ständärd Ⱡ'σяєм ιρѕυм ∂#"
#: drag_and_drop_v2.py
msgid "Assessment"
msgstr "Àsséssmént Ⱡ'σяєм ιρѕυм ∂σłσ#"
#: drag_and_drop_v2.py
#: templates/html/drag_and_drop_edit.html
msgid "Maximum attempts"
msgstr "Mäxïmüm ättémpts Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
#: drag_and_drop_v2.py
msgid ""
"Defines the number of times a student can try to answer this problem. "
"If the value is not set, infinite attempts are allowed."
msgstr ""
"Défïnés thé nümßér öf tïmés ä stüdént çän trý tö änswér thïs prößlém. "
"Ìf thé välüé ïs nöt sét, ïnfïnïté ättémpts äré ällöwéd. Ⱡ'σяєм #"
#: drag_and_drop_v2.py
msgid "Show title" msgid "Show title"
msgstr "Shöw tïtlé Ⱡ'σяєм ιρѕυм ∂σłσ#" msgstr "Shöw tïtlé Ⱡ'σяєм ιρѕυм ∂σłσ#"
...@@ -339,6 +375,10 @@ msgid "Problem title" ...@@ -339,6 +375,10 @@ msgid "Problem title"
msgstr "Prößlém tïtlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#" msgstr "Prößlém tïtlé Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
#: templates/html/drag_and_drop_edit.html #: templates/html/drag_and_drop_edit.html
msgid "Problem mode"
msgstr "Prößlém mödé Ⱡ'σяєм ιρѕυм ∂σłσя ѕ#"
#: templates/html/drag_and_drop_edit.html
msgid "Show title" msgid "Show title"
msgstr "Shöw tïtlé Ⱡ'σяєм ιρѕυм ∂σłσ#" msgstr "Shöw tïtlé Ⱡ'σяєм ιρѕυм ∂σłσ#"
......
...@@ -109,6 +109,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase): ...@@ -109,6 +109,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
body = { body = {
'display_name': "Test Drag & Drop", 'display_name': "Test Drag & Drop",
'mode': DragAndDropBlock.ASSESSMENT_MODE, 'mode': DragAndDropBlock.ASSESSMENT_MODE,
'max_attempts': 1,
'show_title': False, 'show_title': False,
'problem_text': "Problem Drag & Drop", 'problem_text': "Problem Drag & Drop",
'show_problem_header': False, 'show_problem_header': False,
...@@ -124,6 +125,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase): ...@@ -124,6 +125,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
self.assertEqual(self.block.show_title, False) self.assertEqual(self.block.show_title, False)
self.assertEqual(self.block.mode, DragAndDropBlock.ASSESSMENT_MODE) self.assertEqual(self.block.mode, DragAndDropBlock.ASSESSMENT_MODE)
self.assertEqual(self.block.max_attempts, 1)
self.assertEqual(self.block.display_name, "Test Drag & Drop") self.assertEqual(self.block.display_name, "Test Drag & Drop")
self.assertEqual(self.block.question_text, "Problem Drag & Drop") self.assertEqual(self.block.question_text, "Problem Drag & Drop")
self.assertEqual(self.block.show_question_header, False) self.assertEqual(self.block.show_question_header, False)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment