{"version":3,"file":"on-this-page.js","mappings":"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","sources":["webpack://@upstatement/harvard-law-school-wp-theme/./static/js/components/on-this-page.js","webpack://@upstatement/harvard-law-school-wp-theme/./static/js/utils/slugify.js"],"sourcesContent":["import { slugify } from '@src/utils';\n\nconst ACTIVE_LINK_CLASS = 'on-this-page__link--active';\nconst LIST_HAS_ACTIVE_CLASS = 'on-this-page__list--has-active-link';\n\nclass OnThisPage {\n constructor(el) {\n this.listTarget = el.querySelector('.on-this-page__list');\n this.footer = document.querySelector('.footer');\n this.headings = Array.from(\n document.querySelectorAll(\n '.detail-page__body-width > .gutenberg-content > h2, .ups-block__heading',\n ),\n );\n\n this.shadowSections = [];\n this.desktopJumpLinks = [];\n\n // Only build and show jump link components if we have more than 1 heading\n if (this.headings.length > 1) {\n this.buildComponents();\n el.classList.add('on-this-page--visible');\n\n // Only bind active section indicator in desktop el.\n if (el.classList.contains('on-this-page--desktop')) {\n this.buildObserver();\n }\n } else {\n el.remove();\n }\n }\n\n deinit() {\n if (this.observer) {\n this.shadowSections.forEach(section => this.observer.unobserve(section));\n }\n }\n\n /**\n * Build the observer for jump links.\n *\n * @return void\n */\n buildObserver() {\n const observerOptions = {\n rootMargin: `-50% 0px`,\n threshold: 0, // trigger intersection at the top of the element\n };\n\n // Init the observer.\n this.observer = new IntersectionObserver(this.onIntersect.bind(this), observerOptions);\n\n // If we used the IntersectionObserver to observe the header elements directly,\n // things get buggy since the h2 elements aren't that large and can be\n // susceptible to missed hits when a user is scrolling fast. Instead, we can\n // create shadow elements for each section in between the h2s and observe those,\n // which is much more predictable.\n if (!window.shadowElementsBuilt) {\n this.headings.forEach((heading, index) => {\n const shadowElement = document.createElement('div');\n const currTop = heading.getBoundingClientRect().top;\n const nextHeader = this.headings[index + 1];\n\n const height = nextHeader\n ? nextHeader.getBoundingClientRect().top - currTop\n : this.footer.getBoundingClientRect().top - currTop;\n\n shadowElement.classList.add('on-this-page__section-shadow');\n shadowElement.style.height = `${height}px`;\n shadowElement.setAttribute('data-id', heading.id);\n shadowElement.setAttribute('aria-hidden', true);\n heading.parentNode.insertBefore(shadowElement, heading);\n this.shadowSections.push(shadowElement);\n });\n window.shadowElementsBuilt = true;\n } else {\n this.shadowSections = Array.from(document.querySelectorAll('.on-this-page__section-shadow'));\n }\n\n this.shadowSections.forEach(section => this.observer.observe(section));\n }\n\n /**\n * Handle the intersect.\n *\n * @param {array} entries Array of IntersectionObserverEntry objects.\n *\n * @return void\n */\n onIntersect(entries) {\n entries.forEach(entry => {\n const isIntersecting = entry.isIntersecting;\n const newActiveHeader = entry.target.getAttribute('data-id');\n\n const matchingLink = this.desktopJumpLinks.find(\n el => el.getAttribute('href') === `#${newActiveHeader}`,\n );\n\n if (isIntersecting) {\n this.desktopJumpLinks.forEach(el => {\n if (el === matchingLink) {\n el.classList.add(ACTIVE_LINK_CLASS);\n } else {\n el.classList.remove(ACTIVE_LINK_CLASS);\n }\n });\n\n this.listTarget.classList.add(LIST_HAS_ACTIVE_CLASS);\n }\n });\n }\n\n buildComponents() {\n // Extract text node and ID attr from headings\n const jumpLinkObjects = this.headings.map(heading => {\n const text = heading.innerText;\n let id = heading.getAttribute('id');\n\n if (!id) {\n id = slugify(text);\n heading.setAttribute('id', id);\n }\n\n return { id, text };\n });\n\n // Construct markup.\n jumpLinkObjects.forEach(obj => {\n const liItem = document.createElement('li');\n const linkEl = document.createElement('a');\n linkEl.href = `#${obj.id}`;\n linkEl.innerHTML = `${obj.text}`;\n this.desktopJumpLinks.push(linkEl);\n liItem.appendChild(linkEl);\n this.listTarget.appendChild(liItem);\n });\n }\n}\n\nexport default OnThisPage;\n","/**\n * Sanitize a string.\n *\n * @param {string} text Text to sanitize.\n *\n * @return string\n */\nconst slugify = text =>\n text\n .toString() // Cast to string.\n .normalize('NFKD') // The normalize() using NFKD method returns the Unicode Normalization Form of a given string.\n .toLowerCase() // Convert the string to lowercase letters.\n .trim() // Remove whitespace from both sides of a string.\n .replace(/\\s+/g, '-') // Replace spaces with `-`.\n .replace(/[^\\w-]+/g, '') // Remove all non-word chars.\n .replace(/--+/g, '-'); // Replace multiple - with single `-`.\nexport default slugify;\n"],"names":["ACTIVE_LINK_CLASS","OnThisPage","el","_classCallCheck","this","listTarget","querySelector","footer","document","headings","Array","from","querySelectorAll","shadowSections","desktopJumpLinks","length","buildComponents","classList","add","contains","buildObserver","remove","key","value","_this","observer","forEach","section","unobserve","_this2","IntersectionObserver","onIntersect","bind","rootMargin","threshold","window","shadowElementsBuilt","heading","index","shadowElement","createElement","currTop","getBoundingClientRect","top","nextHeader","height","style","concat","setAttribute","id","parentNode","insertBefore","push","observe","entries","_this3","entry","isIntersecting","newActiveHeader","target","getAttribute","matchingLink","find","_this4","map","text","innerText","slugify","obj","liItem","linkEl","href","innerHTML","appendChild","toString","normalize","toLowerCase","trim","replace"],"sourceRoot":""}