+/***
+umd: true
+***/
+
+(function () {
+ // Prepare
+ var $, ScrollTo
+ $ = 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: null,
+ 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, $target, $inline, position,
+ containerScrollTop, containerScrollLeft,
+ containerScrollTopEnd, containerScrollLeftEnd,
+ startOffsetTop, targetOffsetTop, targetOffsetTopAdjusted,
+ startOffsetLeft, targetOffsetLeft, targetOffsetLeftAdjusted,
+ scrollOptions,
+ callback
+
+ // Determine the Scroll
+ collection = collections.pop()
+ $container = collection.$container
+ $target = collection.$target
+
+ // 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 () {
+ // 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.height() ) {
+ 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
+}).call(this)