1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Scroll handling. 6// 7// Switches the sidebar between floating on the left and position:fixed 8// depending on whether it's scrolled into view, and manages the scroll-to-top 9// button: click logic, and when to show it. 10(function() { 11 12var sidebar = document.querySelector('.inline-toc'); 13var articleBody = document.querySelector('[itemprop="articleBody"]'); 14 15// Bomb out unless we're on an article page and have a TOC. 16// Ideally, template shouldn't load this JS file on a non-article page 17if (!(sidebar && articleBody)) { 18 return; 19} 20 21var isLargerThanMobileQuery = 22 window.matchMedia('screen and (min-width: 581px)'); 23 24var toc = sidebar.querySelector('#toc'); 25var tocOffsetTop = sidebar.offsetParent.offsetTop + toc.offsetTop; 26 27function updateTocOffsetTop() { 28 // Note: Attempting to read offsetTop with sticky on causes toc overlap 29 toc.classList.remove('sticky'); 30 tocOffsetTop = sidebar.offsetParent.offsetTop + toc.offsetTop; 31} 32 33function addPermalink(el) { 34 el.classList.add('has-permalink'); 35 var id = el.id || el.textContent.toLowerCase().replace(' ', '-'); 36 el.insertAdjacentHTML('beforeend', 37 '<a class="permalink" title="Permalink" href="#' + id + '">#</a>'); 38} 39 40// Add permalinks to heading elements. 41function addPermalinkHeadings(container) { 42 if (container) { 43 ['h2','h3','h4'].forEach(function(h, i) { 44 [].forEach.call(container.querySelectorAll(h), addPermalink); 45 }); 46 } 47} 48 49function toggleStickySidenav(){ 50 toc.classList.toggle('sticky', window.scrollY >= tocOffsetTop); 51} 52 53function onScroll(e) { 54 toggleStickySidenav(); 55} 56 57function onMediaQuery(e) { 58 if (e.matches) { 59 // On tablet & desktop, show permalinks, manage TOC position. 60 document.body.classList.remove('no-permalink'); 61 document.addEventListener('scroll', onScroll); 62 updateTocOffsetTop(); 63 toggleStickySidenav(); 64 } else { 65 // On mobile, hide permalinks. TOC is hidden, doesn't need to scroll. 66 document.body.classList.add('no-permalink'); 67 document.removeEventListener('scroll', onScroll); 68 } 69} 70 71// Toggle collapsible sections (mobile). 72articleBody.addEventListener('click', function(e) { 73 if (e.target.localName == 'h2' && !isLargerThanMobileQuery.matches) { 74 e.target.parentElement.classList.toggle('active'); 75 } 76}); 77 78toc.addEventListener('click', function(e) { 79 // React only if clicking on a toplevel menu anchor item 80 // that is not currently open 81 if (e.target.classList.contains('hastoc') && 82 !e.target.parentElement.classList.contains('active')) { 83 e.stopPropagation(); 84 85 // close any previously open subnavs 86 [].forEach.call(toc.querySelectorAll('.active'), function(li) { 87 li.classList.remove('active'); 88 }); 89 90 // then open the clicked one 91 e.target.parentElement.classList.add('active'); 92 } 93}); 94 95// Add +/- expander to headings with subheading children. 96[].forEach.call(toc.querySelectorAll('.toplevel'), function(heading) { 97 if (heading.querySelector('.toc')) { 98 heading.firstChild.classList.add('hastoc'); 99 } 100}); 101 102isLargerThanMobileQuery.addListener(onMediaQuery); 103onMediaQuery(isLargerThanMobileQuery); 104 105addPermalinkHeadings(articleBody); 106 107}()); 108