Skip to content

Commit

Permalink
Dropping item into the same zone no longer causes error popup to be s…
Browse files Browse the repository at this point in the history
…hown
  • Loading branch information
E. Kolpakov committed Aug 30, 2016
1 parent 4877cec commit 48f4fea
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 33 deletions.
22 changes: 10 additions & 12 deletions drag_and_drop_v2/drag_and_drop_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from xblockutils.resources import ResourceLoader
from xblockutils.settings import XBlockWithSettingsMixin, ThemableXBlockMixin

from .utils import _, DummyTranslationService, FeedbackMessage, FeedbackMessages, ItemStats, StateMigration
from .utils import _, DummyTranslationService, FeedbackMessage, FeedbackMessages, ItemStats, StateMigration, Constants
from .default_data import DEFAULT_DATA


Expand All @@ -35,8 +35,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
"""
XBlock that implements a friendly Drag-and-Drop problem
"""
STANDARD_MODE = "standard"
ASSESSMENT_MODE = "assessment"

SOLUTION_CORRECT = "correct"
SOLUTION_PARTIAL = "partial"
Expand Down Expand Up @@ -71,10 +69,10 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
),
scope=Scope.settings,
values=[
{"display_name": _("Standard"), "value": STANDARD_MODE},
{"display_name": _("Assessment"), "value": ASSESSMENT_MODE},
{"display_name": _("Standard"), "value": Constants.STANDARD_MODE},
{"display_name": _("Assessment"), "value": Constants.ASSESSMENT_MODE},
],
default=STANDARD_MODE
default=Constants.STANDARD_MODE
)

