{"version":3,"sources":["scrollspy/scrollspy.js"],"names":[],"mappings":"qBASQ,OAAA,4BAA2B,kCAAA,+CAE7B,aAAU,kDAMV,SAAI,IACJ,SAAI,IACJ,OAAI,oHAWE,GAAU,EAAQ,GACtB,MAAI,GAAQ,GAAA,UAAiB,EAAA,GAAU,SAAA,gBAAA,EAAA,sBAGnC,GAAW,GAGf,GAAG,GAAM,QAAW,UAAA,EAAA,EAClB,GAAM,UAAU,EAAA,QAAA,MAChB,GAAa,EAAA,EAAA,QAAA,kDAOf,MADA,GAAI,GAAA,UACA,EAAA,EAGJ,IAGI,GAAA,EAGJ,MAGE,MATE,KAIA,EAAA,EAAA,kCASF,KAAA,WAGA,KAAA,QAAY,EAGZ,EAAA,EAA0B,KAAW,cAAI,EAAA,UACzC,EAAA,EAA6B,KAAA,cAAe,EAAA,UAC5C,EAAA,GAAA,QAAA,KAAA,gEAIoB,EAAA,KAAA,aAAA,EAAA,mHAepB,KAAA,UACA,KAAA,QAAa,uFAQf,iBAGM,GAAA,mDAUK,EAAW,EAAA,YAAiB,EAAe,KAAA,eAAA,mDAMlD,EAAG,EAAiB,GAAA,WAAkB,IAAQ,EAAA,GAAA,OAC9C,MAAG,GAAY,iBAAkB,EAAW,+GAOhD,EAAW,EAAA,GAAA,4HAUH,EAAgB,cAAW,sEAQjC,KACA,EAAe,OAAS,YAAA,UACrB,EAAS,EAAgB,OAAS,OAAS,EAAQ,EAAgB,OAAA,SAAU,SAAO,OACrF,EAAe,OAAS,SAAS,SAAS,YAAA,WAI9C,EAAW,EAAA,OACT,EAAO,OAAA,SAAgB,UACrB,EAAO,EAAI,OAAW,OAAA,EAAA,EAAA,OAAA,SAAA,SAAA,SACrB,OAAA,SAAA,SAAA,SAAA,4CAKL,MAAA,GAAW,OAAe,SAAW,yBAEnC,sCAOQ,QAAA,EAAa,SAAA,GACnB,GAAA,GAAU,SAAc,cAAA,EAAA,2CAEzB,EAAK,QAAe,OAAA,EAAA,YAAA,EAAA,WAAA,EAAA,EAAA,cAIrB,OAAA,SAAA,kDAIF,MAAW,GAAA,UAAA,EAAe,mBAOnB,aAAmB,SAAA,EAAW,KACpB,MAAA,OAAA,EAAA,OAAA,2CAIf,wDAGF,EAAW,CACT,wBAMF,EAAO,SAAA,SAAA,0CAhLP,GAAO,QAAW,QAAA,0GAiMlB,eAAiB,aAAU,WAAoB,aAAK,aAAA,SAAA,EAAA,EAAA,EAAA,8BAIhD,SAAY,EAAW,EAAA,kBAG3B,SAAM,SAAI,SAAY,UAAW,SAAA,GAC/B,QAAI,UAAW,EAAA,MAAA,EAAA,GAAA,EAAA,mBAIf,aAAU,EAAA,OAAA,4GAiBV,mBAAsB,aAAQ,WAAA,aAAA,aAAA,6HAOnC,GAAA,GAAA,QAAA,QAAA","file":"scrollspy.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n"],"sourceRoot":"/source/"}