diff options
| author | Marak <[email protected]> | 2016-03-03 04:38:00 -0500 |
|---|---|---|
| committer | Marak <[email protected]> | 2016-03-03 04:38:00 -0500 |
| commit | aff89dcfbf8611473a1dabb6a6cb1ad17ae34d47 (patch) | |
| tree | 301a4d899c0c49af0e4e1b859342a740c5158bf2 /doc/scripts/toc.js | |
| parent | c252feb52e896f153fd969377532d77777903d69 (diff) | |
| download | faker-aff89dcfbf8611473a1dabb6a6cb1ad17ae34d47.tar.xz faker-aff89dcfbf8611473a1dabb6a6cb1ad17ae34d47.zip | |
[dist] Check /docs back into git #350
Diffstat (limited to 'doc/scripts/toc.js')
| -rw-r--r-- | doc/scripts/toc.js | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/doc/scripts/toc.js b/doc/scripts/toc.js new file mode 100644 index 00000000..e5151284 --- /dev/null +++ b/doc/scripts/toc.js @@ -0,0 +1,203 @@ +(function($) { + var navbarHeight; + var initialised = false; + var navbarOffset; + + function elOffset($el) { + return $el.offset().top - (navbarHeight + navbarOffset); + } + + function scrollToHash(duringPageLoad) { + var elScrollToId = location.hash.replace(/^#/, ''); + var $el; + + function doScroll() { + var offsetTop = elOffset($el); + window.scrollTo(window.pageXOffset || window.scrollX, offsetTop); + } + + if (elScrollToId) { + $el = $(document.getElementById(elScrollToId)); + + if (!$el.length) { + $el = $(document.getElementsByName(elScrollToId)); + } + + if ($el.length) { + if (duringPageLoad) { + $(window).one('scroll', function() { + setTimeout(doScroll, 100); + }); + } else { + setTimeout(doScroll, 0); + } + } + } + } + + function init(opts) { + if (initialised) { + return; + } + initialised = true; + navbarHeight = $('.navbar').height(); + navbarOffset = opts.navbarOffset; + + // some browsers move the offset after changing location. + // also catch external links coming in + $(window).on("hashchange", scrollToHash.bind(null, false)); + $(scrollToHash.bind(null, true)); + } + + $.catchAnchorLinks = function(options) { + var opts = $.extend({}, jQuery.fn.toc.defaults, options); + init(opts); + }; + + $.fn.toc = function(options) { + var self = this; + var opts = $.extend({}, jQuery.fn.toc.defaults, options); + + var container = $(opts.container); + var tocs = []; + var headings = $(opts.selectors, container); + var headingOffsets = []; + var activeClassName = 'active'; + var ANCHOR_PREFIX = "__anchor"; + var maxScrollTo; + var visibleHeight; + var headerHeight = 10; // so if the header is readable, its counted as shown + init(); + + var scrollTo = function(e) { + e.preventDefault(); + var target = $(e.target); + if (target.prop('tagName').toLowerCase() !== "a") { + target = target.parent(); + } + var elScrollToId = target.attr('href').replace(/^#/, '') + ANCHOR_PREFIX; + var $el = $(document.getElementById(elScrollToId)); + + var offsetTop = Math.min(maxScrollTo, elOffset($el)); + + $('body,html').animate({ scrollTop: offsetTop }, 400, 'swing', function() { + location.hash = '#' + elScrollToId; + }); + + $('a', self).removeClass(activeClassName); + target.addClass(activeClassName); + }; + + var calcHadingOffsets = function() { + maxScrollTo = $("body").height() - $(window).height(); + visibleHeight = $(window).height() - navbarHeight; + headingOffsets = []; + headings.each(function(i, heading) { + var anchorSpan = $(heading).prev("span"); + var top = 0; + if (anchorSpan.length) { + top = elOffset(anchorSpan); + } + headingOffsets.push(top > 0 ? top : 0); + }); + } + + //highlight on scroll + var timeout; + var highlightOnScroll = function(e) { + if (!tocs.length) { + return; + } + if (timeout) { + clearTimeout(timeout); + } + timeout = setTimeout(function() { + var top = $(window).scrollTop(), + highlighted; + for (var i = headingOffsets.length - 1; i >= 0; i--) { + var isActive = tocs[i].hasClass(activeClassName); + // at the end of the page, allow any shown header + if (isActive && headingOffsets[i] >= maxScrollTo && top >= maxScrollTo) { + return; + } + // if we have got to the first heading or the heading is the first one visible + if (i === 0 || (headingOffsets[i] + headerHeight >= top && (headingOffsets[i - 1] + headerHeight <= top))) { + // in the case that a heading takes up more than the visible height e.g. we are showing + // only the one above, highlight the one above + if (i > 0 && headingOffsets[i] - visibleHeight >= top) { + i--; + } + $('a', self).removeClass(activeClassName); + if (i >= 0) { + highlighted = tocs[i].addClass(activeClassName); + opts.onHighlight(highlighted); + } + break; + } + } + }, 50); + }; + if (opts.highlightOnScroll) { + $(window).bind('scroll', highlightOnScroll); + $(window).bind('load resize', function() { + calcHadingOffsets(); + highlightOnScroll(); + }); + } + + return this.each(function() { + //build TOC + var el = $(this); + var ul = $('<div class="list-group">'); + + headings.each(function(i, heading) { + var $h = $(heading); + + var anchor = $('<span/>').attr('id', opts.anchorName(i, heading, opts.prefix) + ANCHOR_PREFIX).insertBefore($h); + + var span = $('<span/>') + .text(opts.headerText(i, heading, $h)); + + //build TOC item + var a = $('<a class="list-group-item"/>') + .append(span) + .attr('href', '#' + opts.anchorName(i, heading, opts.prefix)) + .bind('click', function(e) { + scrollTo(e); + el.trigger('selected', $(this).attr('href')); + }); + + span.addClass(opts.itemClass(i, heading, $h, opts.prefix)); + + tocs.push(a); + + ul.append(a); + }); + el.html(ul); + + calcHadingOffsets(); + }); +}; + + +jQuery.fn.toc.defaults = { + container: 'body', + selectors: 'h1,h2,h3', + smoothScrolling: true, + prefix: 'toc', + onHighlight: function() {}, + highlightOnScroll: true, + navbarOffset: 0, + anchorName: function(i, heading, prefix) { + return prefix+i; + }, + headerText: function(i, heading, $heading) { + return $heading.text(); + }, + itemClass: function(i, heading, $heading, prefix) { + return prefix + '-' + $heading[0].tagName.toLowerCase(); + } + +}; + +})(jQuery); |
