Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xblock-drag-and-drop-v2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
xblock-drag-and-drop-v2
Commits
e8b10924
Commit
e8b10924
authored
Dec 18, 2015
by
Tim Krones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make DnDv2 accessible.
parent
c90e8579
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
290 additions
and
72 deletions
+290
-72
drag_and_drop_v2/drag_and_drop_v2.py
+7
-0
drag_and_drop_v2/public/css/drag_and_drop.css
+36
-12
drag_and_drop_v2/public/css/drag_and_drop_edit.css
+12
-6
drag_and_drop_v2/public/js/drag_and_drop.js
+9
-3
drag_and_drop_v2/public/js/drag_and_drop_edit.js
+19
-5
drag_and_drop_v2/public/js/view.js
+24
-5
drag_and_drop_v2/templates/html/drag_and_drop_edit.html
+26
-5
drag_and_drop_v2/templates/html/js_templates.html
+11
-1
tests/integration/data/test_data_a11y.json
+63
-0
tests/integration/data/test_html_data.json
+2
-1
tests/integration/test_base.py
+3
-0
tests/integration/test_custom_data_render.py
+2
-0
tests/integration/test_interaction.py
+3
-3
tests/integration/test_render.py
+64
-29
tests/unit/data/html/config_out.json
+1
-0
tests/unit/data/html/data.json
+2
-1
tests/unit/data/old/config_out.json
+1
-0
tests/unit/data/old/data.json
+2
-1
tests/unit/data/plain/config_out.json
+1
-0
tests/unit/data/plain/data.json
+1
-0
tests/unit/test_basics.py
+1
-0
No files found.
drag_and_drop_v2/drag_and_drop_v2.py
View file @
e8b10924
...
...
@@ -153,6 +153,7 @@ class DragAndDropBlock(XBlock):
"question_text"
:
self
.
question_text
,
"show_question_header"
:
self
.
show_question_header
,
"target_img_expanded_url"
:
self
.
target_img_expanded_url
,
"target_img_description"
:
self
.
target_img_description
,
"item_background_color"
:
self
.
item_background_color
or
None
,
"item_text_color"
:
self
.
item_text_color
or
None
,
"initial_feedback"
:
self
.
data
[
'feedback'
][
'start'
],
...
...
@@ -197,6 +198,7 @@ class DragAndDropBlock(XBlock):
fragment
.
initialize_js
(
'DragAndDropEditBlock'
,
{
'data'
:
self
.
data
,
'target_img_expanded_url'
:
self
.
target_img_expanded_url
,
'target_img_description'
:
self
.
target_img_description
,
'default_background_image_url'
:
self
.
default_background_image_url
,
})
...
...
@@ -329,6 +331,11 @@ class DragAndDropBlock(XBlock):
return
self
.
default_background_image_url
@property
def
target_img_description
(
self
):
""" Get the description for the target image (the image items are dragged onto). """
return
self
.
data
.
get
(
"targetImgDescription"
,
""
)
@property
def
default_background_image_url
(
self
):
""" The URL to the default background image, shown when no custom background is used """
return
self
.
runtime
.
local_resource_url
(
self
,
"public/img/triangle.png"
)
...
...
drag_and_drop_v2/public/css/drag_and_drop.css
View file @
e8b10924
...
...
@@ -23,7 +23,7 @@
/* Shared styles used in header and footer */
.xblock--drag-and-drop
.title1
{
color
:
rgb
(
85
,
85
,
85
)
;
color
:
#555555
;
text-transform
:
uppercase
;
font-weight
:
bold
;
font-style
:
normal
;
...
...
@@ -58,7 +58,7 @@
align-items
:
center
;
position
:
relative
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0.1
);
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0.1
);
border-radius
:
3px
;
padding
:
5px
;
}
...
...
@@ -72,7 +72,7 @@
border-radius
:
3px
;
margin
:
5px
;
padding
:
10px
;
background-color
:
#2
e83cd
;
background-color
:
#2
872b2
;
font-size
:
14px
;
color
:
#fff
;
opacity
:
1
;
...
...
@@ -112,8 +112,14 @@
transform
:
translate
(
-50%
,
-50%
);
/* These blocks are to be centered on their absolute x,y position */
}
/* Focused option */
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:focus
,
.xblock--drag-and-drop
.drag-container
.item-bank
.option
:hover
{
transform
:
scale
(
1.1
);
}
.xblock--drag-and-drop
.drag-container
.ui-draggable-dragging
{
box-shadow
:
0
16px
32px
0
rgba
(
0
,
0
,
0
,
.3
);
box-shadow
:
0
16px
32px
0
rgba
(
0
,
0
,
0
,
0
.3
);
border
:
1px
solid
#ccc
;
opacity
:
.65
;
z-index
:
20
!important
;
...
...
@@ -159,7 +165,7 @@
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.correct
.input
{
background
:
#ceffce
;
color
:
#0
dad0d
;
color
:
#0
87108
;
}
.xblock--drag-and-drop
.drag-container
.option
.numerical-input.incorrect
.input
{
...
...
@@ -224,8 +230,12 @@
}
/* Focused zone */
.xblock--drag-and-drop
.zone
:focus
{
border
:
2px
solid
#a5a5a5
;
}
.xblock--drag-and-drop
.zone
p
{
visibility
:
hidden
;
width
:
100%
;
font-family
:
Arial
;
font-size
:
16px
;
...
...
@@ -250,7 +260,7 @@
/*** FEEDBACK ***/
.xblock--drag-and-drop
.feedback
{
margin-top
:
20px
;
border-top
:
solid
1px
rgb
(
189
,
189
,
189
)
;
border-top
:
solid
1px
#bdbdbd
;
}
.xblock--drag-and-drop
.popup
{
...
...
@@ -258,8 +268,8 @@
display
:
none
;
top
:
5%
;
right
:
5%
;
border
:
1px
solid
white
;
background
:
none
repeat
scroll
0
0
rgba
(
0
,
0
,
0
,
.8
);
border
:
1px
solid
#fff
;
background
:
none
repeat
scroll
0
0
rgba
(
0
,
0
,
0
,
0
.8
);
width
:
500px
;
max-width
:
90%
;
min-height
:
50px
;
...
...
@@ -269,7 +279,7 @@
}
.xblock--drag-and-drop
.popup
.popup-content
{
color
:
#
FFFFFF
;
color
:
#
ffffff
;
margin-left
:
15px
;
margin-top
:
35px
;
margin-bottom
:
15px
;
...
...
@@ -282,7 +292,7 @@
margin-right
:
8px
;
margin-top
:
8px
;
margin-left
:
20px
;
color
:
#
FFFFFF
;
color
:
#
ffffff
;
font-family
:
"fontawesome"
;
font-size
:
18pt
;
}
...
...
@@ -290,6 +300,20 @@
.xblock--drag-and-drop
.reset-button
{
cursor
:
pointer
;
float
:
right
;
color
:
#
3384CA
;
color
:
#
2d74b3
;
margin-top
:
3px
;
}
/* Make sure screen-reader content is hidden in the workbench: */
.xblock--drag-and-drop
.sr
{
border
:
0
;
clip
:
rect
(
0
0
0
0
);
height
:
1px
;
margin
:
-1px
;
overflow
:
hidden
;
padding
:
0
;
position
:
absolute
;
width
:
1px
;
background
:
#ffffff
;
color
:
#000000
;
}
drag_and_drop_v2/public/css/drag_and_drop_edit.css
View file @
e8b10924
...
...
@@ -141,9 +141,12 @@
width
:
18%
;
}
.xblock--drag-and-drop--editor
.zones-form
.zone-row
.title
{
.xblock--drag-and-drop--editor
.zones-form
.zone-row
.title
,
.xblock--drag-and-drop--editor
.zones-form
.zone-row
.description
{
width
:
60%
;
margin
:
0
0
5px
;
line-height
:
2.664rem
;
/* .title gets line-height from a Studio rule that does not apply to .description;
here we make sure that both input fields get the same value for line-height */
}
.xblock--drag-and-drop--editor
.zones-form
.zone-row
.layout
{
...
...
@@ -162,6 +165,7 @@
height
:
128px
;
}
.xblock--drag-and-drop--editor
.target-image-form
.target-image-form-help
,
.xblock--drag-and-drop--editor
.item-styles-form
.item-styles-form-help
{
margin-top
:
5px
;
font-size
:
small
;
...
...
@@ -173,7 +177,7 @@
}
.xblock--drag-and-drop--editor
.items-form
.item
{
background
:
#
73bde7
;
background
:
#
8fcaec
;
padding
:
10px
0
1px
;
margin
:
15px
0
;
}
...
...
@@ -209,11 +213,12 @@
/** Buttons **/
.xblock--drag-and-drop--editor
.btn
{
background
:
#2
e83cd
;
background
:
#2
872b2
;
color
:
#fff
;
border
:
1px
solid
#156ab4
;
border-radius
:
6px
;
padding
:
5px
10px
;
margin-top
:
15px
;
}
.xblock--drag-and-drop--editor
.btn
:hover
{
...
...
@@ -228,7 +233,7 @@
.xblock--drag-and-drop--editor
.add-element
{
text-decoration
:
none
;
color
:
#2
e83cd
;
color
:
#2
36299
;
}
.xblock--drag-and-drop--editor
.remove-zone
{
...
...
@@ -246,7 +251,7 @@
width
:
14px
;
height
:
14px
;
border-radius
:
7px
;
background
:
#2
e83cd
;
background
:
#2
36299
;
position
:
relative
;
float
:
left
;
margin
:
0
5px
0
0
;
...
...
@@ -315,8 +320,9 @@
.xblock--drag-and-drop--editor
.remove-item
.icon.remove
{
background
:
#fff
;
color
:
#0072a7
;
}
.xblock--drag-and-drop--editor
.remove-item
.icon.remove
:before
,
.xblock--drag-and-drop--editor
.remove-item
.icon.remove
:after
{
background
:
#2
e83cd
;
background
:
#2
36299
;
}
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
e8b10924
...
...
@@ -52,10 +52,11 @@ function DragAndDropBlock(runtime, element, configuration) {
promise
.
reject
();
}
},
false
);
img
.
addEventListener
(
"error"
,
function
()
{
promise
.
reject
()
});
img
.
addEventListener
(
"error"
,
function
()
{
promise
.
reject
()
;
});
img
.
src
=
configuration
.
target_img_expanded_url
;
img
.
alt
=
configuration
.
target_img_description
;
return
promise
;
}
}
;
/** Zones are specified in the configuration via pixel values - convert to percentages */
var
computeZoneDimension
=
function
(
zone
,
bg_image_width
,
bg_image_height
)
{
...
...
@@ -310,13 +311,17 @@ function DragAndDropBlock(runtime, element, configuration) {
input
.
class_name
=
item_user_state
.
correct_input
?
'correct'
:
'incorrect'
;
}
}
var
content_html
=
item
.
displayName
;
if
(
item
.
backgroundImage
)
{
content_html
=
'<img src="'
+
item
.
backgroundImage
+
'" alt="'
+
item
.
backgroundDescription
+
'" />'
;
}
var
itemProperties
=
{
value
:
item
.
id
,
drag_disabled
:
Boolean
(
item_user_state
||
state
.
finished
),
class_name
:
item_user_state
&&
(
'input'
in
item_user_state
||
item_user_state
.
correct_input
)
?
'fade'
:
undefined
,
xhr_active
:
(
item_user_state
&&
item_user_state
.
submitting_location
),
input
:
input
,
content_html
:
item
.
backgroundImage
?
'<img src="'
+
item
.
backgroundImage
+
'"/>'
:
item
.
displayName
,
content_html
:
content_html
,
has_image
:
!!
item
.
backgroundImage
};
if
(
item_user_state
)
{
...
...
@@ -340,6 +345,7 @@ function DragAndDropBlock(runtime, element, configuration) {
question_html
:
configuration
.
question_text
,
show_question_header
:
configuration
.
show_question_header
,
target_img_src
:
configuration
.
target_img_expanded_url
,
target_img_description
:
configuration
.
target_img_description
,
display_zone_labels
:
configuration
.
display_zone_labels
,
zones
:
configuration
.
zones
,
items
:
items
,
...
...
drag_and_drop_v2/public/js/drag_and_drop_edit.js
View file @
e8b10924
...
...
@@ -70,9 +70,11 @@ function DragAndDropEditBlock(runtime, element, params) {
}
// Set the target image and bind its event handler:
$
(
'.target-image-form input'
,
element
).
val
(
_fn
.
data
.
targetImg
);
$
(
'.target-image-form input.url-input'
,
element
).
val
(
_fn
.
data
.
targetImg
);
$
(
'.target-image-form input.description-input'
,
element
).
val
(
_fn
.
data
.
targetImgDescription
);
_fn
.
build
.
$el
.
targetImage
.
load
(
_fn
.
build
.
form
.
zone
.
imageLoaded
);
_fn
.
build
.
$el
.
targetImage
.
attr
(
'src'
,
params
.
target_img_expanded_url
);
_fn
.
build
.
$el
.
targetImage
.
attr
(
'alt'
,
params
.
target_img_description
);
if
(
_fn
.
data
.
displayLabels
)
{
$
(
'.display-labels-form input'
,
element
).
prop
(
'checked'
,
true
);
...
...
@@ -122,7 +124,7 @@ function DragAndDropEditBlock(runtime, element, params) {
.
on
(
'click'
,
'.target-image-form button'
,
function
(
e
)
{
e
.
preventDefault
();
var
new_img_url
=
$
.
trim
(
$
(
'.target-image-form input'
,
element
).
val
());
var
new_img_url
=
$
.
trim
(
$
(
'.target-image-form input
.url-input
'
,
element
).
val
());
if
(
new_img_url
)
{
// We may need to 'expand' the URL before it will be valid.
// e.g. '/static/blah.png' becomes '/asset-v1:course+id/blah.png'
...
...
@@ -136,6 +138,12 @@ function DragAndDropEditBlock(runtime, element, params) {
}
_fn
.
data
.
targetImg
=
new_img_url
;
var
new_description
=
$
.
trim
(
$
(
'.target-image-form input.description-input'
,
element
).
val
()
);
_fn
.
build
.
$el
.
targetImage
.
attr
(
'alt'
,
new_description
);
_fn
.
data
.
targetImgDescription
=
new_description
;
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
})
...
...
@@ -176,6 +184,7 @@ function DragAndDropEditBlock(runtime, element, params) {
// Update zone obj
var
zoneObj
=
{
title
:
oldZone
.
title
||
'Zone '
+
num
,
description
:
oldZone
.
description
,
id
:
name
,
index
:
num
,
width
:
oldZone
.
width
||
200
,
...
...
@@ -247,6 +256,7 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
tpl
.
zoneElement
({
id
:
zoneObj
.
id
,
title
:
zoneObj
.
title
,
description
:
zoneObj
.
description
,
x_percent
:
(
+
zoneObj
.
x
)
/
imgWidth
*
100
,
y_percent
:
(
+
zoneObj
.
y
)
/
imgHeight
*
100
,
width_percent
:
(
+
zoneObj
.
width
)
/
imgWidth
*
100
,
...
...
@@ -276,6 +286,8 @@ function DragAndDropEditBlock(runtime, element, params) {
record
.
title
=
$changedInput
.
val
();
}
else
if
(
$changedInput
.
hasClass
(
'width'
))
{
record
.
width
=
$changedInput
.
val
();
}
else
if
(
$changedInput
.
hasClass
(
'description'
))
{
record
.
description
=
$changedInput
.
val
();
}
else
if
(
$changedInput
.
hasClass
(
'height'
))
{
record
.
height
=
$changedInput
.
val
();
}
else
if
(
$changedInput
.
hasClass
(
'x'
))
{
...
...
@@ -376,7 +388,8 @@ function DragAndDropEditBlock(runtime, element, params) {
$form
.
each
(
function
(
i
,
el
)
{
var
$el
=
$
(
el
),
name
=
$el
.
find
(
'.item-text'
).
val
(),
backgroundImage
=
$el
.
find
(
'.background-image'
).
val
();
backgroundImage
=
$el
.
find
(
'.background-image-url'
).
val
(),
backgroundDescription
=
$el
.
find
(
'.background-image-description'
).
val
();
if
(
name
.
length
>
0
||
backgroundImage
.
length
>
0
)
{
// Item width/height are ignored, but preserve the data:
...
...
@@ -401,7 +414,8 @@ function DragAndDropEditBlock(runtime, element, params) {
width
:
width
,
height
:
height
},
backgroundImage
:
backgroundImage
backgroundImage
:
backgroundImage
,
backgroundDescription
:
backgroundDescription
};
var
numValue
=
parseFloat
(
$el
.
find
(
'.item-numerical-value'
).
val
());
...
...
@@ -410,7 +424,7 @@ function DragAndDropEditBlock(runtime, element, params) {
data
.
inputOptions
=
{
value
:
numValue
,
margin
:
isFinite
(
numMargin
)
?
numMargin
:
0
}
}
;
}
items
.
push
(
data
);
...
...
drag_and_drop_v2/public/js/view.js
View file @
e8b10924
...
...
@@ -55,6 +55,7 @@
var
itemTemplate
=
function
(
item
)
{
var
style
=
{};
var
className
=
(
item
.
class_name
)
?
item
.
class_name
:
""
;
var
tabindex
=
0
;
if
(
item
.
background_color
)
{
style
[
'background-color'
]
=
item
.
background_color
;
}
...
...
@@ -64,6 +65,8 @@
if
(
item
.
is_placed
)
{
style
.
left
=
item
.
x_percent
+
"%"
;
style
.
top
=
item
.
y_percent
+
"%"
;
tabindex
=
-
1
;
// If an item has been placed it can no longer be interacted with,
// so remove the ability to move focus to it using the keyboard
}
if
(
item
.
has_image
)
{
className
+=
" "
+
"option-with-image"
;
...
...
@@ -73,7 +76,13 @@
{
key
:
item
.
value
,
className
:
className
,
attributes
:
{
'data-value'
:
item
.
value
,
'data-drag-disabled'
:
item
.
drag_disabled
},
attributes
:
{
'tabindex'
:
tabindex
,
'draggable'
:
true
,
'aria-grabbed'
:
false
,
'data-value'
:
item
.
value
,
'data-drag-disabled'
:
item
.
drag_disabled
},
style
:
style
},
[
itemSpinnerTemplate
(
item
.
xhr_active
),
...
...
@@ -85,18 +94,27 @@
};
var
zoneTemplate
=
function
(
zone
,
ctx
)
{
var
className
=
ctx
.
display_zone_labels
?
'zone-name'
:
'zone-name sr'
;
return
(
h
(
'div.zone'
,
{
id
:
zone
.
id
,
attributes
:
{
'data-zone'
:
zone
.
title
},
attributes
:
{
'tabindex'
:
0
,
'dropzone'
:
'move'
,
'aria-dropeffect'
:
'move'
,
'data-zone'
:
zone
.
title
},
style
:
{
top
:
zone
.
y_percent
+
'%'
,
left
:
zone
.
x_percent
+
"%"
,
width
:
zone
.
width_percent
+
'%'
,
height
:
zone
.
height_percent
+
"%"
,
}
},
ctx
.
display_zone_labels
?
h
(
'p'
,
zone
.
title
)
:
null
[
h
(
'p'
,
{
className
:
className
},
zone
.
title
),
h
(
'p'
,
{
className
:
'zone-description sr'
},
zone
.
description
)
]
)
);
};
...
...
@@ -104,8 +122,9 @@
var
feedbackTemplate
=
function
(
ctx
)
{
var
feedback_display
=
ctx
.
feedback_html
?
'block'
:
'none'
;
var
reset_button_display
=
ctx
.
display_reset_button
?
'block'
:
'none'
;
var
properties
=
{
attributes
:
{
'aria-live'
:
'polite'
}
};
return
(
h
(
'section.feedback'
,
[
h
(
'section.feedback'
,
properties
,
[
h
(
'div.reset-button'
,
{
style
:
{
display
:
reset_button_display
}},
gettext
(
'Reset exercise'
)),
h
(
'h3.title1'
,
{
style
:
{
display
:
feedback_display
}},
gettext
(
'Feedback'
)),
h
(
'p.message'
,
{
style
:
{
display
:
feedback_display
},
...
...
@@ -135,7 +154,7 @@
h
(
'p.popup-content'
,
{
innerHTML
:
ctx
.
popup_html
}),
]),
h
(
'div.target-img-wrapper'
,
[
h
(
'img.target-img'
,
{
src
:
ctx
.
target_img_src
,
alt
:
"Image Description here"
}),
h
(
'img.target-img'
,
{
src
:
ctx
.
target_img_src
,
alt
:
ctx
.
target_img_description
}),
]),
renderCollection
(
zoneTemplate
,
ctx
.
zones
,
ctx
),
renderCollection
(
itemTemplate
,
items_placed
,
ctx
),
...
...
drag_and_drop_v2/templates/html/drag_and_drop_edit.html
View file @
e8b10924
...
...
@@ -41,18 +41,39 @@
<div
class=
"tab zones-tab hidden"
>
<header
class=
"tab-header"
>
<h3>
{% trans "Zone
Position
s" %}
</h3>
<h3>
{% trans "Zones" %}
</h3>
</header>
<section
class=
"tab-content"
>
<section
class=
"tab-content target-image-form"
>
<label>
{% trans "New background URL" %}:
</label>
<input
type=
"text"
>
<form
class=
"target-image-form"
>
<h3
id=
"background-url-label"
>
{% trans "Background URL" %}
</h3>
<input
type=
"text"
class=
"url-input"
aria-labelledby=
"background-url-label"
>
<h3
id=
"background-description-label"
>
{% trans "Background description" %}
</h3>
<input
type=
"text"
class=
"description-input"
aria-labelledby=
"background-description-label"
aria-describedby=
"background-description-description"
>
<div
id=
"background-description-description"
class=
"target-image-form-help"
>
{% blocktrans %}
Please provide a description of the image for non-visual users.
The description should provide sufficient information that would allow anyone
to solve the problem if the image did not load.
{% endblocktrans %}
</div>
<button
class=
"btn"
>
{% trans "Change background" %}
</button>
</form>
</section>
<section
class=
"tab-content display-labels-form"
>
<section
class=
"tab-content"
>
<form
class=
"display-labels-form"
>
<h3>
{% trans "Zone labels" %}
</h3>
<label
for=
"display-labels"
>
{% trans "Display label names on the image" %}:
</label>
<input
name=
"display-labels"
id=
"display-labels"
type=
"checkbox"
/>
</form>
</section>
<section
class=
"tab-content"
>
<div
class=
"zone-editor"
>
<div
class=
"controls"
>
<form
class=
"zones-form"
></form>
...
...
drag_and_drop_v2/templates/html/js_templates.html
View file @
e8b10924
...
...
@@ -5,6 +5,7 @@
width:{{ width_percent }}%;
height:{{ height_percent }}%;"
>
<
p
>
{{{
title
}}}
<
/p
>
<
p
class
=
"sr"
>
{{{
description
}}}
<
/p
>
<
/div
>
</script>
...
...
@@ -15,6 +16,11 @@
<
a
href
=
"#"
class
=
"remove-zone hidden"
>
<
div
class
=
"icon remove"
><
/div
>
<
/a
>
<
label
>
{{
i18n
"Description"
}}
<
/label
>
<
input
type
=
"text"
class
=
"description"
value
=
"{{ description }}"
placeholder
=
"{{i18n 'Describe this zone to non-visual users'}}"
/>
<
div
class
=
"layout"
>
<
label
>
{{
i18n
"width"
}}
<
/label
>
<
input
type
=
"text"
class
=
"size width"
value
=
"{{ width }}"
/>
...
...
@@ -46,7 +52,11 @@
<
/div
>
<
div
class
=
"row"
>
<
label
>
{{
i18n
"Background image URL (alternative to the text)"
}}
<
/label
>
<
textarea
class
=
"background-image"
>
{{
backgroundImage
}}
<
/textarea
>
<
textarea
class
=
"background-image-url"
>
{{
backgroundImage
}}
<
/textarea
>
<
/div
>
<
div
class
=
"row"
>
<
label
>
{{
i18n
"Background image description (should provide sufficient information to place the item even if the image did not load)"
}}
<
/label
>
<
textarea
class
=
"background-image-description"
>
{{
backgroundDescription
}}
<
/textarea
>
<
/div
>
<
div
class
=
"row"
>
<
label
>
{{
i18n
"Success Feedback"
}}
<
/label
>
...
...
tests/integration/data/test_data_a11y.json
0 → 100644
View file @
e8b10924
{
"zones"
:
[
{
"index"
:
1
,
"title"
:
"Zone 1"
,
"description"
:
"This describes zone 1"
,
"height"
:
178
,
"width"
:
196
,
"y"
:
"30"
,
"x"
:
"160"
,
"id"
:
"zone-1"
},
{
"index"
:
2
,
"title"
:
"Zone 2"
,
"description"
:
"This describes zone 2"
,
"height"
:
140
,
"width"
:
340
,
"y"
:
"210"
,
"x"
:
"86"
,
"id"
:
"zone-2"
}
],
"items"
:
[
{
"displayName"
:
"1"
,
"backgroundImage"
:
"https://placehold.it/100x100"
,
"backgroundDescription"
:
"This describes the background image of item 1"
,
"feedback"
:
{
"incorrect"
:
"No, 1 does not belong here"
,
"correct"
:
"Yes, 1 goes here"
},
"zone"
:
"Zone 1"
,
"id"
:
0
},
{
"displayName"
:
"2"
,
"backgroundImage"
:
"https://placehold.it/100x100"
,
"backgroundDescription"
:
"This describes the background image of item 2"
,
"feedback"
:
{
"incorrect"
:
"No, 2 does not belong here"
,
"correct"
:
"Yes, 2 goes here"
},
"zone"
:
"Zone 2"
,
"id"
:
1
},
{
"displayName"
:
"X"
,
"backgroundImage"
:
""
,
"feedback"
:
{
"incorrect"
:
"You silly, there are no zones for X"
,
"correct"
:
""
},
"zone"
:
"none"
,
"id"
:
2
}
],
"feedback"
:
{
"start"
:
"Drag the items onto the image above."
,
"finish"
:
"Good work! You have completed this drag and drop exercise."
},
"targetImgDescription"
:
"This describes the target image"
}
tests/integration/data/test_html_data.json
View file @
e8b10924
...
...
@@ -59,5 +59,6 @@
"start"
:
"Intro <i>Feed</i>"
,
"finish"
:
"Final <b>Feed</b>"
},
"targetImg"
:
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDAiIGhlaWdodD0iNjAwIiBzdHlsZT0iYmFja2dyb3VuZDogI2VlZjsiPjwvc3ZnPg=="
"targetImg"
:
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDAiIGhlaWdodD0iNjAwIiBzdHlsZT0iYmFja2dyb3VuZDogI2VlZjsiPjwvc3ZnPg=="
,
"targetImgDescription"
:
"This describes the target image"
}
tests/integration/test_base.py
View file @
e8b10924
...
...
@@ -57,6 +57,9 @@ class BaseIntegrationTest(SeleniumBaseTest):
def
_get_zones
(
self
):
return
self
.
_page
.
find_elements_by_css_selector
(
".drag-container .zone"
)
def
_get_feedback
(
self
):
return
self
.
_page
.
find_element_by_css_selector
(
".feedback"
)
def
_get_feedback_message
(
self
):
return
self
.
_page
.
find_element_by_css_selector
(
".feedback .message"
)
...
...
tests/integration/test_custom_data_render.py
View file @
e8b10924
...
...
@@ -31,4 +31,6 @@ class TestCustomDataDragAndDropRendering(BaseIntegrationTest):
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciI"
"HdpZHRoPSI4MDAiIGhlaWdodD0iNjAwIiBzdHlsZT0iYmFja2dyb3VuZDogI2VlZjsiPjwvc3ZnPg=="
)
custom_image_description
=
"This describes the target image"
self
.
assertEqual
(
bg_image
.
get_attribute
(
"src"
),
custom_image_url
)
self
.
assertEqual
(
bg_image
.
get_attribute
(
"alt"
),
custom_image_description
)
tests/integration/test_interaction.py
View file @
e8b10924
...
...
@@ -145,7 +145,7 @@ class InteractionTestBase(object):
self
.
assertDictEqual
(
locations_after_reset
[
item_key
],
initial_locations
[
item_key
])
class
InteractionTestFixture
(
InteractionTestBase
):
class
BasicInteractionTest
(
InteractionTestBase
):
"""
Verifying Drag and Drop XBlock rendering against default data - if default data changes this will probably break.
"""
...
...
@@ -184,7 +184,7 @@ class InteractionTestFixture(InteractionTestBase):
self
.
parameterized_final_feedback_and_reset
(
self
.
items_map
,
self
.
feedback
)
class
CustomDataInteractionTest
(
InteractionTestFixture
,
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"
),
...
...
@@ -202,7 +202,7 @@ class CustomDataInteractionTest(InteractionTestFixture, BaseIntegrationTest):
return
self
.
_get_custom_scenario_xml
(
"integration/data/test_data.json"
)
class
CustomHtmlDataInteractionTest
(
InteractionTestFixture
,
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"
),
...
...
tests/integration/test_render.py
View file @
e8b10924
from
ddt
import
ddt
,
unpack
,
data
from
selenium.common.exceptions
import
NoSuchElementException
from
..utils
import
load_resource
from
.test_base
import
BaseIntegrationTest
class
Colors
(
object
):
WHITE
=
'rgb(255, 255, 255)'
BLUE
=
'rgb(4
6, 131, 205
)'
BLUE
=
'rgb(4
0, 114, 178
)'
GREY
=
'rgb(237, 237, 237)'
CORAL
=
'#ff7f50'
CORNFLOWERBLUE
=
'cornflowerblue'
...
...
@@ -32,10 +34,16 @@ class TestDragAndDropRender(BaseIntegrationTest):
def
load_scenario
(
self
,
item_background_color
=
""
,
item_text_color
=
""
):
scenario_xml
=
"""
<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
)
<vertical_demo>
<drag-and-drop-v2 item_background_color='{item_background_color}'
item_text_color='{item_text_color}'
data='{data}' />
</vertical_demo>
"""
.
format
(
item_background_color
=
item_background_color
,
item_text_color
=
item_text_color
,
data
=
load_resource
(
"integration/data/test_data_a11y.json"
)
)
self
.
_add_scenario
(
self
.
PAGE_ID
,
self
.
PAGE_TITLE
,
scenario_xml
)
self
.
browser
.
get
(
self
.
live_server_url
)
...
...
@@ -83,18 +91,9 @@ class TestDragAndDropRender(BaseIntegrationTest):
color
=
self
.
_get_style
(
'.item-bank .option[data-value='
+
item_val
+
']'
,
'color'
)
self
.
assertEquals
(
color
,
expected_color
)
def
test_items
(
self
):
def
test_items
_default_colors
(
self
):
self
.
load_scenario
()
items
=
self
.
_get_items
()
self
.
assertEqual
(
len
(
items
),
3
)
for
index
,
item
in
enumerate
(
items
):
self
.
assertEqual
(
item
.
get_attribute
(
'data-value'
),
str
(
index
))
self
.
assertEqual
(
item
.
text
,
self
.
ITEM_PROPERTIES
[
index
][
'text'
])
self
.
assertIn
(
'ui-draggable'
,
self
.
get_element_classes
(
item
))
self
.
_test_item_style
(
item
,
{})
self
.
_test_items
()
@unpack
@data
(
...
...
@@ -105,21 +104,36 @@ class TestDragAndDropRender(BaseIntegrationTest):
def
test_items_custom_colors
(
self
,
item_background_color
,
item_text_color
):
self
.
load_scenario
(
item_background_color
,
item_text_color
)
items
=
self
.
_get_items
()
self
.
assertEqual
(
len
(
items
),
3
)
color_settings
=
{}
if
item_background_color
:
color_settings
[
'background-color'
]
=
item_background_color
if
item_text_color
:
color_settings
[
'color'
]
=
item_text_color
self
.
_test_items
(
color_settings
=
color_settings
)
def
_test_items
(
self
,
color_settings
=
{}):
# pylint: disable=dangerous-default-value
items
=
self
.
_get_items
()
self
.
assertEqual
(
len
(
items
),
3
)
for
index
,
item
in
enumerate
(
items
):
item_number
=
index
+
1
self
.
assertEqual
(
item
.
get_attribute
(
'tabindex'
),
'0'
)
self
.
assertEqual
(
item
.
get_attribute
(
'draggable'
),
'true'
)
self
.
assertEqual
(
item
.
get_attribute
(
'aria-grabbed'
),
'false'
)
self
.
assertEqual
(
item
.
get_attribute
(
'data-value'
),
str
(
index
))
self
.
assertEqual
(
item
.
text
,
self
.
ITEM_PROPERTIES
[
index
][
'text'
])
self
.
assertIn
(
'ui-draggable'
,
self
.
get_element_classes
(
item
))
self
.
_test_item_style
(
item
,
color_settings
)
try
:
background_image
=
item
.
find_element_by_css_selector
(
'img'
)
except
NoSuchElementException
:
self
.
assertEqual
(
item
.
text
,
self
.
ITEM_PROPERTIES
[
index
][
'text'
])
else
:
self
.
assertEqual
(
background_image
.
get_attribute
(
'alt'
),
'This describes the background image of item {}'
.
format
(
item_number
)
)
def
test_zones
(
self
):
self
.
load_scenario
()
...
...
@@ -128,19 +142,39 @@ class TestDragAndDropRender(BaseIntegrationTest):
self
.
assertEqual
(
len
(
zones
),
2
)
self
.
assertEqual
(
zones
[
0
]
.
get_attribute
(
'data-zone'
),
'Zone 1'
)
self
.
assertIn
(
'ui-droppable'
,
self
.
get_element_classes
(
zones
[
0
]))
self
.
_assert_box_percentages
(
'#zone-1'
,
left
=
31.1284
,
top
=
6.17284
,
width
=
38.1323
,
height
=
36.6255
)
self
.
assertEqual
(
zones
[
1
]
.
get_attribute
(
'data-zone'
),
'Zone 2'
)
self
.
assertIn
(
'ui-droppable'
,
self
.
get_element_classes
(
zones
[
1
]))
self
.
_assert_box_percentages
(
'#zone-2'
,
left
=
16.7315
,
top
=
43.2099
,
width
=
66.1479
,
height
=
28.8066
)
box_percentages
=
[
{
"left"
:
31.1284
,
"top"
:
6.17284
,
"width"
:
38.1323
,
"height"
:
36.6255
},
{
"left"
:
16.7315
,
"top"
:
43.2099
,
"width"
:
66.1479
,
"height"
:
28.8066
}
]
for
index
,
zone
in
enumerate
(
zones
):
zone_number
=
index
+
1
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
.
assertIn
(
'ui-droppable'
,
self
.
get_element_classes
(
zone
))
zone_box_percentages
=
box_percentages
[
index
]
self
.
_assert_box_percentages
(
'#zone-{}'
.
format
(
zone_number
),
left
=
zone_box_percentages
[
'left'
],
top
=
zone_box_percentages
[
'top'
],
width
=
zone_box_percentages
[
'width'
],
height
=
zone_box_percentages
[
'height'
]
)
zone_name
=
zone
.
find_element_by_css_selector
(
'p.zone-name'
)
self
.
assertEqual
(
zone_name
.
text
,
'ZONE {}'
.
format
(
zone_number
))
zone_description
=
zone
.
find_element_by_css_selector
(
'p.zone-description'
)
self
.
assertEqual
(
zone_description
.
text
,
'THIS DESCRIBES ZONE {}'
.
format
(
zone_number
))
# Zone description should only be visible to screen readers:
self
.
assertEqual
(
zone_description
.
get_attribute
(
'class'
),
'zone-description sr'
)
def
test_feedback
(
self
):
self
.
load_scenario
()
feedback
=
self
.
_get_feedback
()
feedback_message
=
self
.
_get_feedback_message
()
self
.
assertEqual
(
feedback
.
get_attribute
(
'aria-live'
),
'polite'
)
self
.
assertEqual
(
feedback_message
.
text
,
"Drag the items onto the image above."
)
def
test_background_image
(
self
):
...
...
@@ -149,3 +183,4 @@ class TestDragAndDropRender(BaseIntegrationTest):
bg_image
=
self
.
browser
.
find_element_by_css_selector
(
".xblock--drag-and-drop .target-img"
)
image_path
=
'/resource/drag-and-drop-v2/public/img/triangle.png'
self
.
assertTrue
(
bg_image
.
get_attribute
(
"src"
)
.
endswith
(
image_path
))
self
.
assertEqual
(
bg_image
.
get_attribute
(
"alt"
),
'This describes the target image'
)
tests/unit/data/html/config_out.json
View file @
e8b10924
...
...
@@ -4,6 +4,7 @@
"question_text"
:
"Solve this <strong>drag-and-drop</strong> problem."
,
"show_question_header"
:
false
,
"target_img_expanded_url"
:
"/expanded/url/to/drag_and_drop_v2/public/img/triangle.png"
,
"target_img_description"
:
"This describes the target image"
,
"item_background_color"
:
"white"
,
"item_text_color"
:
"#000080"
,
"initial_feedback"
:
"HTML <strong>Intro</strong> Feed"
,
...
...
tests/unit/data/html/data.json
View file @
e8b10924
...
...
@@ -69,5 +69,6 @@
"feedback"
:
{
"start"
:
"HTML <strong>Intro</strong> Feed"
,
"finish"
:
"Final <strong>feedback</strong>!"
}
},
"targetImgDescription"
:
"This describes the target image"
}
tests/unit/data/old/config_out.json
View file @
e8b10924
...
...
@@ -4,6 +4,7 @@
"question_text"
:
""
,
"show_question_header"
:
true
,
"target_img_expanded_url"
:
"http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png"
,
"target_img_description"
:
"This describes the target image"
,
"item_background_color"
:
null
,
"item_text_color"
:
null
,
"initial_feedback"
:
"Intro Feed"
,
...
...
tests/unit/data/old/data.json
View file @
e8b10924
...
...
@@ -89,5 +89,6 @@
"start"
:
"Intro Feed"
,
"finish"
:
"Final Feed"
},
"targetImg"
:
"http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png"
"targetImg"
:
"http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png"
,
"targetImgDescription"
:
"This describes the target image"
}
tests/unit/data/plain/config_out.json
View file @
e8b10924
...
...
@@ -4,6 +4,7 @@
"question_text"
:
"Can you solve this drag-and-drop problem?"
,
"show_question_header"
:
true
,
"target_img_expanded_url"
:
"http://placehold.it/800x600"
,
"target_img_description"
:
"This describes the target image"
,
"item_background_color"
:
null
,
"item_text_color"
:
null
,
"initial_feedback"
:
"This is the initial feedback."
,
...
...
tests/unit/data/plain/data.json
View file @
e8b10924
...
...
@@ -76,5 +76,6 @@
"targetImg"
:
"http://placehold.it/800x600"
,
"targetImgDescription"
:
"This describes the target image"
,
"displayLabels"
:
false
}
tests/unit/test_basics.py
View file @
e8b10924
...
...
@@ -36,6 +36,7 @@ class BasicTests(TestCaseMixin, unittest.TestCase):
"question_text"
:
""
,
"show_question_header"
:
True
,
"target_img_expanded_url"
:
'/expanded/url/to/drag_and_drop_v2/public/img/triangle.png'
,
"target_img_description"
:
""
,
"item_background_color"
:
None
,
"item_text_color"
:
None
,
"initial_feedback"
:
DEFAULT_START_FEEDBACK
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment