Browse Source

Added scroll to plugin to scroll to given selector.

Martin Edenhofer 10 years ago
parent
commit
6ce75e975e
1 changed files with 261 additions and 0 deletions
  1. 261 0
      app/assets/javascripts/app/lib/base/jquery-scrollto.js

+ 261 - 0
app/assets/javascripts/app/lib/base/jquery-scrollto.js

@@ -0,0 +1,261 @@
+/*global define:false require:false */
+(function (name, context, definition) {
+	if (typeof module != 'undefined' && module.exports) module.exports = definition();
+	else if (typeof define == 'function' && define.amd) define(definition);
+	else context[name] = definition();
+})('jquery-scrollto', this, function(){
+	// Prepare
+	var jQuery, $, ScrollTo;
+	jQuery = $ = window.jQuery || require('jquery');
+
+	// Fix scrolling animations on html/body on safari
+	$.propHooks.scrollTop = $.propHooks.scrollLeft = {
+		get: function(elem,prop) {
+			var result = null;
+			if ( elem.tagName === 'HTML' || elem.tagName === 'BODY' ) {
+				if ( prop === 'scrollLeft' ) {
+					result = window.scrollX;
+				} else if ( prop === 'scrollTop' ) {
+					result = window.scrollY;
+				}
+			}
+			if ( result == null ) {
+				result = elem[prop];
+			}
+			return result;
+		}
+	};
+	$.Tween.propHooks.scrollTop = $.Tween.propHooks.scrollLeft = {
+		get: function(tween) {
+			return $.propHooks.scrollTop.get(tween.elem, tween.prop);
+		},
+		set: function(tween) {
+			// Our safari fix
+			if ( tween.elem.tagName === 'HTML' || tween.elem.tagName === 'BODY' ) {
+				// Defaults
+				tween.options.bodyScrollLeft = (tween.options.bodyScrollLeft || window.scrollX);
+				tween.options.bodyScrollTop = (tween.options.bodyScrollTop || window.scrollY);
+
+				// Apply
+				if ( tween.prop === 'scrollLeft' ) {
+					tween.options.bodyScrollLeft = Math.round(tween.now);
+				}
+				else if ( tween.prop === 'scrollTop' ) {
+					tween.options.bodyScrollTop = Math.round(tween.now);
+				}
+
+				// Apply
+				window.scrollTo(tween.options.bodyScrollLeft, tween.options.bodyScrollTop);
+			}
+			// jQuery's IE8 Fix
+			else if ( tween.elem.nodeType && tween.elem.parentNode ) {
+				tween.elem[ tween.prop ] = tween.now;
+			}
+		}
+	};
+
+	// jQuery ScrollTo
+	ScrollTo = {
+		// Configuration
+		config: {
+			duration: 400,
+			easing: 'swing',
+			callback: undefined,
+			durationMode: 'each',
+			offsetTop: 0,
+			offsetLeft: 0
+		},
+
+		// Set Configuration
+		configure: function(options){
+			// Apply Options to Config
+			$.extend(ScrollTo.config, options||{});
+
+			// Chain
+			return this;
+		},
+
+		// Perform the Scroll Animation for the Collections
+		// We use $inline here, so we can determine the actual offset start for each overflow:scroll item
+		// Each collection is for each overflow:scroll item
+		scroll: function(collections, config){
+			// Prepare
+			var collection, $container, container, $target, $inline, position, containerTagName,
+				containerScrollTop, containerScrollLeft,
+				containerScrollTopEnd, containerScrollLeftEnd,
+				startOffsetTop, targetOffsetTop, targetOffsetTopAdjusted,
+				startOffsetLeft, targetOffsetLeft, targetOffsetLeftAdjusted,
+				scrollOptions,
+				callback;
+
+			// Determine the Scroll
+			collection = collections.pop();
+			$container = collection.$container;
+			$target = collection.$target;
+			containerTagName = $container.prop('tagName');
+
+			// Prepare the Inline Element of the Container
+			$inline = $('<span/>').css({
+				'position': 'absolute',
+				'top': '0px',
+				'left': '0px'
+			});
+			position = $container.css('position');
+
+			// Insert the Inline Element of the Container
+			$container.css({position:'relative'});
+			$inline.appendTo($container);
+
+			// Determine the top offset
+			startOffsetTop = $inline.offset().top;
+			targetOffsetTop = $target.offset().top;
+			targetOffsetTopAdjusted = targetOffsetTop - startOffsetTop - parseInt(config.offsetTop,10);
+
+			// Determine the left offset
+			startOffsetLeft = $inline.offset().left;
+			targetOffsetLeft = $target.offset().left;
+			targetOffsetLeftAdjusted = targetOffsetLeft - startOffsetLeft - parseInt(config.offsetLeft,10);
+
+			// Determine current scroll positions
+			containerScrollTop = $container.prop('scrollTop');
+			containerScrollLeft = $container.prop('scrollLeft');
+
+			// Reset the Inline Element of the Container
+			$inline.remove();
+			$container.css({position:position});
+
+			// Prepare the scroll options
+			scrollOptions = {};
+
+			// Prepare the callback
+			callback = function(event){
+				// Check
+				if ( collections.length === 0 ) {
+					// Callback
+					if ( typeof config.callback === 'function' ) {
+						config.callback();
+					}
+				}
+				else {
+					// Recurse
+					ScrollTo.scroll(collections,config);
+				}
+				// Return true
+				return true;
+			};
+
+			// Handle if we only want to scroll if we are outside the viewport
+			if ( config.onlyIfOutside ) {
+				// Determine current scroll positions
+				containerScrollTopEnd = containerScrollTop + $container.height();
+				containerScrollLeftEnd = containerScrollLeft + $container.width();
+
+				// Check if we are in the range of the visible area of the container
+				if ( containerScrollTop < targetOffsetTopAdjusted && targetOffsetTopAdjusted < containerScrollTopEnd ) {
+					targetOffsetTopAdjusted = containerScrollTop;
+				}
+				if ( containerScrollLeft < targetOffsetLeftAdjusted && targetOffsetLeftAdjusted < containerScrollLeftEnd ) {
+					targetOffsetLeftAdjusted = containerScrollLeft;
+				}
+			}
+
+			// Determine the scroll options
+			if ( targetOffsetTopAdjusted !== containerScrollTop ) {
+				scrollOptions.scrollTop = targetOffsetTopAdjusted;
+			}
+			if ( targetOffsetLeftAdjusted !== containerScrollLeft ) {
+				scrollOptions.scrollLeft = targetOffsetLeftAdjusted;
+			}
+
+			// Check to see if the scroll is necessary
+			if ( $container.prop('scrollHeight') === $container.width() ) {
+				delete scrollOptions.scrollTop;
+			}
+			if ( $container.prop('scrollWidth') === $container.width() ) {
+				delete scrollOptions.scrollLeft;
+			}
+
+			// Perform the scroll
+			if ( scrollOptions.scrollTop != null || scrollOptions.scrollLeft != null ) {
+				$container.animate(scrollOptions, {
+					duration: config.duration,
+					easing: config.easing,
+					complete: callback
+				});
+			}
+			else {
+				callback();
+			}
+
+			// Return true
+			return true;
+		},
+
+		// ScrollTo the Element using the Options
+		fn: function(options){
+			// Prepare
+			var collections, config, $container, container;
+			collections = [];
+
+			// Prepare
+			var	$target = $(this);
+			if ( $target.length === 0 ) {
+				// Chain
+				return this;
+			}
+
+			// Handle Options
+			config = $.extend({},ScrollTo.config,options);
+
+			// Fetch
+			$container = $target.parent();
+			container = $container.get(0);
+
+			// Cycle through the containers
+			while ( ($container.length === 1) && (container !== document.body) && (container !== document) ) {
+				// Check Container for scroll differences
+				var containerScrollTop, containerScrollLeft;
+				containerScrollTop = $container.css('overflow-y') !== 'visible' && container.scrollHeight !== container.clientHeight;
+				containerScrollLeft =  $container.css('overflow-x') !== 'visible' && container.scrollWidth !== container.clientWidth;
+				if ( containerScrollTop || containerScrollLeft ) {
+					// Push the Collection
+					collections.push({
+						'$container': $container,
+						'$target': $target
+					});
+					// Update the Target
+					$target = $container;
+				}
+				// Update the Container
+				$container = $container.parent();
+				container = $container.get(0);
+			}
+
+			// Add the final collection
+			collections.push({
+				'$container': $('html'),
+				// document.body doesn't work in firefox, html works for all
+				// internet explorer starts at the beggining
+				'$target': $target
+			});
+
+			// Adjust the Config
+			if ( config.durationMode === 'all' ) {
+				config.duration /= collections.length;
+			}
+
+			// Handle
+			ScrollTo.scroll(collections,config);
+
+			// Chain
+			return this;
+		}
+	};
+
+	// Apply our extensions to jQuery
+	$.ScrollTo = $.ScrollTo || ScrollTo;
+	$.fn.ScrollTo = $.fn.ScrollTo || ScrollTo.fn;
+
+	// Export
+	return ScrollTo;
+});