├── .gitignore ├── LICENSE.txt ├── toc.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Alex Ghiculescu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /toc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/ghiculescu/jekyll-table-of-contents 2 | (function($){ 3 | $.fn.toc = function(options) { 4 | var defaults = { 5 | noBackToTopLinks: false, 6 | title: 'Jump to...', 7 | minimumHeaders: 3, 8 | headers: 'h1, h2, h3, h4, h5, h6', 9 | listType: 'ol', // values: [ol|ul] 10 | showEffect: 'show', // values: [show|slideDown|fadeIn|none] 11 | showSpeed: 'slow', // set to 0 to deactivate effect 12 | classes: { list: '', 13 | item: '', 14 | link: '' 15 | } 16 | }, 17 | settings = $.extend(defaults, options); 18 | 19 | function fixedEncodeURIComponent (str) { 20 | return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { 21 | return '%' + c.charCodeAt(0).toString(16); 22 | }); 23 | } 24 | 25 | function createLink (header) { 26 | var innerText = (header.textContent === undefined) ? header.innerText : header.textContent; 27 | return "" + innerText + ""; 28 | } 29 | 30 | var headers = $(settings.headers).filter(function() { 31 | // get all headers with an ID 32 | var previousSiblingName = $(this).prev().attr( "name" ); 33 | if (!this.id && previousSiblingName) { 34 | this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") ); 35 | } 36 | return this.id; 37 | }), output = $(this); 38 | if (!headers.length || headers.length < settings.minimumHeaders || !output.length) { 39 | $(this).hide(); 40 | return; 41 | } 42 | 43 | if (0 === settings.showSpeed) { 44 | settings.showEffect = 'none'; 45 | } 46 | 47 | var render = { 48 | show: function() { output.hide().html(html).show(settings.showSpeed); }, 49 | slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); }, 50 | fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); }, 51 | none: function() { output.html(html); } 52 | }; 53 | 54 | var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }; 55 | var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0]; 56 | var return_to_top = ' '; 57 | 58 | var level = get_level(headers[0]), 59 | this_level, 60 | html = settings.title + " <" +settings.listType + " class=\"" + settings.classes.list +"\">"; 61 | headers.on('click', function() { 62 | if (!settings.noBackToTopLinks) { 63 | window.location.hash = this.id; 64 | } 65 | }) 66 | .addClass('clickable-header') 67 | .each(function(_, header) { 68 | this_level = get_level(header); 69 | if (!settings.noBackToTopLinks && this_level === highest_level) { 70 | $(header).addClass('top-level-header').after(return_to_top); 71 | } 72 | if (this_level === level) // same level as before; same indenting 73 | html += "
  • " + createLink(header); 74 | else if (this_level <= level){ // higher level than before; end parent ol 75 | for(var i = this_level; i < level; i++) { 76 | html += "
  • " 77 | } 78 | html += "
  • " + createLink(header); 79 | } 80 | else if (this_level > level) { // lower level than before; expand the previous to contain a ol 81 | for(i = this_level; i > level; i--) { 82 | html += "<" + settings.listType + " class=\"" + settings.classes.list +"\">" + 83 | "
  • " 84 | } 85 | html += createLink(header); 86 | } 87 | level = this_level; // update for the next one 88 | }); 89 | html += ""; 90 | if (!settings.noBackToTopLinks) { 91 | $(document).on('click', '.back-to-top', function() { 92 | $(window).scrollTop(0); 93 | window.location.hash = ''; 94 | }); 95 | } 96 | 97 | render[settings.showEffect](); 98 | }; 99 | })(jQuery); 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jekyll-table-of-contents 2 | 3 | A simple JavaScript table of contents generator. Works well with [jekyll](https://github.com/mojombo/jekyll) static sites. 4 | 5 | ## Usage 6 | 7 | ### Basic Usage 8 | 9 | The script requires jQuery. First, reference `toc.js` in templates where you would like to add the table of content. 10 | Then, create an HTML element wherever you want your table of contents to appear: 11 | 12 | ```html 13 |
    14 | ``` 15 | 16 | Finally, call the `.toc()` function when the DOM is ready: 17 | 18 | ```html 19 | 24 | ``` 25 | 26 | If you use redcarpet, you need to have the option `with_toc_data` in order to add HTML anchors to each header: 27 | ```yaml 28 | markdown: redcarpet 29 | redcarpet: 30 | extensions: [with_toc_data] 31 | ``` 32 | 33 | If you use rdiscount, enable the following option in order to generate the TOC: 34 | ```yaml 35 | markdown: rdiscount 36 | rdiscount: 37 | extensions: 38 | - generate_toc 39 | ``` 40 | 41 | ### How It Works 42 | 43 | The script works by looking for headers (h1, h2, h3, h4, h5, h6) which have an `id`. 44 | An id is added automatically if you're using Jekyll and [Markdown](http://daringfireball.net/projects/markdown/syntax#header). 45 | 46 | The table of contents automatically handles nesting of headers. For example, this Markdown post: 47 | 48 | ## Title 49 | ## Page 1 50 | ### Note on Paragraph 3 51 | ## Page 2 52 | ### Note on Paragraph 2 53 | ### Note on Paragraph 4 54 | 55 | Will render this table of contents: 56 | 57 | 1. Title 58 | 2. Page 1 59 | a. Note on Paragraph 3 60 | 3. Page 2 61 | a. Note on Paragraph 2 62 | b. Note on Paragraph 4 63 | 64 | ### Configuration 65 | 66 | #### List Type 67 | By default the table of contents is rendered as an `
      `, so you can change the number formatting using CSS. 68 | However you can use the `