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
698f404d
Commit
698f404d
authored
Feb 08, 2016
by
Braden MacDonald
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Identify zones by UID, not by title.
Fixes bugs when zones had numeric titles. Backwards compatible.
parent
4c066e7a
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
206 additions
and
168 deletions
+206
-168
drag_and_drop_v2/default_data.py
+10
-9
drag_and_drop_v2/drag_and_drop_v2.py
+34
-2
drag_and_drop_v2/public/js/drag_and_drop.js
+16
-5
drag_and_drop_v2/public/js/drag_and_drop_edit.js
+51
-51
drag_and_drop_v2/templates/html/js_templates.html
+10
-9
pylintrc
+1
-0
tests/integration/data/test_data.json
+4
-6
tests/integration/data/test_data_a11y.json
+1
-4
tests/integration/data/test_data_other.json
+4
-6
tests/integration/data/test_html_data.json
+4
-6
tests/integration/data/test_sizing_template.json
+6
-6
tests/integration/test_interaction.py
+36
-30
tests/integration/test_render.py
+4
-4
tests/unit/data/html/config_out.json
+2
-4
tests/unit/data/old/config_out.json
+2
-4
tests/unit/data/plain/config_out.json
+2
-4
tests/unit/data/plain/data.json
+4
-6
tests/unit/test_advanced.py
+5
-2
tests/unit/test_basics.py
+10
-10
No files found.
drag_and_drop_v2/default_data.py
View file @
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
,
},
...
...
drag_and_drop_v2/drag_and_drop_v2.py
View file @
698f404d
...
...
@@ -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.
...
...
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
698f404d
...
...
@@ -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_u
id
,
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.
...
...
drag_and_drop_v2/public/js/drag_and_drop_edit.js
View file @
698f404d
...
...
@@ -205,34 +205,28 @@ function DragAndDropEditBlock(runtime, element, params) {
},
form
:
{
zone
:
{
count
:
0
,
formCount
:
0
,
totalZonesCreated
:
0
,
// This counter is used for HTML IDs. Never decremented.
zoneObjects
:
[],
get
ObjByIndex
:
function
(
num
)
{
get
ZoneObjByUID
:
function
(
uid
)
{
for
(
var
i
=
0
;
i
<
_fn
.
build
.
form
.
zone
.
zoneObjects
.
length
;
i
++
)
{
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
[
i
].
index
==
num
)
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
[
i
].
uid
==
uid
)
{
return
_fn
.
build
.
form
.
zone
.
zoneObjects
[
i
];
}
}
},
add
:
function
(
oldZone
)
{
var
inputTemplate
=
_fn
.
tpl
.
zoneInput
,
name
=
'zone-'
,
$elements
=
_fn
.
build
.
$el
,
num
;
if
(
!
oldZone
)
oldZone
=
{};
_fn
.
build
.
form
.
zone
.
count
++
;
_fn
.
build
.
form
.
zone
.
formCount
++
;
num
=
_fn
.
build
.
form
.
zone
.
count
;
name
+=
num
;
var
num
=
_fn
.
build
.
form
.
zone
.
zoneObjects
.
length
+
1
;
// Update zone obj
var
zoneObj
=
{
title
:
oldZone
.
title
||
'Zone '
+
num
,
description
:
oldZone
.
description
,
id
:
name
,
index
:
num
,
// uid: unique ID for this zone. For backwards compatibility,
// this field cannot be called "id" and must inherit the "title"
// property if no 'uid' value is present, since old versions of
// this block used the title as the primary identifier.
uid
:
oldZone
.
uid
||
oldZone
.
title
||
_fn
.
build
.
form
.
zone
.
generateUID
(),
width
:
oldZone
.
width
||
200
,
height
:
oldZone
.
height
||
100
,
x
:
oldZone
.
x
||
0
,
...
...
@@ -241,45 +235,55 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
build
.
form
.
zone
.
zoneObjects
.
push
(
zoneObj
);
// Add fields to zone position form
$zoneNode
=
$
(
inputTemplate
(
zoneObj
));
$zoneNode
.
data
(
'index'
,
num
);
$elements
.
zones
.
form
.
append
(
$zoneNode
);
// Add fields to zone form
$zoneNode
=
$
(
_fn
.
tpl
.
zoneInput
({
zone
:
zoneObj
,
index
:
_fn
.
build
.
form
.
zone
.
totalZonesCreated
++
,
}));
_fn
.
build
.
$el
.
zones
.
form
.
append
(
$zoneNode
);
_fn
.
build
.
form
.
zone
.
enableDelete
();
// Add zone div to target
_fn
.
build
.
form
.
zone
.
renderZonesPreview
();
},
generateUID
:
function
()
{
// Generate a unique ID for a new zone.
for
(
var
i
=
1
;
true
;
i
++
)
{
var
uid
=
"zone-"
+
i
;
if
(
!
_fn
.
build
.
form
.
zone
.
getZoneObjByUID
(
uid
))
{
return
uid
;
}
}
},
remove
:
function
(
e
)
{
var
$el
=
$
(
e
.
currentTarget
).
closest
(
'.zone-row'
),
classes
=
$el
.
attr
(
'class'
),
id
=
classes
.
slice
(
classes
.
indexOf
(
'zone-row'
)
+
9
),
index
=
$el
.
data
(
'index'
),
uid
=
String
(
$el
.
data
(
'uid'
)),
// cast to string since UID must be string but .data() converts data-uid="5" to 5
array_index
;
e
.
preventDefault
();
$el
.
detach
();
// Find the
index
of the zone in the array and remove it.
// Find the
uid
of the zone in the array and remove it.
for
(
array_index
=
0
;
array_index
<
_fn
.
build
.
form
.
zone
.
zoneObjects
.
length
;
array_index
++
)
{
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
[
array_index
].
index
==
index
)
break
;
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
[
array_index
].
uid
==
uid
)
break
;
}
_fn
.
build
.
form
.
zone
.
zoneObjects
.
splice
(
array_index
,
1
);
_fn
.
build
.
form
.
zone
.
renderZonesPreview
();
_fn
.
build
.
form
.
zone
.
formCount
--
;
_fn
.
build
.
form
.
zone
.
disableDelete
();
},
enableDelete
:
function
()
{
if
(
_fn
.
build
.
form
.
zone
.
formCount
>
1
)
{
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
.
length
>
1
)
{
_fn
.
build
.
$el
.
zones
.
form
.
find
(
'.remove-zone'
).
removeClass
(
'hidden'
);
}
},
disableDelete
:
function
()
{
if
(
_fn
.
build
.
form
.
zone
.
formCount
===
1
)
{
if
(
_fn
.
build
.
form
.
zone
.
zoneObjects
.
length
===
1
)
{
_fn
.
build
.
$el
.
zones
.
form
.
find
(
'.remove-zone'
).
addClass
(
'hidden'
);
}
},
...
...
@@ -296,7 +300,7 @@ function DragAndDropEditBlock(runtime, element, params) {
this
.
zoneObjects
.
forEach
(
function
(
zoneObj
)
{
_fn
.
build
.
$el
.
zonesPreview
.
append
(
_fn
.
tpl
.
zoneElement
({
id
:
zoneObj
.
id
,
uid
:
zoneObj
.
u
id
,
title
:
zoneObj
.
title
,
description
:
zoneObj
.
description
,
x_percent
:
(
+
zoneObj
.
x
)
/
imgWidth
*
100
,
...
...
@@ -307,23 +311,11 @@ function DragAndDropEditBlock(runtime, element, params) {
);
});
},
getZoneNames
:
function
()
{
var
zoneNames
=
[];
var
$form
=
_fn
.
build
.
$el
.
zones
.
form
.
find
(
'.title'
);
$form
.
each
(
function
(
i
,
el
)
{
var
val
=
$
(
el
).
val
();
if
(
val
.
length
>
0
)
{
zoneNames
.
push
(
val
);
}
});
return
zoneNames
;
},
changedInputHandler
:
function
(
ev
)
{
// Called when any of the inputs have changed.
var
$changedInput
=
$
(
ev
.
currentTarget
);
var
$row
=
$changedInput
.
closest
(
'.zone-row'
);
var
record
=
_fn
.
build
.
form
.
zone
.
get
ObjByIndex
(
$row
.
data
(
'index'
));
var
record
=
_fn
.
build
.
form
.
zone
.
get
ZoneObjByUID
(
String
(
$row
.
data
(
'uid'
)
));
if
(
$changedInput
.
hasClass
(
'title'
))
{
record
.
title
=
$changedInput
.
val
();
}
else
if
(
$changedInput
.
hasClass
(
'width'
))
{
...
...
@@ -344,18 +336,26 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
build
.
form
.
zone
.
renderZonesPreview
();
},
},
createDropdown
:
function
(
selected
)
{
var
tpl
=
_fn
.
tpl
.
zoneDropdown
,
dropdown
=
[],
html
,
dropdown_items
=
_fn
.
build
.
form
.
zone
.
getZoneNames
().
concat
(
'none'
);
for
(
var
i
=
0
;
i
<
dropdown_items
.
length
;
i
++
)
{
var
is_sel
=
(
dropdown_items
[
i
]
==
selected
)
?
'selected'
:
''
;
dropdown
.
push
(
tpl
({
value
:
dropdown_items
[
i
],
selected
:
is_sel
}));
}
createDropdown
:
function
(
selectedUID
)
{
var
template
=
_fn
.
tpl
.
zoneDropdown
;
var
dropdown
=
[];
var
zoneObjects
=
_fn
.
build
.
form
.
zone
.
zoneObjects
;
zoneObjects
.
forEach
(
function
(
zoneObj
)
{
dropdown
.
push
(
template
({
uid
:
zoneObj
.
uid
,
title
:
zoneObj
.
title
,
selected
:
(
zoneObj
.
uid
==
selectedUID
)
?
'selected'
:
''
,
}));
});
dropdown
.
push
(
template
({
uid
:
"none"
,
title
:
window
.
gettext
(
"None"
),
selected
:
(
selectedUID
===
"none"
)
?
'selected'
:
''
,
}));
html
=
dropdown
.
join
(
''
);
var
html
=
dropdown
.
join
(
''
);
return
new
Handlebars
.
SafeString
(
html
);
},
feedback
:
function
(
$form
)
{
...
...
drag_and_drop_v2/templates/html/js_templates.html
View file @
698f404d
<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
}}
>
{{
valu
e
}}
<
/option
>
<
option
value
=
"{{
uid }}"
{{
selected
}}
>
{{
titl
e
}}
<
/option
>
</script>
<script
id=
"item-input-tpl"
type=
"text/html"
>
...
...
pylintrc
View file @
698f404d
...
...
@@ -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,
...
...
tests/integration/data/test_data.json
View file @
698f404d
{
"zones"
:
[
{
"index"
:
1
,
"width"
:
200
,
"title"
:
"Zone 1"
,
"height"
:
100
,
"y"
:
"200"
,
"x"
:
"100"
,
"id"
:
"zone-1"
"
u
id"
:
"zone-1"
},
{
"index"
:
2
,
"width"
:
200
,
"title"
:
"Zone 2"
,
"height"
:
100
,
"y"
:
0
,
"x"
:
0
,
"id"
:
"zone-2"
"
u
id"
:
"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"
:
{
...
...
tests/integration/data/test_data_a11y.json
View file @
698f404d
{
"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"
:
[
...
...
tests/integration/data/test_data_other.json
View file @
698f404d
{
"zones"
:
[
{
"index"
:
1
,
"width"
:
200
,
"title"
:
"Zone 51"
,
"height"
:
100
,
"y"
:
"400"
,
"x"
:
"200"
,
"id"
:
"zone-51"
"
u
id"
:
"zone-51"
},
{
"index"
:
2
,
"width"
:
200
,
"title"
:
"Zone 52"
,
"height"
:
100
,
"y"
:
"200"
,
"x"
:
"100"
,
"id"
:
"zone-52"
"
u
id"
:
"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"
:
{
...
...
tests/integration/data/test_html_data.json
View file @
698f404d
{
"zones"
:
[
{
"index"
:
1
,
"width"
:
200
,
"title"
:
"Zone <i>1</i>"
,
"height"
:
100
,
"y"
:
200
,
"x"
:
100
,
"id"
:
"zone-1"
"
u
id"
:
"zone-1"
},
{
"index"
:
2
,
"width"
:
200
,
"title"
:
"Zone <b>2</b>"
,
"height"
:
100
,
"y"
:
0
,
"x"
:
0
,
"id"
:
"zone-2"
"
u
id"
:
"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"
:
{
...
...
tests/integration/data/test_sizing_template.json
View file @
698f404d
...
...
@@ -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
,
...
...
tests/integration/test_interaction.py
View file @
698f404d
...
...
@@ -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
=
{
...
...
tests/integration/test_render.py
View file @
698f404d
...
...
@@ -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'
)
...
...
tests/unit/data/html/config_out.json
View file @
698f404d
...
...
@@ -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>
"
}
],
...
...
tests/unit/data/old/config_out.json
View file @
698f404d
...
...
@@ -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"
}
],
...
...
tests/unit/data/plain/config_out.json
View file @
698f404d
...
...
@@ -14,22 +14,20 @@
"zones"
:
[
{
"index"
:
1
,
"title"
:
"Zone 1"
,
"y"
:
123
,
"x"
:
234
,
"width"
:
345
,
"height"
:
456
,
"id"
:
"zone-1"
"
u
id"
:
"zone-1"
},
{
"index"
:
2
,
"title"
:
"Zone 2"
,
"y"
:
20
,
"x"
:
10
,
"width"
:
30
,
"height"
:
40
,
"id"
:
"zone-2"
"
u
id"
:
"zone-2"
}
],
...
...
tests/unit/data/plain/data.json
View file @
698f404d
{
"zones"
:
[
{
"index"
:
1
,
"title"
:
"Zone 1"
,
"y"
:
123
,
"x"
:
234
,
"width"
:
345
,
"height"
:
456
,
"id"
:
"zone-1"
"
u
id"
:
"zone-1"
},
{
"index"
:
2
,
"title"
:
"Zone 2"
,
"y"
:
20
,
"x"
:
10
,
"width"
:
30
,
"height"
:
40
,
"id"
:
"zone-2"
"
u
id"
:
"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"
:
{
...
...
tests/unit/test_advanced.py
View file @
698f404d
...
...
@@ -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"
tests/unit/test_basics.py
View file @
698f404d
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
,
...
...
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