• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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