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
a1852925
Commit
a1852925
authored
Dec 09, 2015
by
Braden MacDonald
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make the image resize to fit the container, make item placement relative
parent
1ace6d32
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
127 additions
and
105 deletions
+127
-105
drag_and_drop_v2/drag_and_drop_v2.py
+5
-3
drag_and_drop_v2/public/css/drag_and_drop.css
+47
-31
drag_and_drop_v2/public/js/drag_and_drop.js
+47
-48
drag_and_drop_v2/public/js/view.js
+28
-23
No files found.
drag_and_drop_v2/drag_and_drop_v2.py
View file @
a1852925
...
...
@@ -220,9 +220,8 @@ class DragAndDropBlock(XBlock):
is_correct
=
True
feedback
=
item
[
'feedback'
][
'correct'
]
state
=
{
'top'
:
attempt
[
'top'
],
'left'
:
attempt
[
'left'
],
'absolute'
:
True
# flag for backwards compatibility (values used to be relative)
'x_percent'
:
attempt
[
'x_percent'
],
'y_percent'
:
attempt
[
'y_percent'
],
}
if
state
:
...
...
@@ -300,6 +299,9 @@ class DragAndDropBlock(XBlock):
if
self
.
item_text_color
:
data
[
'item_text_color'
]
=
self
.
item_text_color
if
not
data
.
get
(
"targetImg"
):
data
[
"targetImg"
]
=
self
.
runtime
.
local_resource_url
(
self
,
"public/img/triangle.png"
)
return
data
def
_get_item_state
(
self
):
...
...
drag_and_drop_v2/public/css/drag_and_drop.css
View file @
a1852925
.xblock--drag-and-drop
{
width
:
770px
;
width
:
auto
;
max-width
:
770px
;
margin
:
0
;
padding
:
0
;
background
:
#fff
;
}
/* Header, instruction text, etc. */
.xblock--drag-and-drop
.problem-header
{
display
:
inline-block
;
margin
:
0
0
15px
0
;
}
.xblock--drag-and-drop
.problem-progress
{
display
:
inline-block
;
padding-left
:
5px
;
color
:
#666
;
font-weight
:
100
;
font-size
:
1em
;
}
.xblock--drag-and-drop
.problem
p
{
margin-bottom
:
1.41575em
;
}
.xblock--drag-and-drop
.drag-container
{
width
:
515px
;
padding
:
1%
;
background
:
#ebf0f2
;
position
:
relative
;
}
.xblock--drag-and-drop
.clear
{
clear
:
both
;
}
/* Shared styles used in header and footer */
.xblock--drag-and-drop
.title1
{
color
:
rgb
(
85
,
85
,
85
);
...
...
@@ -42,22 +27,40 @@
margin-top
:
20px
;
}
/* drag-container holds the .items and the .target image */
.xblock--drag-and-drop
.drag-container
{
width
:
auto
;
padding
:
5px
;
background
:
#ebf0f2
;
}
/*.xblock--drag-and-drop .clear {
clear: both;
}*/
/** Draggable Items **/
.xblock--drag-and-drop
.drag-container
.items
{
display
:
block
;
padding
:
0
!important
;
/* LMS tries to override this */
.xblock--drag-and-drop
.item-bank
{
display
:
flex
;
flex-flow
:
row
wrap
;
/* TODO: prefix the above and test in IE 10 */
justify-content
:
flex-start
;
align-items
:
center
;
position
:
relative
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0.1
);
border-radius
:
3px
;
}
.xblock--drag-and-drop
.drag-container
.option
{
position
:
relative
;
display
:
inline-block
;
width
:
auto
;
min-width
:
4em
;
max-width
:
calc
(
100%
/
3
-
1%
-
1%
-
20px
);
border
:
1px
solid
transparent
;
border-radius
:
3px
;
margin
:
1%
;
padding
:
10px
;
background
:
#2e83cd
;
background
-color
:
#2e83cd
;
font-size
:
14px
;
color
:
#fff
;
opacity
:
1
;
...
...
@@ -65,10 +68,18 @@
z-index
:
10
!important
;
}
/* Placed option */
.xblock--drag-and-drop
.drag-container
.target
.option
{
position
:
absolute
;
margin
:
0
;
transform
:
translate
(
-50%
,
-50%
);
/* These blocks are to be centered on their absolute x,y position */
}
.xblock--drag-and-drop
.drag-container
.ui-draggable-dragging
{
box-shadow
:
0
16px
32px
0
rgba
(
0
,
0
,
0
,
.3
);
border
:
1px
solid
#ccc
;
opacity
:
.65
;
z-index
:
20
!important
;
}
.xblock--drag-and-drop
.drag-container
.option
img
{
...
...
@@ -117,18 +128,23 @@
/*** Drop Target ***/
.xblock--drag-and-drop
.target
{
display
:
block
;
width
:
515px
;
height
:
510px
;
display
:
table
;
width
:
0
;
/* 'display: table' & 'width: 0' make this have the smallest size that fits the .target-img
while still allowing the image to use 'max-width: 100%' and scale proportionally.
The end result is that this element has the same widdth and height as the image, so we
can use it as a 'position: relative' anchor for the placed elements. */
height
:
auto
;
position
:
relative
;
margin-top
:
1%
;
background
:
#fff
;
}
.xblock--drag-and-drop
.target-img
{
background
:
url('../img/triangle.png')
no-repeat
;
width
:
100%
;
height
:
100%
;
width
:
auto
;
max-width
:
100%
;
height
:
auto
;
max-height
:
80vh
;
/* On mobile, don't ever fill the whole screen with the image */
}
.xblock--drag-and-drop
.zone
{
...
...
drag_and_drop_v2/public/js/drag_and_drop.js
View file @
a1852925
...
...
@@ -5,7 +5,10 @@ function DragAndDropBlock(runtime, element) {
window
.
gettext
=
function
gettext_stub
(
string
)
{
return
string
;
};
}
var
root
=
$
(
element
).
find
(
'.xblock--drag-and-drop'
)[
0
];
var
$element
=
$
(
element
);
// root: root node managed by the virtual DOM
var
root
=
$element
.
find
(
'.xblock--drag-and-drop'
)[
0
];
var
$root
=
$
(
root
);
var
__state
;
var
__vdom
=
virtualDom
.
h
();
// blank virtual DOM
...
...
@@ -15,37 +18,21 @@ function DragAndDropBlock(runtime, element) {
dataType
:
'json'
}).
done
(
function
(
data
){
setState
(
data
);
setItemsHeight
();
initDroppable
();
});
$
(
document
).
on
(
'mousedown touchstart'
,
closePopup
);
$
(
element
)
.
on
(
'click'
,
'.reset-button'
,
resetExercise
);
$
(
element
)
.
on
(
'click'
,
'.submit-input'
,
submitInput
);
$
element
.
on
(
'click'
,
'.reset-button'
,
resetExercise
);
$
element
.
on
(
'click'
,
'.submit-input'
,
submitInput
);
publishEvent
({
event_type
:
'xblock.drag-and-drop-v2.loaded'
});
};
var
setItemsHeight
=
function
()
{
var
itemsHeight
=
$
(
'.items'
,
element
).
height
();
// Need to update the DOM here, otherwise .items will resize when first item is moved to target
$
(
'.items'
,
element
).
height
(
itemsHeight
);
__state
.
itemsHeight
=
itemsHeight
;
};
var
getState
=
function
()
{
return
__state
;
};
var
setState
=
function
(
new_state
)
{
var
itemsHeight
;
if
(
__state
===
undefined
)
{
itemsHeight
=
'auto'
;
}
else
{
itemsHeight
=
__state
.
itemsHeight
;
}
new_state
.
itemsHeight
=
itemsHeight
;
if
(
new_state
.
state
.
feedback
)
{
if
(
new_state
.
state
.
feedback
!==
__state
.
state
.
feedback
)
{
publishEvent
({
...
...
@@ -72,6 +59,7 @@ function DragAndDropBlock(runtime, element) {
var
new_vdom
=
render
(
state
);
var
patches
=
virtualDom
.
diff
(
__vdom
,
new_vdom
);
root
=
virtualDom
.
patch
(
root
,
patches
);
$root
=
$
(
root
);
__vdom
=
new_vdom
;
};
...
...
@@ -84,38 +72,43 @@ function DragAndDropBlock(runtime, element) {
};
var
initDroppable
=
function
()
{
$
(
root
)
.
find
(
'.zone'
).
droppable
({
accept
:
'.xblock--drag-and-drop .item
s
.option'
,
$
root
.
find
(
'.zone'
).
droppable
({
accept
:
'.xblock--drag-and-drop .item
-bank
.option'
,
tolerance
:
'pointer'
,
drop
:
function
(
evt
,
ui
)
{
var
item_id
=
ui
.
draggable
.
data
(
'value'
);
var
zone
=
$
(
this
).
data
(
'zone'
);
var
position
=
ui
.
draggable
.
position
();
var
top
=
position
.
top
+
'px'
;
var
left
=
position
.
left
+
'px'
;
var
$target_img
=
$root
.
find
(
'.target-img'
);
// Calculate the position of the center of the dropped element relative to
// the image.
var
x_pos
=
(
ui
.
helper
.
offset
().
left
+
(
ui
.
helper
.
outerWidth
()
/
2
)
-
$target_img
.
offset
().
left
);
var
x_pos_percent
=
x_pos
/
$target_img
.
width
()
*
100
;
var
y_pos
=
(
ui
.
helper
.
offset
().
top
+
(
ui
.
helper
.
outerHeight
()
/
2
)
-
$target_img
.
offset
().
top
);
var
y_pos_percent
=
y_pos
/
$target_img
.
height
()
*
100
;
var
state
=
getState
();
state
.
state
.
items
[
item_id
]
=
{
top
:
top
,
left
:
left
,
absolute
:
true
,
submitting_location
:
true
x_percent
:
x_pos_percent
,
y_percent
:
y_pos_percent
,
submitting_location
:
true
,
};
// Wrap in setTimeout to let the droppable event finish.
setTimeout
(
function
()
{
setState
(
state
);
submitLocation
(
item_id
,
zone
,
top
,
lef
t
);
submitLocation
(
item_id
,
zone
,
x_pos_percent
,
y_pos_percen
t
);
},
0
);
}
});
};
var
initDraggable
=
function
()
{
$
(
root
).
find
(
'.items
.option'
).
not
(
'[data-drag-disabled=true]'
).
each
(
function
()
{
$
root
.
find
(
'.item-bank
.option'
).
not
(
'[data-drag-disabled=true]'
).
each
(
function
()
{
try
{
$
(
this
).
draggable
({
containment
:
'.xblock--drag-and-drop .drag-container'
,
cursor
:
'move'
,
stack
:
'.xblock--drag-and-drop .item
s
.option'
,
stack
:
'.xblock--drag-and-drop .item
-bank
.option'
,
revert
:
'invalid'
,
revertDuration
:
150
,
start
:
function
(
evt
,
ui
)
{
...
...
@@ -134,7 +127,7 @@ function DragAndDropBlock(runtime, element) {
};
var
destroyDraggable
=
function
()
{
$
(
root
).
find
(
'.items
.option[data-drag-disabled=true]'
).
each
(
function
()
{
$
root
.
find
(
'.item-bank
.option[data-drag-disabled=true]'
).
each
(
function
()
{
try
{
$
(
this
).
draggable
(
'destroy'
);
}
catch
(
e
)
{
...
...
@@ -144,12 +137,17 @@ function DragAndDropBlock(runtime, element) {
});
};
var
submitLocation
=
function
(
item_id
,
zone
,
top
,
lef
t
)
{
var
submitLocation
=
function
(
item_id
,
zone
,
x_percent
,
y_percen
t
)
{
if
(
!
zone
)
{
return
;
}
var
url
=
runtime
.
handlerUrl
(
element
,
'do_attempt'
);
var
data
=
{
val
:
item_id
,
zone
:
zone
,
top
:
top
,
left
:
left
};
var
data
=
{
val
:
item_id
,
zone
:
zone
,
x_percent
:
x_percent
,
y_percent
:
y_percent
,
};
$
.
post
(
url
,
JSON
.
stringify
(
data
),
'json'
).
done
(
function
(
data
){
var
state
=
getState
();
if
(
data
.
correct_location
)
{
...
...
@@ -238,32 +236,33 @@ function DragAndDropBlock(runtime, element) {
var
render
=
function
(
state
)
{
var
items
=
state
.
items
.
map
(
function
(
item
)
{
var
item_state
=
state
.
state
.
items
[
item
.
id
];
var
position
=
item_state
||
{};
var
input
=
null
;
var
item_user_state
=
state
.
state
.
items
[
item
.
id
];
if
(
item
.
inputOptions
)
{
input
=
{
is_visible
:
item_
state
&&
!
item
_state
.
submitting_location
,
has_value
:
Boolean
(
item_
state
&&
'input'
in
item
_state
),
value
:
(
item_
state
&&
item
_state
.
input
)
||
''
,
class_name
:
undefined
is_visible
:
item_
user_state
&&
!
item_user
_state
.
submitting_location
,
has_value
:
Boolean
(
item_
user_state
&&
'input'
in
item_user
_state
),
value
:
(
item_
user_state
&&
item_user
_state
.
input
)
||
''
,
class_name
:
undefined
,
};
if
(
input
.
has_value
&&
!
item_state
.
submitting_input
)
{
input
.
class_name
=
item_state
.
correct_input
?
'correct'
:
'incorrect'
;
if
(
input
.
has_value
&&
!
item_
user_
state
.
submitting_input
)
{
input
.
class_name
=
item_
user_
state
.
correct_input
?
'correct'
:
'incorrect'
;
}
}
var
itemProperties
=
{
value
:
item
.
id
,
drag_disabled
:
Boolean
(
item_state
||
state
.
state
.
finished
),
drag_disabled
:
Boolean
(
item_
user_
state
||
state
.
state
.
finished
),
width
:
item
.
size
.
width
,
height
:
item
.
size
.
height
,
top
:
position
.
top
,
left
:
position
.
left
,
position
:
position
.
absolute
?
'absolute'
:
'relative'
,
class_name
:
item_state
&&
(
'input'
in
item_state
||
item_state
.
correct_input
)
?
'fade'
:
undefined
,
class_name
:
item_user_state
&&
(
'input'
in
item_user_state
||
item_user_state
.
correct_input
)
?
'fade'
:
undefined
,
input
:
input
,
content_html
:
item
.
backgroundImage
?
'<img src="'
+
item
.
backgroundImage
+
'"/>'
:
item
.
displayName
};
if
(
item_user_state
)
{
itemProperties
.
is_placed
=
true
;
itemProperties
.
x_percent
=
item_user_state
.
x_percent
;
itemProperties
.
y_percent
=
item_user_state
.
y_percent
;
}
if
(
state
.
item_background_color
)
{
itemProperties
.
background_color
=
state
.
item_background_color
;
}
...
...
@@ -282,7 +281,7 @@ function DragAndDropBlock(runtime, element) {
feedback_html
:
$
.
trim
(
state
.
state
.
finished
?
state
.
feedback
.
finish
:
state
.
feedback
.
start
),
target_img_src
:
state
.
targetImg
,
display_zone_labels
:
state
.
displayLabels
,
display_reset_button
:
state
.
state
.
finished
,
display_reset_button
:
Object
.
keys
(
state
.
state
.
items
).
length
>
0
,
zones
:
state
.
zones
,
items
:
items
};
...
...
drag_and_drop_v2/public/js/view.js
View file @
a1852925
(
function
(
h
)
{
"use strict"
;
var
FocusHook
=
function
()
{
if
(
!
(
this
instanceof
FocusHook
))
{
return
new
FocusHook
();
...
...
@@ -40,26 +40,29 @@
};
var
itemTemplate
=
function
(
item
)
{
var
style
=
{
width
:
item
.
width
,
height
:
item
.
height
,
top
:
item
.
top
,
left
:
item
.
left
,
position
:
item
.
position
};
var
style
=
{};
if
(
item
.
background_color
)
{
style
[
'background-color'
]
=
item
.
background_color
;
}
if
(
item
.
color
)
{
style
.
color
=
item
.
color
;
}
if
(
item
.
is_placed
)
{
style
.
left
=
item
.
x_percent
+
"%"
;
style
.
top
=
item
.
y_percent
+
"%"
;
}
return
(
h
(
'div.option'
,
{
className
:
item
.
class_name
,
attributes
:
{
'data-value'
:
item
.
value
,
'data-drag-disabled'
:
item
.
drag_disabled
},
style
:
style
},
[
h
(
'div'
,
{
innerHTML
:
item
.
content_html
}),
itemInputTemplate
(
item
.
input
)
])
h
(
'div.option'
,
{
key
:
item
.
value
,
className
:
item
.
class_name
,
attributes
:
{
'data-value'
:
item
.
value
,
'data-drag-disabled'
:
item
.
drag_disabled
},
style
:
style
},
[
h
(
'div'
,
{
innerHTML
:
item
.
content_html
}),
itemInputTemplate
(
item
.
input
)
]
)
);
};
...
...
@@ -88,28 +91,30 @@
var
mainTemplate
=
function
(
ctx
)
{
var
problemHeader
=
ctx
.
show_title
?
h
(
'h2.problem-header'
,
{
innerHTML
:
ctx
.
header_html
})
:
null
;
var
questionHeader
=
ctx
.
show_question_header
?
h
(
'h3.title1'
,
gettext
(
'Question'
))
:
null
;
var
is_item_placed
=
function
(
i
)
{
return
i
.
is_placed
;
};
var
items_placed
=
$
.
grep
(
ctx
.
items
,
is_item_placed
);
var
items_in_bank
=
$
.
grep
(
ctx
.
items
,
is_item_placed
,
true
);
return
(
h
(
'section.xblock--drag-and-drop'
,
[
problemHeader
,
h
(
'section.problem'
,
{
role
:
'application'
},
[
questionHeader
,
h
(
'p'
,
{
innerHTML
:
ctx
.
question_html
})
h
(
'p'
,
{
innerHTML
:
ctx
.
question_html
})
,
]),
h
(
'section.drag-container'
,
[
h
(
'div.item
s'
,
{
height
:
ctx
.
itemsHeight
},
renderCollection
(
itemTemplate
,
ctx
.
items
,
ctx
)),
h
(
'div.item
-bank'
,
renderCollection
(
itemTemplate
,
items_in_bank
,
ctx
)),
h
(
'div.target'
,
[
h
(
'div.popup'
,
{
style
:
{
display
:
ctx
.
popup_html
?
'block'
:
'none'
}},
[
h
(
'div.close.icon-remove-sign.fa-times-circle'
),
h
(
'p.popup-content'
,
{
innerHTML
:
ctx
.
popup_html
})
h
(
'p.popup-content'
,
{
innerHTML
:
ctx
.
popup_html
})
,
]),
h
(
'div.target-img'
,
{
style
:
{
backgroundImage
:
ctx
.
target_img_src
?
'url('
+
ctx
.
target_img_src
+
')'
:
undefined
}},
renderCollection
(
zoneTemplate
,
ctx
.
zones
,
ctx
))
h
(
'img.target-img'
,
{
src
:
ctx
.
target_img_src
,
alt
:
"Image Description here"
}),
renderCollection
(
zoneTemplate
,
ctx
.
zones
,
ctx
),
renderCollection
(
itemTemplate
,
items_placed
,
ctx
),
]),
h
(
'div.clear'
)
//h('div.clear'),
]),
feedbackTemplate
(
ctx
)
feedbackTemplate
(
ctx
)
,
])
);
};
...
...
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