feat(refresher): Allow refrsher to work with native scrolling

This update allows `<ion-refresher>` to work with native scrolling. Native scrolling can be enabled in the state deffinition, through the `$ionicConfigProvider` like `$ionicConfig.scrolling.jsScrolling(false);` or in the controller directly. It should function exactly the same as with JS scrolling enabled.

This is a merge of the wip-scrolling branch.
This commit is contained in:
perry
2015-02-05 11:41:53 -06:00
parent e90477c10e
commit 7134114bd5
9 changed files with 565 additions and 120 deletions

View File

@@ -0,0 +1,129 @@
describe('$ionicRefresh Controller', function() {
beforeEach(module('ionic'));
beforeEach(inject(function($ionicConfig) {
ionic.Platform.ready = function(cb) { cb(); };
ionic.requestAnimationFrame = function(cb) { cb(); };
$ionicConfig.scrolling.jsScrolling(false);
}));
function setup(options) {
options = options || {};
options.el = options.el ||
angular.element('<ion-refresher></ion-refresher><div class="list"></div>')[0];
scrollEl = options.parent ||
angular.element('<div class="ionic-scroll"><div class="scroll"></div></div>');
scrollEl.find('.scroll').append(options.el);
inject(function($controller, $rootScope, $timeout, $compile) {
scope = $rootScope.$new();
$compile(scrollEl)(scope);
scope.$apply();
scope.$onRefresh = jasmine.createSpy('onRefresh');
scope.$onPulling = jasmine.createSpy('onPulling');
refresher = scrollEl.find('.scroll-refresher')[0];
ctrl = angular.element(refresher).controller('ionRefresher');
timeout = $timeout;
});
}
function evt(y) {
return {
touches: [
{screenY:y}
],
preventDefault: function() {}
};
}
it('should error if not child of scroll view', function() {
setup({parent: angular.element('<div></div>')});
expect(ctrl).toBe(undefined);
});
it('should oversroll using CSS transforms', function() {
setup();
ctrl.__handleTouchmove(evt(0));
ctrl.__handleTouchmove(evt(10));
ctrl.__handleTouchmove(evt(20));
expect(ctrl.__getScrollChild().style[ionic.CSS.TRANSFORM]).toBe('translateY(10px)');
expect(ctrl.__getScrollChild().classList.contains('overscroll')).toBe(true);
expect(refresher.classList.contains('invisible')).toBe(false);
});
it('should resume native scrolling when overscroll is done', function() {
setup();
var domMethods = ctrl.getRefresherDomMethods();
spyOn(domMethods, 'activate');
spyOn(domMethods, 'deactivate');
ctrl.__handleTouchmove(evt(0));
ctrl.__handleTouchmove(evt(10));
expect(refresher.classList.contains('invisible')).toBe(false);
ctrl.__handleTouchmove(evt(0));
expect(ctrl.__getScrollChild().style[ionic.CSS.TRANSFORM]).toBe('translateY(0px)');
expect(ctrl.__getScrollChild().classList.contains('overscroll')).toBe(false);
expect(refresher.classList.contains('invisible')).toBe(true);
});
it('should activate and deactivate when dragging past activation threshold', function() {
setup();
var domMethods = ctrl.getRefresherDomMethods();
spyOn(domMethods, 'activate');
spyOn(domMethods, 'deactivate');
ctrl.__handleTouchmove(evt(0));
ctrl.__handleTouchmove(evt(10));
ctrl.__handleTouchmove(evt(100));
expect(ctrl.__getScrollChild().style[ionic.CSS.TRANSFORM]).toBe('translateY(90px)');
expect(ctrl.__getScrollChild().classList.contains('overscroll')).toBe(true);
expect(refresher.classList.contains('invisible')).toBe(false);
expect(refresher.classList.contains('active')).toBe(true);
ctrl.__handleTouchmove(evt(0));
timeout.flush();
expect(ctrl.__getScrollChild().style[ionic.CSS.TRANSFORM]).toBe('translateY(0px)');
expect(ctrl.__getScrollChild().classList.contains('overscroll')).toBe(false);
expect(refresher.classList.contains('invisible')).toBe(true);
expect(refresher.classList.contains('active')).toBe(false);
});
it('should update refresher class when shared methods fire', function() {
setup();
scope.$onRefresh = jasmine.createSpy('onRefresh');
scope.$onPulling = jasmine.createSpy('onPulling');
expect(refresher.classList.contains('active')).toBe(false);
expect(refresher.classList.contains('refreshing')).toBe(false);
expect(refresher.classList.contains('invisible')).toBe(true);
expect(scope.$onRefresh).not.toHaveBeenCalled();
expect(scope.$onPulling).not.toHaveBeenCalled();
ctrl.getRefresherDomMethods().show();
expect(refresher.classList.contains('invisible')).toBe(false);
ctrl.getRefresherDomMethods().activate();
expect(refresher.classList.contains('active')).toBe(true);
expect(refresher.classList.contains('refreshing')).toBe(false);
expect(scope.$onPulling).toHaveBeenCalled();
ctrl.getRefresherDomMethods().start();
expect(refresher.classList.contains('refreshing')).toBe(true);
expect(scope.$onRefresh).toHaveBeenCalled();
ctrl.getRefresherDomMethods().tail();
expect(refresher.classList.contains('refreshing-tail')).toBe(true);
ctrl.getRefresherDomMethods().deactivate();
timeout.flush();
expect(refresher.classList.contains('active')).toBe(false);
expect(refresher.classList.contains('refreshing')).toBe(false);
expect(refresher.classList.contains('refreshing-tail')).toBe(false);
ctrl.getRefresherDomMethods().hide();
expect(refresher.classList.contains('invisible')).toBe(true);
});
});