max_attempts = Integer(
Expand Down Expand Up @@ -372,9 +370,9 @@ def drop_item(self, item_attempt, suffix=''):
"""
self._validate_drop_item(item_attempt)

if self.mode == self.ASSESSMENT_MODE:
if self.mode == Constants.ASSESSMENT_MODE:
return self._drop_item_assessment(item_attempt)
elif self.mode == self.STANDARD_MODE:
elif self.mode == Constants.STANDARD_MODE:
return self._drop_item_standard(item_attempt)
else:
raise JsonHandlerError(
Expand Down Expand Up @@ -478,7 +476,7 @@ def _validate_do_attempt(self):
"""
Validates if `do_attempt` handler should be executed
"""
if self.mode != self.ASSESSMENT_MODE:
if self.mode != Constants.ASSESSMENT_MODE:
raise JsonHandlerError(
400,
self.i18n_service.gettext("do_attempt handler should only be called for assessment mode")
Expand All @@ -496,7 +494,7 @@ def _get_feedback(self):
answer_correctness = self._answer_correctness()
is_correct = answer_correctness == self.SOLUTION_CORRECT

if self.mode == self.STANDARD_MODE or not self.attempts:
if self.mode == Constants.STANDARD_MODE or not self.attempts:
feedback_key = 'finish' if is_correct else 'start'
return [FeedbackMessage(self.data['feedback'][feedback_key], None)], set()

Expand Down Expand Up @@ -698,11 +696,11 @@ def _get_user_state(self):
# In assessment mode, if item is placed correctly and than the page is refreshed, "correct"
# will spill to the frontend, making item "disabled", thus allowing students to obtain answer by trial
# and error + refreshing the page. In order to avoid that, we remove "correct" from an item here
if self.mode == self.ASSESSMENT_MODE:
if self.mode == Constants.ASSESSMENT_MODE:
del item["correct"]

overall_feedback_msgs, __ = self._get_feedback()
if self.mode == self.STANDARD_MODE:
if self.mode == Constants.STANDARD_MODE:
is_finished = self._is_answer_correct()
else:
is_finished = not self.attempts_remain
Expand Down
9 changes: 5 additions & 4 deletions drag_and_drop_v2/public/js/drag_and_drop.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ function DragAndDropBlock(runtime, element, configuration) {
var zone = String($zone.data('uid'));
var zone_align = $zone.data('zone_align');

var items_in_zone_count = countItemsInZone(zone);
var items_in_zone_count = countItemsInZone(zone, [item_id.toString()]);
if (configuration.max_items_per_zone && configuration.max_items_per_zone <= items_in_zone_count) {
state.last_action_correct = false;
state.feedback = gettext("You cannot add any more items to this zone.");
Expand All @@ -770,9 +770,10 @@ function DragAndDropBlock(runtime, element, configuration) {
}, 0);
};

var countItemsInZone = function(zone) {
return Object.keys(state.items).filter(function(key) {
return state.items[key].zone === zone;
var countItemsInZone = function(zone, exclude_ids) {
var ids_to_exclude = exclude_ids ? exclude_ids : [];
return Object.keys(state.items).filter(function(item_id) {
return state.items[item_id].zone === zone && $.inArray(item_id, ids_to_exclude) === -1;
}).length;
};

Expand Down
3 changes: 3 additions & 0 deletions drag_and_drop_v2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class Constants(object):
ALLOWED_ZONE_ALIGNMENTS = ['left', 'right', 'center']
DEFAULT_ZONE_ALIGNMENT = 'center'

STANDARD_MODE = "standard"
ASSESSMENT_MODE = "assessment"


class StateMigration(object):
"""
Expand Down
6 changes: 5 additions & 1 deletion tests/integration/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from xblockutils.base_test import SeleniumBaseTest

from drag_and_drop_v2.utils import Constants

from drag_and_drop_v2.default_data import (
DEFAULT_DATA, START_FEEDBACK, FINISH_FEEDBACK,
TOP_ZONE_ID, TOP_ZONE_TITLE, MIDDLE_ZONE_ID, MIDDLE_ZONE_TITLE, BOTTOM_ZONE_ID, BOTTOM_ZONE_TITLE,
Expand Down Expand Up @@ -49,7 +51,7 @@ class BaseIntegrationTest(SeleniumBaseTest):
@classmethod
def _make_scenario_xml(
cls, display_name="Test DnDv2", show_title=True, problem_text="Question", completed=False,
show_problem_header=True, max_items_per_zone=0, data=None
show_problem_header=True, max_items_per_zone=0, data=None, mode=Constants.STANDARD_MODE
):
if not data:
data = json.dumps(DEFAULT_DATA)
Expand All @@ -63,6 +65,7 @@ def _make_scenario_xml(
weight='1'
completed='{completed}'
max_items_per_zone='{max_items_per_zone}'
mode='{mode}'
data='{data}'
/>
</vertical_demo>
Expand All @@ -73,6 +76,7 @@ def _make_scenario_xml(
show_problem_header=show_problem_header,
completed=completed,
max_items_per_zone=max_items_per_zone,
mode=mode,
data=escape(data, cls._additional_escapes)
)

Expand Down
17 changes: 11 additions & 6 deletions tests/integration/test_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ class TestMaxItemsPerZone(InteractionTestBase, BaseIntegrationTest):
PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2'

assessment_mode = False

def _get_scenario_xml(self):
scenario_data = loader.load_unicode("data/test_zone_align.json")
return self._make_scenario_xml(data=scenario_data, max_items_per_zone=2)
Expand All @@ -522,12 +524,15 @@ def test_item_returned_to_bank(self):
self.place_item(1, zone_id)

# precondition check - max items placed into zone
self.assert_placed_item(0, zone_id)
self.assert_placed_item(1, zone_id)
self.assert_placed_item(0, zone_id, assessment_mode=self.assessment_mode)
self.assert_placed_item(1, zone_id, assessment_mode=self.assessment_mode)

self.place_item(2, zone_id)

self.assert_reverted_item(2)
feedback_popup = self._get_popup()
self.assertTrue(feedback_popup.is_displayed())

feedback_popup_content = self._get_popup_content()
self.assertEqual(
feedback_popup_content.get_attribute('innerHTML'),
Expand All @@ -540,15 +545,15 @@ def test_item_returned_to_bank_after_refresh(self):
self.place_item(7, zone_id)

# precondition check - max items placed into zone
self.assert_placed_item(6, zone_id)
self.assert_placed_item(7, zone_id)
self.assert_placed_item(6, zone_id, assessment_mode=self.assessment_mode)
self.assert_placed_item(7, zone_id, assessment_mode=self.assessment_mode)

self.place_item(8, zone_id)

self.assert_reverted_item(8)

self._page = self.go_to_page(self.PAGE_TITLE) # refresh the page

self.assert_placed_item(6, zone_id)
self.assert_placed_item(7, zone_id)
self.assert_placed_item(6, zone_id, assessment_mode=self.assessment_mode)
self.assert_placed_item(7, zone_id, assessment_mode=self.assessment_mode)
self.assert_reverted_item(8)
34 changes: 30 additions & 4 deletions tests/integration/test_interaction_assessment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
TOP_ZONE_ID, MIDDLE_ZONE_ID, BOTTOM_ZONE_ID,
TOP_ZONE_TITLE, START_FEEDBACK, FINISH_FEEDBACK
)
from drag_and_drop_v2.utils import FeedbackMessages
from drag_and_drop_v2.utils import FeedbackMessages, Constants
from .test_base import BaseIntegrationTest
from .test_interaction import InteractionTestBase, DefaultDataTestMixin, ParameterizedTestsMixin
from .test_interaction import InteractionTestBase, DefaultDataTestMixin, ParameterizedTestsMixin, TestMaxItemsPerZone


# Globals ###########################################################
Expand All @@ -33,8 +33,8 @@ class DefaultAssessmentDataTestMixin(DefaultDataTestMixin):

def _get_scenario_xml(self): # pylint: disable=no-self-use
return """
<vertical_demo><drag-and-drop-v2 mode='assessment' max_attempts='{max_attempts}'/></vertical_demo>
""".format(max_attempts=self.MAX_ATTEMPTS)
<vertical_demo><drag-and-drop-v2 mode='{mode}' max_attempts='{max_attempts}'/></vertical_demo>
""".format(mode=Constants.ASSESSMENT_MODE, max_attempts=self.MAX_ATTEMPTS)


class AssessmentTestMixin(object):
Expand Down Expand Up @@ -218,3 +218,29 @@ def test_grade(self):
published_grade = next((event[0][2] for event in events if event[0][1] == 'grade'))
expected_grade = {'max_value': 1, 'value': (1.0 / 5.0)}
self.assertEqual(published_grade, expected_grade)


class TestMaxItemsPerZoneAssessment(TestMaxItemsPerZone):
assessment_mode = True

def _get_scenario_xml(self):
scenario_data = loader.load_unicode("data/test_zone_align.json")
return self._make_scenario_xml(data=scenario_data, max_items_per_zone=2, mode=Constants.ASSESSMENT_MODE)

def test_drop_item_to_same_zone_does_not_show_popup(self):
zone_id = "Zone Left Align"
self.place_item(6, zone_id)
self.place_item(7, zone_id)

popup = self._get_popup()

# precondition check - max items placed into zone
self.assert_placed_item(6, zone_id, assessment_mode=self.assessment_mode)
self.assert_placed_item(7, zone_id, assessment_mode=self.assessment_mode)

self.place_item(6, zone_id, Keys.RETURN)
self.assertFalse(popup.is_displayed())

self.place_item(7, zone_id, Keys.RETURN)
self.assertFalse(popup.is_displayed())

12 changes: 6 additions & 6 deletions tests/unit/test_basics.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ddt
import unittest

from drag_and_drop_v2.drag_and_drop_v2 import DragAndDropBlock
from drag_and_drop_v2.utils import Constants
from drag_and_drop_v2.default_data import (
TARGET_IMG_DESCRIPTION, TOP_ZONE_ID, MIDDLE_ZONE_ID, BOTTOM_ZONE_ID,
START_FEEDBACK, FINISH_FEEDBACK, DEFAULT_DATA
Expand All @@ -23,7 +23,7 @@ def _make_submission(modify_submission=None):

submission = {
'display_name': "Test Drag & Drop",
'mode': DragAndDropBlock.STANDARD_MODE,
'mode': Constants.STANDARD_MODE,
'max_attempts': 1,
'show_title': False,
'problem_text': "Problem Drag & Drop",
Expand Down Expand Up @@ -56,7 +56,7 @@ def test_get_configuration(self):
zones = config.pop("zones")
items = config.pop("items")
self.assertEqual(config, {
"mode": DragAndDropBlock.STANDARD_MODE,
"mode": Constants.STANDARD_MODE,
"max_attempts": None,
"display_zone_borders": False,
"display_zone_labels": False,
Expand Down Expand Up @@ -142,7 +142,7 @@ def test_studio_submit(self):
self.assertEqual(res, {'result': 'success'})

self.assertEqual(self.block.show_title, False)
self.assertEqual(self.block.mode, DragAndDropBlock.STANDARD_MODE)
self.assertEqual(self.block.mode, Constants.STANDARD_MODE)
self.assertEqual(self.block.max_attempts, 1)
self.assertEqual(self.block.display_name, "Test Drag & Drop")
self.assertEqual(self.block.question_text, "Problem Drag & Drop")
Expand All @@ -156,7 +156,7 @@ def test_studio_submit(self):
def test_studio_submit_assessment(self):
def modify_submission(submission):
submission.update({
'mode': DragAndDropBlock.ASSESSMENT_MODE,
'mode': Constants.ASSESSMENT_MODE,
'max_items_per_zone': 4,
'show_problem_header': True,
'show_title': True,
Expand All @@ -170,7 +170,7 @@ def modify_submission(submission):
self.assertEqual(res, {'result': 'success'})

self.assertEqual(self.block.show_title, True)
self.assertEqual(self.block.mode, DragAndDropBlock.ASSESSMENT_MODE)
self.assertEqual(self.block.mode, Constants.ASSESSMENT_MODE)
self.assertEqual(self.block.max_attempts, 12)
self.assertEqual(self.block.display_name, "Test Drag & Drop")
self.assertEqual(self.block.question_text, "Problem Drag & Drop")
Expand Down

0 comments on commit 48f4fea

Please sign in to comment.