mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
feat(scrolling): Allow native scrolling to be configurable, add infinite scroll support for native scrolling
This commit is contained in:
115
js/angular/controller/infiniteScrollController.js
vendored
Normal file
115
js/angular/controller/infiniteScrollController.js
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
IonicModule
|
||||
.controller('$ionInfiniteScroll', [
|
||||
'$scope',
|
||||
'$attrs',
|
||||
'$element',
|
||||
'$timeout',
|
||||
function($scope, $attrs, $element, $timeout) {
|
||||
var self = this;
|
||||
self.isLoading = false;
|
||||
|
||||
$scope.icon = function() {
|
||||
return angular.isDefined($attrs.icon) ? $attrs.icon : 'ion-loading-d';
|
||||
};
|
||||
|
||||
$scope.$on('scroll.infiniteScrollComplete', function() {
|
||||
finishInfiniteScroll();
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
if (self.scrollCtrl && self.scrollCtrl.$element) self.scrollCtrl.$element.off('scroll', self.checkBounds);
|
||||
if (self.scrollEl && self.scrollEl.removeEventListener) {
|
||||
self.scrollEl.removeEventListener('scroll', self.checkBounds);
|
||||
}
|
||||
});
|
||||
|
||||
// debounce checking infinite scroll events
|
||||
self.checkBounds = ionic.Utils.throttle(checkInfiniteBounds, 300);
|
||||
|
||||
function onInfinite() {
|
||||
ionic.requestAnimationFrame(function() {
|
||||
$element[0].classList.add('active');
|
||||
});
|
||||
self.isLoading = true;
|
||||
$scope.$parent && $scope.$parent.$apply($attrs.onInfinite || '');
|
||||
}
|
||||
|
||||
function finishInfiniteScroll() {
|
||||
ionic.requestAnimationFrame(function() {
|
||||
$element[0].classList.remove('active');
|
||||
});
|
||||
$timeout(function() {
|
||||
if (self.jsScrolling) self.scrollView.resize();
|
||||
self.checkBounds();
|
||||
}, 30, false);
|
||||
self.isLoading = false;
|
||||
}
|
||||
|
||||
// check if we've scrolled far enough to trigger an infinite scroll
|
||||
function checkInfiniteBounds() {
|
||||
if (self.isLoading) return;
|
||||
var maxScroll = {};
|
||||
|
||||
if (self.jsScrolling) {
|
||||
maxScroll = self.getJSMaxScroll();
|
||||
var scrollValues = self.scrollView.getValues();
|
||||
if ((maxScroll.left !== -1 && scrollValues.left >= maxScroll.left) ||
|
||||
(maxScroll.top !== -1 && scrollValues.top >= maxScroll.top)) {
|
||||
onInfinite();
|
||||
}
|
||||
} else {
|
||||
maxScroll = self.getNativeMaxScroll();
|
||||
if ((
|
||||
maxScroll.left !== -1 &&
|
||||
self.scrollEl.scrollLeft >= maxScroll.left - self.scrollEl.clientWidth
|
||||
) || (
|
||||
maxScroll.top !== -1 &&
|
||||
self.scrollEl.scrollTop >= maxScroll.top - self.scrollEl.clientHeight
|
||||
)) {
|
||||
onInfinite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// determine the threshold at which we should fire an infinite scroll
|
||||
// note: this gets processed every scroll event, can it be cached?
|
||||
self.getJSMaxScroll = function() {
|
||||
var maxValues = self.scrollView.getScrollMax();
|
||||
return {
|
||||
left: self.scrollView.options.scrollingX ?
|
||||
calculateMaxValue(maxValues.left) :
|
||||
-1,
|
||||
top: self.scrollView.options.scrollingY ?
|
||||
calculateMaxValue(maxValues.top) :
|
||||
-1
|
||||
};
|
||||
};
|
||||
|
||||
self.getNativeMaxScroll = function() {
|
||||
var maxValues = {
|
||||
left: self.scrollEl.scrollWidth,
|
||||
top: self.scrollEl.scrollHeight
|
||||
};
|
||||
var computedStyle = window.getComputedStyle(self.scrollEl) || {};
|
||||
return {
|
||||
left: computedStyle.overflowX === 'scroll' ||
|
||||
computedStyle.overflowX === 'auto' ||
|
||||
self.scrollEl.style['overflow-x'] === 'scroll' ?
|
||||
calculateMaxValue(maxValues.left) : -1,
|
||||
top: computedStyle.overflowY === 'scroll' ||
|
||||
computedStyle.overflowY === 'auto' ||
|
||||
self.scrollEl.style['overflow-y'] === 'scroll' ?
|
||||
calculateMaxValue(maxValues.top) : -1
|
||||
};
|
||||
};
|
||||
|
||||
// determine pixel refresh distance based on % or value
|
||||
function calculateMaxValue(maximum) {
|
||||
distance = ($attrs.distance || '2.5%').trim();
|
||||
isPercent = distance.indexOf('%') !== -1;
|
||||
return isPercent ?
|
||||
maximum * (1 - parseFloat(distance) / 100) :
|
||||
maximum - parseFloat(distance);
|
||||
}
|
||||
|
||||
}]);
|
||||
6
js/angular/directive/content.js
vendored
6
js/angular/directive/content.js
vendored
@@ -45,7 +45,8 @@ IonicModule
|
||||
'$timeout',
|
||||
'$controller',
|
||||
'$ionicBind',
|
||||
function($timeout, $controller, $ionicBind) {
|
||||
'$ionicConfig',
|
||||
function($timeout, $controller, $ionicBind, $ionicConfig) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '^?ionNavView',
|
||||
@@ -108,7 +109,8 @@ function($timeout, $controller, $ionicBind) {
|
||||
|
||||
if ($attr.scroll === "false") {
|
||||
//do nothing
|
||||
} else if(attr.overflowScroll === "true") {
|
||||
} else if (attr.overflowScroll === "true" || !$ionicConfig.scrolling.jsScrolling()) {
|
||||
// use native scrolling
|
||||
$element.addClass('overflow-scroll');
|
||||
} else {
|
||||
var scrollViewOptions = {
|
||||
|
||||
101
js/angular/directive/infiniteScroll.js
vendored
101
js/angular/directive/infiniteScroll.js
vendored
@@ -19,6 +19,7 @@
|
||||
* @param {string=} distance The distance from the bottom that the scroll must
|
||||
* reach to trigger the on-infinite expression. Default: 1%.
|
||||
* @param {string=} icon The icon to show while loading. Default: 'ion-loading-d'.
|
||||
* @param {boolean=} immediate-check Whether to check the infinite scroll bounds immediately on load.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
@@ -63,84 +64,40 @@
|
||||
*/
|
||||
IonicModule
|
||||
.directive('ionInfiniteScroll', ['$timeout', function($timeout) {
|
||||
function calculateMaxValue(distance, maximum, isPercent) {
|
||||
return isPercent ?
|
||||
maximum * (1 - parseFloat(distance,10) / 100) :
|
||||
maximum - parseFloat(distance, 10);
|
||||
}
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: ['^$ionicScroll', 'ionInfiniteScroll'],
|
||||
template: '<i class="icon {{icon()}} icon-refreshing"></i>',
|
||||
scope: {
|
||||
load: '&onInfinite'
|
||||
},
|
||||
controller: ['$scope', '$attrs', function($scope, $attrs) {
|
||||
this.isLoading = false;
|
||||
this.scrollView = null; //given by link function
|
||||
this.getMaxScroll = function() {
|
||||
var distance = ($attrs.distance || '2.5%').trim();
|
||||
var isPercent = distance.indexOf('%') !== -1;
|
||||
var maxValues = this.scrollView.getScrollMax();
|
||||
return {
|
||||
left: this.scrollView.options.scrollingX ?
|
||||
calculateMaxValue(distance, maxValues.left, isPercent) :
|
||||
-1,
|
||||
top: this.scrollView.options.scrollingY ?
|
||||
calculateMaxValue(distance, maxValues.top, isPercent) :
|
||||
-1
|
||||
};
|
||||
};
|
||||
}],
|
||||
require: ['?^$ionicScroll', 'ionInfiniteScroll'],
|
||||
template: '<i class="icon {{icon()}} icon-refreshing {{scrollingType}}"></i>',
|
||||
scope: true,
|
||||
controller: '$ionInfiniteScroll',
|
||||
link: function($scope, $element, $attrs, ctrls) {
|
||||
var scrollCtrl = ctrls[0];
|
||||
var infiniteScrollCtrl = ctrls[1];
|
||||
var scrollView = infiniteScrollCtrl.scrollView = scrollCtrl.scrollView;
|
||||
|
||||
$scope.icon = function() {
|
||||
return angular.isDefined($attrs.icon) ? $attrs.icon : 'ion-loading-d';
|
||||
};
|
||||
|
||||
var onInfinite = function() {
|
||||
$element[0].classList.add('active');
|
||||
infiniteScrollCtrl.isLoading = true;
|
||||
$scope.load();
|
||||
};
|
||||
|
||||
var finishInfiniteScroll = function() {
|
||||
$element[0].classList.remove('active');
|
||||
$timeout(function() {
|
||||
scrollView.resize();
|
||||
checkBounds();
|
||||
}, 0, false);
|
||||
infiniteScrollCtrl.isLoading = false;
|
||||
};
|
||||
|
||||
$scope.$on('scroll.infiniteScrollComplete', function() {
|
||||
finishInfiniteScroll();
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
if(scrollCtrl && scrollCtrl.$element)scrollCtrl.$element.off('scroll', checkBounds);
|
||||
});
|
||||
|
||||
var checkBounds = ionic.animationFrameThrottle(checkInfiniteBounds);
|
||||
|
||||
//Check bounds on start, after scrollView is fully rendered
|
||||
$timeout(checkBounds, 0, false);
|
||||
scrollCtrl.$element.on('scroll', checkBounds);
|
||||
|
||||
function checkInfiniteBounds() {
|
||||
if (infiniteScrollCtrl.isLoading) return;
|
||||
|
||||
var scrollValues = scrollView.getValues();
|
||||
var maxScroll = infiniteScrollCtrl.getMaxScroll();
|
||||
|
||||
if ((maxScroll.left !== -1 && scrollValues.left >= maxScroll.left) ||
|
||||
(maxScroll.top !== -1 && scrollValues.top >= maxScroll.top)) {
|
||||
onInfinite();
|
||||
var scrollCtrl = infiniteScrollCtrl.scrollCtrl = ctrls[0];
|
||||
var jsScrolling = infiniteScrollCtrl.jsScrolling = !!scrollCtrl;
|
||||
// if this view is not beneath a scrollCtrl, it can't be injected, proceed w/ native scrolling
|
||||
if (jsScrolling) {
|
||||
infiniteScrollCtrl.scrollView = scrollCtrl.scrollView;
|
||||
} else {
|
||||
// grabbing the scrollable element, to determine dimensions, and current scroll pos
|
||||
var scrollEl = ionic.DomUtil.getParentOrSelfWithClass($element[0].parentNode,'overflow-scroll');
|
||||
infiniteScrollCtrl.scrollEl = scrollEl;
|
||||
// if there's no scroll controller, and no overflow scroll div, infinite scroll wont work
|
||||
if (!scrollEl) {
|
||||
throw 'Infinite scroll must be used inside a scrollable div';
|
||||
}
|
||||
}
|
||||
//bind to appropriate scroll event
|
||||
if (jsScrolling) {
|
||||
$scope.scrollingType = 'js-scrolling';
|
||||
scrollCtrl.$element.on('scroll', infiniteScrollCtrl.checkBounds);
|
||||
} else {
|
||||
infiniteScrollCtrl.scrollEl.addEventListener('scroll', infiniteScrollCtrl.checkBounds);
|
||||
}
|
||||
// Optionally check bounds on start after scrollView is fully rendered
|
||||
var doImmediateCheck = angular.isDefined($attrs.immediateCheck) ? $scope.$eval($attrs.immediateCheck) : true;
|
||||
if (doImmediateCheck) {
|
||||
$timeout(function() { infiniteScrollCtrl.checkBounds(); });
|
||||
}
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
7
js/angular/service/ionicConfig.js
vendored
7
js/angular/service/ionicConfig.js
vendored
@@ -222,6 +222,9 @@ IonicModule
|
||||
form: {
|
||||
checkbox: PLATFORM
|
||||
},
|
||||
scrolling: {
|
||||
jsScrolling: PLATFORM
|
||||
},
|
||||
tabs: {
|
||||
style: PLATFORM,
|
||||
position: PLATFORM
|
||||
@@ -262,6 +265,10 @@ IonicModule
|
||||
checkbox: 'circle'
|
||||
},
|
||||
|
||||
scrolling: {
|
||||
jsScrolling: true
|
||||
},
|
||||
|
||||
tabs: {
|
||||
style: 'standard',
|
||||
position: 'bottom'
|
||||
|
||||
@@ -261,25 +261,37 @@ body.grade-c {
|
||||
ion-infinite-scroll {
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
|
||||
display: block;
|
||||
|
||||
@include transition(opacity 0.25s);
|
||||
// @include transition(opacity 0.25s);
|
||||
@include display-flex();
|
||||
@include flex-direction(row);
|
||||
@include justify-content(center);
|
||||
@include align-items(center);
|
||||
|
||||
.icon {
|
||||
|
||||
color: #666666;
|
||||
font-size: 30px;
|
||||
color: $scroll-refresh-icon-color;
|
||||
&:before{
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
&:not(.active) .icon:before{
|
||||
-webkit-transform: translate3d(-1000px,0,0);
|
||||
transform: translate3d(-1000px,0,0);
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
// removing the animation when the spinner isn't shown
|
||||
// this breaks up animations on iOS, so they are left with unnecessary reflows
|
||||
body:not(.platform-ios) ion-infinite-scroll:not(.active) .icon{
|
||||
-webkit-animation: none;
|
||||
animation:none;
|
||||
}
|
||||
|
||||
.overflow-scroll {
|
||||
overflow-x: hidden;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user