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
6b977414
Commit
6b977414
authored
Jan 18, 2016
by
Braden MacDonald
Browse files
Options
Browse Files
Download
Plain Diff
Update this branch with latest changes from master
# Conflicts: # tests/integration/test_interaction.py
parents
9e32e448
d31dce44
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
411 additions
and
195 deletions
+411
-195
.travis.yml
+1
-0
README.md
+257
-0
drag_and_drop_v2/drag_and_drop_v2.py
+1
-7
drag_and_drop_v2/public/css/drag_and_drop.css
+1
-12
drag_and_drop_v2/public/css/drag_and_drop_edit.css
+0
-11
drag_and_drop_v2/public/js/drag_and_drop.js
+42
-29
drag_and_drop_v2/public/js/drag_and_drop_edit.js
+0
-16
drag_and_drop_v2/public/js/vendor/jquery.html5-placeholder-shim.js
+0
-109
drag_and_drop_v2/public/js/view.js
+0
-1
drag_and_drop_v2/public/themes/apros.css
+1
-1
setup.py
+2
-1
tests/integration/test_interaction.py
+106
-8
No files found.
.travis.yml
View file @
6b977414
language
:
python
sudo
:
false
python
:
-
"
2.7"
before_install
:
...
...
README.md
View file @
6b977414
...
...
@@ -137,6 +137,263 @@ any zone.
You can define an arbitrary number of drag items.
Analytics Events
----------------
The following analytics events are provided by this block.
## `edx.drag_and_drop_v2.loaded`
Fired when the Drag and Drop XBlock is finished loading.
Example ("common" fields that are not interesting in this context have been left out):
```
{
...
"event": {},
"event_source": "server", -- Common field, contains event source.
"event_type": "edx.drag_and_drop_v2.loaded", -- Common field, contains event name.
...
```
Real event example (taken from a devstack):
```
{
"username": "staff",
"event_type": "edx.drag_and_drop_v2.loaded",
"ip": "10.0.2.2",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"host": "precise64",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {},
"event_source": "server",
"context": {
"course_user_tags": {},
"user_id": 5,
"org_id": "DnD",
"module": {
"usage_key": "block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3",
"display_name": "Drag and Drop"
},
"course_id": "course-v1:DnD+DnD+DnD",
"path": "/courses/course-v1:DnD+DnD+DnD/xblock/block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3/handler/publish_event"
},
"time": "2016-01-13T01:52:41.330049+00:00",
"page": "x_module"
}
```
## `edx.drag_and_drop_v2.item.picked_up`
Fired when a student picks up a draggable item.
Example ("common" fields that are not interesting in this context have been left out):
```
{
...
"event": {
"item_id": 0, -- ID of the draggable item.
},
"event_source": "server", -- Common field, contains event source.
"event_type": "edx.drag_and_drop_v2.picked_up", -- Common field, contains event name.
...
```
Real event example (taken from a devstack):
```
{
"username": "staff",
"event_type": "edx.drag_and_drop_v2.item.picked_up",
"ip": "10.0.2.2",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"host": "precise64",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {
"item_id": 0,
},
"event_source": "server",
"context": {
"course_user_tags": {},
"user_id": 5,
"org_id": "DnD",
"module": {
"usage_key": "block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3",
"display_name": "Drag and Drop"
},
"course_id": "course-v1:DnD+DnD+DnD",
"path": "/courses/course-v1:DnD+DnD+DnD/xblock/block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3/handler/publish_event"
},
"time": "2016-01-13T01:58:44.395935+00:00",
"page": "x_module"
}
```
## `edx.drag_and_drop_v2.item.dropped`
Fired when a student drops a draggable item.
This event will be emitted when a student drops a draggable item.
Example ("common" fields that are not interesting in this context have been left out):
```
{
...
"event": {
"input": null,
"is_correct": true, -- False if there is an input in the draggable item, and the student provided the wrong answer. Otherwise true.
"is_correct_location": true, -- Whether the draggable item has been placed in the correct location.
"item_id": 0, -- ID of the draggable item.
"location": "The Top Zone", -- Name of the location the item was dragged to.
},
"event_source": "server", -- Common field, contains event source.
"event_type": "edx.drag_and_drop_v2.dropped", -- Common field, contains event name.
...
```
Real event example (taken from a devstack):
```
{
"username": "staff",
"event_type": "edx.drag_and_drop_v2.item.dropped",
"ip": "10.0.2.2",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"host": "precise64",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {
"is_correct_location": true,
"is_correct": true,
"location": "The Top Zone",
"item_id": 0,
"input": null
},
"event_source": "server",
"context": {
"course_user_tags": {},
"user_id": 5,
"org_id": "DnD",
"module": {
"usage_key": "block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3",
"display_name": "Drag and Drop"
},
"course_id": "course-v1:DnD+DnD+DnD",
"path": "/courses/course-v1:DnD+DnD+DnD/xblock/block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3/handler/do_attempt"
},
"time": "2016-01-13T01:58:45.202313+00:00",
"page": "x_module"
}
```
## `edx.drag_and_drop_v2.feedback.opened`
Fired when the feedback pop-up is opened.
Example ("common" fields that are not interesting in this context have been left out):
```
{
...
"event": {
"content": "Correct! This one belongs to The Top Zone.", -- Content of the feedback popup.
"truncated": false, -- Boolean indicating whether "content" field was truncated.
},
"event_source": "server", -- Common field, contains event source.
"event_type": "edx.drag_and_drop_v2.feedback.opened", -- Common field, contains event name.
...
```
Real event example (taken from a devstack):
```
{
"username": "staff",
"event_type": "edx.drag_and_drop_v2.feedback.opened",
"ip": "10.0.2.2",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"host": "precise64",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {
"content": "Correct! This one belongs to The Top Zone.",
"truncated": false,
},
"event_source": "server",
"context": {
"course_user_tags": {},
"user_id": 5,
"org_id": "DnD",
"module": {
"usage_key": "block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3",
"display_name": "Drag and Drop"
},
"course_id": "course-v1:DnD+DnD+DnD",
"path": "/courses/course-v1:DnD+DnD+DnD/xblock/block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@6b80ce1e8b78426898b47a834d72ffd3/handler/publish_event"
},
"time": "2016-01-13T01:58:45.844986+00:00",
"page": "x_module"
}
```
## `edx.drag_and_drop_v2.feedback.closed`
Fired when the feedback popup is closed.
Example ("common" fields that are not interesting in this context have been left out):
```
{
...
"event": {
"content": "No, this item does not belong here. Try again." -- Message of the feedback popup that was closed.
"manually": true, -- Whether or not the user closed the feedback window manually or if it was auto-closed.
"truncated": false, -- Boolean indicating whether "content" field was truncated.
},
"event_source": "server", -- Common field, contains event source.
"event_type": "edx.drag_and_drop_v2.feedback.closed", -- Common field, contains event name.
...
```
Real event example (taken from a devstack):
```
{
"username": "staff",
"event_type": "edx.drag_and_drop_v2.feedback.closed",
"ip": "10.0.2.2",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"host": "precise64",
"referer": "http://example.com/courses/course-v1:DnD+DnD+DnD/courseware/ec546c58d2f447b7a9223c57b5de7344/756071f8de7f47c3b0ae726586ebbe16/1?activate_block_id=block-v1%3ADnD%2BDnD%2BDnD%2Btype%40vertical%2Bblock%40d2fc47476ca14c55816c4a1264a27280",
"accept_language": "en;q=1.0, en;q=0.5",
"event": {
"content": "No, this item does not belong here. Try again."
"manually": true
"truncated": false,
},
"event_source": "server",
"context": {
"course_user_tags": {},
"user_id": 5,
"org_id": "DnD",
"module": {
"usage_key": "block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@13d1b859a2304c858e1810ccc23f29b2",
"display_name": "Drag and Drop"
},
"course_id": "course-v1:DnD+DnD+DnD",
"path": "/courses/course-v1:DnD+DnD+DnD/xblock/block-v1:DnD+DnD+DnD+type@drag-and-drop-v2+block@13d1b859a2304c858e1810ccc23f29b2/handler/publish_event"
},
"time": "2016-01-13T02:07:00.988534+00:00",
"page": "x_module"
}
```
Testing
-------
...
...
drag_and_drop_v2/drag_and_drop_v2.py
View file @
6b977414
...
...
@@ -198,7 +198,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
)
js_urls
=
(
'public/js/vendor/jquery-ui-1.10.4.custom.min.js'
,
'public/js/vendor/jquery.html5-placeholder-shim.js'
,
'public/js/vendor/handlebars-v1.1.2.js'
,
'public/js/drag_and_drop_edit.js'
,
)
...
...
@@ -287,9 +286,7 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
# so we have to figure that we're running in Studio for now
pass
self
.
runtime
.
publish
(
self
,
'xblock.drag-and-drop-v2.item.dropped'
,
{
'user_id'
:
self
.
scope_ids
.
user_id
,
'component_id'
:
self
.
_get_unique_id
(),
self
.
runtime
.
publish
(
self
,
'edx.drag_and_drop_v2.item.dropped'
,
{
'item_id'
:
item
[
'id'
],
'location'
:
attempt
.
get
(
'zone'
),
'input'
:
attempt
.
get
(
'input'
),
...
...
@@ -444,9 +441,6 @@ class DragAndDropBlock(XBlock, XBlockWithSettingsMixin, ThemableXBlockMixin):
except
KeyError
:
return
{
'result'
:
'error'
,
'message'
:
'Missing event_type in JSON data'
}
data
[
'user_id'
]
=
self
.
scope_ids
.
user_id
data
[
'component_id'
]
=
self
.
_get_unique_id
()
self
.
runtime
.
publish
(
self
,
event_type
,
data
)
return
{
'result'
:
'success'
}
...
...
drag_and_drop_v2/public/css/drag_and_drop.css
View file @
6b977414
...
...
@@ -244,7 +244,7 @@
border
:
2px
solid
#a5a5a5
;
}
.xblock--drag-and-drop
.zone
p
{
.xblock--drag-and-drop
.
drag-container
.target
.
zone
p
{
width
:
100%
;
font-family
:
Arial
;
font-size
:
16px
;
...
...
@@ -255,17 +255,6 @@
margin-bottom
:
auto
;
}
/*** IE9 alignment fix ***/
.lt-ie10
.xblock--drag-and-drop
.zone
{
display
:
table
;
}
.lt-ie10
.xblock--drag-and-drop
.zone
p
{
display
:
table-cell
;
vertical-align
:
middle
;
text-align
:
center
;
}
/*** FEEDBACK ***/
.xblock--drag-and-drop
.feedback
{
...
...
drag_and_drop_v2/public/css/drag_and_drop_edit.css
View file @
6b977414
...
...
@@ -50,17 +50,6 @@
margin-bottom
:
auto
;
}
/*** IE9 alignment fix ***/
.lt-ie10
.xblock--drag-and-drop--editor
.zone
{
display
:
table
;
}
.lt-ie10
.xblock--drag-and-drop--editor
.zone
p
{
display
:
table-cell
;
vertical-align
:
middle
;
text-align
:
center
;
}
/** Builder **/
.xblock--drag-and-drop--editor
.hidden
{
display
:
none
!important
;
...
...
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
6b977414
...
...
@@ -13,13 +13,15 @@ function DragAndDropBlock(runtime, element, configuration) {
var
bgImgNaturalWidth
=
undefined
;
// pixel width of the background image (when not scaled)
var
__vdom
=
virtualDom
.
h
();
// blank virtual DOM
// Event string size limit.
var
MAX_LENGTH
=
255
;
// Keyboard accessibility
var
ESC
=
27
;
var
RET
=
13
;
var
SPC
=
32
;
var
TAB
=
9
;
var
M
=
77
;
var
QUESTION_MARK
=
63
;
var
placementMode
=
false
;
var
$selectedItem
;
...
...
@@ -48,9 +50,6 @@ function DragAndDropBlock(runtime, element, configuration) {
// Set up event handlers:
$
(
document
).
on
(
'keydown mousedown touchstart'
,
closePopup
);
$
(
document
).
on
(
'keypress'
,
function
(
evt
)
{
runOnKey
(
evt
,
QUESTION_MARK
,
showKeyboardHelp
);
});
$element
.
on
(
'click'
,
'.keyboard-help-button'
,
showKeyboardHelp
);
$element
.
on
(
'keydown'
,
'.keyboard-help-button'
,
function
(
evt
)
{
runOnKey
(
evt
,
RET
,
showKeyboardHelp
);
...
...
@@ -69,7 +68,7 @@ function DragAndDropBlock(runtime, element, configuration) {
initDroppable
();
// Indicate that exercise is done loading
publishEvent
({
event_type
:
'
xblock.drag-and-drop-
v2.loaded'
});
publishEvent
({
event_type
:
'
edx.drag_and_drop_
v2.loaded'
});
}).
fail
(
function
()
{
$root
.
text
(
gettext
(
"An error occurred. Unable to load drag and drop exercise."
));
});
...
...
@@ -96,6 +95,15 @@ function DragAndDropBlock(runtime, element, configuration) {
}
};
var
truncateField
=
function
(
data
,
fieldName
){
if
(
data
[
fieldName
].
length
>
MAX_LENGTH
)
{
data
[
fieldName
]
=
data
[
fieldName
].
substring
(
0
,
MAX_LENGTH
);
data
[
'truncated'
]
=
true
;
}
else
{
data
[
'truncated'
]
=
false
;
}
};
var
focusModalButton
=
function
()
{
$root
.
find
(
'.keyboard-help-dialog .modal-dismiss-button '
).
focus
();
};
...
...
@@ -204,28 +212,26 @@ function DragAndDropBlock(runtime, element, configuration) {
* Update the DOM to reflect 'state'.
*/
var
applyState
=
function
()
{
// Is there a change to the feedback popup?
if
(
state
.
feedback
!==
previousFeedback
)
{
if
(
state
.
feedback
)
{
if
(
previousFeedback
)
{
publishEvent
({
event_type
:
'xblock.drag-and-drop-v2.feedback.closed'
,
content
:
previousFeedback
,
manually
:
false
,
});
}
publishEvent
({
event_type
:
'xblock.drag-and-drop-v2.feedback.opened'
,
content
:
state
.
feedback
,
});
}
else
{
publishEvent
({
event_type
:
'xblock.drag-and-drop-v2.feedback.closed'
,
content
:
state
.
feedback
,
manually
:
true
,
});
}
previousFeedback
=
state
.
feedback
;
// Has the feedback popup been closed?
if
(
state
.
closing
)
{
var
data
=
{
event_type
:
'edx.drag_and_drop_v2.feedback.closed'
,
content
:
previousFeedback
||
state
.
feedback
,
manually
:
state
.
manually_closed
,
};
truncateField
(
data
,
'content'
);
publishEvent
(
data
);
delete
state
.
feedback
;
delete
state
.
closing
;
}
// Has feedback been set?
if
(
state
.
feedback
)
{
var
data
=
{
event_type
:
'edx.drag_and_drop_v2.feedback.opened'
,
content
:
state
.
feedback
,
};
truncateField
(
data
,
'content'
);
publishEvent
(
data
);
}
updateDOM
();
...
...
@@ -380,7 +386,7 @@ function DragAndDropBlock(runtime, element, configuration) {
var
$item
=
$
(
this
);
grabItem
(
$item
);
publishEvent
({
event_type
:
'
xblock.drag-and-drop-v2.item.picked-
up'
,
event_type
:
'
edx.drag_and_drop_v2.item.picked_
up'
,
item_id
:
$item
.
data
(
'value'
),
});
},
...
...
@@ -515,7 +521,14 @@ function DragAndDropBlock(runtime, element, configuration) {
return
;
}
delete
state
.
feedback
;
state
.
closing
=
true
;
previousFeedback
=
state
.
feedback
;
if
(
target
.
is
(
close_button
))
{
state
.
manually_closed
=
true
;
}
else
{
state
.
manually_closed
=
false
;
}
applyState
();
};
...
...
drag_and_drop_v2/public/js/drag_and_drop_edit.js
View file @
6b977414
...
...
@@ -94,9 +94,6 @@ function DragAndDropEditBlock(runtime, element, params) {
$fbkTab
.
addClass
(
'hidden'
);
$zoneTab
.
removeClass
(
'hidden'
);
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
$
(
this
).
one
(
'click'
,
function
(
e
)
{
// $zoneTab -> $itemTab
e
.
preventDefault
();
...
...
@@ -111,9 +108,6 @@ function DragAndDropEditBlock(runtime, element, params) {
$zoneTab
.
addClass
(
'hidden'
);
$itemTab
.
removeClass
(
'hidden'
);
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
$
(
this
).
addClass
(
'hidden'
);
$
(
'.save-button'
,
element
).
parent
()
.
removeClass
(
'hidden'
)
...
...
@@ -155,8 +149,6 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
build
.
$el
.
targetImage
.
attr
(
'alt'
,
new_description
);
_fn
.
data
.
targetImgDescription
=
new_description
;
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
})
.
on
(
'click'
,
'.display-labels-form input'
,
function
(
e
)
{
_fn
.
data
.
displayLabels
=
$
(
'.display-labels-form input'
,
element
).
is
(
':checked'
);
...
...
@@ -219,8 +211,6 @@ function DragAndDropEditBlock(runtime, element, params) {
// Add zone div to target
_fn
.
build
.
form
.
zone
.
renderZonesPreview
();
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
},
remove
:
function
(
e
)
{
var
$el
=
$
(
e
.
currentTarget
).
closest
(
'.zone-row'
),
...
...
@@ -243,8 +233,6 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
build
.
form
.
zone
.
formCount
--
;
_fn
.
build
.
form
.
zone
.
disableDelete
();
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
},
enableDelete
:
function
()
{
if
(
_fn
.
build
.
form
.
zone
.
formCount
>
1
)
{
...
...
@@ -378,8 +366,6 @@ function DragAndDropEditBlock(runtime, element, params) {
$form
.
append
(
tpl
(
ctx
));
_fn
.
build
.
form
.
item
.
enableDelete
();
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
},
remove
:
function
(
e
)
{
var
$el
=
$
(
e
.
currentTarget
).
closest
(
'.item'
);
...
...
@@ -390,8 +376,6 @@ function DragAndDropEditBlock(runtime, element, params) {
_fn
.
build
.
form
.
item
.
count
--
;
_fn
.
build
.
form
.
item
.
disableDelete
();
// Placeholder shim for IE9
$
.
placeholder
.
shim
();
},
enableDelete
:
function
()
{
if
(
_fn
.
build
.
form
.
item
.
count
>
1
)
{
...
...
drag_and_drop_v2/public/js/vendor/jquery.html5-placeholder-shim.js
deleted
100644 → 0
View file @
9e32e448
(
function
(
$
)
{
// @todo Document this.
$
.
extend
(
$
,{
placeholder
:
{
browser_supported
:
function
()
{
return
this
.
_supported
!==
undefined
?
this
.
_supported
:
(
this
.
_supported
=
!!
(
'placeholder'
in
$
(
'<input type="text">'
)[
0
])
);
},
shim
:
function
(
opts
)
{
var
config
=
{
color
:
'#888'
,
cls
:
'placeholder'
,
selector
:
'input[placeholder], textarea[placeholder]'
};
$
.
extend
(
config
,
opts
);
return
!
this
.
browser_supported
()
&&
$
(
config
.
selector
).
_placeholder_shim
(
config
);
}
}});
$
.
extend
(
$
.
fn
,{
_placeholder_shim
:
function
(
config
)
{
function
calcPositionCss
(
target
)
{
var
op
=
$
(
target
).
offsetParent
().
offset
();
var
ot
=
$
(
target
).
offset
();
return
{
top
:
ot
.
top
-
op
.
top
,
left
:
ot
.
left
-
op
.
left
,
width
:
$
(
target
).
width
()
};
}
function
adjustToResizing
(
label
)
{
var
$target
=
label
.
data
(
'target'
);
if
(
typeof
$target
!==
"undefined"
)
{
label
.
css
(
calcPositionCss
(
$target
));
$
(
window
).
one
(
"resize"
,
function
()
{
adjustToResizing
(
label
);
});
}
}
return
this
.
each
(
function
()
{
var
$this
=
$
(
this
);
if
(
$this
.
is
(
':visible'
)
)
{
if
(
$this
.
data
(
'placeholder'
)
)
{
var
$ol
=
$this
.
data
(
'placeholder'
);
$ol
.
css
(
calcPositionCss
(
$this
));
return
true
;
}
var
possible_line_height
=
{};
if
(
!
$this
.
is
(
'textarea'
)
&&
$this
.
css
(
'height'
)
!=
'auto'
)
{
possible_line_height
=
{
lineHeight
:
$this
.
css
(
'height'
),
whiteSpace
:
'nowrap'
};
}
var
isBorderBox
=
(
$this
.
css
(
'box-sizing'
)
===
'border-box'
);
var
ol
=
$
(
'<label />'
)
.
text
(
$this
.
attr
(
'placeholder'
))
.
addClass
(
config
.
cls
)
.
css
(
$
.
extend
({
position
:
'absolute'
,
display
:
'inline'
,
'float'
:
'none'
,
overflow
:
'hidden'
,
textAlign
:
'left'
,
color
:
config
.
color
,
cursor
:
'text'
,
paddingTop
:
isBorderBox
?
'0'
:
$this
.
css
(
'padding-top'
),
paddingRight
:
$this
.
css
(
'padding-right'
),
paddingBottom
:
isBorderBox
?
'0'
:
$this
.
css
(
'padding-bottom'
),
paddingLeft
:
$this
.
css
(
'padding-left'
),
fontSize
:
$this
.
css
(
'font-size'
),
fontFamily
:
$this
.
css
(
'font-family'
),
fontStyle
:
$this
.
css
(
'font-style'
),
fontWeight
:
$this
.
css
(
'font-weight'
),
textTransform
:
$this
.
css
(
'text-transform'
),
backgroundColor
:
'transparent'
,
zIndex
:
99
},
possible_line_height
))
.
css
(
calcPositionCss
(
this
))
.
attr
(
'for'
,
this
.
id
)
.
data
(
'target'
,
$this
)
.
click
(
function
(){
if
(
!
$
(
this
).
data
(
'target'
).
is
(
':disabled'
))
{
$
(
this
).
data
(
'target'
).
focus
();
}
})
.
insertBefore
(
this
);
$this
.
data
(
'placeholder'
,
ol
)
.
keydown
(
function
(){
ol
.
hide
();
})
.
blur
(
function
()
{
ol
[
$this
.
val
().
length
?
'hide'
:
'show'
]();
}).
triggerHandler
(
'blur'
);
$
(
window
).
one
(
"resize"
,
function
()
{
adjustToResizing
(
ol
);
});
}
});
}
});
})(
jQuery
);
jQuery
(
document
).
add
(
window
).
bind
(
'ready load'
,
function
()
{
if
(
jQuery
.
placeholder
)
{
jQuery
.
placeholder
.
shim
();
}
});
drag_and_drop_v2/public/js/view.js
View file @
6b977414
...
...
@@ -197,7 +197,6 @@
h
(
'li'
,
gettext
(
'Press "Enter", "Space", "Ctrl-m", or "⌘-m" on an item to select it for dropping, then navigate to the zone you want to drop it on.'
)),
h
(
'li'
,
gettext
(
'Press "Enter", "Space", "Ctrl-m", or "⌘-m" to drop the item on the current zone.'
)),
h
(
'li'
,
gettext
(
'Press "Escape" if you want to cancel the drop operation (e.g. because you would like to select a different item).'
)),
h
(
'li'
,
gettext
(
'Press "?" at any time to bring up this dialog.'
)),
])
]),
h
(
'div.modal-actions'
,
[
...
...
drag_and_drop_v2/public/themes/apros.css
View file @
6b977414
...
...
@@ -51,7 +51,7 @@
background-color
:
#fff
;
}
.themed-xblock.xblock--drag-and-drop
.zone
p
{
.themed-xblock.xblock--drag-and-drop
.
drag-container
.target
.
zone
p
{
font-family
:
Arial
;
font-size
:
16px
;
font-weight
:
bold
;
...
...
setup.py
View file @
6b977414
...
...
@@ -29,7 +29,8 @@ setup(
install_requires
=
[
'XBlock'
,
'xblock-utils'
,
'ddt'
'ddt'
,
'mock'
,
],
entry_points
=
{
'xblock.v1'
:
'drag-and-drop-v2 = drag_and_drop_v2:DragAndDropBlock'
,
...
...
tests/integration/test_interaction.py
View file @
6b977414
# Imports ###########################################################
from
ddt
import
ddt
,
data
from
ddt
import
ddt
,
data
,
unpack
from
mock
import
Mock
,
patch
from
selenium.common.exceptions
import
NoSuchElementException
from
selenium.webdriver
import
ActionChains
from
selenium.webdriver.common.keys
import
Keys
from
workbench.runtime
import
WorkbenchRuntime
from
xblockutils.resources
import
ResourceLoader
from
drag_and_drop_v2.default_data
import
(
...
...
@@ -77,6 +79,14 @@ class InteractionTestBase(object):
element
=
self
.
_get_item_by_value
(
item_value
)
return
element
.
find_element_by_class_name
(
'numerical-input'
)
def
_get_dialog_components
(
self
,
dialog
):
# pylint: disable=no-self-use
dialog_modal_overlay
=
dialog
.
find_element_by_css_selector
(
'.modal-window-overlay'
)
dialog_modal
=
dialog
.
find_element_by_css_selector
(
'.modal-window'
)
return
dialog_modal_overlay
,
dialog_modal
def
_get_dialog_dismiss_button
(
self
,
dialog_modal
):
# pylint: disable=no-self-use
return
dialog_modal
.
find_element_by_css_selector
(
'.modal-dismiss-button'
)
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
)
...
...
@@ -256,9 +266,8 @@ class InteractionTestBase(object):
def
interact_with_keyboard_help
(
self
,
scroll_down
=
250
,
use_keyboard
=
False
):
keyboard_help_button
=
self
.
_get_keyboard_help_button
()
keyboard_help_dialog
=
self
.
_get_keyboard_help_dialog
()
dialog_modal_overlay
=
keyboard_help_dialog
.
find_element_by_css_selector
(
'.modal-window-overlay'
)
dialog_modal
=
keyboard_help_dialog
.
find_element_by_css_selector
(
'.modal-window'
)
dialog_dismiss_button
=
dialog_modal
.
find_element_by_css_selector
(
'.modal-dismiss-button'
)
dialog_modal_overlay
,
dialog_modal
=
self
.
_get_dialog_components
(
keyboard_help_dialog
)
dialog_dismiss_button
=
self
.
_get_dialog_dismiss_button
(
dialog_modal
)
# Scroll "Keyboard help" button into view to make sure Selenium can successfully click it
self
.
scroll_down
(
pixels
=
scroll_down
)
...
...
@@ -279,21 +288,26 @@ class InteractionTestBase(object):
self
.
assertFalse
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertFalse
(
dialog_modal
.
is_displayed
())
if
use_keyboard
:
#
Try again with "?" key
self
.
_page
.
send_keys
(
"?"
)
if
use_keyboard
:
#
Check if "Keyboard Help" dialog can be dismissed using "ESC"
keyboard_help_button
.
send_keys
(
Keys
.
RETURN
)
self
.
assertTrue
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertTrue
(
dialog_modal
.
is_displayed
())
self
.
_page
.
send_keys
(
Keys
.
ESCAPE
)
self
.
assertFalse
(
dialog_modal_overlay
.
is_displayed
())
self
.
assertFalse
(
dialog_modal
.
is_displayed
())
def
_switch_to_block
(
self
,
idx
):
""" Only needed if ther eare multiple blocks on the page. """
self
.
_page
=
self
.
browser
.
find_elements_by_css_selector
(
self
.
default_css_selector
)[
idx
]
self
.
scroll_down
(
0
)
class
BasicInteractionTest
(
InteractionTestBase
):
class
DefaultDataTestMixin
(
object
):
"""
Testing interactions with Drag and Drop XBlock against default data. If default data changes this will break
.
Provides a test scenario with default options
.
"""
PAGE_TITLE
=
'Drag and Drop v2'
PAGE_ID
=
'drag_and_drop_v2'
...
...
@@ -321,6 +335,11 @@ class BasicInteractionTest(InteractionTestBase):
def
_get_scenario_xml
(
self
):
# pylint: disable=no-self-use
return
"<vertical_demo><drag-and-drop-v2/></vertical_demo>"
class
BasicInteractionTest
(
DefaultDataTestMixin
,
InteractionTestBase
):
"""
Testing interactions with Drag and Drop XBlock against default data. If default data changes this will break.
"""
def
test_item_positive_feedback_on_good_move
(
self
):
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
)
...
...
@@ -341,6 +360,74 @@ class BasicInteractionTest(InteractionTestBase):
@ddt
class
EventsFiredTest
(
DefaultDataTestMixin
,
InteractionTestBase
,
BaseIntegrationTest
):
"""
Tests that the analytics events are fired and in the proper order.
"""
# These events must be fired in this order.
scenarios
=
(
{
'name'
:
'edx.drag_and_drop_v2.loaded'
,
'data'
:
{},
},
{
'name'
:
'edx.drag_and_drop_v2.item.picked_up'
,
'data'
:
{
'item_id'
:
0
},
},
{
'name'
:
'grade'
,
'data'
:
{
'max_value'
:
1
,
'value'
:
(
1.0
/
3
)},
},
{
'name'
:
'edx.drag_and_drop_v2.item.dropped'
,
'data'
:
{
'input'
:
None
,
'is_correct'
:
True
,
'is_correct_location'
:
True
,
'item_id'
:
0
,
'location'
:
u'The Top Zone'
,
},
},
{
'name'
:
'edx.drag_and_drop_v2.feedback.opened'
,
'data'
:
{
'content'
:
u'Correct! This one belongs to The Top Zone.'
,
'truncated'
:
False
,
},
},
{
'name'
:
'edx.drag_and_drop_v2.feedback.closed'
,
'data'
:
{
'manually'
:
False
,
'content'
:
u'Correct! This one belongs to The Top Zone.'
,
'truncated'
:
False
,
},
},
)
def
setUp
(
self
):
mock
=
Mock
()
context
=
patch
.
object
(
WorkbenchRuntime
,
'publish'
,
mock
)
context
.
start
()
self
.
addCleanup
(
context
.
stop
)
self
.
publish
=
mock
super
(
EventsFiredTest
,
self
)
.
setUp
()
def
_get_scenario_xml
(
self
):
# pylint: disable=no-self-use
return
"<vertical_demo><drag-and-drop-v2/></vertical_demo>"
@data
(
*
enumerate
(
scenarios
))
# pylint: disable=star-args
@unpack
def
test_event
(
self
,
index
,
event
):
self
.
parameterized_item_positive_feedback_on_good_move
(
self
.
items_map
)
dummy
,
name
,
published_data
=
self
.
publish
.
call_args_list
[
index
][
0
]
self
.
assertEqual
(
name
,
event
[
'name'
])
self
.
assertEqual
(
published_data
,
event
[
'data'
]
)
@ddt
class
KeyboardInteractionTest
(
BasicInteractionTest
,
BaseIntegrationTest
):
@data
(
Keys
.
RETURN
,
Keys
.
SPACE
,
Keys
.
CONTROL
+
'm'
,
Keys
.
COMMAND
+
'm'
)
def
test_item_positive_feedback_on_good_move_with_keyboard
(
self
,
action_key
):
...
...
@@ -471,3 +558,14 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
self
.
parameterized_final_feedback_and_reset
(
self
.
item_maps
[
'block1'
],
self
.
feedback
[
'block1'
])
self
.
_switch_to_block
(
1
)
self
.
parameterized_final_feedback_and_reset
(
self
.
item_maps
[
'block2'
],
self
.
feedback
[
'block2'
],
scroll_down
=
900
)
def
test_keyboard_help
(
self
):
self
.
_switch_to_block
(
0
)
# Test mouse and keyboard interaction
self
.
interact_with_keyboard_help
()
self
.
interact_with_keyboard_help
(
use_keyboard
=
True
)
self
.
_switch_to_block
(
1
)
# Test mouse and keyboard interaction
self
.
interact_with_keyboard_help
(
scroll_down
=
900
)
self
.
interact_with_keyboard_help
(
scroll_down
=
0
,
use_keyboard
=
True
)
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