scroll: add $ionicScrollDelegate with new pattern

Addresses #877
This commit is contained in:
Andy Joslin
2014-03-24 15:56:23 -06:00
parent b1a7c1990a
commit c1d2571d5e
12 changed files with 437 additions and 152 deletions

View File

@@ -1,8 +1,173 @@
(function() {
'use strict';
angular.module('ionic.ui.scroll')
/**
* @ngdoc service
* @name $ionicScrollDelegate
* @module ionic
* @description
* Delegate for controlling scrollViews (created by
* {@link ionic.directive:ionContent} and
* {@link ionic.directive:ionScroll} directives).
*
* Each method on $ionicScrollDelegate can be called on the service itself to control all scrollViews. Alternatively, one can control one specific scrollView using `withHandle` and `delegate-handle`. See the example below.
*
* @usage
*
* Basic Usage:
*
* ```html
* <body ng-controller="MainCtrl">
* <ion-content>
* <button ng-click="scrollTop()">Scroll to Top!</button>
* </ion-content>
* </body>
* ```
* ```js
* function MainCtrl($scope, $ionicScrollDelegate) {
* $scope.scrollTop = function() {
* $ionicScrollDelegate.scrollTop();
* };
* }
* ```
*
* Example of advanced usage, with two scroll areas using `delegate-handle`
* for fine control.
*
* ```html
* <body ng-controller="MainCtrl">
* <ion-content delegate-handle="mainScroll">
* <button ng-click="scrollMainToTop()">
* Scroll content to top!
* </button>
* <ion-scroll delegate-handle="small" style="height: 100px;">
* <button ng-click="scrollSmallToTop()">
* Scroll small area to top!
* </button>
* </ion-scroll>
* </ion-content>
* </body>
* ```
* ```js
* function MainCtrl($scope, $ionicScrollDelegate) {
* $scope.scrollMainToTop = function() {
* $ionicScrollDelegate.withHandle('mainScroll').scrollTop();
* };
* $scope.scrollSmallToTop = function() {
* $ionicScrollDelegate.withHandle('small').scrollTop();
* };
* }
* ```
*/
/**
* @ngdoc method
* @name $ionicScrollDelegate#withHandle
* @param {string} handle
* @returns `delegateInstance` A delegate instance that controls only the
* scrollView with delegate-handle matching the given handle.
*/
.service('$ionicScrollDelegate', delegateService([
/**
* @ngdoc method
* @name $ionicScrollDelegate#resize
* @description Tell the scrollView to recalculate the size of its container.
*/
'resize',
/**
* @ngdoc method
* @name $ionicScrollDelegate#scrollTop
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
'scrollTop',
/**
* @ngdoc method
* @name $ionicScrollDelegate#scrollBottom
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
'scrollBottom',
/**
* @ngdoc method
* @name $ionicScrollDelegate#scroll
* @param {number} left The x-value to scroll to.
* @param {number} top The y-value to scroll to.
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
'scrollTo',
/**
* @ngdoc method
* @name $ionicScrollDelegate#anchorScroll
* @description Tell the scrollView to scroll to the element with an id
* matching window.location.hash.
*
* If no matching element is found, it will scroll to top.
*
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
'anchorScroll',
/**
* @ngdoc method
* @name $ionicScrollDelegate#rememberScrollPosition
* @description
* Will make it so, when this scrollView is destroyed (user leaves the page),
* the last scroll position the page was on will be saved, indexed by the
* given id.
*
* Note: for pages associated with a view under an ion-nav-view,
* rememberScrollPosition automatically saves their scroll.
*
* Related methods: scrollToRememberedPosition, forgetScrollPosition (below).
*
* In the following example, the scroll position of the ion-scroll element
* will persist, even when the user changes the toggle switch.
*
* ```html
* <ion-toggle ng-model="shouldShowScrollView"></ion-toggle>
* <ion-scroll delegate-handle="myScroll" ng-if="shouldShowScrollView">
* <div ng-controller="ScrollCtrl">
* <ion-list>
* <ion-item ng-repeat="i in items">{{i}}</ion-item>
* </ion-list>
* </div>
* </ion-scroll>
* ```
* ```js
* function ScrollCtrl($scope, $ionicScrollDelegate) {
* var delegate = $ionicScrollDelegate.withHandle('myScroll');
*
* // Put any unique ID here. The point of this is: every time the controller is recreated
* // we want to load the correct remembered scroll values.
* delegate.rememberScrollPosition('my-scroll-id');
* delegate.scrollToRememberedPosition();
* $scope.items = [];
* for (var i=0; i<100; i++) {
* $scope.items.push(i);
* }
* }
* ```
*
* @param {string} id The id to remember the scroll position of this
* scrollView by.
*/
'rememberScrollPosition',
/**
* @ngdoc method
* @name $ionicScrollDelegate#forgetScrollPosition
* @description
* Stop remembering the scroll position for this scrollView.
*/
'forgetScrollPosition',
/**
* @ngdoc method
* @name $ionicScrollDelegate#scrollToRememberedPosition
* @description
* If this scrollView has an id associated with its scroll position,
* (through calling rememberScrollPosition), and that position is remembered,
* load the position and scroll to it.
* @param {boolean=} shouldAnimate Whether to animate the scroll.
*/
'scrollToRememberedPosition'
]))
/**
* @private
*/
@@ -10,14 +175,6 @@ angular.module('ionic.ui.scroll')
return {};
})
/**
* @ngdoc controller
* @name ionicScroll
* @module ionic
* @description
* Controller for the {@link ionic.directive:ionContent} and
* {@link ionic.directive:ionScroll} directives.
*/
.controller('$ionicScroll', [
'$scope',
'scrollViewOptions',
@@ -25,13 +182,18 @@ angular.module('ionic.ui.scroll')
'$window',
'$$scrollValueCache',
'$location',
'$parse',
'$rootScope',
'$document',
function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $location, $parse, $rootScope, $document) {
'$ionicScrollDelegate',
'$parse', //DEPRECATED
function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $location, $rootScope, $document, $ionicScrollDelegate, $parse) {
var self = this;
this._scrollViewOptions = scrollViewOptions; //for testing
$parse('$ionicScrollController').assign($scope.$parent || $scope, this);
var element = this.element = scrollViewOptions.el;
var $element = this.$element = angular.element(element);
var scrollView = this.scrollView = new ionic.views.Scroll(scrollViewOptions);
@@ -42,8 +204,9 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
($element.parent().length ? $element.parent() : $element)
.data('$$ionicScrollController', this);
$parse(scrollViewOptions.controllerBind || '$ionicScrollController')
.assign($scope.$parent || $scope, this);
var deregisterInstance = $ionicScrollDelegate._registerInstance(
this, scrollViewOptions.delegateHandle
);
if (!angular.isDefined(scrollViewOptions.bouncing)) {
ionic.Platform.ready(function() {
@@ -58,6 +221,7 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
var backListenDone = angular.noop;
$scope.$on('$destroy', function() {
deregisterInstance();
ionic.off('resize', resize, $window);
$window.removeEventListener('resize', resize);
backListenDone();
@@ -101,31 +265,16 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
this._rememberScrollId = null;
/**
* @ngdoc method
* @name ionicScroll#resize
* @description Tell the scrollView to recalculate the size of its container.
*/
this.resize = function() {
return $timeout(resize);
};
/**
* @ngdoc method
* @name ionicScroll#scrollTop
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
this.scrollTop = function(shouldAnimate) {
this.resize().then(function() {
scrollView.scrollTo(0, 0, !!shouldAnimate);
});
};
/**
* @ngdoc method
* @name ionicScroll#scrollBottom
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
this.scrollBottom = function(shouldAnimate) {
this.resize().then(function() {
var max = scrollView.getScrollMax();
@@ -133,29 +282,12 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
});
};
/**
* @ngdoc method
* @name ionicScroll#scroll
* @param {number} left The x-value to scroll to.
* @param {number} top The y-value to scroll to.
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
this.scrollTo = function(left, top, shouldAnimate) {
this.resize().then(function() {
scrollView.scrollTo(left, top, !!shouldAnimate);
});
};
/**
* @ngdoc method
* @name ionicScroll#anchorScroll
* @description Tell the scrollView to scroll to the element with an id
* matching window.location.hash.
*
* If no matching element is found, it will scroll to top.
*
* @param {boolean=} shouldAnimate Whether the scroll should animate.
*/
this.anchorScroll = function(shouldAnimate) {
this.resize().then(function() {
var hash = $location.hash();
@@ -169,75 +301,16 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
});
};
/**
* @ngdoc method
* @name ionicScroll#rememberScrollPosition
* @description
* Will make it so, when this scrollView is destroyed (user leaves the page),
* the last scroll position the page was on will be saved, indexed by the
* given id.
*
* Note: for pages associated with a view under an ion-nav-view,
* rememberScrollPosition automatically saves their scroll.
*
* Related methods: scrollToRememberedPosition, forgetScrollPosition (below).
*
* In the following example, the scroll position of the ion-scroll element
* will persist, even when the user changes the toggle switch.
*
* ```html
* <ion-toggle ng-model="shouldShowScrollView"></ion-toggle>
* <ion-scroll ng-if="shouldShowScrollView">
* <div ng-controller="ScrollCtrl">
* <ion-list>
* <ion-item ng-repeat="i in items">{{i}}</ion-item>
* </ion-list>
* </div>
* </ion-scroll>
* ```
* ```js
* function ScrollCtrl($scope) {
* // Put any unique ID here. The point of this is: every time the controller is recreated
* // we want to load the correct remembered scroll values.
* $scope.$ionicScrollController.rememberScrollPosition('my-scroll-id');
*
* $scope.$ionicScrollController.scrollToRememberedPosition();
* $scope.items = [];
* for (var i=0; i<100; i++) {
* $scope.items.push(i);
* }
* }
* ```
*
* @param {string} id The id to remember the scroll position of this
* scrollView by.
*/
this.rememberScrollPosition = function(id) {
if (!id) {
throw new Error("Must supply an id to remember the scroll by!");
}
this._rememberScrollId = id;
};
/**
* @ngdoc method
* @name ionicScroll#forgetScrollPosition
* @description
* Stop remembering the scroll position for this scrollView.
*/
this.forgetScrollPosition = function() {
delete $$scrollValueCache[this._rememberScrollId];
this._rememberScrollId = null;
};
/**
* @ngdoc method
* @name ionicScroll#scrollToRememberedPosition
* @description
* If this scrollView has an id associated with its scroll position,
* (through calling rememberScrollPosition), and that position is remembered,
* load the position and scroll to it.
* @param {boolean=} shouldAnimate Whether to animate the scroll.
*/
this.scrollToRememberedPosition = function(shouldAnimate) {
var values = $$scrollValueCache[this._rememberScrollId];
if (values) {
@@ -268,4 +341,3 @@ function($scope, scrollViewOptions, $timeout, $window, $$scrollValueCache, $loca
};
}]);
})();