extjs-gpl
Version:
GPL licensed version of Sencha Ext JS
606 lines (496 loc) • 19.9 kB
JavaScript
describe("Ext.event.gesture.Drag", function() {
var helper = Ext.testHelper,
recognizer = Ext.event.gesture.Drag.instance,
minDistance = recognizer.getMinDistance(),
targetEl, dragstartHandler, dragHandler, dragendHandler, dragcancelHandler,
dragstartEvent, dragEvent, dragendEvent, dragcancelEvent;
function start(cfg, target) {
helper.touchStart(target || targetEl, cfg);
}
function move(cfg, target) {
helper.touchMove(target || targetEl, cfg);
}
function end(cfg, target) {
helper.touchEnd(target || targetEl, cfg);
}
function cancel(cfg, target) {
helper.touchCancel(target || targetEl, cfg);
}
function expectInfo(e, info) {
var name;
for (name in info) {
expect(e[name]).toBe(info[name]);
}
}
beforeEach(function() {
targetEl = Ext.getBody().createChild({
id: 'target',
style: 'width: 200px; height: 200px; border: 1px solid red;'
});
dragstartHandler = jasmine.createSpy();
dragHandler = jasmine.createSpy();
dragendHandler = jasmine.createSpy();
dragcancelHandler = jasmine.createSpy();
dragstartHandler.andCallFake(function(event) {
dragstartEvent = event;
});
dragHandler.andCallFake(function(event) {
dragEvent = event;
});
dragendHandler.andCallFake(function(event) {
dragendEvent = event;
});
dragcancelHandler.andCallFake(function(event) {
dragcancelEvent = event;
});
targetEl.on('dragstart', dragstartHandler);
targetEl.on('drag', dragHandler);
targetEl.on('dragend', dragendHandler);
targetEl.on('dragcancel', dragcancelHandler);
});
afterEach(function() {
targetEl.destroy();
});
it("should fire dragstart, drag, and dragend when the distance exceeds minDistance", function() {
runs(function() {
start({ id: 1, x: 100, y: 101 });
move({ id: 1, x: 99, y: 101 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragstartHandler).toHaveBeenCalled();
expect(dragHandler).toHaveBeenCalled();
expectInfo(dragstartEvent, {
x: 99,
y: 101 - minDistance,
pageX: 99,
pageY: 101 - minDistance,
startX: 100,
startY: 101,
previousX: 100,
previousY: 101,
deltaX: -1,
deltaY: -minDistance,
absDeltaX: 1,
absDeltaY: minDistance,
previousDeltaX: 0,
previousDeltaY: 0,
longpress: false
});
expectInfo(dragEvent, {
x: 99,
y: 101 - minDistance,
pageX: 99,
pageY: 101 - minDistance,
startX: 100,
startY: 101,
previousX: 100,
previousY: 101,
deltaX: -1,
deltaY: -minDistance,
absDeltaX: 1,
absDeltaY: minDistance,
previousDeltaX: 0,
previousDeltaY: 0,
longpress: false
});
move({ id: 1, x: 97, y: 100 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
expectInfo(dragEvent, {
x: 97,
y: 100 - minDistance,
pageX: 97,
pageY: 100 - minDistance,
startX: 100,
startY: 101,
previousX: 99,
previousY: 101 - minDistance,
deltaX: -3,
deltaY: -(minDistance + 1),
absDeltaX: 3,
absDeltaY: minDistance + 1,
previousDeltaX: -1,
previousDeltaY: -minDistance,
longpress: false
});
end({ id: 1, x: 96, y: 99 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).toHaveBeenCalled();
expectInfo(dragendEvent, {
x: 96,
y: 99 - minDistance,
pageX: 96,
pageY: 99 - minDistance,
startX: 100,
startY: 101,
previousX: 97,
previousY: 100 - minDistance,
deltaX: -4,
deltaY: -(minDistance + 2),
absDeltaX: 4,
absDeltaY: minDistance + 2,
previousDeltaX: -3,
previousDeltaY: -(minDistance + 1),
longpress: false
});
});
});
it("should not fire dragstart, drag, and dragend when the distance is less than minDistance", function() {
runs(function() {
start({ id: 1, x: 100, y: 101 });
move({ id: 1, x: 99, y: 99 + minDistance });
end({ id: 1, x: 99, y: 99 + minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragstartHandler).not.toHaveBeenCalled();
expect(dragHandler).not.toHaveBeenCalled();
expect(dragendHandler).not.toHaveBeenCalled();
});
});
it("should not fire dragstart when touchstart is stopped and the sequence tap in, tap out, tap in is followed", function() {
var touchStart = jasmine.createSpy();
targetEl.on('touchstart', touchStart.andCallFake(function(e) {
e.stopPropagation();
}));
start({id: 1, x: 100, y: 101});
end({id: 1, x: 100, y: 100});
expect(touchStart.callCount).toBe(1);
expect(dragstartHandler).not.toHaveBeenCalled();
start({id: 2, x: 400, y: 400}, Ext.getBody());
end({id: 2, x: 400, y: 400}, Ext.getBody());
expect(touchStart.callCount).toBe(1);
expect(dragstartHandler).not.toHaveBeenCalled();
start({id: 3, x: 100, y: 101});
end({id: 3, x: 100, y: 100});
expect(touchStart.callCount).toBe(2);
expect(dragstartHandler).not.toHaveBeenCalled();
});
if (Ext.supports.Touch) {
it("should fire dragcancel and not dragend if the touch is canceled after dragstart", function() {
runs(function() {
start({ id: 1, x: 100, y: 101 });
move({ id: 1, x: 99, y: 101 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragstartHandler).toHaveBeenCalled();
expect(dragHandler).toHaveBeenCalled();
move({ id: 1, x: 97, y: 100 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
cancel({ id: 1, x: 96, y: 99 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).not.toHaveBeenCalled();
expect(dragcancelHandler).toHaveBeenCalled();
expectInfo(dragcancelEvent, {
x: 96,
y: 99 - minDistance,
pageX: 96,
pageY: 99 - minDistance,
startX: 100,
startY: 101,
previousX: 97,
previousY: 100 - minDistance,
deltaX: -4,
deltaY: -(minDistance + 2),
absDeltaX: 4,
absDeltaY: minDistance + 2,
previousDeltaX: -3,
previousDeltaY: -(minDistance + 1),
longpress: false
});
});
});
it("should fire dragcancel when a second touch begins", function() {
runs(function() {
start({ id: 1, x: 100, y: 101 });
move({ id: 1, x: 99, y: 101 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragstartHandler).toHaveBeenCalled();
expect(dragHandler).toHaveBeenCalled();
move({ id: 1, x: 97, y: 100 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
start({ id: 2, x: 200, y: 300 });
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).not.toHaveBeenCalled();
expect(dragcancelHandler).toHaveBeenCalled();
expectInfo(dragcancelEvent, {
x: 97,
y: 100 - minDistance,
pageX: 97,
pageY: 100 - minDistance,
startX: 100,
startY: 101,
previousX: 99,
previousY: 101 - minDistance,
deltaX: -3,
deltaY: -(minDistance + 1),
absDeltaX: 3,
absDeltaY: minDistance + 1,
previousDeltaX: -1,
previousDeltaY: -minDistance,
longpress: false
});
});
});
}
it("should have the correct e.target if the mouse is moved off of the target", function() {
runs(function() {
start({ id: 1, x: 500, y: 300 });
helper.touchMove(document.body, { id: 1, x: 200, y: 700 });
});
waitsForAnimation();
runs(function() {
expect(dragEvent.target).toBe(targetEl.dom);
end({ id: 1, x: 200, y: 700 });
});
waitsForAnimation();
});
describe("longpress to drag", function() {
it("should not initiate drag with longpress by default", function() {
var longpressed = false;
targetEl.on('longpress', function() {
longpressed = true;
});
runs(function() {
start({ id: 1, x: 100, y: 101 });
});
waitsFor(function() {
return longpressed;
}, "longpress handler was never called", 3000);
runs(function() {
expect(dragstartHandler).not.toHaveBeenCalled();
});
});
it("should initiate drag with longpress when e.startDrag() is invoked", function() {
var longpressed = false;
targetEl.on('longpress', function(e) {
e.startDrag();
longpressed = true;
});
runs(function() {
start({ id: 1, x: 100, y: 101 });
});
waitsFor(function() {
return longpressed;
}, "longpress handler was never called", 3000);
runs(function() {
expect(dragstartHandler).toHaveBeenCalled();
expectInfo(dragstartEvent, {
x: 100,
y: 101,
pageX: 100,
pageY: 101,
startX: 100,
startY: 101,
previousX: 100,
previousY: 101,
deltaX: 0,
deltaY: 0,
absDeltaX: 0,
absDeltaY: 0,
previousDeltaX: 0,
previousDeltaY: 0,
longpress: true
});
});
runs(function() {
move({ id: 1, x: 99, y: 97 });
});
waitsForAnimation();
runs(function() {
expect(dragHandler).toHaveBeenCalled();
expectInfo(dragEvent, {
x: 99,
y: 97,
pageX: 99,
pageY: 97,
startX: 100,
startY: 101,
previousX: 100,
previousY: 101,
deltaX: -1,
deltaY: -4,
absDeltaX: 1,
absDeltaY: 4,
previousDeltaX: 0,
previousDeltaY: 0,
longpress: true
});
move({ id: 1, x: 97, y: 100 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
expectInfo(dragEvent, {
x: 97,
y: 100 - minDistance,
pageX: 97,
pageY: 100 - minDistance,
startX: 100,
startY: 101,
previousX: 99,
previousY: 97,
deltaX: -3,
deltaY: -(minDistance + 1),
absDeltaX: 3,
absDeltaY: minDistance + 1,
previousDeltaX: -1,
previousDeltaY: -4,
longpress: true
});
end({ id: 1, x: 96, y: 99 - minDistance });
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).toHaveBeenCalled();
expectInfo(dragendEvent, {
x: 96,
y: 99 - minDistance,
pageX: 96,
pageY: 99 - minDistance,
startX: 100,
startY: 101,
previousX: 97,
previousY: 100 - minDistance,
deltaX: -4,
deltaY: -(minDistance + 2),
absDeltaX: 4,
absDeltaY: minDistance + 2,
previousDeltaX: -3,
previousDeltaY: -(minDistance + 1),
longpress: true
});
});
});
it("should claim the drag gesture when startDrag is called", function() {
var longpressHandled = false;
targetEl.on('longpress', function(e) {
e.startDrag();
longpressHandled = true;
});
helper.touchStart(targetEl, {id: 1, x: 10, y: 15});
waitsFor(function() {
return longpressHandled;
});
runs(function() {
expect(Ext.event.gesture.Drag.instance.isActive).toBe(true);
expect(Ext.event.gesture.DoubleTap.instance.isActive).toBe(false);
expect(Ext.event.gesture.EdgeSwipe.instance.isActive).toBe(false);
expect(Ext.event.gesture.LongPress.instance.isActive).toBe(false);
expect(Ext.event.gesture.Pinch.instance.isActive).toBe(false);
expect(Ext.event.gesture.Rotate.instance.isActive).toBe(false);
expect(Ext.event.gesture.Swipe.instance.isActive).toBe(false);
expect(Ext.event.gesture.Tap.instance.isActive).toBe(false);
});
});
});
function makeRemoveSuite(useRemoveChild) {
describe("when the target element is removed from the dom mid-drag " + (useRemoveChild ? "(using removeChild)" : "(using innerHTML)"), function() {
var parent, target, firingTarget;
function removeTarget() {
if (useRemoveChild) {
parent.dom.removeChild(target.dom);
} else {
parent.dom.innerHTML = '';
}
}
beforeEach(function() {
parent = Ext.getBody().createChild({
id: 'parent'
});
target = parent.createChild({
id: 'child'
});
// the "firingTarget" attempts to emulate the target that the browser uses
// after an element is removed from the dom
if (Ext.supports.TouchEvents) {
// with touch events, the element remains the target of current touches
// even after the element is removed from the dom
firingTarget = target;
} else {
// with mouse and pointer events, once the element is removed from the dom
// we get a new target. Assume the worst - we removed the element AND
// moved the mouse or pointer off of the parent element which has the
// listeners. This is primarily to ensure that things like buffered grids
// work correctly when using the touch scroller and dragging past the
// edge of the buffer zone.
firingTarget = document.body;
}
});
afterEach(function() {
parent.destroy();
target.destroy();
});
it("should recover gracefully when the listener is attached above the target", function() {
runs(function() {
parent.on('drag', dragHandler);
parent.on('dragend', dragendHandler);
start({ id: 1, x: 100, y: 100 }, target);
move({ id: 1, x: 100, y: 100 + minDistance }, target);
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(1);
removeTarget();
move({ id: 1, x: 120, y: 150 + minDistance }, firingTarget);
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
expect(dragEvent.target).toBe(target.dom);
end({ id: 1, x: 120, y: 150 + minDistance }, firingTarget);
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).toHaveBeenCalled();
expect(dragendEvent.target).toBe(target.dom);
});
});
it("should recover gracefully when the listener is attached to the target", function() {
runs(function() {
target.on('drag', dragHandler);
target.on('dragend', dragendHandler);
start({ id: 1, x: 100, y: 100 }, target);
move({ id: 1, x: 100, y: 100 + minDistance }, target);
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(1);
removeTarget();
move({ id: 1, x: 120, y: 150 + minDistance }, firingTarget);
});
waitsForAnimation();
runs(function() {
expect(dragHandler.callCount).toBe(2);
expect(dragEvent.target).toBe(target.dom);
end({ id: 1, x: 120, y: 150 + minDistance }, firingTarget);
});
waitsForAnimation();
runs(function() {
expect(dragendHandler).toHaveBeenCalled();
expect(dragendEvent.target).toBe(target.dom);
});
});
});
}
makeRemoveSuite(true); // using removeChild
makeRemoveSuite(false); // using innerHTML = '' on an ancestor
});