From 6ce75e975eb31a40ed366e22ee345ad48e387674 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 15 Dec 2014 20:58:59 +0100 Subject: [PATCH] Added scroll to plugin to scroll to given selector. --- .../app/lib/base/jquery-scrollto.js | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100755 app/assets/javascripts/app/lib/base/jquery-scrollto.js diff --git a/app/assets/javascripts/app/lib/base/jquery-scrollto.js b/app/assets/javascripts/app/lib/base/jquery-scrollto.js new file mode 100755 index 000000000..26b2bd98d --- /dev/null +++ b/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 = $('').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; +}); \ No newline at end of file