_toc.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //= require ../lib/_jquery
  2. //= require ../lib/_imagesloaded.min
  3. ;(function () {
  4. 'use strict';
  5. var htmlPattern = /<[^>]*>/g;
  6. var loaded = false;
  7. var debounce = function(func, waitTime) {
  8. var timeout = false;
  9. return function() {
  10. if (timeout === false) {
  11. setTimeout(function() {
  12. func();
  13. timeout = false;
  14. }, waitTime);
  15. timeout = true;
  16. }
  17. };
  18. };
  19. var closeToc = function() {
  20. $(".toc-wrapper").removeClass('open');
  21. $("#nav-button").removeClass('open');
  22. };
  23. function loadToc($toc, tocLinkSelector, tocListSelector, scrollOffset) {
  24. var headerHeights = {};
  25. var pageHeight = 0;
  26. var windowHeight = 0;
  27. var originalTitle = document.title;
  28. var recacheHeights = function() {
  29. headerHeights = {};
  30. pageHeight = $(document).height();
  31. windowHeight = $(window).height();
  32. $toc.find(tocLinkSelector).each(function() {
  33. var targetId = $(this).attr('href');
  34. if (targetId[0] === "#") {
  35. headerHeights[targetId] = $("#" + $.escapeSelector(targetId.substring(1))).offset().top;
  36. }
  37. });
  38. };
  39. var refreshToc = function() {
  40. var currentTop = $(document).scrollTop() + scrollOffset;
  41. if (currentTop + windowHeight >= pageHeight) {
  42. // at bottom of page, so just select last header by making currentTop very large
  43. // this fixes the problem where the last header won't ever show as active if its content
  44. // is shorter than the window height
  45. currentTop = pageHeight + 1000;
  46. }
  47. var best = null;
  48. for (var name in headerHeights) {
  49. if ((headerHeights[name] < currentTop && headerHeights[name] > headerHeights[best]) || best === null) {
  50. best = name;
  51. }
  52. }
  53. // Catch the initial load case
  54. if (currentTop == scrollOffset && !loaded) {
  55. best = window.location.hash;
  56. loaded = true;
  57. }
  58. var $best = $toc.find("[href='" + best + "']").first();
  59. if (!$best.hasClass("active")) {
  60. // .active is applied to the ToC link we're currently on, and its parent <ul>s selected by tocListSelector
  61. // .active-expanded is applied to the ToC links that are parents of this one
  62. $toc.find(".active").removeClass("active");
  63. $toc.find(".active-parent").removeClass("active-parent");
  64. $best.addClass("active");
  65. $best.parents(tocListSelector).addClass("active").siblings(tocLinkSelector).addClass('active-parent');
  66. $best.siblings(tocListSelector).addClass("active");
  67. $toc.find(tocListSelector).filter(":not(.active)").slideUp(150);
  68. $toc.find(tocListSelector).filter(".active").slideDown(150);
  69. if (window.history.replaceState) {
  70. window.history.replaceState(null, "", best);
  71. }
  72. var thisTitle = $best.data("title");
  73. if (thisTitle !== undefined && thisTitle.length > 0) {
  74. document.title = thisTitle.replace(htmlPattern, "") + " – " + originalTitle;
  75. } else {
  76. document.title = originalTitle;
  77. }
  78. }
  79. };
  80. var makeToc = function() {
  81. recacheHeights();
  82. refreshToc();
  83. $("#nav-button").click(function() {
  84. $(".toc-wrapper").toggleClass('open');
  85. $("#nav-button").toggleClass('open');
  86. return false;
  87. });
  88. $(".page-wrapper").click(closeToc);
  89. $(".toc-link").click(closeToc);
  90. // reload immediately after scrolling on toc click
  91. $toc.find(tocLinkSelector).click(function() {
  92. setTimeout(function() {
  93. refreshToc();
  94. }, 0);
  95. });
  96. $(window).scroll(debounce(refreshToc, 200));
  97. $(window).resize(debounce(recacheHeights, 200));
  98. };
  99. makeToc();
  100. window.recacheHeights = recacheHeights;
  101. window.refreshToc = refreshToc;
  102. }
  103. window.loadToc = loadToc;
  104. })();