123 lines
3.8 KiB
JavaScript
123 lines
3.8 KiB
JavaScript
//= require ../lib/_jquery
|
||
//= require ../lib/_imagesloaded.min
|
||
;(function () {
|
||
'use strict';
|
||
|
||
var htmlPattern = /<[^>]*>/g;
|
||
var loaded = false;
|
||
|
||
var debounce = function(func, waitTime) {
|
||
var timeout = false;
|
||
return function() {
|
||
if (timeout === false) {
|
||
setTimeout(function() {
|
||
func();
|
||
timeout = false;
|
||
}, waitTime);
|
||
timeout = true;
|
||
}
|
||
};
|
||
};
|
||
|
||
var closeToc = function() {
|
||
$(".toc-wrapper").removeClass('open');
|
||
$("#nav-button").removeClass('open');
|
||
};
|
||
|
||
function loadToc($toc, tocLinkSelector, tocListSelector, scrollOffset) {
|
||
var headerHeights = {};
|
||
var pageHeight = 0;
|
||
var windowHeight = 0;
|
||
var originalTitle = document.title;
|
||
|
||
var recacheHeights = function() {
|
||
headerHeights = {};
|
||
pageHeight = $(document).height();
|
||
windowHeight = $(window).height();
|
||
|
||
$toc.find(tocLinkSelector).each(function() {
|
||
var targetId = $(this).attr('href');
|
||
if (targetId[0] === "#") {
|
||
headerHeights[targetId] = $("#" + $.escapeSelector(targetId.substring(1))).offset().top;
|
||
}
|
||
});
|
||
};
|
||
|
||
var refreshToc = function() {
|
||
var currentTop = $(document).scrollTop() + scrollOffset;
|
||
|
||
if (currentTop + windowHeight >= pageHeight) {
|
||
// at bottom of page, so just select last header by making currentTop very large
|
||
// this fixes the problem where the last header won't ever show as active if its content
|
||
// is shorter than the window height
|
||
currentTop = pageHeight + 1000;
|
||
}
|
||
|
||
var best = null;
|
||
for (var name in headerHeights) {
|
||
if ((headerHeights[name] < currentTop && headerHeights[name] > headerHeights[best]) || best === null) {
|
||
best = name;
|
||
}
|
||
}
|
||
|
||
// Catch the initial load case
|
||
if (currentTop == scrollOffset && !loaded) {
|
||
best = window.location.hash;
|
||
loaded = true;
|
||
}
|
||
|
||
var $best = $toc.find("[href='" + best + "']").first();
|
||
if (!$best.hasClass("active")) {
|
||
// .active is applied to the ToC link we're currently on, and its parent <ul>s selected by tocListSelector
|
||
// .active-expanded is applied to the ToC links that are parents of this one
|
||
$toc.find(".active").removeClass("active");
|
||
$toc.find(".active-parent").removeClass("active-parent");
|
||
$best.addClass("active");
|
||
$best.parents(tocListSelector).addClass("active").siblings(tocLinkSelector).addClass('active-parent');
|
||
$best.siblings(tocListSelector).addClass("active");
|
||
$toc.find(tocListSelector).filter(":not(.active)").slideUp(150);
|
||
$toc.find(tocListSelector).filter(".active").slideDown(150);
|
||
if (window.history.replaceState) {
|
||
window.history.replaceState(null, "", best);
|
||
}
|
||
var thisTitle = $best.data("title");
|
||
if (thisTitle !== undefined && thisTitle.length > 0) {
|
||
document.title = thisTitle.replace(htmlPattern, "") + " – " + originalTitle;
|
||
} else {
|
||
document.title = originalTitle;
|
||
}
|
||
}
|
||
};
|
||
|
||
var makeToc = function() {
|
||
recacheHeights();
|
||
refreshToc();
|
||
|
||
$("#nav-button").click(function() {
|
||
$(".toc-wrapper").toggleClass('open');
|
||
$("#nav-button").toggleClass('open');
|
||
return false;
|
||
});
|
||
$(".page-wrapper").click(closeToc);
|
||
$(".toc-link").click(closeToc);
|
||
|
||
// reload immediately after scrolling on toc click
|
||
$toc.find(tocLinkSelector).click(function() {
|
||
setTimeout(function() {
|
||
refreshToc();
|
||
}, 0);
|
||
});
|
||
|
||
$(window).scroll(debounce(refreshToc, 200));
|
||
$(window).resize(debounce(recacheHeights, 200));
|
||
};
|
||
|
||
makeToc();
|
||
|
||
window.recacheHeights = recacheHeights;
|
||
window.refreshToc = refreshToc;
|
||
}
|
||
|
||
window.loadToc = loadToc;
|
||
})();
|