// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Scroll handling. // // Switches the sidebar between floating on the left and position:fixed // depending on whether it's scrolled into view, and manages the scroll-to-top // button: click logic, and when to show it. (function() { var sidebar = document.querySelector('.inline-toc'); var articleBody = document.querySelector('[itemprop="articleBody"]'); // Bomb out unless we're on an article page and have a TOC. // Ideally, template shouldn't load this JS file on a non-article page if (!(sidebar && articleBody)) { return; } var isLargerThanMobileQuery = window.matchMedia('screen and (min-width: 581px)'); var toc = sidebar.querySelector('#toc'); var tocOffsetTop = sidebar.offsetParent.offsetTop + toc.offsetTop; function updateTocOffsetTop() { // Note: Attempting to read offsetTop with sticky on causes toc overlap toc.classList.remove('sticky'); tocOffsetTop = sidebar.offsetParent.offsetTop + toc.offsetTop; } function addPermalink(el) { el.classList.add('has-permalink'); var id = el.id || el.textContent.toLowerCase().replace(' ', '-'); el.insertAdjacentHTML('beforeend', ''); } // Add permalinks to heading elements. function addPermalinkHeadings(container) { if (container) { ['h2','h3','h4'].forEach(function(h, i) { [].forEach.call(container.querySelectorAll(h), addPermalink); }); } } function toggleStickySidenav(){ toc.classList.toggle('sticky', window.scrollY >= tocOffsetTop); } function onScroll(e) { toggleStickySidenav(); } function onMediaQuery(e) { if (e.matches) { // On tablet & desktop, show permalinks, manage TOC position. document.body.classList.remove('no-permalink'); document.addEventListener('scroll', onScroll); updateTocOffsetTop(); toggleStickySidenav(); } else { // On mobile, hide permalinks. TOC is hidden, doesn't need to scroll. document.body.classList.add('no-permalink'); document.removeEventListener('scroll', onScroll); } } // Toggle collapsible sections (mobile). articleBody.addEventListener('click', function(e) { if (e.target.localName == 'h2' && !isLargerThanMobileQuery.matches) { e.target.parentElement.classList.toggle('active'); } }); toc.addEventListener('click', function(e) { // React only if clicking on a toplevel menu anchor item // that is not currently open if (e.target.classList.contains('hastoc') && !e.target.parentElement.classList.contains('active')) { e.stopPropagation(); // close any previously open subnavs [].forEach.call(toc.querySelectorAll('.active'), function(li) { li.classList.remove('active'); }); // then open the clicked one e.target.parentElement.classList.add('active'); } }); // Add +/- expander to headings with subheading children. [].forEach.call(toc.querySelectorAll('.toplevel'), function(heading) { if (heading.querySelector('.toc')) { heading.firstChild.classList.add('hastoc'); } }); isLargerThanMobileQuery.addListener(onMediaQuery); onMediaQuery(isLargerThanMobileQuery); addPermalinkHeadings(articleBody); }());