Commit 97c5c4d8 by Matjaz Gregoric

Keep items in dropped position in assessment mode.

Items dropped onto wrong zones in standard mode are immediately removed
from the board and sent back to the bank.

In assessment mode, items should stick in the dropped position until the
entire problem is explicitly submitted by clicking a button.

This commit only implements the "stick" part, but does not implement the
submit button and associated handler.

This commit also fixes an existing bug where the template function
would gett reused between blocks.

The template function (which is slightly different for each block,
depending on block's configuration) was getting assigned to the global
DragAndDropBlock function. Each block would overwrite the previous
value, which caused bugs.
parent cd689891
......@@ -190,6 +190,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
return items
return {
"mode": self.mode,
"zones": self._get_zones(),
# SDK doesn't supply url_name.
"url_name": getattr(self, 'url_name', ''),
......@@ -337,12 +338,18 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
'is_correct': is_correct,
})
return {
'correct': is_correct,
'finished': self._is_finished(),
'overall_feedback': overall_feedback,
'feedback': feedback
}
if self.mode == self.ASSESSMENT_MODE:
# In assessment mode we don't send any feedback on drop.
result = {}
else:
result = {
'correct': is_correct,
'finished': self._is_finished(),
'overall_feedback': overall_feedback,
'feedback': feedback
}
return result
@XBlock.json_handler
def reset(self, data, suffix=''):
......
function DragNDropTemplates(url_name) {
function DragAndDropTemplates(configuration) {
"use strict";
var h = virtualDom.h;
// Set up a mock for gettext if it isn't available in the client runtime:
......@@ -107,13 +107,22 @@ function DragNDropTemplates(url_name) {
var item_content = h('div', { innerHTML: item_content_html, className: "item-content" });
if (item.is_placed) {
// Insert information about zone in which this item has been placed
var item_description_id = url_name + '-item-' + item.value + '-description';
var item_description_id = configuration.url_name + '-item-' + item.value + '-description';
item_content.properties.attributes = { 'aria-describedby': item_description_id };
var zone_title = (zone.title || "Unknown Zone"); // This "Unknown" text should never be seen, so does not need i18n
var description_content;
if (configuration.mode === DragAndDropBlock.ASSESSMENT_MODE) {
// In assessment mode placed items will "stick" even when not in correct zone.
description_content = gettext('Placed in: {zone_title}').replace('{zone_title}', zone_title);
} else {
// In standard mode item is immediately returned back to the bank if dropped on a wrong zone,
// so all placed items are always in the correct zone.
description_content = gettext('Correctly placed in: {zone_title}').replace('{zone_title}', zone_title);
}
var item_description = h(
'div',
{ id: item_description_id, className: 'sr' },
gettext('Correctly placed in: ') + zone_title
description_content
);
children.splice(1, 0, item_description);
}
......@@ -283,14 +292,17 @@ function DragNDropTemplates(url_name) {
);
};
DragAndDropBlock.renderView = mainTemplate;
return mainTemplate;
}
function DragAndDropBlock(runtime, element, configuration) {
"use strict";
DragNDropTemplates(configuration.url_name);
DragAndDropBlock.STANDARD_MODE = 'standard';
DragAndDropBlock.ASSESSMENT_MODE = 'assessment';
var renderView = DragAndDropTemplates(configuration);
// Set up a mock for gettext if it isn't available in the client runtime:
if (!window.gettext) { window.gettext = function gettext_stub(string) { return string; }; }
......@@ -747,17 +759,21 @@ function DragAndDropBlock(runtime, element, configuration) {
$.post(url, JSON.stringify(data), 'json')
.done(function(data){
state.last_action_correct = data.correct;
if (data.correct) {
state.items[item_id].correct = true;
state.items[item_id].submitting_location = false;
} else {
delete state.items[item_id];
}
state.feedback = data.feedback;
if (data.finished) {
state.finished = true;
state.overall_feedback = data.overall_feedback;
state.items[item_id].submitting_location = false;
// In standard mode we immediately return item to the bank if dropped on wrong zone.
// In assessment mode we leave it in the chosen zone until explicit answer submission.
if (configuration.mode === DragAndDropBlock.STANDARD_MODE) {
state.last_action_correct = data.correct;
if (data.correct) {
state.items[item_id].correct = true;
} else {
delete state.items[item_id];
}
state.feedback = data.feedback;
if (data.finished) {
state.finished = true;
state.overall_feedback = data.overall_feedback;
}
}
applyState();
})
......@@ -866,7 +882,7 @@ function DragAndDropBlock(runtime, element, configuration) {
display_reset_button: Object.keys(state.items).length > 0,
};
return DragAndDropBlock.renderView(context);
return renderView(context);
};
/**
......
......@@ -409,6 +409,10 @@ msgid "ok"
msgstr ""
#: public/js/drag_and_drop.js
msgid "Placed in: "
msgstr ""
#: public/js/drag_and_drop.js
msgid "Correctly placed in: "
msgstr ""
......
......@@ -494,6 +494,10 @@ msgid "ok"
msgstr "ök Ⱡ'σя#"
#: public/js/drag_and_drop.js
msgid "Placed in: "
msgstr "Pläçéd ïn: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
#: public/js/drag_and_drop.js
msgid "Correctly placed in: "
msgstr "Çörréçtlý pläçéd ïn: Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
......
{
"title": "DnDv2 XBlock with HTML instructions",
"mode": "standard",
"show_title": false,
"problem_text": "Solve this <strong>drag-and-drop</strong> problem.",
"show_problem_header": false,
......
{
"title": "Drag and Drop",
"mode": "standard",
"show_title": true,
"problem_text": "",
"show_problem_header": true,
......
{
"title": "DnDv2 XBlock with plain text instructions",
"mode": "standard",
"show_title": true,
"problem_text": "Can you solve this drag-and-drop problem?",
"show_problem_header": true,
......
......@@ -5,6 +5,8 @@ import unittest
from xblockutils.resources import ResourceLoader
from drag_and_drop_v2.drag_and_drop_v2 import DragAndDropBlock
from ..utils import make_block, TestCaseMixin
......@@ -90,6 +92,14 @@ class BaseDragAndDropAjaxFixture(TestCaseMixin):
"feedback": self.FEEDBACK[item_id]["correct"]
})
def test_do_attempt_in_assessment_mode(self):
self.block.mode = DragAndDropBlock.ASSESSMENT_MODE
item_id, zone_id = 0, self.ZONE_1
data = {"val": item_id, "zone": zone_id, "x_percent": "33%", "y_percent": "11%"}
res = self.call_handler('do_attempt', data)
# In assessment mode, the do_attempt doesn't return any data.
self.assertEqual(res, {})
def test_grading(self):
published_grades = []
......
......@@ -30,6 +30,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
zones = config.pop("zones")
items = config.pop("items")
self.assertEqual(config, {
"mode": DragAndDropBlock.STANDARD_MODE,
"display_zone_borders": False,
"display_zone_labels": False,
"title": "Drag and Drop",
......
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