Skip to content

Commit

Permalink
test(scroller): start scroller tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ajoslin committed Jul 26, 2013
1 parent 7581661 commit 2698a5a
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 73 deletions.
16 changes: 0 additions & 16 deletions src/services/dragger.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,6 @@ angular.module('ajoslin.scrolly.dragger', [])
* </pre>
*/

var hasTouch = 'ontouchstart' in $window;

//Creates a dragger for an element
function $dragger(elm) {
var self = {};
Expand Down Expand Up @@ -187,20 +185,6 @@ angular.module('ajoslin.scrolly.dragger', [])
elm.bind('touchmove', dragMove);
elm.bind('touchend touchcancel', dragEnd);

//Hack taken from iscroll for mouse events
elm.bind('mouseout', function mouseout(e) {
e = e.originalEvent || e;
var t = e.relatedTarget;
if (!t) {
dragEnd(e);
} else {
while ( (t = t.parentNode) ) {
if (t === elm) return;
}
dragEnd(e);
}
});

//Restarts the drag at the given position
function restartDragState(y) {
state.startPos = state.pos = y;
Expand Down
8 changes: 0 additions & 8 deletions src/services/dragger.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ describe('scrolly.dragger', function() {
dragger = new $dragger(elm);
}));

it('should expose $dragger service as a function', function() {
expect(typeof $dragger).toBe('function');
});

it('should create a dragger object from the element', function() {
expect(typeof dragger).toBe('object');
});

it('should error if passing a non-function to addListener', function() {
expect(function() {
dragger.addListener('not a function');
Expand Down
94 changes: 50 additions & 44 deletions src/services/scroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

angular.module('ajoslin.scrolly.scroller', [
'ajoslin.scrolly.dragger',
'ajoslin.scrolly.scroller'
'ajoslin.scrolly.transformer'
])
.provider('$scroller', function() {

Expand Down Expand Up @@ -110,33 +110,36 @@ angular.module('ajoslin.scrolly.scroller', [
return _bounceBackDistanceMulti;
};

function getRect(raw) {
var style = window.getComputedStyle(raw);
var offTop = parseInt(style['margin-top'], 10) +
parseInt(style['padding-top'], 10);
var offBottom = parseInt(style['margin-bottom'], 10) +
parseInt(style['padding-bottom'], 10);
var height = parseInt(style.height, 10);
var top = parseInt(style.top, 10);
var bottom = parseInt(style.bottom, 10);
return {
top: offTop + (isNaN(top) ? 0 : top),
bottom: offBottom + (isNaN(bottom) ? 0 : bottom),
height: height
};
}

//Quicker than Math.floor
//http://jsperf.com/math-floor-vs-math-round-vs-parseint/69
function floor(n) { return n | 0; }

function bounceTime(howMuchOut) {
return Math.abs(howMuchOut) * _bounceBackDistanceMulti +
_bounceBackMinTime;
}

this.$get = function($dragger, $transformer, $window, $document) {

$scroller.getContentRect = function(raw) {
var top, bottom;
var style = window.getComputedStyle(raw);
var offTop = parseInt(style['margin-top'], 10) +
parseInt(style['padding-top'], 10) +
isNaN( (top = parseInt(style.top, 10)) ) ? 0 : top;

var offBottom = parseInt(style['margin-bottom'], 10) +
parseInt(style['padding-bottom'], 10) +
isNaN( (bottom = parseInt(style.bottom, 10)) ) ? 0 : bottom;

var height = parseInt(style.height, 10);
return {
top: offTop,
bottom: offBottom,
height: height
};
};

function bounceTime(howMuchOut) {
return Math.abs(howMuchOut) * _bounceBackDistanceMulti +
_bounceBackMinTime;
}

/**
* @ngdoc object
* @name ajoslin.scrolly.$scroller
Expand All @@ -152,13 +155,14 @@ angular.module('ajoslin.scrolly.scroller', [
*
*/

function scroller(elm) {
function $scroller(elm) {
var self = {};
var raw = elm[0];

var transformer = new $transformer(elm);
var dragger = new $dragger(elm);
var transformer = self.transformer = new $transformer(elm);
var dragger = self.dragger = new $dragger(elm);

/*
var SCROLL_OFFSET = 200;
setTimeout(function() {
document.body.scrollTop = SCROLL_OFFSET;
Expand All @@ -178,9 +182,10 @@ angular.module('ajoslin.scrolly.scroller', [
}
document.body.scrollTop = SCROLL_OFFSET;
});
*/

function calculateHeight() {
var rect = getRect(raw);
self.calculateHeight = function() {
var rect = $scroller.getContentRect(raw);
//TODO find a better way to get the height of the wrapper/screen
var screenHeight = $window.innerHeight;
//If our content doesn't fill the whole area, just act like it's
Expand All @@ -191,29 +196,29 @@ angular.module('ajoslin.scrolly.scroller', [
self.scrollHeight = rect.height - screenHeight + rect.top + rect.bottom;
}
return self.scrollHeight;
}
calculateHeight();
};
self.calculateHeight();

function outOfBounds(pos) {
self.outOfBounds = function(pos) {
if (pos > 0) return pos;
if (pos < -self.scrollHeight) return pos + self.scrollHeight;
return false;
}
};

function dragListener(dragData) {
switch(dragData.type) {
case 'start':
if (transformer.changing) {
transformer.stop();
}
calculateHeight();
self.calculateHeight();
break;

case 'move':
var newPos = transformer.pos + dragData.delta;
//If going past boundaries, scroll at half speed
//TODO make the 0.5 a provider option
if ( outOfBounds(newPos) ) {
if ( self.outOfBounds(newPos) ) {
newPos = transformer.pos + floor(dragData.delta * 0.5);
}
transformer.setTo(newPos);
Expand All @@ -222,11 +227,10 @@ angular.module('ajoslin.scrolly.scroller', [
case 'end':
//If we're out of bounds, or held on to our spot for too long,
//no momentum. Just check that we're in bounds.
if (outOfBounds(transformer.pos) || dragData.inactiveDrag) {
if (self.outOfBounds(transformer.pos) || dragData.inactiveDrag) {
checkBoundaries();
} else {
calculateHeight();
var momentum = calcMomentum(dragData);
var momentum = self.momentum(dragData);
if (momentum.position !== transformer.pos) {
transformer.easeTo(
momentum.position,
Expand All @@ -238,23 +242,25 @@ angular.module('ajoslin.scrolly.scroller', [
break;
}
}
function checkBoundaries() {
calculateHeight();
self.checkBoundaries = function() {
self.calculateHeight();

var howMuchOut = outOfBounds(transformer.pos);
var howMuchOut = self.outOfBounds(transformer.pos);
if (howMuchOut) {
var newPosition = howMuchOut > 0 ? 0 : -self.scrollHeight;
transformer.easeTo(newPosition, bounceTime(howMuchOut));
}
}
function calcMomentum(dragData) {
};
self.momentum = function(dragData) {
self.calculateHeight();

var speed = Math.abs(dragData.distance) / dragData.duration;
var newPos = transformer.pos + (speed * speed) /
(2 * _decelerationRate) *
(dragData.distance < 0 ? -1 : 1);
var time = speed / _decelerationRate;

var howMuchOver = outOfBounds(newPos);
var howMuchOver = self.outOfBounds(newPos);
var distance;
if (howMuchOver) {
if (howMuchOver > 0) {
Expand All @@ -269,7 +275,7 @@ angular.module('ajoslin.scrolly.scroller', [
position: newPos,
time: floor(time)
};
}
};

dragger.addListener(dragListener);
elm.bind('$destroy', function() {
Expand All @@ -279,7 +285,7 @@ angular.module('ajoslin.scrolly.scroller', [
return self;
}

return scroller;
return $scroller;
};

});
92 changes: 92 additions & 0 deletions src/services/scroller.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
describe('scroller', function() {

beforeEach(module('ajoslin.scrolly.scroller', function($provide) {
$provide.factory('$window', function() {
return angular.mock.createMockWindow();
});
}));

var scroller, elm, $scroller, dimensions, $window;
beforeEach(inject(function(_$scroller_, $compile, _$window_) {
elm = $("<div>");
$scroller = _$scroller_;
scroller = new $scroller(elm);
$window = _$window_;

dimensions = {
top: 40,
bottom: 40,
height: 500
};
spyOn($scroller, 'getContentRect').andCallFake(function() {
return dimensions;
});
}));

describe('calculateHeight', function() {
it('should set scrollHeight to window\'s height relative to dimensions', function() {
$window.innerHeight = 300;
scroller.calculateHeight();
expect(scroller.scrollHeight).toEqual(dimensions.height - 300 + 40 + 40);
});
it('should set scrollHeight to 0 if content height is less than window height', function() {
$window.innerHeight = 100;
dimensions.height = 50;
scroller.calculateHeight();
expect(scroller.scrollHeight).toBe(0);
});
});

describe('outOfBounds', function() {
it('should return falsy -scrollHeight < pos < 0', function() {
scroller.scrollHeight = 10;
expect(scroller.outOfBounds(-5)).toBeFalsy();
});
it('should return how much out of bounds if pos < -scrollHeight', function() {
scroller.scrollHeight = 10;
expect(scroller.outOfBounds(-13)).toBe(-3);
});
it('should return how much out of bounds if pos > 0', function() {
expect(scroller.outOfBounds(7)).toBe(7);
});
});

describe('checkBoundaries', function() {
beforeEach(function() {
spyOn(scroller.transformer, 'easeTo').andCallThrough();
spyOn(scroller, 'calculateHeight').andCallFake(function() {
return self.scrollHeight;
});
});

it('should do nothing if in boundaries', function() {
scroller.scrollHeight = 100;
scroller.transformer.pos = -50;
scroller.checkBoundaries();
expect(scroller.transformer.easeTo).not.toHaveBeenCalled();
});

it('should ease back to boundaries if outside', function() {
scroller.scrollHeight = 100;
scroller.transformer.pos = 30;
scroller.checkBoundaries();
expect(scroller.transformer.easeTo).toHaveBeenCalled();
expect(scroller.transformer.easeTo.mostRecentCall.args[0]).toBe(0);

scroller.transformer.easeTo.reset();
scroller.transformer.pos = -144;
scroller.checkBoundaries();
expect(scroller.transformer.easeTo).toHaveBeenCalled();
expect(scroller.transformer.easeTo.mostRecentCall.args[0]).toBe(-100);
});

});

describe('momentum', function() {
//TODO momentum tests
});

describe('drag', function() {
//TODO drag -> scroll tests
});
});
6 changes: 1 addition & 5 deletions src/services/transformer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ describe('scrolly.transformer', function() {
$provide.factory('$nextFrame', function($window) {
return angular.mock.createMockWindow().setTimeout;
});
$provide.decorator('$sniffer', function($delegate) {
$delegate.vendorPrefix = 'webkit';
return $delegate;
});
}));

var $transformer, transformer, elm, $window, $nextFrame;
Expand Down Expand Up @@ -77,7 +73,7 @@ describe('scrolly.transformer', function() {
expect(transformer.pos).toBe(100);
});

it('should stop before easeing if already easing', function() {
it('should stop before easing if already easing', function() {
spyOn(transformer, 'stop').andCallThrough();
spyOn(transformer, 'easeTo').andCallThrough();

Expand Down

0 comments on commit 2698a5a

Please sign in to comment.