refact(ionicBar): make tapScrollToTop work on navBar too

Closes #750
This commit is contained in:
Andy Joslin
2014-03-24 07:57:22 -06:00
parent f692aaeec0
commit dd2c0c776b
2 changed files with 85 additions and 77 deletions

View File

@@ -3,39 +3,8 @@
angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize'])
.directive('ionHeaderBar', ['$document', function($document) {
return {
restrict: 'E',
link: function($scope, $element, $attr, scrollCtrl) {
ionic.requestAnimationFrame(function() {
var scrollCtrl = $element.controller('$ionicScroll');
if (!scrollCtrl) {
return;
}
ionic.on('tap', onTap, $element[0]);
$scope.$on('$destroy', function() {
ionic.off('tap', onTap, $element[0]);
});
function onTap(e) {
if (ionic.DomUtil.getParentOrSelfWithClass(e.target, 'button', 4)) {
return;
}
var touch = e.gesture && e.gesture.touches[0] || e.detail.touches[0];
var bounds = $element[0].getBoundingClientRect();
if(ionic.DomUtil.rectContains(
touch.pageX, touch.pageY,
bounds.left, bounds.top - 20,
bounds.left + bounds.width, bounds.top + bounds.height)
) {
scrollCtrl.scrollTop(true);
}
}
});
}
};
}])
.directive('ionNavBar', TapScrollToTopDirective())
.directive('ionHeaderBar', TapScrollToTopDirective())
/**
* @ngdoc directive
@@ -111,6 +80,43 @@ angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize'])
*/
.directive('ionFooterBar', barDirective(false));
function TapScrollToTopDirective() {
return ['$document', function($document) {
return {
restrict: 'E',
link: function($scope, $element, $attr, scrollCtrl) {
ionic.requestAnimationFrame(function() {
var scrollCtrl = $element.controller('$ionicScroll');
if (!scrollCtrl) {
return;
}
ionic.on('tap', onTap, $element[0]);
$scope.$on('$destroy', function() {
ionic.off('tap', onTap, $element[0]);
});
function onTap(e) {
if (ionic.DomUtil.getParentOrSelfWithClass(e.target, 'button', 4)) {
return;
}
var touch = e.gesture && e.gesture.touches[0] || e.detail.touches[0];
var bounds = $element[0].getBoundingClientRect();
if(ionic.DomUtil.rectContains(
touch.pageX, touch.pageY,
bounds.left, bounds.top - 20,
bounds.left + bounds.width, bounds.top + bounds.height)
) {
scrollCtrl.scrollTop(true);
}
}
});
}
};
}];
}
function barDirective(isHeader) {
return ['$parse', function($parse) {
return {

View File

@@ -1,54 +1,56 @@
describe('bar directives', function() {
beforeEach(module('ionic'));
describe('tapScrollToTop', function() {
function setup() {
var el;
inject(function($compile, $rootScope) {
el = angular.element('<ion-header-bar>')
var container = angular.element('<ion-content>').append(el);
ionic.requestAnimationFrame = function(cb) { cb(); };
$compile(container)($rootScope.$new());
container.controller('$ionicScroll').scrollTop = jasmine.createSpy('scrollTop')
$rootScope.$apply();
['<ion-header-bar>', '<ion-nav-bar>'].forEach(function(tpl) {
describe('tapScrollToTop ' + tpl, function() {
function setup() {
var el;
inject(function($compile, $rootScope) {
el = angular.element(tpl);
var container = angular.element('<ion-content>').append(el);
ionic.requestAnimationFrame = function(cb) { cb(); };
$compile(container)($rootScope.$new());
container.controller('$ionicScroll').scrollTop = jasmine.createSpy('scrollTop');
$rootScope.$apply();
});
return el;
}
it('should listen for tap, unlisten on destroy', function() {
var callback;
spyOn(ionic, 'on').andCallFake(function(name, cb) {
callback = cb;
});
spyOn(ionic, 'off');
var el = setup();
expect(ionic.on).toHaveBeenCalledWith('tap', jasmine.any(Function), el[0]);
expect(ionic.off).not.toHaveBeenCalled();
el.scope().$destroy();
expect(ionic.off).toHaveBeenCalledWith('tap', callback, el[0]);
});
return el;
}
it('should listen for tap, unlisten on destroy', function() {
var callback;
spyOn(ionic, 'on').andCallFake(function(name, cb) {
callback = cb;
it('should ignore tap if it\'s in a button', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains');
var child = angular.element('<div class="button">');
el.append(child);
ionic.trigger('tap', { target: child[0] }, true, true);
expect(ionic.DomUtil.rectContains).not.toHaveBeenCalled();
});
spyOn(ionic, 'off');
var el = setup();
expect(ionic.on).toHaveBeenCalledWith('tap', jasmine.any(Function), el[0]);
expect(ionic.off).not.toHaveBeenCalled();
el.scope().$destroy();
expect(ionic.off).toHaveBeenCalledWith('tap', callback, el[0]);
});
it('should ignore tap if it\'s in a button', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains');
var child = angular.element('<div class="button">');
el.append(child);
ionic.trigger('tap', { target: child[0] }, true, true);
expect(ionic.DomUtil.rectContains).not.toHaveBeenCalled();
});
it('should scrollTop if tap is inside headerBar', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains').andCallFake(function() {
return true;
it('should scrollTop if tap is inside headerBar', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains').andCallFake(function() {
return true;
});
ionic.trigger('tap', { target: el[0], touches: [{pageX:0,pageY:0}] });
expect(el.controller('$ionicScroll').scrollTop).toHaveBeenCalledWith(true);
});
ionic.trigger('tap', { target: el[0], touches: [{pageX:0,pageY:0}] });
expect(el.controller('$ionicScroll').scrollTop).toHaveBeenCalledWith(true);
});
it('should not scrollTop if tap isnt inside headerBar', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains').andCallFake(function() {
return false;
it('should not scrollTop if tap isnt inside headerBar', function() {
var el = setup();
spyOn(ionic.DomUtil, 'rectContains').andCallFake(function() {
return false;
});
ionic.trigger('tap', { target: el[0], touches: [{pageX:0,pageY:0}] });
expect(el.controller('$ionicScroll').scrollTop).not.toHaveBeenCalled();
});
ionic.trigger('tap', { target: el[0], touches: [{pageX:0,pageY:0}] });
expect(el.controller('$ionicScroll').scrollTop).not.toHaveBeenCalled();
});
});