github.com/GregorioDiStefano/go-file-storage@v0.0.0-20161001105139-5707ab351525/static/js/angular-smooth-scroll.js (about)

     1  /*!
     2   *	 Angular Smooth Scroll (ngSmoothScroll)
     3   *	 Animates scrolling to elements, by David Oliveros.
     4   *
     5   *   Callback hooks contributed by Ben Armston https://github.com/benarmston
     6   *	 Easing support contributed by Willem Liu. https://github.com/willemliu
     7   *	 Easing functions forked from Gaƫtan Renaudeau. https://gist.github.com/gre/1650294
     8   *	 Infinite loop bugs in iOS and Chrome (when zoomed) by Alex Guzman. https://github.com/alexguzman
     9   *	 Support for scrolling in custom containers by Joseph Matthias Goh. https://github.com/zephinzer
    10   *	 Influenced by Chris Ferdinandi
    11   *	 https://github.com/cferdinandi
    12   *
    13   *	 Version: 2.0.0
    14   * 	 License: MIT
    15   */
    16  
    17  (function () {
    18  	'use strict';
    19  
    20  	var module = angular.module('smoothScroll', []);
    21  
    22  
    23  	/**
    24  	 * Smooth scrolls the window/div to the provided element.
    25  	 *
    26  	 * 20150713 EDIT - zephinzer
    27  	 * 	Added new option - containerId to account for scrolling within a DIV
    28  	 */
    29  	var smoothScroll = function (element, options) {
    30  		options = options || {};
    31  
    32  		// Options
    33  		var duration = options.duration || 800,
    34  			offset = options.offset || 0,
    35  			easing = options.easing || 'easeInOutQuart',
    36  			callbackBefore = options.callbackBefore || function() {},
    37  			callbackAfter = options.callbackAfter || function() {},
    38  			container = document.getElementById(options.containerId) || null,
    39  			containerPresent = (container != undefined && container != null);
    40  
    41  		/**
    42  		 * Retrieve current location
    43  		 */
    44  		var getScrollLocation = function() {
    45  			if(containerPresent) {
    46  				return container.scrollTop;
    47  			} else {
    48  				if(window.pageYOffset) {
    49  					return window.pageYOffset;
    50  				} else {
    51  					return document.documentElement.scrollTop;
    52  				}
    53  			}
    54  		};
    55  
    56  		/**
    57  		 * Calculate easing pattern.
    58  		 *
    59  		 * 20150713 edit - zephinzer
    60  		 * - changed if-else to switch
    61  		 * @see http://archive.oreilly.com/pub/a/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
    62  		 */
    63  		var getEasingPattern = function(type, time) {
    64  			switch(type) {
    65  				case 'easeInQuad': 		return time * time; // accelerating from zero velocity
    66  				case 'easeOutQuad': 	return time * (2 - time); // decelerating to zero velocity
    67  				case 'easeInOutQuad': 	return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
    68  				case 'easeInCubic': 	return time * time * time; // accelerating from zero velocity
    69  				case 'easeOutCubic': 	return (--time) * time * time + 1; // decelerating to zero velocity
    70  				case 'easeInOutCubic': 	return time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
    71  				case 'easeInQuart': 	return time * time * time * time; // accelerating from zero velocity
    72  				case 'easeOutQuart': 	return 1 - (--time) * time * time * time; // decelerating to zero velocity
    73  				case 'easeInOutQuart': 	return time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
    74  				case 'easeInQuint': 	return time * time * time * time * time; // accelerating from zero velocity
    75  				case 'easeOutQuint': 	return 1 + (--time) * time * time * time * time; // decelerating to zero velocity
    76  				case 'easeInOutQuint': 	return time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
    77  				default:				return time;
    78  			}
    79  		};
    80  
    81  		/**
    82  		 * Calculate how far to scroll
    83  		 */
    84  		var getEndLocation = function(element) {
    85  			var location = 0;
    86  			if (element.offsetParent) {
    87  				do {
    88  					location += element.offsetTop;
    89  					element = element.offsetParent;
    90  				} while (element);
    91  			}
    92  			location = Math.max(location - offset, 0);
    93  			return location;
    94  		};
    95  
    96  		// Initialize the whole thing
    97  		setTimeout( function() {
    98  			var currentLocation = null,
    99  				startLocation 	= getScrollLocation(),
   100  				endLocation 	= getEndLocation(element),
   101  				timeLapsed 		= 0,
   102  				distance 		= endLocation - startLocation,
   103  				percentage,
   104  				position,
   105  				scrollHeight,
   106  				internalHeight;
   107  
   108  			/**
   109  			 * Stop the scrolling animation when the anchor is reached (or at the top/bottom of the page)
   110  			 */
   111  			var stopAnimation = function () {
   112  				currentLocation = getScrollLocation();
   113  				if(containerPresent) {
   114  					scrollHeight = container.scrollHeight;
   115  					internalHeight = container.clientHeight + currentLocation;
   116  				} else {
   117  					scrollHeight = document.body.scrollheight;
   118  					internalHeight = window.innerHeight + currentLocation;
   119  				}
   120  
   121  				if (
   122  					( // condition 1
   123  						position == endLocation
   124  					) ||
   125  					( // condition 2
   126  						currentLocation == endLocation
   127  					) ||
   128  					( // condition 3
   129  						internalHeight >= scrollHeight
   130  					)
   131  				) { // stop
   132  					clearInterval(runAnimation);
   133  					callbackAfter(element);
   134  				}
   135  			};
   136  
   137  			/**
   138  			 * Scroll the page by an increment, and check if it's time to stop
   139  			 */
   140  			var animateScroll = function () {
   141  				timeLapsed += 16;
   142  				percentage = ( timeLapsed / duration );
   143  				percentage = ( percentage > 1 ) ? 1 : percentage;
   144  				position = startLocation + ( distance * getEasingPattern(easing, percentage) );
   145  				if(containerPresent) {
   146  					container.scrollTop = position;
   147  				} else {
   148  					window.scrollTo( 0, position );
   149  				}
   150  				stopAnimation();
   151  			};
   152  
   153  			callbackBefore(element);
   154  			var runAnimation = setInterval(animateScroll, 16);
   155  		}, 0);
   156  	};
   157  
   158  
   159  	// Expose the library in a factory
   160  	//
   161  	module.factory('smoothScroll', function() {
   162  		return smoothScroll;
   163  	});
   164  
   165  
   166  	/**
   167  	 * Scrolls the window to this element, optionally validating an expression
   168  	 *
   169  	 * 20150713 EDIT - zephinzer
   170  	 * 	Added containerId to attributes for smooth scrolling within a DIV
   171  	 */
   172  	module.directive('smoothScroll', ['smoothScroll', function(smoothScroll) {
   173  		return {
   174  			restrict: 'A',
   175  			scope: {
   176  				callbackBefore: '&',
   177  				callbackAfter: '&',
   178  			},
   179  			link: function($scope, $elem, $attrs) {
   180  				if ( typeof $attrs.scrollIf === 'undefined' || $attrs.scrollIf === 'true' ) {
   181  					setTimeout( function() {
   182  
   183  						var callbackBefore = function(element) {
   184  							if ( $attrs.callbackBefore ) {
   185  								var exprHandler = $scope.callbackBefore({ element: element });
   186  								if (typeof exprHandler === 'function') {
   187  									exprHandler(element);
   188  								}
   189  							}
   190  						};
   191  
   192  						var callbackAfter = function(element) {
   193  							if ( $attrs.callbackAfter ) {
   194  								var exprHandler = $scope.callbackAfter({ element: element });
   195  								if (typeof exprHandler === 'function') {
   196  									exprHandler(element);
   197  								}
   198  							}
   199  						};
   200  
   201  						smoothScroll($elem[0], {
   202  							duration: $attrs.duration,
   203  							offset: $attrs.offset,
   204  							easing: $attrs.easing,
   205  							callbackBefore: callbackBefore,
   206  							callbackAfter: callbackAfter,
   207  							containerId: $attrs.containerId
   208  						});
   209  					}, 0);
   210  				}
   211  			}
   212  		};
   213  	}]);
   214  
   215  
   216  	/**
   217  	 * Scrolls to a specified element ID when this element is clicked
   218  	 *
   219  	 * 20150713 EDIT - zephinzer
   220  	 * 	Added containerId to attributes for smooth scrolling within a DIV
   221  	 */
   222  	module.directive('scrollTo', ['smoothScroll', function(smoothScroll) {
   223  		return {
   224  			restrict: 'A',
   225  			scope: {
   226  				callbackBefore: '&',
   227  				callbackAfter: '&',
   228  			},
   229  			link: function($scope, $elem, $attrs) {
   230  				var targetElement;
   231  
   232  				$elem.on('click', function(e) {
   233  					e.preventDefault();
   234  
   235  					targetElement = document.getElementById($attrs.scrollTo);
   236  					if ( !targetElement ) return;
   237  
   238  					var callbackBefore = function(element) {
   239  						if ( $attrs.callbackBefore ) {
   240  							var exprHandler = $scope.callbackBefore({element: element});
   241  							if (typeof exprHandler === 'function') {
   242  								exprHandler(element);
   243  							}
   244  						}
   245  					};
   246  
   247  					var callbackAfter = function(element) {
   248  						if ( $attrs.callbackAfter ) {
   249  							var exprHandler = $scope.callbackAfter({element: element});
   250  							if (typeof exprHandler === 'function') {
   251  								exprHandler(element);
   252  							}
   253  						}
   254  					};
   255  
   256  					smoothScroll(targetElement, {
   257  						duration: $attrs.duration,
   258  						offset: $attrs.offset,
   259  						easing: $attrs.easing,
   260  						callbackBefore: callbackBefore,
   261  						callbackAfter: callbackAfter,
   262  						containerId: $attrs.containerId
   263  					});
   264  
   265  					return false;
   266  				});
   267  			}
   268  		};
   269  	}]);
   270  
   271  }());