Commit 2ec7da2b by Braden MacDonald

Merge pull request #54 from open-craft/braden/bugfixes

Various Bug Fixes
parents 7b8b4abb 698f404d
......@@ -6,6 +6,10 @@ TARGET_IMG_DESCRIPTION = _(
"and the narrowest layer is located at the top."
)
TOP_ZONE_ID = "top"
MIDDLE_ZONE_ID = "middle"
BOTTOM_ZONE_ID = "bottom"
TOP_ZONE_TITLE = _("The Top Zone")
MIDDLE_ZONE_TITLE = _("The Middle Zone")
BOTTOM_ZONE_TITLE = _("The Bottom Zone")
......@@ -25,8 +29,7 @@ DEFAULT_DATA = {
"targetImgDescription": TARGET_IMG_DESCRIPTION,
"zones": [
{
"index": 1,
"id": "zone-1",
"uid": TOP_ZONE_ID,
"title": TOP_ZONE_TITLE,
"description": TOP_ZONE_DESCRIPTION,
"x": 160,
......@@ -35,8 +38,7 @@ DEFAULT_DATA = {
"height": 178,
},
{
"index": 2,
"id": "zone-2",
"uid": MIDDLE_ZONE_ID,
"title": MIDDLE_ZONE_TITLE,
"description": MIDDLE_ZONE_DESCRIPTION,
"x": 86,
......@@ -45,8 +47,7 @@ DEFAULT_DATA = {
"height": 138,
},
{
"index": 3,
"id": "zone-3",
"uid": BOTTOM_ZONE_ID,
"title": BOTTOM_ZONE_TITLE,
"description": BOTTOM_ZONE_DESCRIPTION,
"x": 15,
......@@ -62,7 +63,7 @@ DEFAULT_DATA = {
"incorrect": ITEM_INCORRECT_FEEDBACK,
"correct": ITEM_CORRECT_FEEDBACK.format(zone=TOP_ZONE_TITLE)
},
"zone": TOP_ZONE_TITLE,
"zone": TOP_ZONE_ID,
"imageURL": "",
"id": 0,
},
......@@ -72,7 +73,7 @@ DEFAULT_DATA = {
"incorrect": ITEM_INCORRECT_FEEDBACK,
"correct": ITEM_CORRECT_FEEDBACK.format(zone=MIDDLE_ZONE_TITLE)
},
"zone": MIDDLE_ZONE_TITLE,
"zone": MIDDLE_ZONE_ID,
"imageURL": "",
"id": 1,
},
......@@ -82,7 +83,7 @@ DEFAULT_DATA = {
"incorrect": ITEM_INCORRECT_FEEDBACK,
"correct": ITEM_CORRECT_FEEDBACK.format(zone=BOTTOM_ZONE_TITLE)
},
"zone": BOTTOM_ZONE_TITLE,
"zone": BOTTOM_ZONE_ID,
"imageURL": "",
"id": 2,
},
......
......@@ -9,6 +9,7 @@ import copy
import urllib
from xblock.core import XBlock
from xblock.exceptions import JsonHandlerError
from xblock.fields import Scope, String, Dict, Float, Boolean
from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader
......@@ -154,7 +155,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
return items
return {
"zones": self.data.get('zones', []),
"zones": self._get_zones(),
# SDK doesn't supply url_name.
"url_name": getattr(self, 'url_name', ''),
"display_zone_labels": self.data.get('displayLabels', False),
......@@ -234,6 +235,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
item = self._get_item_definition(attempt['val'])
state = None
zone = None
feedback = item['feedback']['incorrect']
overall_feedback = None
is_correct = False
......@@ -268,6 +270,11 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
if state:
self.item_state[str(item['id'])] = state
zone = self._get_zone_by_uid(state['zone'])
else:
zone = self._get_zone_by_uid(attempt['zone'])
if not zone:
raise JsonHandlerError(400, "Item zone data invalid.")
if self._is_finished():
overall_feedback = self.data['feedback']['finish']
......@@ -288,7 +295,8 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
self.runtime.publish(self, 'edx.drag_and_drop_v2.item.dropped', {
'item_id': item['id'],
'location': attempt.get('zone'),
'location': zone.get("title"),
'location_id': zone.get("uid"),
'input': attempt.get('input'),
'is_correct_location': is_correct_location,
'is_correct': is_correct,
......@@ -395,6 +403,30 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
"""
return next(i for i in self.data['items'] if i['id'] == item_id)
def _get_zones(self):
"""
Get drop zone data, defined by the author.
"""
# Convert zone data from old to new format if necessary
zones = []
for zone in self.data.get('zones', []):
zone = zone.copy()
if "uid" not in zone:
zone["uid"] = zone.get("title") # Older versions used title as the zone UID
# Remove old, now-unused zone attributes, if present:
zone.pop("id", None)
zone.pop("index", None)
zones.append(zone)
return zones
def _get_zone_by_uid(self, uid):
"""
Given a zone UID, return that zone, or None.
"""
for zone in self._get_zones():
if zone["uid"] == uid:
return zone
def _get_grade(self):
"""
Returns the student's grade for this block.
......
......@@ -52,6 +52,16 @@ function DragNDropTemplates(url_name) {
);
};
var getZoneTitle = function(zoneUID, ctx) {
// Given the context and a zone UID, return the zone's title
for (var i = 0; i < ctx.zones.length; i++) {
if (ctx.zones[i].uid === zoneUID) {
return ctx.zones[i].title;
}
}
return "Unknown Zone"; // This title should never be seen, so does not need i18n
}
var itemTemplate = function(item, ctx) {
// Define properties
var className = (item.class_name) ? item.class_name : "";
......@@ -119,7 +129,7 @@ function DragNDropTemplates(url_name) {
var item_description = h(
'div',
{ id: item_description_id, className: 'sr' },
gettext('Correctly placed in: ') + item.zone
gettext('Correctly placed in: ') + getZoneTitle(item.zone, ctx)
);
children.splice(1, 0, item_description);
}
......@@ -147,12 +157,12 @@ function DragNDropTemplates(url_name) {
h(
selector,
{
id: zone.id,
id: zone.prefixed_uid,
attributes: {
'tabindex': 0,
'dropzone': 'move',
'aria-dropeffect': 'move',
'data-zone': zone.title,
'data-uid': zone.uid,
'role': 'button',
},
style: {
......@@ -449,7 +459,8 @@ function DragAndDropBlock(runtime, element, configuration) {
delete zone.width;
zone.height_percent = (+zone.height) / bg_image_height * 100;
delete zone.height;
zone.id = configuration.url_name + '-' + zone.id;
// Generate an HTML ID value that's unique within the DOM and not containing spaces etc:
zone.prefixed_uid = configuration.url_name + '-' + zone.uid.replace(/([^\w\-])/g, "_");
}
};
......@@ -582,7 +593,7 @@ function DragAndDropBlock(runtime, element, configuration) {
// so use relevant properties of *zone* when calculating new position below.
$anchor = $zone;
}
var zone = $zone.data('zone');
var zone = String($zone.data('uid'));
var $target_img = $root.find('.target-img');
// Calculate the position of the item to place relative to the image.
......
{% load i18n %}
{% load l10n %}
<div class="xblock--drag-and-drop--editor editor-with-buttons">
{{ js_templates|safe }}
......@@ -21,7 +22,7 @@
</label>
<label class="h3" for="weight">{% trans "Maximum score" %}</label>
<input id="weight" type="number" step="0.1" value="{{ self.weight }}" />
<input id="weight" type="number" step="0.1" value="{{ self.weight|unlocalize }}" />
<label class="h3" for="problem-text">{% trans "Problem text" %}</label>
<textarea id="problem-text">{{ self.question_text }}</textarea>
......
<script id="zone-element-tpl" type="text/html">
<div id="{{ id }}" class="zone" data-zone="{{ title }}" style="
<div class="zone" data-zone="{{ uid }}" style="
top:{{ y_percent }}%;
left:{{ x_percent }}%;
width:{{ width_percent }}%;
......@@ -10,12 +10,13 @@
</script>
<script id="zone-input-tpl" type="text/html">
<div class="zone-row {{ id }}" data-index="{{index}}">
<div class="zone-row" data-uid="{{zone.uid}}">
<!-- uid values from old versions of the block may contain spaces and other characters, so we use 'index' as an alternate unique ID here. -->
<label for="zone-{{index}}-title">{{i18n "Text"}}</label>
<input type="text"
id="zone-{{index}}-title"
class="title"
value="{{ title }}"
value="{{ zone.title }}"
required />
<a href="#" class="remove-zone hidden">
<div class="icon remove"></div>
......@@ -24,7 +25,7 @@
<input type="text"
id="zone-{{index}}-description"
class="description"
value="{{ description }}"
value="{{ zone.description }}"
placeholder="{{i18n 'Describe this zone to non-visual users'}}"
required />
<div class="layout">
......@@ -32,29 +33,29 @@
<input type="text"
id="zone-{{index}}-width"
class="size width"
value="{{ width }}" />
value="{{ zone.width }}" />
<label for="zone-{{index}}-height">{{i18n "height"}}</label>
<input type="text"
id="zone-{{index}}-height"
class="size height"
value="{{ height }}" />
value="{{ zone.height }}" />
<br />
<label for="zone-{{index}}-x">x</label>
<input type="text"
id="zone-{{index}}-x"
class="coord x"
value="{{ x }}" />
value="{{ zone.x }}" />
<label for="zone-{{index}}-y">y</label>
<input type="text"
id="zone-{{index}}-y"
class="coord y"
value="{{ y }}" />
value="{{ zone.y }}" />
</div>
</div>
</script>
<script id="zone-dropdown-tpl" type="text/html">
<option value="{{ value }}" {{ selected }}>{{ value }}</option>
<option value="{{ uid }}" {{ selected }}>{{ title }}</option>
</script>
<script id="item-input-tpl" type="text/html">
......
......@@ -11,6 +11,7 @@ disable=
missing-docstring,
too-many-ancestors,
too-many-arguments,
too-many-branches,
too-many-instance-attributes,
too-few-public-methods,
too-many-public-methods,
......
{
"zones": [
{
"index": 1,
"width": 200,
"title": "Zone 1",
"height": 100,
"y": "200",
"x": "100",
"id": "zone-1"
"uid": "zone-1"
},
{
"index": 2,
"width": 200,
"title": "Zone 2",
"height": 100,
"y": 0,
"x": 0,
"id": "zone-2"
"uid": "zone-2"
}
],
"items": [
......@@ -26,7 +24,7 @@
"incorrect": "No 1",
"correct": "Yes 1"
},
"zone": "Zone 1",
"zone": "zone-1",
"imageURL": "",
"id": 0
},
......@@ -36,7 +34,7 @@
"incorrect": "No 2",
"correct": "Yes 2"
},
"zone": "Zone 2",
"zone": "zone-2",
"imageURL": "",
"id": 1,
"inputOptions": {
......
{
"zones": [
{
"index": 1,
"title": "Zone 1",
"description": "This describes zone 1",
"height": 178,
"width": 196,
"y": "30",
"x": "160",
"id": "zone-1"
"id": "the deprecated id attribute is ignored."
},
{
"index": 2,
"title": "Zone 2",
"description": "This describes zone 2",
"height": 140,
"width": 340,
"y": "210",
"x": "86",
"id": "zone-2"
}
],
"items": [
......
{
"zones": [
{
"index": 1,
"width": 200,
"title": "Zone 51",
"height": 100,
"y": "400",
"x": "200",
"id": "zone-51"
"uid": "zone-51"
},
{
"index": 2,
"width": 200,
"title": "Zone 52",
"height": 100,
"y": "200",
"x": "100",
"id": "zone-52"
"uid": "zone-52"
}
],
"items": [
......@@ -26,7 +24,7 @@
"incorrect": "Incorrect 1",
"correct": "Correct 1"
},
"zone": "Zone 51",
"zone": "zone-51",
"imageURL": "",
"id": 10
},
......@@ -36,7 +34,7 @@
"incorrect": "Incorrect 2",
"correct": "Correct 2"
},
"zone": "Zone 52",
"zone": "zone-52",
"imageURL": "",
"id": 20,
"inputOptions": {
......
{
"zones": [
{
"index": 1,
"width": 200,
"title": "Zone <i>1</i>",
"height": 100,
"y": 200,
"x": 100,
"id": "zone-1"
"uid": "zone-1"
},
{
"index": 2,
"width": 200,
"title": "Zone <b>2</b>",
"height": 100,
"y": 0,
"x": 0,
"id": "zone-2"
"uid": "zone-2"
}
],
"items": [
......@@ -26,7 +24,7 @@
"incorrect": "No <b>1</b>",
"correct": "Yes <b>1</b>"
},
"zone": "Zone <i>1</i>",
"zone": "zone-1",
"imageURL": "",
"id": 0
},
......@@ -36,7 +34,7 @@
"incorrect": "No <i>2</i>",
"correct": "Yes <i>2</i>"
},
"zone": "Zone <b>2</b>",
"zone": "zone-2",
"imageURL": "",
"id": 1,
"inputOptions": {
......
......@@ -2,16 +2,16 @@
{% if img == "wide" %}
"targetImg": "{{img_wide_url}}",
"zones": [
{"index": 1, "title": "Zone 1/3", "width": 533, "height": 200, "x": "0", "y": "0", "id": "zone-1"},
{"index": 2, "title": "Zone 50%", "width": 800, "height": 200, "x": "0", "y": "350", "id": "zone-2"},
{"index": 3, "title": "Zone 75%", "width": 1200, "height": 200, "x": "0", "y": "700", "id": "zone-3"}
{"title": "Zone 1/3", "width": 533, "height": 200, "x": "0", "y": "0"},
{"title": "Zone 50%", "width": 800, "height": 200, "x": "0", "y": "350"},
{"title": "Zone 75%", "width": 1200, "height": 200, "x": "0", "y": "700"}
],
{% else %}
"targetImg": "{{img_square_url}}",
"zones": [
{"index": 1, "title": "Zone 1/3", "width": 166, "height": 100, "x": "0", "y": "0", "id": "zone-1"},
{"index": 2, "title": "Zone 50%", "width": 250, "height": 100, "x": "0", "y": "200", "id": "zone-2"},
{"index": 3, "title": "Zone 75%", "width": 375, "height": 100, "x": "0", "y": "400", "id": "zone-3"}
{"title": "Zone 1/3", "width": 166, "height": 100, "x": "0", "y": "0"},
{"title": "Zone 50%", "width": 250, "height": 100, "x": "0", "y": "200"},
{"title": "Zone 75%", "width": 375, "height": 100, "x": "0", "y": "400"}
],
{% endif %}
"displayBorders": true,
......
......@@ -11,6 +11,7 @@ from workbench.runtime import WorkbenchRuntime
from xblockutils.resources import ResourceLoader
from drag_and_drop_v2.default_data import (
TOP_ZONE_ID, MIDDLE_ZONE_ID, BOTTOM_ZONE_ID,
TOP_ZONE_TITLE, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_TITLE,
ITEM_CORRECT_FEEDBACK, ITEM_INCORRECT_FEEDBACK, ITEM_NO_ZONE_FEEDBACK,
START_FEEDBACK, FINISH_FEEDBACK
......@@ -26,10 +27,11 @@ loader = ResourceLoader(__name__)
# Classes ###########################################################
class ItemDefinition(object):
def __init__(self, item_id, zone_id, feedback_positive, feedback_negative, input_value=None):
def __init__(self, item_id, zone_id, zone_title, feedback_positive, feedback_negative, input_value=None):
self.feedback_negative = feedback_negative
self.feedback_positive = feedback_positive
self.zone_id = zone_id
self.zone_title = zone_title
self.item_id = item_id
self.input = input_value
......@@ -73,7 +75,7 @@ class InteractionTestBase(object):
def _get_zone_by_id(self, zone_id):
zones_container = self._page.find_element_by_css_selector('.target')
return zones_container.find_elements_by_xpath(".//div[@data-zone='{zone_id}']".format(zone_id=zone_id))[0]
return zones_container.find_elements_by_xpath(".//div[@data-uid='{zone_id}']".format(zone_id=zone_id))[0]
def _get_input_div_by_value(self, item_value):
element = self._get_item_by_value(item_value)
......@@ -89,7 +91,7 @@ class InteractionTestBase(object):
def _get_zone_position(self, zone_id):
return self.browser.execute_script(
'return $("div[data-zone=\'{zone_id}\']").prevAll(".zone").length'.format(zone_id=zone_id)
'return $("div[data-uid=\'{zone_id}\']").prevAll(".zone").length'.format(zone_id=zone_id)
)
def place_item(self, item_value, zone_id, action_key=None):
......@@ -126,7 +128,7 @@ class InteractionTestBase(object):
def assert_grabbed_item(self, item):
self.assertEqual(item.get_attribute('aria-grabbed'), 'true')
def assert_placed_item(self, item_value, zone_id):
def assert_placed_item(self, item_value, zone_title):
item = self._get_placed_item_by_value(item_value)
self.wait_until_visible(item)
item_content = item.find_element_by_css_selector('.item-content')
......@@ -138,7 +140,7 @@ class InteractionTestBase(object):
self.assertEqual(item.get_attribute('data-drag-disabled'), 'true')
self.assertEqual(item_content.get_attribute('aria-describedby'), item_description_id)
self.assertEqual(item_description.get_attribute('id'), item_description_id)
self.assertEqual(item_description.text, 'Correctly placed in: {}'.format(zone_id))
self.assertEqual(item_description.text, 'Correctly placed in: {}'.format(zone_title))
def assert_reverted_item(self, item_value):
item = self._get_item_by_value(item_value)
......@@ -180,7 +182,7 @@ class InteractionTestBase(object):
self.place_item(definition.item_id, definition.zone_id, action_key)
self.wait_until_html_in(definition.feedback_positive, feedback_popup_content)
self.assertEqual(popup.get_attribute('class'), 'popup')
self.assert_placed_item(definition.item_id, definition.zone_id)
self.assert_placed_item(definition.item_id, definition.zone_title)
def parameterized_item_positive_feedback_on_good_input(self, items_map, scroll_down=100, action_key=None):
popup = self._get_popup()
......@@ -195,7 +197,7 @@ class InteractionTestBase(object):
self.send_input(definition.item_id, definition.input)
self.wait_until_html_in(definition.feedback_positive, feedback_popup_content)
self.assertEqual(popup.get_attribute('class'), 'popup')
self.assert_placed_item(definition.item_id, definition.zone_id)
self.assert_placed_item(definition.item_id, definition.zone_title)
input_div = self._get_input_div_by_value(definition.item_id)
self.wait_until_has_class('correct', input_div)
......@@ -228,7 +230,7 @@ class InteractionTestBase(object):
self.send_input(definition.item_id, '1999999')
self.wait_until_html_in(definition.feedback_negative, feedback_popup_content)
self.assertEqual(popup.get_attribute('class'), 'popup popup-incorrect')
self.assert_placed_item(definition.item_id, definition.zone_id)
self.assert_placed_item(definition.item_id, definition.zone_title)
input_div = self._get_input_div_by_value(definition.item_id)
self.wait_until_has_class('incorrect', input_div)
......@@ -252,7 +254,7 @@ class InteractionTestBase(object):
self.send_input(item_key, definition.input)
input_div = self._get_input_div_by_value(item_key)
self.wait_until_has_class('correct', input_div)
self.assert_placed_item(definition.item_id, definition.zone_id)
self.assert_placed_item(definition.item_id, definition.zone_title)
self.wait_until_html_in(feedback['final'], self._get_feedback_message())
......@@ -326,18 +328,21 @@ class DefaultDataTestMixin(object):
items_map = {
0: ItemDefinition(
0, TOP_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=TOP_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
0, TOP_ZONE_ID, TOP_ZONE_TITLE,
ITEM_CORRECT_FEEDBACK.format(zone=TOP_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
),
1: ItemDefinition(
1, MIDDLE_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=MIDDLE_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
1, MIDDLE_ZONE_ID, MIDDLE_ZONE_TITLE,
ITEM_CORRECT_FEEDBACK.format(zone=MIDDLE_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
),
2: ItemDefinition(
2, BOTTOM_ZONE_TITLE, ITEM_CORRECT_FEEDBACK.format(zone=BOTTOM_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
2, BOTTOM_ZONE_ID, BOTTOM_ZONE_TITLE,
ITEM_CORRECT_FEEDBACK.format(zone=BOTTOM_ZONE_TITLE), ITEM_INCORRECT_FEEDBACK
),
3: ItemDefinition(3, None, "", ITEM_NO_ZONE_FEEDBACK),
3: ItemDefinition(3, None, None, "", ITEM_NO_ZONE_FEEDBACK),
}
all_zones = [TOP_ZONE_TITLE, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_TITLE]
all_zones = [TOP_ZONE_ID, MIDDLE_ZONE_ID, BOTTOM_ZONE_ID]
feedback = {
"intro": START_FEEDBACK,
......@@ -398,6 +403,7 @@ class EventsFiredTest(DefaultDataTestMixin, InteractionTestBase, BaseIntegration
'is_correct_location': True,
'item_id': 0,
'location': TOP_ZONE_TITLE,
'location_id': TOP_ZONE_ID,
},
},
{
......@@ -467,12 +473,12 @@ class KeyboardInteractionTest(BasicInteractionTest, BaseIntegrationTest):
class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
items_map = {
0: ItemDefinition(0, 'Zone 1', "Yes 1", "No 1"),
1: ItemDefinition(1, 'Zone 2', "Yes 2", "No 2", "102"),
2: ItemDefinition(2, None, "", "No Zone for this")
0: ItemDefinition(0, 'zone-1', "Zone 1", "Yes 1", "No 1"),
1: ItemDefinition(1, 'zone-2', "Zone 2", "Yes 2", "No 2", "102"),
2: ItemDefinition(2, None, None, "", "No Zone for this")
}
all_zones = ['Zone 1', 'Zone 2']
all_zones = ['zone-1', 'zone-2']
feedback = {
"intro": "Some Intro Feed",
......@@ -485,12 +491,12 @@ class CustomDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
class CustomHtmlDataInteractionTest(BasicInteractionTest, BaseIntegrationTest):
items_map = {
0: ItemDefinition(0, 'Zone <i>1</i>', "Yes <b>1</b>", "No <b>1</b>"),
1: ItemDefinition(1, 'Zone <b>2</b>', "Yes <i>2</i>", "No <i>2</i>", "95"),
2: ItemDefinition(2, None, "", "No Zone for <i>X</i>")
0: ItemDefinition(0, 'zone-1', 'Zone <i>1</i>', "Yes <b>1</b>", "No <b>1</b>"),
1: ItemDefinition(1, 'zone-2', 'Zone <b>2</b>', "Yes <i>2</i>", "No <i>2</i>", "95"),
2: ItemDefinition(2, None, None, "", "No Zone for <i>X</i>")
}
all_zones = ['Zone <i>1</i>', 'Zone <b>2</b>']
all_zones = ['zone-1', 'zone-2']
feedback = {
"intro": "Intro <i>Feed</i>",
......@@ -510,20 +516,20 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
item_maps = {
'block1': {
0: ItemDefinition(0, 'Zone 1', "Yes 1", "No 1"),
1: ItemDefinition(1, 'Zone 2', "Yes 2", "No 2", "102"),
2: ItemDefinition(2, None, "", "No Zone for this")
0: ItemDefinition(0, 'zone-1', 'Zone 1', "Yes 1", "No 1"),
1: ItemDefinition(1, 'zone-2', 'Zone 2', "Yes 2", "No 2", "102"),
2: ItemDefinition(2, None, None, "", "No Zone for this")
},
'block2': {
10: ItemDefinition(10, 'Zone 51', "Correct 1", "Incorrect 1"),
20: ItemDefinition(20, 'Zone 52', "Correct 2", "Incorrect 2", "102"),
30: ItemDefinition(30, None, "", "No Zone for this")
10: ItemDefinition(10, 'zone-51', 'Zone 51', "Correct 1", "Incorrect 1"),
20: ItemDefinition(20, 'zone-52', 'Zone 52', "Correct 2", "Incorrect 2", "102"),
30: ItemDefinition(30, None, None, "", "No Zone for this")
},
}
all_zones = {
'block1': ['Zone 1', 'Zone 2'],
'block2': ['Zone 51', 'Zone 52']
'block1': ['zone-1', 'zone-2'],
'block2': ['zone-51', 'zone-52']
}
feedback = {
......
......@@ -187,11 +187,11 @@ class TestDragAndDropRender(BaseIntegrationTest):
self.assertEqual(zone.get_attribute('tabindex'), '0')
self.assertEqual(zone.get_attribute('dropzone'), 'move')
self.assertEqual(zone.get_attribute('aria-dropeffect'), 'move')
self.assertEqual(zone.get_attribute('data-zone'), 'Zone {}'.format(zone_number))
self.assertEqual(zone.get_attribute('data-uid'), 'Zone {}'.format(zone_number))
self.assertIn('ui-droppable', self.get_element_classes(zone))
zone_box_percentages = box_percentages[index]
self._assert_box_percentages( # pylint: disable=star-args
'#-zone-{}'.format(zone_number), **zone_box_percentages
'#-Zone_{}'.format(zone_number), **zone_box_percentages
)
zone_name = zone.find_element_by_css_selector('p.zone-name')
self.assertEqual(zone_name.text, 'Zone {}'.format(zone_number))
......@@ -244,7 +244,7 @@ class TestDragAndDropRender(BaseIntegrationTest):
self.load_scenario()
zones = self._get_zones()
for index, dummy in enumerate(zones, start=1):
zone = '#-zone-{}'.format(index)
zone = '#-Zone_{}'.format(index)
for side in self.SIDES:
self.assertEqual(self._get_style(zone, 'border{}Width'.format(side), True), '0px')
self.assertEqual(self._get_style(zone, 'border{}Style'.format(side), True), 'none')
......@@ -253,7 +253,7 @@ class TestDragAndDropRender(BaseIntegrationTest):
self.load_scenario(zone_borders=True)
zones = self._get_zones()
for index, dummy in enumerate(zones, start=1):
zone = '#-zone-{}'.format(index)
zone = '#-Zone_{}'.format(index)
for side in self.SIDES:
self.assertEqual(self._get_style(zone, 'border{}Width'.format(side), True), '1px')
self.assertEqual(self._get_style(zone, 'border{}Style'.format(side), True), 'dotted')
......
......@@ -14,22 +14,20 @@
"zones": [
{
"index": 1,
"title": "Zone <i>1</i>",
"x": 100,
"y": 200,
"width": 200,
"height": 100,
"id": "zone-1"
"uid": "Zone <i>1</i>"
},
{
"index": 2,
"title": "Zone <b>2</b>",
"x": 0,
"y": 0,
"width": 200,
"height": 100,
"id": "zone-2"
"uid": "Zone <b>2</b>"
}
],
......
......@@ -14,22 +14,20 @@
"zones": [
{
"index": 1,
"title": "Zone 1",
"x": "100",
"y": "200",
"width": 200,
"height": 100,
"id": "zone-1"
"uid": "Zone 1"
},
{
"index": 2,
"title": "Zone 2",
"x": 0,
"y": 0,
"width": 200,
"height": 100,
"id": "zone-2"
"uid": "Zone 2"
}
],
......
......@@ -14,22 +14,20 @@
"zones": [
{
"index": 1,
"title": "Zone 1",
"y": 123,
"x": 234,
"width": 345,
"height": 456,
"id": "zone-1"
"uid": "zone-1"
},
{
"index": 2,
"title": "Zone 2",
"y": 20,
"x": 10,
"width": 30,
"height": 40,
"id": "zone-2"
"uid": "zone-2"
}
],
......
{
"zones": [
{
"index": 1,
"title": "Zone 1",
"y": 123,
"x": 234,
"width": 345,
"height": 456,
"id": "zone-1"
"uid": "zone-1"
},
{
"index": 2,
"title": "Zone 2",
"y": 20,
"x": 10,
"width": 30,
"height": 40,
"id": "zone-2"
"uid": "zone-2"
}
],
......@@ -28,7 +26,7 @@
"incorrect": "No 1",
"correct": "Yes 1"
},
"zone": "Zone 1",
"zone": "zone-1",
"imageURL": "",
"id": 0
},
......@@ -38,7 +36,7 @@
"incorrect": "No 2",
"correct": "Yes 2"
},
"zone": "Zone 2",
"zone": "zone-2",
"imageURL": "",
"id": 1,
"inputOptions": {
......
......@@ -248,8 +248,8 @@ class TestDragAndDropHtmlData(BaseDragAndDropAjaxFixture, unittest.TestCase):
class TestDragAndDropPlainData(BaseDragAndDropAjaxFixture, unittest.TestCase):
FOLDER = "plain"
ZONE_1 = "Zone 1"
ZONE_2 = "Zone 2"
ZONE_1 = "zone-1"
ZONE_2 = "zone-2"
FEEDBACK = {
0: {"correct": "Yes 1", "incorrect": "No 1"},
......@@ -266,3 +266,6 @@ class TestOldDataFormat(TestDragAndDropPlainData):
"""
FOLDER = "old"
FINAL_FEEDBACK = "Final Feed"
ZONE_1 = "Zone 1"
ZONE_2 = "Zone 2"
import unittest
from drag_and_drop_v2.default_data import (
TARGET_IMG_DESCRIPTION, TOP_ZONE_TITLE, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_TITLE,
TARGET_IMG_DESCRIPTION, TOP_ZONE_ID, MIDDLE_ZONE_ID, BOTTOM_ZONE_ID,
START_FEEDBACK, FINISH_FEEDBACK, DEFAULT_DATA
)
from ..utils import make_block, TestCaseMixin
......@@ -65,25 +65,25 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
assert_user_state_empty()
# Drag three items into the correct spot:
data = {"val": 0, "zone": TOP_ZONE_TITLE, "x_percent": "33%", "y_percent": "11%"}
data = {"val": 0, "zone": TOP_ZONE_ID, "x_percent": "33%", "y_percent": "11%"}
self.call_handler('do_attempt', data)
data = {"val": 1, "zone": MIDDLE_ZONE_TITLE, "x_percent": "67%", "y_percent": "80%"}
data = {"val": 1, "zone": MIDDLE_ZONE_ID, "x_percent": "67%", "y_percent": "80%"}
self.call_handler('do_attempt', data)
data = {"val": 2, "zone": BOTTOM_ZONE_TITLE, "x_percent": "99%", "y_percent": "95%"}
data = {"val": 2, "zone": BOTTOM_ZONE_ID, "x_percent": "99%", "y_percent": "95%"}
self.call_handler('do_attempt', data)
# Check the result:
self.assertTrue(self.block.completed)
self.assertEqual(self.block.item_state, {
'0': {'x_percent': '33%', 'y_percent': '11%', 'zone': TOP_ZONE_TITLE},
'1': {'x_percent': '67%', 'y_percent': '80%', 'zone': MIDDLE_ZONE_TITLE},
'2': {'x_percent': '99%', 'y_percent': '95%', 'zone': BOTTOM_ZONE_TITLE},
'0': {'x_percent': '33%', 'y_percent': '11%', 'zone': TOP_ZONE_ID},
'1': {'x_percent': '67%', 'y_percent': '80%', 'zone': MIDDLE_ZONE_ID},
'2': {'x_percent': '99%', 'y_percent': '95%', 'zone': BOTTOM_ZONE_ID},
})
self.assertEqual(self.call_handler('get_user_state'), {
'items': {
'0': {'x_percent': '33%', 'y_percent': '11%', 'correct_input': True, 'zone': TOP_ZONE_TITLE},
'1': {'x_percent': '67%', 'y_percent': '80%', 'correct_input': True, 'zone': MIDDLE_ZONE_TITLE},
'2': {'x_percent': '99%', 'y_percent': '95%', 'correct_input': True, 'zone': BOTTOM_ZONE_TITLE},
'0': {'x_percent': '33%', 'y_percent': '11%', 'correct_input': True, 'zone': TOP_ZONE_ID},
'1': {'x_percent': '67%', 'y_percent': '80%', 'correct_input': True, 'zone': MIDDLE_ZONE_ID},
'2': {'x_percent': '99%', 'y_percent': '95%', 'correct_input': True, 'zone': BOTTOM_ZONE_ID},
},
'finished': True,
'overall_feedback': FINISH_FEEDBACK,
......
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