Commit 7a42ee57 by Tim Krones

Allow authors to set color of draggable items.

parent 8dbe34cf
...@@ -50,6 +50,26 @@ class DragAndDropBlock(XBlock): ...@@ -50,6 +50,26 @@ class DragAndDropBlock(XBlock):
default=1 default=1
) )
item_background_color = String(
display_name="Item background color",
help=(
"Background color to use for draggable items. "
"Defaults to color specified by current theme, or blue if no theme is set."
),
scope=Scope.settings,
default=""
)
item_text_color = String(
display_name="Item text color",
help=(
"Text color to use for draggable items. "
"Defaults to color specified by current theme, or blue if no theme is set."
),
scope=Scope.settings,
default=""
)
data = Dict( data = Dict(
display_name="Drag and Drop", display_name="Drag and Drop",
help="JSON spec as generated by the builder", help="JSON spec as generated by the builder",
...@@ -138,6 +158,8 @@ class DragAndDropBlock(XBlock): ...@@ -138,6 +158,8 @@ class DragAndDropBlock(XBlock):
self.show_title = submissions['show_title'] self.show_title = submissions['show_title']
self.question_text = submissions['question_text'] self.question_text = submissions['question_text']
self.weight = float(submissions['weight']) self.weight = float(submissions['weight'])
self.item_background_color = submissions['item_background_color']
self.item_text_color = submissions['item_text_color']
self.data = submissions['data'] self.data = submissions['data']
return { return {
...@@ -255,6 +277,11 @@ class DragAndDropBlock(XBlock): ...@@ -255,6 +277,11 @@ class DragAndDropBlock(XBlock):
data['show_title'] = self.show_title data['show_title'] = self.show_title
data['question_text'] = self.question_text data['question_text'] = self.question_text
if self.item_background_color:
data['item_background_color'] = self.item_background_color
if self.item_text_color:
data['item_text_color'] = self.item_text_color
return data return data
def _get_item_state(self): def _get_item_state(self):
......
...@@ -54,18 +54,24 @@ ...@@ -54,18 +54,24 @@
} }
.xblock--drag-and-drop .drag-container .option { .xblock--drag-and-drop .drag-container .option {
width: 190px; position: relative;
font-size: 14px; display: inline-block;
width: auto;
border-radius: 3px;
margin: 1%;
padding: 10px;
background: #2e83cd; background: #2e83cd;
font-size: 14px;
color: #fff; color: #fff;
position: relative; opacity: 1;
float: left;
display: inline;
/* Some versions of the drag and drop library try to fiddle with this */ /* Some versions of the drag and drop library try to fiddle with this */
z-index: 10 !important; z-index: 10 !important;
margin-bottom: 5px; }
padding: 10px;
opacity: 1; .xblock--drag-and-drop .drag-container .ui-draggable-dragging {
box-shadow: 0 16px 32px 0 rgba(0,0,0,.3);
border: 1px solid #ccc;
opacity: .65;
} }
.xblock--drag-and-drop .drag-container .option img { .xblock--drag-and-drop .drag-container .option img {
......
...@@ -222,13 +222,13 @@ function DragAndDropBlock(runtime, element) { ...@@ -222,13 +222,13 @@ function DragAndDropBlock(runtime, element) {
is_visible: item_state && !item_state.submitting_location, is_visible: item_state && !item_state.submitting_location,
has_value: Boolean(item_state && 'input' in item_state), has_value: Boolean(item_state && 'input' in item_state),
value : (item_state && item_state.input) || '', value : (item_state && item_state.input) || '',
class_name: undefined, class_name: undefined
}; };
if (input.has_value && !item_state.submitting_input) { if (input.has_value && !item_state.submitting_input) {
input.class_name = item_state.correct_input ? 'correct' : 'incorrect'; input.class_name = item_state.correct_input ? 'correct' : 'incorrect';
} }
} }
return { var itemProperties = {
value: item.id, value: item.id,
drag_disabled: Boolean(item_state || state.state.finished), drag_disabled: Boolean(item_state || state.state.finished),
width: item.size.width, width: item.size.width,
...@@ -240,6 +240,13 @@ function DragAndDropBlock(runtime, element) { ...@@ -240,6 +240,13 @@ function DragAndDropBlock(runtime, element) {
input: input, input: input,
content_html: item.backgroundImage ? '<img src="' + item.backgroundImage + '"/>' : item.displayName content_html: item.backgroundImage ? '<img src="' + item.backgroundImage + '"/>' : item.displayName
}; };
if (state.item_background_color) {
itemProperties.background_color = state.item_background_color;
}
if (state.item_text_color) {
itemProperties.color = state.item_text_color;
}
return itemProperties;
}); });
var context = { var context = {
......
...@@ -413,6 +413,8 @@ function DragAndDropEditBlock(runtime, element) { ...@@ -413,6 +413,8 @@ function DragAndDropEditBlock(runtime, element) {
'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(),
'question_text': $(element).find('.question-text').val(), 'question_text': $(element).find('.question-text').val(),
'item_background_color': $(element).find('.item-background-color').val(),
'item_text_color': $(element).find('.item-text-color').val(),
'data': _fn.data, 'data': _fn.data,
}; };
......
...@@ -40,11 +40,23 @@ ...@@ -40,11 +40,23 @@
}; };
var itemTemplate = function(item) { var itemTemplate = function(item) {
var style = {
width: item.width,
height: item.height,
top: item.top,
left: item.left,
position: item.position
};
if (item.background_color) {
style['background-color'] = item.background_color;
}
if (item.color) {
style.color = item.color;
}
return ( return (
h('div.option', {className: item.class_name, h('div.option', {className: item.class_name,
attributes: {'data-value': item.value, 'data-drag-disabled': item.drag_disabled}, attributes: {'data-value': item.value, 'data-drag-disabled': item.drag_disabled},
style: {width: item.width, height: item.height, style: style}, [
top: item.top, left: item.left, position: item.position}}, [
h('div', {innerHTML: item.content_html}), h('div', {innerHTML: item.content_html}),
itemInputTemplate(item.input) itemInputTemplate(item.input)
]) ])
......
...@@ -64,6 +64,18 @@ ...@@ -64,6 +64,18 @@
<h3>Items</h3> <h3>Items</h3>
</header> </header>
<section class="tab-content"> <section class="tab-content">
<section class="tab-content item-background-color-form">
<label>
Background color for items:
<input class="item-background-color" type="text" value="{{ self.item_background_color}}">
</label>
</section>
<section class="tab-content item-text-color-form">
<label>
Text color for items:
<input class="item-text-color" type="text" value="{{ self.item_text_color}}">
</label>
</section>
<form class="items-form"></form> <form class="items-form"></form>
</section> </section>
<footer class="tab-footer"> <footer class="tab-footer">
......
from ddt import ddt, unpack, data
from tests.integration.test_base import BaseIntegrationTest from tests.integration.test_base import BaseIntegrationTest
class Colors(object):
GREY = 'rgb(237, 237, 237)'
CORAL = '#ff7f50'
CORNFLOWERBLUE = 'cornflowerblue'
@classmethod
def rgb(cls, color):
if color == cls.GREY:
return color
elif color == cls.CORAL:
return 'rgb(255, 127, 80)'
elif color == cls.CORNFLOWERBLUE:
return 'rgb(100, 149, 237)'
@ddt
class TestDragAndDropRender(BaseIntegrationTest): class TestDragAndDropRender(BaseIntegrationTest):
""" """
Verifying Drag and Drop XBlock rendering against default data - if default data changes this would probably broke Verifying Drag and Drop XBlock rendering against default data - if default data changes this would probably broke
...@@ -8,22 +25,73 @@ class TestDragAndDropRender(BaseIntegrationTest): ...@@ -8,22 +25,73 @@ class TestDragAndDropRender(BaseIntegrationTest):
PAGE_TITLE = 'Drag and Drop v2' PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2' PAGE_ID = 'drag_and_drop_v2'
def setUp(self): def load_scenario(self, item_background_color="", item_text_color=""):
super(TestDragAndDropRender, self).setUp() scenario_xml = """
<vertical_demo>
scenario_xml = "<vertical_demo><drag-and-drop-v2/></vertical_demo>" <drag-and-drop-v2 item_background_color='{item_background_color}' item_text_color='{item_text_color}' />
</vertical_demo>
""".format(item_background_color=item_background_color, item_text_color=item_text_color)
self._add_scenario(self.PAGE_ID, self.PAGE_TITLE, scenario_xml) self._add_scenario(self.PAGE_ID, self.PAGE_TITLE, scenario_xml)
self.browser.get(self.live_server_url) self.browser.get(self.live_server_url)
self._page = self.go_to_page(self.PAGE_TITLE) self._page = self.go_to_page(self.PAGE_TITLE)
def _test_style(self, item, style_settings): def _test_style(self, element, style_settings, element_type):
style = item.get_attribute('style') style = element.get_attribute('style')
for style_prop, expected_value in style_settings.items(): for style_prop, expected_value in style_settings.items():
if style_prop == 'color' or style_prop == 'background-color' and expected_value.startswith('#'):
expected_value = Colors.rgb(expected_value)
expected = u"{0}: {1}".format(style_prop, expected_value) expected = u"{0}: {1}".format(style_prop, expected_value)
self.assertIn(expected, style) self.assertIn(expected, style)
if element_type == "item":
self._test_item_style(element, style_settings, style)
def _test_item_style(self, item, style_settings, style):
background_color_property = 'background-color'
if background_color_property not in style_settings:
self.assertNotIn(background_color_property, style)
color_property = 'color'
if color_property not in style_settings:
self.assertNotIn(' ' + color_property, style) # Leading space makes sure that
# test does not find "color" in "background-color"
def test_items(self): def test_items(self):
self.load_scenario()
items = self._get_items()
self.assertEqual(len(items), 3)
self.assertEqual(items[0].get_attribute('data-value'), '0')
self.assertEqual(items[0].text, '1')
self.assertIn('ui-draggable', self.get_element_classes(items[0]))
self._test_style(items[0], {'width': '190px', 'height': 'auto'}, element_type='item')
self.assertEqual(items[1].get_attribute('data-value'), '1')
self.assertEqual(items[1].text, '2')
self.assertIn('ui-draggable', self.get_element_classes(items[1]))
self._test_style(items[1], {'width': '190px', 'height': 'auto'}, element_type='item')
self.assertEqual(items[2].get_attribute('data-value'), '2')
self.assertEqual(items[2].text, 'X')
self.assertIn('ui-draggable', self.get_element_classes(items[2]))
self._test_style(items[2], {'width': '100px', 'height': '100px'}, element_type='item')
@unpack
@data(
(Colors.CORNFLOWERBLUE, Colors.GREY),
(Colors.CORAL, ''),
('', Colors.GREY),
)
def test_items_custom_colors(self, item_background_color, item_text_color):
self.load_scenario(item_background_color, item_text_color)
color_settings = {}
if item_background_color:
color_settings['background-color'] = item_background_color
if item_text_color:
color_settings['color'] = item_text_color
print(color_settings)
items = self._get_items() items = self._get_items()
self.assertEqual(len(items), 3) self.assertEqual(len(items), 3)
...@@ -31,37 +99,53 @@ class TestDragAndDropRender(BaseIntegrationTest): ...@@ -31,37 +99,53 @@ class TestDragAndDropRender(BaseIntegrationTest):
self.assertEqual(items[0].get_attribute('data-value'), '0') self.assertEqual(items[0].get_attribute('data-value'), '0')
self.assertEqual(items[0].text, '1') self.assertEqual(items[0].text, '1')
self.assertIn('ui-draggable', self.get_element_classes(items[0])) self.assertIn('ui-draggable', self.get_element_classes(items[0]))
self._test_style(items[0], {'width': '190px', 'height': 'auto'}) self._test_style(
items[0], dict({'width': '190px', 'height': 'auto'}, **color_settings), element_type='item'
)
self.assertEqual(items[1].get_attribute('data-value'), '1') self.assertEqual(items[1].get_attribute('data-value'), '1')
self.assertEqual(items[1].text, '2') self.assertEqual(items[1].text, '2')
self.assertIn('ui-draggable', self.get_element_classes(items[1])) self.assertIn('ui-draggable', self.get_element_classes(items[1]))
self._test_style(items[1], {'width': '190px', 'height': 'auto'}) self._test_style(
items[1], dict({'width': '190px', 'height': 'auto'}, **color_settings), element_type='item'
)
self.assertEqual(items[2].get_attribute('data-value'), '2') self.assertEqual(items[2].get_attribute('data-value'), '2')
self.assertEqual(items[2].text, 'X') self.assertEqual(items[2].text, 'X')
self.assertIn('ui-draggable', self.get_element_classes(items[2])) self.assertIn('ui-draggable', self.get_element_classes(items[2]))
self._test_style(items[2], {'width': '100px', 'height': '100px'}) self._test_style(
items[2], dict({'width': '100px', 'height': '100px'}, **color_settings), element_type='item'
)
def test_zones(self): def test_zones(self):
self.load_scenario()
zones = self._get_zones() zones = self._get_zones()
self.assertEqual(len(zones), 2) self.assertEqual(len(zones), 2)
self.assertEqual(zones[0].get_attribute('data-zone'), 'Zone 1') self.assertEqual(zones[0].get_attribute('data-zone'), 'Zone 1')
self.assertIn('ui-droppable', self.get_element_classes(zones[0])) self.assertIn('ui-droppable', self.get_element_classes(zones[0]))
self._test_style(zones[0], {'top': '200px', 'left': '120px', 'width': '200px', 'height': '100px'}) self._test_style(
zones[0], {'top': '200px', 'left': '120px', 'width': '200px', 'height': '100px'}, element_type='zone'
)
self.assertEqual(zones[1].get_attribute('data-zone'), 'Zone 2') self.assertEqual(zones[1].get_attribute('data-zone'), 'Zone 2')
self.assertIn('ui-droppable', self.get_element_classes(zones[1])) self.assertIn('ui-droppable', self.get_element_classes(zones[1]))
self._test_style(zones[1], {'top': '360px', 'left': '120px', 'width': '200px', 'height': '100px'}) self._test_style(
zones[1], {'top': '360px', 'left': '120px', 'width': '200px', 'height': '100px'}, element_type='zone'
)
def test_feedback(self): def test_feedback(self):
self.load_scenario()
feedback_message = self._get_feedback_message() feedback_message = self._get_feedback_message()
self.assertEqual(feedback_message.text, "Intro Feed") self.assertEqual(feedback_message.text, "Intro Feed")
def test_background_image(self): def test_background_image(self):
self.load_scenario()
bg_image = self.browser.execute_script('return jQuery(".target-img").css("background-image")') bg_image = self.browser.execute_script('return jQuery(".target-img").css("background-image")')
image_path = '/resource/drag-and-drop-v2/public/img/triangle.png' image_path = '/resource/drag-and-drop-v2/public/img/triangle.png'
self.assertEqual(bg_image, 'url("{0}{1}")'.format(self.live_server_url, image_path)) self.assertEqual(bg_image, 'url("{0}{1}")'.format(self.live_server_url, image_path))
...@@ -61,6 +61,8 @@ def test_studio_submit(): ...@@ -61,6 +61,8 @@ def test_studio_submit():
'display_name': "Test Drag & Drop", 'display_name': "Test Drag & Drop",
'show_title': True, 'show_title': True,
'question_text': "Question Drag & Drop", 'question_text': "Question Drag & Drop",
'item_background_color': 'cornflowerblue',
'item_text_color': 'coral',
'weight': '5', 'weight': '5',
'data': { 'data': {
'foo': 1 'foo': 1
...@@ -72,6 +74,8 @@ def test_studio_submit(): ...@@ -72,6 +74,8 @@ def test_studio_submit():
assert_equals(block.display_name, "Test Drag & Drop") assert_equals(block.display_name, "Test Drag & Drop")
assert_equals(block.question_text, "Question Drag & Drop") assert_equals(block.question_text, "Question Drag & Drop")
assert_equals(block.item_background_color, "cornflowerblue")
assert_equals(block.item_text_color, "coral")
assert_equals(block.weight, 5) assert_equals(block.weight, 5)
assert_equals(block.data, {'foo': 1}) assert_equals(block.data, {'foo': 1})
......
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