|
| 1 | +// https://github.com/ghiculescu/jekyll-table-of-contents |
| 2 | +// share under MIT License |
| 3 | +(function($){ |
| 4 | + $.fn.toc = function(options) { |
| 5 | + var defaults = { |
| 6 | + noBackToTopLinks: false, |
| 7 | + title: '<i>Jump to...</i>', |
| 8 | + minimumHeaders: 3, |
| 9 | + headers: 'h1, h2, h3, h4, h5, h6', |
| 10 | + listType: 'ol', // values: [ol|ul] |
| 11 | + showEffect: 'show', // values: [show|slideDown|fadeIn|none] |
| 12 | + showSpeed: 'slow', // set to 0 to deactivate effect |
| 13 | + classes: { list: '', |
| 14 | + item: '', |
| 15 | + link: '' |
| 16 | + } |
| 17 | + }, |
| 18 | + settings = $.extend(defaults, options); |
| 19 | + |
| 20 | + function fixedEncodeURIComponent (str) { |
| 21 | + return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { |
| 22 | + return '%' + c.charCodeAt(0).toString(16); |
| 23 | + }); |
| 24 | + } |
| 25 | + |
| 26 | + function createLink (header) { |
| 27 | + var innerText = (header.textContent === undefined) ? header.innerText : header.textContent; |
| 28 | + return "<a class='"+settings.classes.link+"' href='#" + fixedEncodeURIComponent(header.id) + "'>" + innerText + "</a>"; |
| 29 | + } |
| 30 | + |
| 31 | + var headers = $(settings.headers).filter(function() { |
| 32 | + // get all headers with an ID |
| 33 | + var previousSiblingName = $(this).prev().attr( "name" ); |
| 34 | + if (!this.id && previousSiblingName) { |
| 35 | + this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") ); |
| 36 | + } |
| 37 | + return this.id; |
| 38 | + }), output = $(this); |
| 39 | + if (!headers.length || headers.length < settings.minimumHeaders || !output.length) { |
| 40 | + $(this).hide(); |
| 41 | + return; |
| 42 | + } |
| 43 | + |
| 44 | + if (0 === settings.showSpeed) { |
| 45 | + settings.showEffect = 'none'; |
| 46 | + } |
| 47 | + |
| 48 | + var render = { |
| 49 | + show: function() { output.hide().html(html).show(settings.showSpeed); }, |
| 50 | + slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); }, |
| 51 | + fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); }, |
| 52 | + none: function() { output.html(html); } |
| 53 | + }; |
| 54 | + |
| 55 | + var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }; |
| 56 | + var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0]; |
| 57 | + var return_to_top = '<i class="icon-arrow-up back-to-top"> </i>'; |
| 58 | + |
| 59 | + var level = get_level(headers[0]), |
| 60 | + this_level, |
| 61 | + html = settings.title + " <" +settings.listType + " class=\"" + settings.classes.list +"\">"; |
| 62 | + headers.on('click', function() { |
| 63 | + if (!settings.noBackToTopLinks) { |
| 64 | + window.location.hash = this.id; |
| 65 | + } |
| 66 | + }) |
| 67 | + .addClass('clickable-header') |
| 68 | + .each(function(_, header) { |
| 69 | + this_level = get_level(header); |
| 70 | + if (!settings.noBackToTopLinks && this_level === highest_level) { |
| 71 | + $(header).addClass('top-level-header').after(return_to_top); |
| 72 | + } |
| 73 | + if (this_level === level) // same level as before; same indenting |
| 74 | + html += "<li class=\"" + settings.classes.item + "\">" + createLink(header); |
| 75 | + else if (this_level <= level){ // higher level than before; end parent ol |
| 76 | + for(var i = this_level; i < level; i++) { |
| 77 | + html += "</li></"+settings.listType+">" |
| 78 | + } |
| 79 | + html += "<li class=\"" + settings.classes.item + "\">" + createLink(header); |
| 80 | + } |
| 81 | + else if (this_level > level) { // lower level than before; expand the previous to contain a ol |
| 82 | + for(i = this_level; i > level; i--) { |
| 83 | + html += "<" + settings.listType + " class=\"" + settings.classes.list +"\">" + |
| 84 | + "<li class=\"" + settings.classes.item + "\">" |
| 85 | + } |
| 86 | + html += createLink(header); |
| 87 | + } |
| 88 | + level = this_level; // update for the next one |
| 89 | + }); |
| 90 | + html += "</"+settings.listType+">"; |
| 91 | + if (!settings.noBackToTopLinks) { |
| 92 | + $(document).on('click', '.back-to-top', function() { |
| 93 | + $(window).scrollTop(0); |
| 94 | + window.location.hash = ''; |
| 95 | + }); |
| 96 | + } |
| 97 | + |
| 98 | + render[settings.showEffect](); |
| 99 | + }; |
| 100 | +})(jQuery); |
0 commit comments