feat(content): remember scroll of previous page

`content` directive stores scroll in view page history.

The history is passed down through $viewContentLoaded event, which is
broadcasted by navView directive when it loads a page.
This commit is contained in:
Andy Joslin
2014-02-04 08:46:40 -05:00
parent 479175bf5d
commit 2d1b71c8e2
10 changed files with 311 additions and 156 deletions

View File

File diff suppressed because one or more lines are too long

View File

@@ -616,7 +616,7 @@ angular.module('ionic.service.templateLoad', [])
angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
.run( ['$rootScope', '$state', '$location', '$document', '$animate', '$ionicPlatform',
.run( ['$rootScope', '$state', '$location', '$document', '$animate', '$ionicPlatform',
function( $rootScope, $state, $location, $document, $animate, $ionicPlatform) {
// init the variables that keep track of the view history
@@ -644,7 +644,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
if(!data.url && data.uiSref) {
data.url = $state.href(data.uiSref);
}
if(data.url) {
// don't let it start with a #, messes with $location.url()
if(data.url.indexOf('#') === 0) {
@@ -681,7 +681,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
}])
.factory('$ionicViewService', ['$rootScope', '$state', '$location', '$window', '$injector',
.factory('$ionicViewService', ['$rootScope', '$state', '$location', '$window', '$injector',
function( $rootScope, $state, $location, $window, $injector) {
var $animate = $injector.has('$animate') ? $injector.get('$animate') : false;
@@ -721,7 +721,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
};
function createViewId(stateId) {
return ('_' + stateId + '_' + Math.round(Math.random() * 99999999)).replace(/\./g, '_');
return ionic.Utils.nextUid();
}
return {
@@ -750,7 +750,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
return rsp;
}
if(currentView &&
if(currentView &&
currentView.stateId === currentStateId &&
currentView.historyId === hist.historyId) {
// do nothing if its the same stateId in the same history
@@ -782,7 +782,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
rsp.historyId = forwardView.historyId;
}
} else if(currentView && currentView.historyId !== hist.historyId &&
} else if(currentView && currentView.historyId !== hist.historyId &&
hist.cursor > -1 && hist.stack.length > 0 && hist.cursor < hist.stack.length &&
hist.stack[hist.cursor].stateId === currentStateId) {
// they just changed to a different history and the history already has views in it
@@ -825,7 +825,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
}
// add the new view to the stack
viewHistory.histories[rsp.viewId] = this.createView({
viewHistory.histories[rsp.viewId] = this.createView({
viewId: rsp.viewId,
index: hist.stack.length,
historyId: hist.historyId,
@@ -834,7 +834,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
stateId: currentStateId,
stateName: this.getCurrentStateName(),
stateParams: this.getCurrentStateParams(),
url: $location.url()
url: $location.url(),
});
// add the new view to this history's stack
@@ -861,7 +861,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
},
registerHistory: function(scope) {
scope.$historyId = 'h' + Math.round(Math.random() * 99999999999);
scope.$historyId = ionic.Utils.nextUid();
},
createView: function(data) {
@@ -890,9 +890,9 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
},
isCurrentStateNavView: function(navView) {
return ($state &&
$state.current &&
$state.current.views &&
return ($state &&
$state.current &&
$state.current.views &&
$state.current.views[navView] ? true : false);
},
@@ -923,7 +923,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
return id;
}
// if something goes wrong make sure its got a unique stateId
return 'r' + Math.round(Math.random() * 9999999);
return ionic.Utils.nextUid();
},
_getView: function(viewId) {
@@ -944,8 +944,8 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
if( !$rootScope.$viewHistory.histories[ histObj.historyId ] ) {
// this history object exists in parent scope, but doesn't
// exist in the history data yet
$rootScope.$viewHistory.histories[ histObj.historyId ] = {
historyId: histObj.historyId,
$rootScope.$viewHistory.histories[ histObj.historyId ] = {
historyId: histObj.historyId,
parentHistoryId: this._getParentHistoryObj(histObj.scope.$parent).historyId,
stack: [],
cursor: -1
@@ -1000,7 +1000,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
return function(shouldAnimate) {
return {
enter: function(element) {
if(doAnimation && shouldAnimate) {
@@ -1012,7 +1012,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
$animate.enter(element, navViewElement, null, function() {
document.body.classList.remove('disable-pointer-events');
});
});
return;
}
@@ -1027,8 +1027,8 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
// leave with an animation
setAnimationClass();
$animate.leave(element, function() {
element.remove();
$animate.leave(element, function() {
element.remove();
});
return;
}
@@ -1041,6 +1041,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
// register a new view
registerData = service.register(navViewScope, element);
doAnimation = (animationClass !== null && registerData.navDirection !== null);
return registerData;
}
};
@@ -1305,6 +1306,7 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
replace: true,
template: '<div class="scroll-content"><div class="scroll" ng-transclude></div></div>',
transclude: true,
require: '^?navView',
scope: {
onRefresh: '&',
onRefreshOpening: '&',
@@ -1332,7 +1334,7 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
if(attr.hasTabs == "true") { element.addClass('has-tabs'); }
if(attr.padding == "true") { element.find('div').addClass('padding'); }
return function link($scope, $element, $attr) {
return function link($scope, $element, $attr, navViewCtrl) {
var clone, sc, sv,
c = angular.element($element.children()[0]);
@@ -1340,78 +1342,100 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
// No scrolling
return;
}
// If they want plain overflow scrolling, add that as a class
if(attr.overflowScroll === "true") {
$element.addClass('overflow-scroll');
return;
if (navViewCtrl) {
// If we do have a parent navView, wait for them to give us $viewContentLoaded event
// before we fully initialize
$scope.$on('$viewContentLoaded', function(e, viewHistoryData) {
initScroll(viewHistoryData);
});
} else {
// If we are standalone view, just initialize immediately.
initScroll();
}
// Otherwise, use our scroll system
function initScroll(viewHistoryData) {
viewHistoryData || (viewHistoryData = {});
var savedScroll = viewHistoryData.scrollValues || {};
var refresher = $element[0].querySelector('.scroll-refresher');
var refresherHeight = refresher && refresher.clientHeight || 0;
// If they want plain overflow scrolling, add that as a class
if(attr.overflowScroll === "true") {
$element.addClass('overflow-scroll');
return;
}
if(attr.refreshComplete) {
$scope.refreshComplete = function() {
if($scope.scrollView) {
refresher && refresher.classList.remove('active');
$scope.scrollView.finishPullToRefresh();
$scope.$parent.$broadcast('scroll.onRefreshComplete');
// Otherwise, use our scroll system
var hasBouncing = $scope.$eval($scope.hasBouncing);
var enableBouncing = (!ionic.Platform.isAndroid() && hasBouncing !== false) || hasBouncing === true;
// No bouncing by default for Android users, lest they take up pitchforks
// to our bouncing goodness
sv = new ionic.views.Scroll({
el: $element[0],
bouncing: enableBouncing,
startX: $scope.$eval($scope.startX) || savedScroll.left || 0,
startY: $scope.$eval($scope.startY) || savedScroll.top || 0,
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
scrollingX: $scope.$eval($scope.hasScrollX) === true,
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
scrollingComplete: function() {
$scope.onScrollComplete({
scrollTop: this.__scrollTop,
scrollLeft: this.__scrollLeft
});
}
};
}
});
// Otherwise, supercharge this baby!
var hasBouncing = $scope.$eval($scope.hasBouncing);
var enableBouncing = (!ionic.Platform.isAndroid() && hasBouncing !== false) || hasBouncing === true;
// No bouncing by default for Android users, lest they take up pitchforks
// to our bouncing goodness
sv = new ionic.views.Scroll({
el: $element[0],
bouncing: enableBouncing,
startX: $scope.$eval($scope.startX) || 0,
startY: $scope.$eval($scope.startY) || 0,
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
scrollingX: $scope.$eval($scope.hasScrollX) === true,
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
scrollingComplete: function() {
$scope.onScrollComplete({
scrollTop: this.__scrollTop,
scrollLeft: this.__scrollLeft
//Save scroll onto viewHistoryData when scope is destroyed
$scope.$on('$destroy', function() {
viewHistoryData.scrollValues = sv.getValues();
});
var refresher = $element[0].querySelector('.scroll-refresher');
var refresherHeight = refresher && refresher.clientHeight || 0;
if(attr.refreshComplete) {
$scope.refreshComplete = function() {
if($scope.scrollView) {
refresher && refresher.classList.remove('active');
$scope.scrollView.finishPullToRefresh();
$scope.$parent.$broadcast('scroll.onRefreshComplete');
}
};
}
// Activate pull-to-refresh
if(refresher) {
sv.activatePullToRefresh(50, function() {
refresher.classList.add('active');
}, function() {
refresher.classList.remove('refreshing');
refresher.classList.remove('active');
}, function() {
refresher.classList.add('refreshing');
$scope.onRefresh();
$scope.$parent.$broadcast('scroll.onRefresh');
});
}
});
// Activate pull-to-refresh
if(refresher) {
sv.activatePullToRefresh(50, function() {
refresher.classList.add('active');
}, function() {
refresher.classList.remove('refreshing');
refresher.classList.remove('active');
}, function() {
refresher.classList.add('refreshing');
$scope.onRefresh();
$scope.$parent.$broadcast('scroll.onRefresh');
// Register for scroll delegate event handling
$ionicScrollDelegate.register($scope, $element);
// Let child scopes access this
$scope.$parent.scrollView = sv;
$timeout(function() {
// Give child containers a chance to build and size themselves
sv.run();
});
return sv;
}
// Register for scroll delegate event handling
$ionicScrollDelegate.register($scope, $element);
// Let child scopes access this
$scope.$parent.scrollView = sv;
$timeout(function() {
// Give child containers a chance to build and size themselves
sv.run();
});
// Check if this supports infinite scrolling and listen for scroll events
// to trigger the infinite scrolling
// TODO(ajoslin): move functionality out of this function and make testable
var infiniteScroll = $element.find('infinite-scroll');
var infiniteStarted = false;
if(infiniteScroll) {
@@ -2895,6 +2919,7 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
terminal: true,
priority: 2000,
transclude: true,
controller: function() {}, //noop controller so this can be required
compile: function (element, attr, transclude) {
return function(scope, element, attr) {
var viewScope, viewLocals,
@@ -2948,7 +2973,7 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
}
var newElement = angular.element('<div></div>').html(locals.$template).contents();
renderer().register(newElement);
var viewRegisterData = renderer().register(newElement);
// Remove existing content
renderer(doAnimate).leave();
@@ -2967,7 +2992,10 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
element.children().data('$ngControllerController', controller);
}
link(viewScope);
viewScope.$emit('$viewContentLoaded');
var viewHistoryData = $ionicViewService._getView(viewRegisterData.viewId) || {};
viewScope.$broadcast('$viewContentLoaded', viewHistoryData);
if (onloadExp) viewScope.$eval(onloadExp);
newElement = null;
@@ -2978,7 +3006,6 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
return directive;
}]);
})();
;
(function() {

View File

File diff suppressed because one or more lines are too long

37
dist/js/ionic.js vendored
View File

@@ -2163,6 +2163,9 @@ window.ionic = {
})(this, document, ionic);
;
(function(ionic) {
/* for nextUid() function below */
var uid = ['0','0','0'];
/**
* Various utilities used throughout Ionic
@@ -2303,6 +2306,36 @@ window.ionic = {
}
}
return obj;
},
/**
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
* the number string gets longer over time, and it can also overflow, where as the nextId
* will grow much slower, it is a string, and it will never overflow.
*
* @returns an unique alpha-numeric string
*/
nextUid: function() {
var index = uid.length;
var digit;
while(index) {
index--;
digit = uid[index].charCodeAt(0);
if (digit == 57 /*'9'*/) {
uid[index] = 'A';
return uid.join('');
}
if (digit == 90 /*'Z'*/) {
uid[index] = '0';
} else {
uid[index] = String.fromCharCode(digit + 1);
return uid.join('');
}
}
uid.unshift('0');
return uid.join('');
}
};
@@ -4334,7 +4367,7 @@ ionic.views.Scroll = ionic.views.View.inherit({
// Slow down until slow enough, then flip back to snap position
if (scrollOutsideX !== 0) {
if (scrollOutsideX * self.__decelerationVelocityX <= 0) {
if (scrollOutsideX * self.__decelerationVelocityX <= self.__minDecelerationScrollLeft) {
self.__decelerationVelocityX += scrollOutsideX * penetrationDeceleration;
} else {
self.__decelerationVelocityX = scrollOutsideX * penetrationAcceleration;
@@ -4342,7 +4375,7 @@ ionic.views.Scroll = ionic.views.View.inherit({
}
if (scrollOutsideY !== 0) {
if (scrollOutsideY * self.__decelerationVelocityY <= 0) {
if (scrollOutsideY * self.__decelerationVelocityY <= self.__minDecelerationScrollTop) {
self.__decelerationVelocityY += scrollOutsideY * penetrationDeceleration;
} else {
self.__decelerationVelocityY = scrollOutsideY * penetrationAcceleration;

View File

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,7 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
replace: true,
template: '<div class="scroll-content"><div class="scroll" ng-transclude></div></div>',
transclude: true,
require: '^?navView',
scope: {
onRefresh: '&',
onRefreshOpening: '&',
@@ -51,7 +52,7 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
if(attr.hasTabs == "true") { element.addClass('has-tabs'); }
if(attr.padding == "true") { element.find('div').addClass('padding'); }
return function link($scope, $element, $attr) {
return function link($scope, $element, $attr, navViewCtrl) {
var clone, sc, sv,
c = angular.element($element.children()[0]);
@@ -59,78 +60,100 @@ angular.module('ionic.ui.content', ['ionic.ui.service'])
// No scrolling
return;
}
// If they want plain overflow scrolling, add that as a class
if(attr.overflowScroll === "true") {
$element.addClass('overflow-scroll');
return;
if (navViewCtrl) {
// If we do have a parent navView, wait for them to give us $viewContentLoaded event
// before we fully initialize
$scope.$on('$viewContentLoaded', function(e, viewHistoryData) {
initScroll(viewHistoryData);
});
} else {
// If we are standalone view, just initialize immediately.
initScroll();
}
// Otherwise, use our scroll system
function initScroll(viewHistoryData) {
viewHistoryData || (viewHistoryData = {});
var savedScroll = viewHistoryData.scrollValues || {};
var refresher = $element[0].querySelector('.scroll-refresher');
var refresherHeight = refresher && refresher.clientHeight || 0;
// If they want plain overflow scrolling, add that as a class
if(attr.overflowScroll === "true") {
$element.addClass('overflow-scroll');
return;
}
if(attr.refreshComplete) {
$scope.refreshComplete = function() {
if($scope.scrollView) {
refresher && refresher.classList.remove('active');
$scope.scrollView.finishPullToRefresh();
$scope.$parent.$broadcast('scroll.onRefreshComplete');
// Otherwise, use our scroll system
var hasBouncing = $scope.$eval($scope.hasBouncing);
var enableBouncing = (!ionic.Platform.isAndroid() && hasBouncing !== false) || hasBouncing === true;
// No bouncing by default for Android users, lest they take up pitchforks
// to our bouncing goodness
sv = new ionic.views.Scroll({
el: $element[0],
bouncing: enableBouncing,
startX: $scope.$eval($scope.startX) || savedScroll.left || 0,
startY: $scope.$eval($scope.startY) || savedScroll.top || 0,
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
scrollingX: $scope.$eval($scope.hasScrollX) === true,
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
scrollingComplete: function() {
$scope.onScrollComplete({
scrollTop: this.__scrollTop,
scrollLeft: this.__scrollLeft
});
}
};
}
});
// Otherwise, supercharge this baby!
var hasBouncing = $scope.$eval($scope.hasBouncing);
var enableBouncing = (!ionic.Platform.isAndroid() && hasBouncing !== false) || hasBouncing === true;
// No bouncing by default for Android users, lest they take up pitchforks
// to our bouncing goodness
sv = new ionic.views.Scroll({
el: $element[0],
bouncing: enableBouncing,
startX: $scope.$eval($scope.startX) || 0,
startY: $scope.$eval($scope.startY) || 0,
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
scrollingX: $scope.$eval($scope.hasScrollX) === true,
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
scrollingComplete: function() {
$scope.onScrollComplete({
scrollTop: this.__scrollTop,
scrollLeft: this.__scrollLeft
//Save scroll onto viewHistoryData when scope is destroyed
$scope.$on('$destroy', function() {
viewHistoryData.scrollValues = sv.getValues();
});
var refresher = $element[0].querySelector('.scroll-refresher');
var refresherHeight = refresher && refresher.clientHeight || 0;
if(attr.refreshComplete) {
$scope.refreshComplete = function() {
if($scope.scrollView) {
refresher && refresher.classList.remove('active');
$scope.scrollView.finishPullToRefresh();
$scope.$parent.$broadcast('scroll.onRefreshComplete');
}
};
}
// Activate pull-to-refresh
if(refresher) {
sv.activatePullToRefresh(50, function() {
refresher.classList.add('active');
}, function() {
refresher.classList.remove('refreshing');
refresher.classList.remove('active');
}, function() {
refresher.classList.add('refreshing');
$scope.onRefresh();
$scope.$parent.$broadcast('scroll.onRefresh');
});
}
});
// Activate pull-to-refresh
if(refresher) {
sv.activatePullToRefresh(50, function() {
refresher.classList.add('active');
}, function() {
refresher.classList.remove('refreshing');
refresher.classList.remove('active');
}, function() {
refresher.classList.add('refreshing');
$scope.onRefresh();
$scope.$parent.$broadcast('scroll.onRefresh');
// Register for scroll delegate event handling
$ionicScrollDelegate.register($scope, $element);
// Let child scopes access this
$scope.$parent.scrollView = sv;
$timeout(function() {
// Give child containers a chance to build and size themselves
sv.run();
});
return sv;
}
// Register for scroll delegate event handling
$ionicScrollDelegate.register($scope, $element);
// Let child scopes access this
$scope.$parent.scrollView = sv;
$timeout(function() {
// Give child containers a chance to build and size themselves
sv.run();
});
// Check if this supports infinite scrolling and listen for scroll events
// to trigger the infinite scrolling
// TODO(ajoslin): move functionality out of this function and make testable
var infiniteScroll = $element.find('infinite-scroll');
var infiniteStarted = false;
if(infiniteScroll) {

View File

@@ -270,6 +270,7 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
terminal: true,
priority: 2000,
transclude: true,
controller: function() {}, //noop controller so this can be required
compile: function (element, attr, transclude) {
return function(scope, element, attr) {
var viewScope, viewLocals,
@@ -323,7 +324,7 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
}
var newElement = angular.element('<div></div>').html(locals.$template).contents();
renderer().register(newElement);
var viewRegisterData = renderer().register(newElement);
// Remove existing content
renderer(doAnimate).leave();
@@ -342,7 +343,10 @@ angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gestu
element.children().data('$ngControllerController', controller);
}
link(viewScope);
viewScope.$emit('$viewContentLoaded');
var viewHistoryData = $ionicViewService._getView(viewRegisterData.viewId) || {};
viewScope.$broadcast('$viewContentLoaded', viewHistoryData);
if (onloadExp) viewScope.$eval(onloadExp);
newElement = null;

View File

@@ -426,6 +426,7 @@ angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
// register a new view
registerData = service.register(navViewScope, element);
doAnimation = (animationClass !== null && registerData.navDirection !== null);
return registerData;
}
};

View File

@@ -32,7 +32,7 @@ describe('Ionic Content directive', function() {
it('Enables bouncing by default', function() {
ionic.Platform.setPlatform('iPhone');
element = compile('<content has-header="true"></content>')(scope);
timeout.flush();
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
expect(scrollView.options.bouncing).toBe(true);
@@ -41,7 +41,7 @@ describe('Ionic Content directive', function() {
it('Disables bouncing when has-bouncing = false', function() {
ionic.Platform.setPlatform('iPhone');
element = compile('<content has-header="true" has-bouncing="false"></content>')(scope);
timeout.flush();
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
expect(scrollView.options.bouncing).toBe(false);
@@ -50,7 +50,7 @@ describe('Ionic Content directive', function() {
it('Disables bouncing by default on Android', function() {
ionic.Platform.setPlatform('Android');
element = compile('<content has-header="true"></content>')(scope);
timeout.flush();
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
expect(scrollView.options.bouncing).toBe(false);
@@ -59,7 +59,7 @@ describe('Ionic Content directive', function() {
it('Disables bouncing by default on Android unless has-bouncing = true', function() {
ionic.Platform.setPlatform('Android');
element = compile('<content has-header="true" has-bouncing="true"></content>')(scope);
timeout.flush();
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
expect(scrollView.options.bouncing).toBe(true);
@@ -68,11 +68,57 @@ describe('Ionic Content directive', function() {
it('Should set start x and y', function() {
element = compile('<content start-x="100" start-y="300" has-header="true"></content>')(scope);
timeout.flush();
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
var vals = scrollView.getValues();
expect(vals.left).toBe(100);
expect(vals.top).toBe(300);
});
describe('save scroll', function() {
function compileWithParent() {
var parent = angular.element('<div>');
//Make a phony element that tells the world it's a navView when in reality it's just a div
parent.data('$navViewController', true);
parent.append('<content></content>');
compile(parent)(scope);
scope.$apply();
}
it('should not initialize scroll until $viewContentLoaded if there is a parent view', function() {
compileWithParent();
expect(scope.scrollView).toBeUndefined();
scope.$broadcast('$viewContentLoaded', {});
expect(scope.scrollView instanceof ionic.views.Scroll).toBe(true);
});
it('should set start x and y with historyData.scroll passed in through $viewContentLoaded', function() {
compileWithParent();
scope.$broadcast('$viewContentLoaded', {
scrollValues: { top: 40, left: -20 }
});
timeout.flush();
var scrollView = scope.scrollView;
var vals = scrollView.getValues();
expect(vals.top).toBe(40);
expect(vals.left).toBe(-20);
});
it('should save scroll on the historyData passed in on $destroy', function() {
compileWithParent();
var historyData = {};
scope.$broadcast('$viewContentLoaded', historyData);
timeout.flush();
scope.scrollView.scrollTo(null, 9, false);
expect(historyData.scrollValues).toBeUndefined(); //sanity test
scope.$destroy();
expect(historyData.scrollValues).toEqual({
left: 0,
top: 9,
zoom: 1
});
});
});
});

View File

@@ -0,0 +1,21 @@
describe('Ionic nav-view', function() {
beforeEach(module('ionic.ui.viewState'));
var compile, scope;
beforeEach(inject(function($compile, $rootScope) {
compile = $compile;
scope = $rootScope.$new();
}));
it('should publish a controller', function() {
var view = angular.element('<nav-view></nav-view>');
compile(view)(scope);
scope.$apply();
expect(view.controller('navView')).toBeTruthy();
});
/*
* TODO adapt the tests from uiRouter
*/
});