feat(scrolling): Allow native scrolling to be configurable, add infinite scroll support for native scrolling

This commit is contained in:
perry
2015-01-14 17:04:42 -06:00
parent d24ac308c3
commit 54c27ff85b
7 changed files with 305 additions and 112 deletions

View File

@@ -1,13 +1,14 @@
describe('Ionic Content directive', function() {
var compile, scope, timeout, window;
var compile, scope, timeout, window, ionicConfig;
beforeEach(module('ionic'));
beforeEach(inject(function($compile, $rootScope, $timeout, $window) {
beforeEach(inject(function($compile, $rootScope, $timeout, $window, $ionicConfig) {
compile = $compile;
scope = $rootScope;
timeout = $timeout;
window = $window;
ionicConfig = $ionicConfig;
ionic.Platform.setPlatform('Android');
}));
@@ -128,6 +129,12 @@ describe('Ionic Content directive', function() {
expect(vals.top).toBe(300);
});
it('Should allow native scrolling to be set by $ionicConfig ', function() {
ionicConfig.scrolling.jsScrolling(false);
var element = compile('<ion-content></ion-content>')(scope);
expect(element.hasClass('overflow-scroll')).toBe(true);
});
});
/* Tests #555, #1155 */
describe('Ionic Content Directive scoping', function() {

View File

@@ -1,21 +1,17 @@
describe('ionicInfiniteScroll directive', function() {
beforeEach(module('ionic'));
var scrollTopValue;
var scrollTopMaxValue;
var scrollLeftValue;
var scrollLeftMaxValue;
var scrollTopValue = 50;
var scrollTopMaxValue = 60;
var scrollLeftValue = 101;
var scrollLeftMaxValue = 121;
var ctrl;
function setup(attrs, scopeProps, options) {
function setupJS(attrs, scopeProps, options) {
var element;
scrollTopValue = 50;
scrollLeftValue = 60;
scrollLeftMaxValue = 101;
scrollTopMaxValue = 121;
inject(function($rootScope, $compile) {
var scope = $rootScope.$new();
angular.extend(scope, scopeProps || {});
element = angular.element('<ion-infinite-scroll '+(attrs||'')+'></ion-infinite-scroll>');
element = angular.element('<ion-infinite-scroll ' + (attrs || '') + '></ion-infinite-scroll>');
ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
element.data('$$ionicScrollController', {
scrollView: {
@@ -47,7 +43,40 @@ describe('ionicInfiniteScroll directive', function() {
return element;
}
it('should error if no ionicScroll parent', function() {
function setupNative(attrs, scopeProps, options) {
var element, parent;
inject(function($rootScope, $compile, $document) {
var scope = $rootScope.$new();
angular.extend(scope, scopeProps || {});
parent = angular.element('<ion-content class="overflow-scroll"><ion-infinite-scroll ' + (attrs || '') +
'></ion-infinite-scroll></ion-content></ion-content>');
if (options && !!options.scrollingX) parent[0].style['overflow-x'] ='scroll';
if (options && !!options.scrollingY) parent[0].style['overflow-y'] ='scroll';
element = parent.find('ion-infinite-scroll');
ionic.animationFrameThrottle = function(cb) { return function() { cb(); }; };
$compile(element)(scope);
ctrl = element.controller('ionInfiniteScroll');
// create a fake scrollEl since they can't be faked if we're passing in scroll data
if (options) {
ctrl.scrollEl = {style:{
'overflow-x':'hidden',
'overflow-y':'hidden'
}};
if (!!options.scrollingX) ctrl.scrollEl.style['overflow-x'] ='scroll';
if (!!options.scrollingY) ctrl.scrollEl.style['overflow-y'] ='scroll';
ctrl.scrollEl.clientWidth = ctrl.scrollEl.scrollLeft = scrollLeftValue;
ctrl.scrollEl.clientHeight = ctrl.scrollEl.scrollTop = scrollTopValue;
ctrl.scrollEl.scrollWidth = scrollLeftMaxValue;
ctrl.scrollEl.scrollHeight = scrollTopMaxValue;
}
scope.$apply();
});
return element;
}
it('should error if no ionicScroll or native scroll parent', function() {
expect(function() {
inject(function($compile, $rootScope) {
$compile('<ion-infinite-scroll></ion-infinite-scroll>')($rootScope.$new());
@@ -56,34 +85,42 @@ describe('ionicInfiniteScroll directive', function() {
});
it('should not have class or be loading by default', function() {
var el = setup();
var el = setupJS();
expect(el.hasClass('active')).toBe(false);
expect(ctrl.isLoading).toBe(false);
el = setupNative();
expect(el.hasClass('active')).toBe(false);
expect(ctrl.isLoading).toBe(false);
});
it('should unbind scroll event on destroy', function() {
var el = setup();
var el = setupJS();
spyOn(el.controller('$ionicScroll').$element, 'off');
el.scope().$destroy();
expect(el.controller('$ionicScroll').$element.off).toHaveBeenCalledWith('scroll', jasmine.any(Function));
el = setupNative();
spyOn(ctrl.scrollEl, 'removeEventListener');
el.scope().$destroy();
expect(ctrl.scrollEl.removeEventListener).toHaveBeenCalled();
});
describe('icon', function() {
it('should have default icon ion-loading-d', function() {
var el = setup();
var el = setupJS();
var icon = angular.element(el[0].querySelector('.icon'));
expect(icon.hasClass('ion-loading-d')).toBe(true);
});
it('should allow icon attr blank', function() {
var el = setup('icon=""');
var el = setupJS('icon=""');
var icon = angular.element(el[0].querySelector('.icon'));
expect(icon.hasClass('ion-loading-d')).toBe(false);
});
it('should allow interpolated icon attr', function() {
var el = setup('icon="{{someIcon}}"');
var el = setupJS('icon="{{someIcon}}"');
var icon = angular.element(el[0].querySelector('.icon'));
expect(icon.hasClass('ion-loading-d')).toBe(false);
el.scope().$apply('someIcon = "super-icon"');
@@ -92,31 +129,49 @@ describe('ionicInfiniteScroll directive', function() {
});
describe('getMaxScroll', function() {
[ { scrollingX: true, scrollingY: true, },
{ scrollingX: false, scrollingY: true },
{ scrollingX: true, scrollingY: false }
[{ scrollingX: true, scrollingY: true },
{ scrollingX: false, scrollingY: true },
{ scrollingX: true, scrollingY: false }
].forEach(function(opts) {
describe('with scrollingX='+opts.scrollingX+', scrollingY='+opts.scrollingY, function() {
describe('with scrollingX=' + opts.scrollingX + ', scrollingY=' + opts.scrollingY, function() {
it('should default to 2.5%', function() {
var el = setup('', {}, opts);
expect(ctrl.getMaxScroll()).toEqual({
setupJS('', {}, opts);
expect(ctrl.getJSMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
});
setupNative('', {}, opts);
expect(ctrl.getNativeMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue * 0.975 : -1,
top: opts.scrollingY ? scrollTopMaxValue * 0.975 : -1
});
});
it('should use attr.distance as number', function() {
var el = setup('distance=3', {}, opts);
expect(ctrl.getMaxScroll()).toEqual({
setupJS('distance=3', {}, opts);
expect(ctrl.getJSMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
});
setupNative('distance=3', {}, opts);
expect(ctrl.getNativeMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue - 3 : -1,
top: opts.scrollingY ? scrollTopMaxValue - 3 : -1
});
});
it('should use attr.distance as percent', function() {
var el = setup('distance=5%', {}, opts);
expect(ctrl.getMaxScroll()).toEqual({
setupJS('distance=5%', {}, opts);
expect(ctrl.getJSMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
});
setupNative('distance=5%', {}, opts);
expect(ctrl.getNativeMaxScroll()).toEqual({
left: opts.scrollingX ? scrollLeftMaxValue * 0.95 : -1,
top: opts.scrollingY ? scrollTopMaxValue * 0.95 : -1
});
@@ -129,34 +184,57 @@ describe('ionicInfiniteScroll directive', function() {
describe('scroll event', function() {
it('should do nothing if < left and top', function() {
var el = setup('on-infinite="foo=1"');
var el = setupJS('on-infinite="foo=1"');
el.controller('$ionicScroll').$element.triggerHandler('scroll');
expect(el.hasClass('active')).toBe(false);
expect(ctrl.isLoading).toBe(false);
expect(el.scope().foo).not.toBe(1);
var el = setupNative('on-infinite="foo=1"');
var scrollEvent = new Event('scroll');
ctrl.scrollEl.dispatchEvent(scrollEvent);
expect(el.hasClass('active')).toBe(false);
expect(ctrl.isLoading).toBe(false);
expect(el.scope().foo).not.toBe(1);
});
it('should add active and call attr.onInfinite if >= top', function() {
var el = setup('on-infinite="foo=1"');
var el = setupJS('on-infinite="foo=1"');
scrollTopValue = scrollTopMaxValue;
el.controller('$ionicScroll').$element.triggerHandler('scroll');
expect(el.hasClass('active')).toBe(true);
expect(ctrl.isLoading).toBe(true);
expect(el.scope().foo).toBe(1);
scrollTopValue = scrollTopMaxValue;
var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
ctrl.checkBounds();
expect(el.hasClass('active')).toBe(true);
expect(ctrl.isLoading).toBe(true);
expect(el.scope().foo).toBe(1);
});
it('should add active and call attr.onInfinite if >= left', function() {
var el = setup('on-infinite="foo=1"');
var el = setupJS('on-infinite="foo=1"');
scrollLeftValue = scrollLeftMaxValue;
el.controller('$ionicScroll').$element.triggerHandler('scroll');
expect(el.hasClass('active')).toBe(true);
expect(ctrl.isLoading).toBe(true);
expect(el.scope().foo).toBe(1);
scrollLeftValue = scrollLeftMaxValue;
var el = setupNative('on-infinite="foo=1"', {}, { scrollingX: true, scrollingY: true });
ctrl.checkBounds();
expect(el.hasClass('active')).toBe(true);
expect(ctrl.isLoading).toBe(true);
expect(el.scope().foo).toBe(1);
});
it('should not run the event twice if isLoading is true', function() {
var onScrollSpy = jasmine.createSpy('onInfiniteScroll');
var el = setup('', { $onInfiniteScroll: onScrollSpy });
var el = setupJS('', { $onInfiniteScroll: onScrollSpy });
scrollTopValue = scrollTopMaxValue;
el.controller('$ionicScroll').$element.triggerHandler('scroll');
@@ -170,8 +248,24 @@ describe('ionicInfiniteScroll directive', function() {
});
it('should checkbounds on launch', inject(function($timeout) {
var el = setupJS();
spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
$timeout.flush();
expect(el.controller('ionInfiniteScroll').checkBounds).toHaveBeenCalled();
}));
it('should not checkbounds on launch if immediate-check=false', inject(function($timeout) {
var el = setupJS('immediate-check="false"');
spyOn(el.controller('ionInfiniteScroll'),'checkBounds');
expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
$timeout.flush();
expect(el.controller('ionInfiniteScroll').checkBounds).not.toHaveBeenCalled();
}));
it('scroll.infiniteScrollComplete should work', inject(function($timeout) {
var el = setup();
var el = setupJS();
ctrl.isLoading = true;
el.addClass('active');
el.scope().$broadcast('scroll.infiniteScrollComplete');
@@ -181,5 +275,4 @@ describe('ionicInfiniteScroll directive', function() {
$timeout.flush();
expect(el.controller('$ionicScroll').scrollView.resize).toHaveBeenCalled();
}));
});