View File

@@ -242,19 +242,41 @@ describe('$ionicScroll Controller', function() {
expect(ctrl.scrollView.activatePullToRefresh).not.toHaveBeenCalled();
});
it('should activatePullToRefresh and work when setRefresher', function() {
var startCb, refreshingCb, doneCb, refresherEl;
it('should activatePullToRefresh and work when setRefresher', inject(function($compile) {
var refresherEl,
activateCB,
deactivateCB,
startCB,
showCB,
hideCB,
tailCB,
onPullProgressCB;
setup({
el: angular.element('<div><div class="scroll-refresher"></div></div>')[0]
el: angular.element('<div><ion-refresher class="refresher"></ion-refresher></div>')[0]
});
spyOn(ctrl.scrollView, 'activatePullToRefresh').andCallFake(function(height, start, refreshing, done, show, hide) {
startCb = start;
refreshingCb = refreshing;
doneCb = done;
showCb = show;
hideCb = hide;
$compile(ctrl.element)(scope);
scope.$apply();
spyOn(ctrl.scrollView, 'activatePullToRefresh').andCallFake(function(height, start, done, refreshing, show, hide, tail, onPull) {
activateCB = start;
deactivateCB = done;
startCB = refreshing;
showCB = show;
hideCB = hide;
tailCB = tail;
onPullProgressCB = onPull;
});
ctrl._setRefresher(scope, ctrl.element);
var refresher = ctrl.refresher;
var refreshCtrl = angular.element(refresher).controller('ionRefresher');
var dm = refreshCtrl.getRefresherDomMethods()
ctrl._setRefresher(
scope,
ctrl.element,
dm
);
var scrollOnRefreshSpy = jasmine.createSpy('scroll.onRefresh');
@@ -262,31 +284,29 @@ describe('$ionicScroll Controller', function() {
scope.$onPulling = jasmine.createSpy('onPulling');
timeout.flush();
var refresher = ctrl.refresher;
expect(refresher.classList.contains('active')).toBe(false);
expect(refresher.classList.contains('refreshing')).toBe(false);
startCb();
dm.activate();
expect(refresher.classList.contains('active')).toBe(true);
expect(refresher.classList.contains('refreshing')).toBe(false);
expect(scope.$onPulling).toHaveBeenCalled();
refreshingCb();
expect(refresher.classList.contains('refreshing')).toBe(false);
expect(scope.$onRefresh).not.toHaveBeenCalled();
doneCb();
dm.start();
expect(refresher.classList.contains('refreshing')).toBe(true);
expect(scope.$onRefresh).toHaveBeenCalled();
dm.deactivate();
timeout.flush();
expect(refresher.classList.contains('active')).toBe(false);
showCb();
dm.show();
expect(refresher.classList.contains('invisible')).toBe(false);
hideCb();
dm.hide();
expect(refresher.classList.contains('invisible')).toBe(true);
});
}));
});