{"version":3,"sources":["nav_affixed.js"],"names":["window","ScrollNav","this","handleClick","bind","handleScroll","handleScrollEnd","activeLinkId","isBusy","isListening","getOffset","el","_x","_y","isNaN","offsetLeft","offsetTop","scrollLeft","scrollTop","offsetParent","top","left","getDocumentElement","document","documentElement","body","affixer","affixables","affixable","Affixable","initClasses","parent","parentNode","topStyle","getTopStyle","getTop","maxY","getMaxY","prototype","classList","contains","remove","getBottom","offsetHeight","pageYOffset","getBoundingClientRect","parseInt","style","paddingBottom","refreshClasses","scrollBottom","innerHeight","add","setMaxY","init","$","length","scrollspy","slice","call","querySelectorAll","forEach","affixObject","push","registerListeners","initialized","addEventListener","attachEvent","reInit","map","firstTime","links","sections","section","querySelector","hash","id","offset","filter","sort","sectionA","sectionB","addScrollListener","e","preventDefault","targetId","currentTarget","substring","reduce","acc","setActiveLink","removeScrollListener","location","scrollPosition","removeEventListener","parentElement","getElementById","scrollNav","lodashDebounce","resize"],"mappings":"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","sourceRoot":"/assets","sourcesContent":["(function(window) {\n /**\n * Affixer\n */\n window.affixer = {\n affixables: [],\n affixable: (function() {\n function Affixable(el) {\n this.el = el;\n\n this.initClasses();\n this.parent = el.parentNode;\n this.topStyle = this.getTopStyle();\n this.top = this.getTop();\n this.maxY = this.getMaxY();\n }\n\n Affixable.prototype.initClasses = function() {\n if (this.el.classList.contains('affix-bottom')) {\n this.el.classList.remove('affix-bottom');\n }\n if (this.el.classList.contains('affix')) {\n this.el.classList.remove('affix');\n }\n };\n\n Affixable.prototype.getBottom = function() {\n return this.maxY - this.el.offsetHeight - this.topStyle;\n };\n\n Affixable.prototype.getMaxY = function() {\n return window.pageYOffset + this.parent.getBoundingClientRect().top + this.parent.offsetHeight - (parseInt(this.parent.style.paddingBottom) || 0);\n };\n\n Affixable.prototype.getTop = function() {\n return parseInt(window.pageYOffset + this.el.getBoundingClientRect().top - this.topStyle);\n };\n\n Affixable.prototype.getTopStyle = function() {\n return parseInt(this.el.style.top) || 0;\n };\n\n Affixable.prototype.refreshClasses = function() {\n var scrollTop = window.pageYOffset;\n var scrollBottom = scrollTop + window.innerHeight;\n // if the top of the window is past the top of the element\n if (scrollTop \u003e= this.top) {\n if (!this.el.classList.contains('affix')) {\n this.el.classList.add('affix');\n }\n // if there is a bottom\n if (this.maxY) {\n // if the bottom of the window is past the bottom of the container,\n // and the top of the window is past the maximum point the top of the\n // element can be at\n if (scrollBottom \u003e this.maxY \u0026\u0026 scrollTop \u003e this.getBottom()) {\n if (!this.el.classList.contains('affix-bottom')) {\n this.el.classList.add('affix-bottom');\n }\n } else if (this.el.classList.contains('affix-bottom')) {\n this.el.classList.remove('affix-bottom');\n }\n }\n } else if (this.el.classList.contains('affix')) {\n this.el.classList.remove('affix');\n }\n };\n\n Affixable.prototype.setMaxY = function() {\n this.maxY = this.getMaxY();\n };\n\n return Affixable;\n })(),\n init: function(){\n // TODO: what does this do?\n if ($('#scroll-nav').length){\n $('body').scrollspy('refresh');\n }\n\n [].slice.call(document.querySelectorAll('.affixable')).forEach(function(el) {\n var affixObject = new this.affixable(el);\n affixObject.refreshClasses();\n this.affixables.push(affixObject);\n }.bind(this));\n this.registerListeners();\n this.initialized = true;\n },\n initialized: false,\n registerListeners: function() {\n if (window.addEventListener) {\n window.addEventListener('scroll', this.refreshClasses.bind(this));\n } else {\n window.attachEvent('onscroll', this.refreshClasses.bind(this));\n }\n },\n reInit: function(){\n // reinitialize all cached properties on affixables. useful after major dom rearrangement\n this.affixables = this.affixables.map(function(affixObject) {\n return new this.affixable(affixObject.el);\n }.bind(this));\n\n this.refreshClasses();\n },\n refreshClasses: function() {\n this.affixables.forEach(function(affixObject) { affixObject.refreshClasses(); });\n }\n };\n\n /**\n * ScrollNav\n */\n function ScrollNav() {\n this.handleClick = this.handleClick.bind(this);\n this.handleScroll = this.handleScroll.bind(this);\n this.handleScrollEnd = this.handleScrollEnd.bind(this);\n\n // state properties\n this.activeLinkId;\n this.isBusy;\n this.isListening;\n }\n\n ScrollNav.prototype.init = function(firstTime) {\n var links = [].slice.call(document.querySelectorAll(\"#scroll-nav a\"));\n\n this.sections = links.map(function(el) {\n var section = document.querySelector(el.hash);\n if (section) {\n /* Setting scroll offset 10px higher to indicate accurately the current\n active link when there are small discrepancies */\n return {id: section.id, offset: (getOffset(section).top - 10)};\n }\n })\n .filter(function(section) { return !!section; })\n .sort(function(sectionA, sectionB) { return sectionA.offset - sectionB.offset; });\n\n if (firstTime) {\n this.isBusy = false;\n this.addScrollListener();\n\n links.forEach(function(el) {\n el.addEventListener('click', this.handleClick);\n }.bind(this))\n }\n\n this.handleScroll();\n };\n\n ScrollNav.prototype.handleClick = function(e) {\n if (this.isBusy) {\n e.preventDefault();\n return;\n }\n\n var targetId = e.currentTarget.hash.substring(1);\n\n var targetOffset = this.sections.reduce(function(acc, section) {\n if (acc !== null) return acc;\n return (section.id === targetId) ? section.offset : acc;\n }, null);\n\n if (targetOffset !== null) {\n e.preventDefault();\n this.isBusy = true;\n this.setActiveLink(targetId);\n\n this.removeScrollListener();\n\n // Hster.Utils.smoothScroll(targetOffset, 500, this.handleScrollEnd);\n\n // Temporary solution to fix lazy embeds' messing with initial scroll offsets\n window.location.hash = targetId;\n this.handleScrollEnd();\n }\n };\n\n ScrollNav.prototype.handleScroll = function() {\n if (this.sections.length === 0) return;\n\n var scrollPosition = getDocumentElement().scrollTop;\n\n var id = this.sections.reduce(function(acc, section) {\n if (section.offset \u003c= scrollPosition) {\n return section.id;\n }\n return acc;\n }, this.sections[0].id);\n\n if (id !== this.activeLinkId) {\n this.setActiveLink(id);\n }\n };\n\n ScrollNav.prototype.handleScrollEnd = function() {\n this.addScrollListener();\n this.isBusy = false;\n };\n\n ScrollNav.prototype.addScrollListener = function() {\n if (this.isListening) return; // memory leak safeguard\n\n window.addEventListener('scroll', this.handleScroll);\n this.isListening = true;\n };\n\n ScrollNav.prototype.removeScrollListener = function() {\n window.removeEventListener('scroll', this.handleScroll);\n this.isListening = false;\n };\n\n ScrollNav.prototype.setActiveLink = function(id) {\n this.activeLinkId = id;\n document.querySelector('#scroll-nav .active').classList.remove('active');\n document.querySelector('#scroll-nav a[href$=' + id + ']').parentElement.classList.add('active');\n };\n\n /**\n * Offset relative to document using scrollTop/scrollLeft, so result will be integers.\n * Calculated differently from jQuery offset method, which can return floats.\n * source: https://stackoverflow.com/a/442474/1389981\n */\n function getOffset(el) {\n var _x = 0;\n var _y = 0;\n while (el \u0026\u0026 !isNaN( el.offsetLeft) \u0026\u0026 !isNaN(el.offsetTop)) {\n _x += el.offsetLeft - el.scrollLeft;\n _y += el.offsetTop - el.scrollTop;\n el = el.offsetParent;\n }\n return { top: _y, left: _x };\n }\n\n function getDocumentElement() {\n return document.documentElement || document.body;\n }\n\n window.addEventListener('load', function(event) {\n if (document.getElementById('scroll-nav')) {\n var scrollNav = new ScrollNav();\n scrollNav.init(true);\n\n var reInit = lodashDebounce(function() { scrollNav.init(false); }, 300);\n $('.middle-column').resize(reInit);\n }\n });\n})(window);\n"]}