Home | History | Annotate | Download | only in js
      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 
     12 var sidebar = document.querySelector('.inline-toc');
     13 var 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
     17 if (!(sidebar && articleBody)) {
     18   return;
     19 }
     20 
     21 var isLargerThanMobileQuery =
     22     window.matchMedia('screen and (min-width: 581px)');
     23 
     24 var toc = sidebar.querySelector('#toc');
     25 var tocOffsetTop = sidebar.offsetParent.offsetTop + toc.offsetTop;
     26 
     27 function 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 
     33 function 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.
     41 function addPermalinkHeadings(container) {
     42   if (container) {
     43     ['h2','h3','h4'].forEach(function(h, i) {
     44       [].forEach.call(container.querySelectorAll(h), addPermalink);
     45     });
     46   }
     47 }
     48 
     49 function toggleStickySidenav(){
     50   toc.classList.toggle('sticky', window.scrollY >= tocOffsetTop);
     51 }
     52 
     53 function onScroll(e) {
     54   toggleStickySidenav();
     55 }
     56 
     57 function 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).
     72 articleBody.addEventListener('click', function(e) {
     73   if (e.target.localName == 'h2' && !isLargerThanMobileQuery.matches) {
     74     e.target.parentElement.classList.toggle('active');
     75   }
     76 });
     77 
     78 toc.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 
    102 isLargerThanMobileQuery.addListener(onMediaQuery);
    103 onMediaQuery(isLargerThanMobileQuery);
    104 
    105 addPermalinkHeadings(articleBody);
    106 
    107 }());
    108