Move overview drag and drop code to a utility class.
This commit is contained in:
313
cms/static/js/spec/utils/drag_and_drop_spec.js
Normal file
313
cms/static/js/spec/utils/drag_and_drop_spec.js
Normal file
@@ -0,0 +1,313 @@
|
||||
define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec/create_sinon", "jquery"],
|
||||
function (ContentDragger, Notification, create_sinon, $) {
|
||||
describe("Overview drag and drop functionality", function () {
|
||||
beforeEach(function () {
|
||||
setFixtures(readFixtures('mock/mock-outline.underscore'));
|
||||
ContentDragger.makeDraggable('.unit', '.unit-drag-handle', 'ol.sortable-unit-list', 'li.courseware-subsection, article.subsection-body');
|
||||
ContentDragger.makeDraggable('.courseware-subsection', '.subsection-drag-handle', '.sortable-subsection-list', 'section');
|
||||
});
|
||||
|
||||
describe("findDestination", function () {
|
||||
it("correctly finds the drop target of a drag", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#unit-1');
|
||||
$ele.offset({
|
||||
top: $ele.offset().top + 10,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination.ele).toBe($('#unit-2'));
|
||||
expect(destination.attachMethod).toBe('before');
|
||||
});
|
||||
it("can drag and drop across section boundaries, with special handling for single sibling", function () {
|
||||
var $ele, $unit0, $unit4, destination;
|
||||
$ele = $('#unit-1');
|
||||
$unit4 = $('#unit-4');
|
||||
$ele.offset({
|
||||
top: $unit4.offset().top + 8,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination.ele).toBe($unit4);
|
||||
expect(destination.attachMethod).toBe('after');
|
||||
destination = ContentDragger.findDestination($ele, -1);
|
||||
expect(destination.ele).toBe($unit4);
|
||||
expect(destination.attachMethod).toBe('before');
|
||||
$ele.offset({
|
||||
top: $unit4.offset().top + $unit4.height() + 1,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 0);
|
||||
expect(destination.ele).toBe($unit4);
|
||||
expect(destination.attachMethod).toBe('after');
|
||||
$unit0 = $('#unit-0');
|
||||
$ele.offset({
|
||||
top: $unit0.offset().top - 16,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 0);
|
||||
expect(destination.ele).toBe($unit0);
|
||||
expect(destination.attachMethod).toBe('before');
|
||||
});
|
||||
it("can drop before the first element, even if element being dragged is\nslightly before the first element", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#subsection-2');
|
||||
$ele.offset({
|
||||
top: $('#subsection-0').offset().top - 5,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, -1);
|
||||
expect(destination.ele).toBe($('#subsection-0'));
|
||||
expect(destination.attachMethod).toBe('before');
|
||||
});
|
||||
it("can drag and drop across section boundaries, with special handling for last element", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#unit-4');
|
||||
$ele.offset({
|
||||
top: $('#unit-3').offset().bottom + 4,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, -1);
|
||||
expect(destination.ele).toBe($('#unit-3'));
|
||||
expect(destination.attachMethod).toBe('after');
|
||||
$ele.offset({
|
||||
top: $('#unit-3').offset().top + 4,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, -1);
|
||||
expect(destination.ele).toBe($('#unit-3'));
|
||||
expect(destination.attachMethod).toBe('before');
|
||||
});
|
||||
it("can drop past the last element, even if element being dragged is\nslightly before/taller then the last element", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#subsection-2');
|
||||
$ele.offset({
|
||||
top: $('#subsection-4').offset().top - 1,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination.ele).toBe($('#subsection-4'));
|
||||
expect(destination.attachMethod).toBe('after');
|
||||
});
|
||||
it("can drag into an empty list", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#unit-1');
|
||||
$ele.offset({
|
||||
top: $('#subsection-3').offset().top + 10,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination.ele).toBe($('#subsection-list-3'));
|
||||
expect(destination.attachMethod).toBe('prepend');
|
||||
});
|
||||
it("reports a null destination on a failed drag", function () {
|
||||
var $ele, destination;
|
||||
$ele = $('#unit-1');
|
||||
$ele.offset({
|
||||
top: $ele.offset().top + 200,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination).toEqual({
|
||||
ele: null,
|
||||
attachMethod: ""
|
||||
});
|
||||
});
|
||||
it("can drag into a collapsed list", function () {
|
||||
var $ele, destination;
|
||||
$('#subsection-2').addClass('collapsed');
|
||||
$ele = $('#unit-2');
|
||||
$ele.offset({
|
||||
top: $('#subsection-2').offset().top + 3,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
destination = ContentDragger.findDestination($ele, 1);
|
||||
expect(destination.ele).toBe($('#subsection-list-2'));
|
||||
expect(destination.parentList).toBe($('#subsection-2'));
|
||||
expect(destination.attachMethod).toBe('prepend');
|
||||
});
|
||||
});
|
||||
describe("onDragStart", function () {
|
||||
it("sets the dragState to its default values", function () {
|
||||
expect(ContentDragger.dragState).toEqual({});
|
||||
ContentDragger.onDragStart({
|
||||
element: $('#unit-1')
|
||||
}, null, null);
|
||||
expect(ContentDragger.dragState).toEqual({
|
||||
dropDestination: null,
|
||||
attachMethod: '',
|
||||
parentList: null,
|
||||
lastY: 0,
|
||||
dragDirection: 0
|
||||
});
|
||||
});
|
||||
it("collapses expanded elements", function () {
|
||||
expect($('#subsection-1')).not.toHaveClass('collapsed');
|
||||
ContentDragger.onDragStart({
|
||||
element: $('#subsection-1')
|
||||
}, null, null);
|
||||
expect($('#subsection-1')).toHaveClass('collapsed');
|
||||
expect($('#subsection-1')).toHaveClass('expand-on-drop');
|
||||
});
|
||||
});
|
||||
describe("onDragMove", function () {
|
||||
beforeEach(function () {
|
||||
this.scrollSpy = spyOn(window, 'scrollBy').andCallThrough();
|
||||
});
|
||||
it("adds the correct CSS class to the drop destination", function () {
|
||||
var $ele, dragX, dragY;
|
||||
$ele = $('#unit-1');
|
||||
dragY = $ele.offset().top + 10;
|
||||
dragX = $ele.offset().left;
|
||||
$ele.offset({
|
||||
top: dragY,
|
||||
left: dragX
|
||||
});
|
||||
ContentDragger.onDragMove({
|
||||
element: $ele,
|
||||
dragPoint: {
|
||||
y: dragY
|
||||
}
|
||||
}, '', {
|
||||
clientX: dragX
|
||||
});
|
||||
expect($('#unit-2')).toHaveClass('drop-target drop-target-before');
|
||||
expect($ele).toHaveClass('valid-drop');
|
||||
});
|
||||
it("does not add CSS class to the drop destination if out of bounds", function () {
|
||||
var $ele, dragY;
|
||||
$ele = $('#unit-1');
|
||||
dragY = $ele.offset().top + 10;
|
||||
$ele.offset({
|
||||
top: dragY,
|
||||
left: $ele.offset().left
|
||||
});
|
||||
ContentDragger.onDragMove({
|
||||
element: $ele,
|
||||
dragPoint: {
|
||||
y: dragY
|
||||
}
|
||||
}, '', {
|
||||
clientX: $ele.offset().left - 3
|
||||
});
|
||||
expect($('#unit-2')).not.toHaveClass('drop-target drop-target-before');
|
||||
expect($ele).not.toHaveClass('valid-drop');
|
||||
});
|
||||
it("scrolls up if necessary", function () {
|
||||
ContentDragger.onDragMove({
|
||||
element: $('#unit-1')
|
||||
}, '', {
|
||||
clientY: 2
|
||||
});
|
||||
expect(this.scrollSpy).toHaveBeenCalledWith(0, -10);
|
||||
});
|
||||
it("scrolls down if necessary", function () {
|
||||
ContentDragger.onDragMove({
|
||||
element: $('#unit-1')
|
||||
}, '', {
|
||||
clientY: window.innerHeight - 5
|
||||
});
|
||||
expect(this.scrollSpy).toHaveBeenCalledWith(0, 10);
|
||||
});
|
||||
});
|
||||
describe("onDragEnd", function () {
|
||||
beforeEach(function () {
|
||||
this.reorderSpy = spyOn(ContentDragger, 'handleReorder');
|
||||
});
|
||||
afterEach(function () {
|
||||
this.reorderSpy.reset();
|
||||
});
|
||||
it("calls handleReorder on a successful drag", function () {
|
||||
ContentDragger.dragState.dropDestination = $('#unit-2');
|
||||
ContentDragger.dragState.attachMethod = "before";
|
||||
ContentDragger.dragState.parentList = $('#subsection-1');
|
||||
$('#unit-1').offset({
|
||||
top: $('#unit-1').offset().top + 10,
|
||||
left: $('#unit-1').offset().left
|
||||
});
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#unit-1')
|
||||
}, null, {
|
||||
clientX: $('#unit-1').offset().left
|
||||
});
|
||||
expect(this.reorderSpy).toHaveBeenCalled();
|
||||
});
|
||||
it("clears out the drag state", function () {
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#unit-1')
|
||||
}, null, null);
|
||||
expect(ContentDragger.dragState).toEqual({});
|
||||
});
|
||||
it("sets the element to the correct position", function () {
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#unit-1')
|
||||
}, null, null);
|
||||
expect(['0px', 'auto']).toContain($('#unit-1').css('top'));
|
||||
expect(['0px', 'auto']).toContain($('#unit-1').css('left'));
|
||||
});
|
||||
it("expands an element if it was collapsed on drag start", function () {
|
||||
$('#subsection-1').addClass('collapsed');
|
||||
$('#subsection-1').addClass('expand-on-drop');
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#subsection-1')
|
||||
}, null, null);
|
||||
expect($('#subsection-1')).not.toHaveClass('collapsed');
|
||||
expect($('#subsection-1')).not.toHaveClass('expand-on-drop');
|
||||
});
|
||||
it("expands a collapsed element when something is dropped in it", function () {
|
||||
$('#subsection-2').addClass('collapsed');
|
||||
ContentDragger.dragState.dropDestination = $('#list-2');
|
||||
ContentDragger.dragState.attachMethod = "prepend";
|
||||
ContentDragger.dragState.parentList = $('#subsection-2');
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#unit-1')
|
||||
}, null, {
|
||||
clientX: $('#unit-1').offset().left
|
||||
});
|
||||
expect($('#subsection-2')).not.toHaveClass('collapsed');
|
||||
});
|
||||
});
|
||||
describe("AJAX", function () {
|
||||
beforeEach(function () {
|
||||
this.savingSpies = spyOnConstructor(Notification, "Mini", ["show", "hide"]);
|
||||
this.savingSpies.show.andReturn(this.savingSpies);
|
||||
this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
afterEach(function () {
|
||||
this.clock.restore();
|
||||
});
|
||||
it("should send an update on reorder", function () {
|
||||
var requests, savingOptions;
|
||||
requests = create_sinon["requests"](this);
|
||||
ContentDragger.dragState.dropDestination = $('#unit-4');
|
||||
ContentDragger.dragState.attachMethod = "after";
|
||||
ContentDragger.dragState.parentList = $('#subsection-2');
|
||||
$('#unit-1').offset({
|
||||
top: $('#unit-4').offset().top + 10,
|
||||
left: $('#unit-4').offset().left
|
||||
});
|
||||
ContentDragger.onDragEnd({
|
||||
element: $('#unit-1')
|
||||
}, null, {
|
||||
clientX: $('#unit-1').offset().left
|
||||
});
|
||||
expect(requests.length).toEqual(2);
|
||||
expect(this.savingSpies.constructor).toHaveBeenCalled();
|
||||
expect(this.savingSpies.show).toHaveBeenCalled();
|
||||
expect(this.savingSpies.hide).not.toHaveBeenCalled();
|
||||
savingOptions = this.savingSpies.constructor.mostRecentCall.args[0];
|
||||
expect(savingOptions.title).toMatch(/Saving/);
|
||||
expect($('#unit-1')).toHaveClass('was-dropped');
|
||||
expect(requests[0].requestBody).toEqual('{"children":["second-unit-id","third-unit-id"]}');
|
||||
requests[0].respond(200);
|
||||
expect(this.savingSpies.hide).not.toHaveBeenCalled();
|
||||
expect(requests[1].requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}');
|
||||
requests[1].respond(200);
|
||||
expect(this.savingSpies.hide).toHaveBeenCalled();
|
||||
this.clock.tick(1001);
|
||||
expect($('#unit-1')).not.toHaveClass('was-dropped');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user