Files
ionic-framework/js/angular/controller/scrollController.js
Andrew 9b601b5523 fix(scrollController): allow tab $historyId to remember scroll
Fixes a bug with tabs, where tabs would only remember their scroll
position when directly related to a view state.

Closes #1654
2014-06-24 09:57:53 +09:00

199 lines
5.6 KiB
JavaScript

/**
* @private
*/
IonicModule
.factory('$$scrollValueCache', function() {
return {};
})
.controller('$ionicScroll', [
'$scope',
'scrollViewOptions',
'$timeout',
'$window',
'$$scrollValueCache',
'$location',
'$rootScope',
'$document',
'$ionicScrollDelegate',
function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $location, $rootScope, $document, $ionicScrollDelegate) {
var self = this;
this._scrollViewOptions = scrollViewOptions; //for testing
var element = this.element = scrollViewOptions.el;
var $element = this.$element = jqLite(element);
var scrollView = this.scrollView = new ionic.views.Scroll(scrollViewOptions);
//Attach self to element as a controller so other directives can require this controller
//through `require: '$ionicScroll'
//Also attach to parent so that sibling elements can require this
($element.parent().length ? $element.parent() : $element)
.data('$$ionicScrollController', this);
var deregisterInstance = $ionicScrollDelegate._registerInstance(
this, scrollViewOptions.delegateHandle
);
if (!angular.isDefined(scrollViewOptions.bouncing)) {
ionic.Platform.ready(function() {
scrollView.options.bouncing = true;
if(ionic.Platform.isAndroid()) {
// No bouncing by default on Android
scrollView.options.bouncing = false;
// Faster scroll decel
scrollView.options.deceleration = 0.95;
} else {
}
});
}
var resize = angular.bind(scrollView, scrollView.resize);
ionic.on('resize', resize, $window);
// set by rootScope listener if needed
var backListenDone = angular.noop;
$scope.$on('$destroy', function() {
deregisterInstance();
scrollView.__removeEventHandlers();
ionic.off('resize', resize, $window);
$window.removeEventListener('resize', resize);
backListenDone();
if (self._rememberScrollId) {
$$scrollValueCache[self._rememberScrollId] = scrollView.getValues();
console.log($$scrollValueCache);
}
});
$element.on('scroll', function(e) {
var detail = (e.originalEvent || e).detail || {};
$scope.$onScroll && $scope.$onScroll({
event: e,
scrollTop: detail.scrollTop || 0,
scrollLeft: detail.scrollLeft || 0
});
});
$scope.$on('$viewContentLoaded', function(e, historyData) {
//only the top-most scroll area under a view should remember that view's
//scroll position
if (e.defaultPrevented) { return; }
e.preventDefault();
var viewId = historyData && historyData.viewId || $scope.$historyId;
if (viewId) {
$timeout(function() {
self.rememberScrollPosition(viewId);
self.scrollToRememberedPosition();
console.log("scrollToRememberedPosition: ",viewId, $$scrollValueCache);
backListenDone = $rootScope.$on('$viewHistory.viewBack', function(e, fromViewId, toViewId) {
//When going back from this view, forget its saved scroll position
if (viewId === fromViewId) {
self.forgetScrollPosition();
}
});
}, 0, false);
}
});
$timeout(function() {
scrollView.run();
});
this._rememberScrollId = null;
this.getScrollView = function() {
return this.scrollView;
};
this.getScrollPosition = function() {
return this.scrollView.getValues();
};
this.resize = function() {
return $timeout(resize);
};
this.scrollTop = function(shouldAnimate) {
this.resize().then(function() {
scrollView.scrollTo(0, 0, !!shouldAnimate);
});
};
this.scrollBottom = function(shouldAnimate) {
this.resize().then(function() {
var max = scrollView.getScrollMax();
scrollView.scrollTo(max.left, max.top, !!shouldAnimate);
});
};
this.scrollTo = function(left, top, shouldAnimate) {
this.resize().then(function() {
scrollView.scrollTo(left, top, !!shouldAnimate);
});
};
this.scrollBy = function(left, top, shouldAnimate) {
this.resize().then(function() {
scrollView.scrollBy(left, top, !!shouldAnimate);
});
};
this.anchorScroll = function(shouldAnimate) {
this.resize().then(function() {
var hash = $location.hash();
var elm = hash && $document[0].getElementById(hash);
if (hash && elm) {
var scroll = ionic.DomUtil.getPositionInParent(elm, self.$element);
scrollView.scrollTo(scroll.left, scroll.top, !!shouldAnimate);
} else {
scrollView.scrollTo(0,0, !!shouldAnimate);
}
});
};
this.rememberScrollPosition = function(id) {
if (!id) {
throw new Error("Must supply an id to remember the scroll by!");
}
this._rememberScrollId = id;
};
this.forgetScrollPosition = function() {
delete $$scrollValueCache[this._rememberScrollId];
this._rememberScrollId = null;
};
this.scrollToRememberedPosition = function(shouldAnimate) {
var values = $$scrollValueCache[this._rememberScrollId];
if (values) {
this.resize().then(function() {
scrollView.scrollTo(+values.left, +values.top, shouldAnimate);
});
}
};
/**
* @private
*/
this._setRefresher = function(refresherScope, refresherElement) {
var refresher = this.refresher = refresherElement;
var refresherHeight = self.refresher.clientHeight || 0;
scrollView.activatePullToRefresh(refresherHeight, function() {
refresher.classList.add('active');
refresherScope.$onPulling();
}, function() {
refresher.classList.remove('refreshing');
refresher.classList.remove('active');
}, function() {
refresher.classList.add('refreshing');
refresherScope.$onRefresh();
});
};
}]);