{"version":3,"sources":["affix/affix.js"],"names":[],"mappings":"4JAaM,GAAI,KAAW,iCAIb,MAAI,UAAS,WAAA,aAAA,SAAA,EAAA,EAAA,2BAqKJ,GAAsB,EAAA,EAAY,SAE/B,IACR,EAAO,UAEA,IAAP,+DAKK,+BAQT,MAAO,GAAA,KAAA,EAAA,EAAA,YAAA,EAAA,GAAA,sFAhLP,GAAI,MAGA,EAAA,QAAA,UAAmB,EAAA,GACnB,EAAA,EAAY,OAGZ,EAAQ,oCAER,EAAiB,MAEjB,EAAQ,EACV,EAAY,EACV,EAAS,OACP,qBAIF,EAAA,oGAOF,GAAA,QAAmB,QAAA,EAAW,uBAI9B,KAAY,WAEZ,KAAA,2DAKA,EAAK,GAAA,SAAA,KAAA,yHAOL,KAAA,sNAiBA,WAAI,EAAY,cAAA,yCAQb,EAAY,EAAO,OAAA,EAAA,IACtB,EAAU,EAAA,OAAA,EAAA,IAGV,EAAQ,EAAmB,EAAS,EAAY,EAG9C,KAAQ,MACA,6DAKA,WACR,EAAI,OACF,IAAU,WAAQ,EAAc,aAAA,GAAA,iBAE7B,IAAA,QAAA,qBAGK,WAAR,GAEF,kBAAa,EAAV,EAAU,aAKR,EAAA,IAAA,EAEF,GACD,EAAQ,IAAI,QAAS,IAEvB,EAAQ,IAAI,WAAY,EAAA,aAAA,GAAA,YACxB,EAAQ,IAAI,MAAO,EAAkB,aAAA,GAAA,EAAA,GAAA,aAAA,EAAA,EAAA,EAAA,uDAMvC,EAAO,IAAA,WAAA,SACP,EAAO,IAAA,MAAA,EAAA,WAKH,UAAA,6BAEJ,EAAA,mBAEG,mBAAmB,EAAA,EAAA,UAAA,MAElB,cAAQ,qCAGR,IAAA,WAAoB,EAAoB,aAAA,GAAA,cAEtC,qCAEG,UAAA,uDAKL,EADG,EAAA,aACS,EAAQ,OAAY,EAAA,IAAA,IAAA,EAAA,EAAA,uEAOhC,EAAe,EAAf,EAAe,6JAenB,EAAI,IAAA,WAAY,sDA7JlB,EAAI,QAAU,QAAe,0BAsMzB,WAAW,SAAO,UAAO,SAAW,EAAQ,wDAK5C,SAAe,EAAS,EAAA,EAAA,MAE1B,IAAS,MAAM,EAAA,UAAA,OAAA,OAAA,EAAA,EAAA,SAAA,QAAA,QAAA,YACf,SAAU,YAAA,eAAA,eAAA,eAAA,SAAA,GACV,QAAQ,UAAA,EAAA,MAAA,EAAA,GAAA,EAAA","file":"affix.min.js","sourcesContent":["'use strict';\n\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto'\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n element.css('position', (options.offsetParent) ? '' : 'relative');\n if(setWidth) {\n element.css('width', '');\n }\n element.css('top', '');\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n element.css('position', (options.offsetParent) ? '' : 'relative');\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n element.css('position', initialPosition);\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n"],"sourceRoot":"/source/"}