Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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
edx
edx-platform
Commits
85be9b42
Commit
85be9b42
authored
Aug 12, 2013
by
Peter Fogg
Committed by
cahrens
Oct 07, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Jasmine tests for drag/drop.
parent
7640ade4
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
192 additions
and
54 deletions
+192
-54
cms/static/coffee/spec/views/overview_spec.coffee
+147
-10
cms/static/js/views/overview.js
+45
-44
No files found.
cms/static/coffee/spec/views/overview_spec.coffee
View file @
85be9b42
describe
"Course Overview"
,
->
beforeEach
->
_
.
each
[
"/static/js/vendor/date.js"
,
"/static/js/vendor/timepicker/jquery.timepicker.js"
,
"/jsi18n/"
],
(
path
)
->
_
.
each
[
"/static/js/vendor/date.js"
,
"/static/js/vendor/timepicker/jquery.timepicker.js"
,
"/jsi18n/"
,
"/static/js/vendor/draggabilly.pkgd.js"
],
(
path
)
->
appendSetFixtures
"""
<script type="text/javascript" src="
#{
path
}
"></script>
"""
...
...
@@ -45,15 +45,23 @@ describe "Course Overview", ->
</section>
"""
# appendSetFixtures """
# <div class="subsection-list">
# <ol data-id="parent-list-id">
# <li class="unit" data-id="first-unit-id" data-parent-id="parent-list-id"></li>
# <li class="unit" data-id="second-unit-id" data-parent-id="parent-list-id"></li>
# <li class="unit" data-id="third-unit-id" data-parent-id="parent-list-id"></li>
# </ol>
# </div>
# """
appendSetFixtures
"""
<div class="subsection-list">
<ol class="sortable-unit-list" id="list-1" data-id="parent-list-id-1">
<li class="unit" id="unit-1" data-id="first-unit-id" data-parent-id="parent-list-id-1"></li>
<li class="unit" id="unit-2" data-id="second-unit-id" data-parent-id="parent-list-id-1"></li>
<li class="unit" id="unit-3" data-id="third-unit-id" data-parent-id="parent-list-id-1"></li>
</ol>
</div>
</div class="subsection-list">
<ol class="sortable-unit-list" id="list-2" data-id="parent-list-id-2">
<li class="unit" id="unit-4" data-id="first-unit-id" data-parent-id="parent-list-id-2"></li>
</ol>
</div>
<div class="subsection-list">
<ol class="sortable-unit-list" id="list-3" data-id="parent-list-id-3"></ol>
</div>
"""
#"
spyOn
(
window
,
'saveSetSectionScheduleDate'
).
andCallThrough
()
# Have to do this here, as it normally gets bound in document.ready()
...
...
@@ -68,6 +76,13 @@ describe "Course Overview", ->
requests
=
@
requests
=
[]
@
xhr
.
onCreate
=
(
req
)
->
requests
.
push
(
req
)
CMS
.
Views
.
Draggabilly
.
makeDraggable
(
'.unit'
,
'.unit-drag-handle'
,
'ol.sortable-unit-list'
,
'li.branch, article.subsection-body'
)
afterEach
->
delete
window
.
analytics
delete
window
.
course_location_analytics
...
...
@@ -100,3 +115,125 @@ describe "Course Overview", ->
$
(
'a.delete-section-button'
).
click
()
$
(
'a.action-primary'
).
click
()
expect
(
@
notificationSpy
).
toHaveBeenCalled
()
describe
"findDestination"
,
->
it
"correctly finds the drop target of a drag"
,
->
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$ele
.
offset
().
top
+
10
,
left
:
$ele
.
offset
().
left
)
destination
=
CMS
.
Views
.
Draggabilly
.
findDestination
(
$ele
)
expect
(
destination
.
ele
).
toBe
(
$
(
'#unit-2'
))
expect
(
destination
.
attachMethod
).
toBe
(
'before'
)
it
"can drag and drop across section boundaries"
,
->
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$
(
'#unit-4'
).
offset
().
top
+
10
left
:
$ele
.
offset
().
left
)
destination
=
CMS
.
Views
.
Draggabilly
.
findDestination
(
$ele
)
expect
(
destination
.
ele
).
toBe
(
$
(
'#unit-4'
))
expect
(
destination
.
attachMethod
).
toBe
(
'after'
)
it
"can drag into an empty list"
,
->
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$
(
'#list-3'
).
offset
().
top
+
10
left
:
$ele
.
offset
().
left
)
destination
=
CMS
.
Views
.
Draggabilly
.
findDestination
(
$ele
)
expect
(
destination
.
ele
).
toBe
(
$
(
'#list-3'
))
expect
(
destination
.
attachMethod
).
toBe
(
'prepend'
)
it
"reports a null destination on a failed drag"
,
->
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$ele
.
offset
().
top
+
200
,
left
:
$ele
.
offset
().
left
)
destination
=
CMS
.
Views
.
Draggabilly
.
findDestination
(
$ele
)
expect
(
destination
).
toEqual
(
ele
:
null
attachMethod
:
""
)
describe
"onDragStart"
,
->
it
"sets the dragState to its default values"
,
->
expect
(
CMS
.
Views
.
Draggabilly
.
dragState
).
toEqual
({})
# Call with some dummy data
CMS
.
Views
.
Draggabilly
.
onDragStart
(
{
element
:
$
(
'#unit-1'
)},
null
,
null
)
expect
(
CMS
.
Views
.
Draggabilly
.
dragState
).
toEqual
(
offset
:
$
(
'#unit-1'
).
offset
()
dropDestination
:
null
,
expandTimer
:
null
,
toExpand
:
null
)
describe
"onDragMove"
,
->
it
"clears the expand timer state"
,
->
timerSpy
=
spyOn
(
window
,
'clearTimeout'
).
andCallThrough
()
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$ele
.
offset
().
top
+
10
left
:
$ele
.
offset
().
left
)
CMS
.
Views
.
Draggabilly
.
onDragMove
(
{
element
:
$ele
},
null
,
null
)
expect
(
timerSpy
).
toHaveBeenCalled
()
timerSpy
.
reset
()
it
"adds the correct CSS class to the drop destination"
,
->
$ele
=
$
(
'#unit-1'
)
$ele
.
offset
(
top
:
$ele
.
offset
().
top
+
10
,
left
:
$ele
.
offset
().
left
)
CMS
.
Views
.
Draggabilly
.
onDragMove
(
{
element
:
$ele
},
''
,
''
)
expect
(
$
(
'#unit-2'
)).
toHaveClass
(
'drop-target drop-target-before'
)
describe
"onDragEnd"
,
->
beforeEach
->
@
reorderSpy
=
spyOn
(
CMS
.
Views
.
Draggabilly
,
'handleReorder'
)
afterEach
->
@
reorderSpy
.
reset
()
it
"calls handleReorder on a successful drag"
,
->
$
(
'#unit-1'
).
offset
(
top
:
$
(
'#unit-1'
).
offset
().
top
+
10
left
:
$
(
'#unit-1'
).
offset
().
left
)
CMS
.
Views
.
Draggabilly
.
onDragEnd
(
{
element
:
$
(
'#unit-1'
)},
null
,
{
x
:
$
(
'#unit-1'
).
offset
().
left
}
)
expect
(
@
reorderSpy
).
toHaveBeenCalled
()
it
"clears out the drag state"
,
->
CMS
.
Views
.
Draggabilly
.
onDragEnd
(
{
element
:
$
(
'#unit-1'
)},
null
,
null
)
expect
(
CMS
.
Views
.
Draggabilly
.
dragState
).
toEqual
({})
it
"sets the element to the correct position"
,
->
CMS
.
Views
.
Draggabilly
.
onDragEnd
(
{
element
:
$
(
'#unit-1'
)},
null
,
null
)
# Chrome sets the CSS to 'auto', but Firefox uses '0px'.
expect
([
'0px'
,
'auto'
]).
toContain
(
$
(
'#unit-1'
).
css
(
'top'
))
expect
([
'0px'
,
'auto'
]).
toContain
(
$
(
'#unit-1'
).
css
(
'left'
))
cms/static/js/views/overview.js
View file @
85be9b42
$
(
document
).
ready
(
function
()
{
var
droppableClasses
=
'drop-target drop-target-prepend drop-target-before drop-target-after'
;
CMS
.
Views
.
Draggabilly
=
{
droppableClasses
:
'drop-target drop-target-prepend drop-target-before drop-target-after'
,
/*
* Determine information about where to drop the currently dragged
* element. Returns the element to attach to and the method of
* attachment ('before', 'after', or 'prepend').
*/
var
findDestination
=
function
(
ele
)
{
findDestination
:
function
(
ele
)
{
var
eleY
=
ele
.
offset
().
top
;
var
containers
=
$
(
ele
.
data
(
'droppable-class'
));
...
...
@@ -55,7 +54,7 @@ $(document).ready(function() {
// element is actually on top of the sibling,
// rather than next to it. This prevents
// saving when expanding/collapsing a list.
if
(
Math
.
abs
(
eleY
-
siblingY
)
<
$sibling
.
height
()
-
1
)
{
if
(
Math
.
abs
(
eleY
-
siblingY
)
<
ele
.
height
()
-
1
)
{
return
{
ele
:
$sibling
,
attachMethod
:
siblingY
>
eleY
?
'before'
:
'after'
...
...
@@ -69,15 +68,15 @@ $(document).ready(function() {
return
{
ele
:
null
,
attachMethod
:
''
}
;
}
;
}
}
,
// Information about the current drag.
var
dragState
=
{};
dragState
:
{},
var
onDragStart
=
function
(
draggie
,
event
,
pointer
)
{
onDragStart
:
function
(
draggie
,
event
,
pointer
)
{
var
ele
=
$
(
draggie
.
element
);
dragState
=
{
this
.
dragState
=
{
// Where we started, in case of a failed drag
offset
:
ele
.
offset
(),
// Which element will be dropped into/onto on success
...
...
@@ -87,42 +86,42 @@ $(document).ready(function() {
// The list which will be expanded on hover
toExpand
:
null
};
}
;
}
,
var
onDragMove
=
function
(
draggie
,
event
,
pointer
)
{
onDragMove
:
function
(
draggie
,
event
,
pointer
)
{
var
ele
=
$
(
draggie
.
element
);
var
destinationInfo
=
findDestination
(
ele
);
var
destinationInfo
=
this
.
findDestination
(
ele
);
var
destinationEle
=
destinationInfo
.
ele
;
var
parentList
=
destinationInfo
.
parentList
;
// Clear the timer if we're not hovering over any element
if
(
!
parentList
)
{
clearTimeout
(
dragState
.
expandTimer
);
clearTimeout
(
this
.
dragState
.
expandTimer
);
}
// If we're hovering over a new element, clear the timer and
// set a new one
else
if
(
!
dragState
.
toExpand
||
parentList
[
0
]
!==
dragState
.
toExpand
[
0
])
{
clearTimeout
(
dragState
.
expandTimer
);
dragState
.
expandTimer
=
setTimeout
(
function
()
{
else
if
(
!
this
.
dragState
.
toExpand
||
parentList
[
0
]
!==
this
.
dragState
.
toExpand
[
0
])
{
clearTimeout
(
this
.
dragState
.
expandTimer
);
this
.
dragState
.
expandTimer
=
setTimeout
(
function
()
{
parentList
.
removeClass
(
'collapsed'
);
parentList
.
find
(
'.expand-collapse-icon'
).
removeClass
(
'expand'
).
addClass
(
'collapse'
);
},
400
);
dragState
.
toExpand
=
parentList
;
this
.
dragState
.
toExpand
=
parentList
;
}
// Clear out the old destination
if
(
dragState
.
dropDestination
)
{
dragState
.
dropDestination
.
removeClass
(
droppableClasses
);
if
(
this
.
dragState
.
dropDestination
)
{
this
.
dragState
.
dropDestination
.
removeClass
(
this
.
droppableClasses
);
}
// Mark the new destination
if
(
destinationEle
)
{
destinationEle
.
addClass
(
'drop-target drop-target-'
+
destinationInfo
.
attachMethod
);
dragState
.
dropDestination
=
destinationEle
;
this
.
dragState
.
dropDestination
=
destinationEle
;
}
}
;
}
,
var
onDragEnd
=
function
(
draggie
,
event
,
pointer
)
{
onDragEnd
:
function
(
draggie
,
event
,
pointer
)
{
var
ele
=
$
(
draggie
.
element
);
var
destinationInfo
=
findDestination
(
ele
);
var
destinationInfo
=
this
.
findDestination
(
ele
);
var
destination
=
destinationInfo
.
ele
;
// If the drag succeeded, rearrange the DOM and send the result.
...
...
@@ -134,7 +133,7 @@ $(document).ready(function() {
}
var
method
=
destinationInfo
.
attachMethod
;
destination
[
method
](
ele
);
handleReorder
(
ele
);
this
.
handleReorder
(
ele
);
}
// Everything in its right place
...
...
@@ -144,17 +143,17 @@ $(document).ready(function() {
});
// Clear dragging state in preparation for the next event.
if
(
dragState
.
dropDestination
)
{
dragState
.
dropDestination
.
removeClass
(
droppableClasses
);
if
(
this
.
dragState
.
dropDestination
)
{
this
.
dragState
.
dropDestination
.
removeClass
(
this
.
droppableClasses
);
}
clearTimeout
(
dragState
.
expandTimer
);
dragState
=
{};
}
;
clearTimeout
(
this
.
dragState
.
expandTimer
);
this
.
dragState
=
{};
}
,
/*
* Find all parent-child changes and save them.
*/
var
handleReorder
=
function
(
ele
)
{
handleReorder
:
function
(
ele
)
{
var
parentSelector
=
ele
.
data
(
'parent-location-selector'
);
var
childrenSelector
=
ele
.
data
(
'child-selector'
);
var
newParentEle
=
ele
.
parents
(
parentSelector
).
first
();
...
...
@@ -166,7 +165,7 @@ $(document).ready(function() {
var
oldParentEle
=
$
(
parentSelector
).
filter
(
function
()
{
return
$
(
this
).
data
(
'id'
)
===
oldParentID
;
});
saveItem
(
oldParentEle
,
childrenSelector
,
function
()
{
this
.
saveItem
(
oldParentEle
,
childrenSelector
,
function
()
{
ele
.
data
(
'parent-id'
,
newParentID
);
});
}
...
...
@@ -174,17 +173,17 @@ $(document).ready(function() {
title
:
gettext
(
'Saving…'
)
});
saving
.
show
();
saveItem
(
newParentEle
,
childrenSelector
,
function
()
{
this
.
saveItem
(
newParentEle
,
childrenSelector
,
function
()
{
saving
.
hide
();
});
}
;
}
,
/*
* Actually save the update to the server. Takes the element
* representing the parent item to save, a CSS selector to find
* its children, and a success callback.
*/
var
saveItem
=
function
(
ele
,
childrenSelector
,
success
)
{
saveItem
:
function
(
ele
,
childrenSelector
,
success
)
{
// Find all current child IDs.
var
children
=
_
.
map
(
ele
.
find
(
childrenSelector
),
...
...
@@ -203,14 +202,14 @@ $(document).ready(function() {
}),
success
:
success
});
}
;
}
,
/*
* Make `type` draggable using `handleClass`, able to be dropped
* into `droppableClass`, and with parent type
* `parentLocationSelector`.
*/
var
makeDraggable
=
function
(
type
,
handleClass
,
droppableClass
,
parentLocationSelector
)
{
makeDraggable
:
function
(
type
,
handleClass
,
droppableClass
,
parentLocationSelector
)
{
_
.
each
(
$
(
type
),
function
(
ele
)
{
...
...
@@ -222,29 +221,31 @@ $(document).ready(function() {
handle
:
handleClass
,
axis
:
'y'
});
draggable
.
on
(
'dragStart'
,
onDragStart
);
draggable
.
on
(
'dragMove'
,
onDragMove
);
draggable
.
on
(
'dragEnd'
,
onDragEnd
);
draggable
.
on
(
'dragStart'
,
_
.
bind
(
CMS
.
Views
.
Draggabilly
.
onDragStart
,
CMS
.
Views
.
Draggabilly
)
);
draggable
.
on
(
'dragMove'
,
_
.
bind
(
CMS
.
Views
.
Draggabilly
.
onDragMove
,
CMS
.
Views
.
Draggabilly
)
);
draggable
.
on
(
'dragEnd'
,
_
.
bind
(
CMS
.
Views
.
Draggabilly
.
onDragEnd
,
CMS
.
Views
.
Draggabilly
)
);
}
);
};
}
};
$
(
document
).
ready
(
function
()
{
// Section
makeDraggable
(
CMS
.
Views
.
Draggabilly
.
makeDraggable
(
'.courseware-section'
,
'.section-drag-handle'
,
'.courseware-overview'
,
'article.courseware-overview'
);
// Subsection
makeDraggable
(
CMS
.
Views
.
Draggabilly
.
makeDraggable
(
'.id-holder'
,
'.subsection-drag-handle'
,
'.subsection-list > ol'
,
'.courseware-section'
);
// Unit
makeDraggable
(
CMS
.
Views
.
Draggabilly
.
makeDraggable
(
'.unit'
,
'.unit-drag-handle'
,
'ol.sortable-unit-list'
,
...
...
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