|
| 1 | +{% capture tocWorkspace %} |
| 2 | + {% comment %} |
| 3 | + Copyright (c) 2017 Vladimir "allejo" Jimenez |
| 4 | + |
| 5 | + Permission is hereby granted, free of charge, to any person |
| 6 | + obtaining a copy of this software and associated documentation |
| 7 | + files (the "Software"), to deal in the Software without |
| 8 | + restriction, including without limitation the rights to use, |
| 9 | + copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | + copies of the Software, and to permit persons to whom the |
| 11 | + Software is furnished to do so, subject to the following |
| 12 | + conditions: |
| 13 | + |
| 14 | + The above copyright notice and this permission notice shall be |
| 15 | + included in all copies or substantial portions of the Software. |
| 16 | + |
| 17 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 18 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| 19 | + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 20 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 21 | + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 22 | + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 23 | + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 24 | + OTHER DEALINGS IN THE SOFTWARE. |
| 25 | + {% endcomment %} |
| 26 | + {% comment %} |
| 27 | + Version 1.2.1 |
| 28 | + https://github.com/allejo/jekyll-toc |
| 29 | + |
| 30 | + "...like all things liquid - where there's a will, and ~36 hours to spare, there's usually a/some way" ~jaybe |
| 31 | + |
| 32 | + Usage: |
| 33 | + {% include toc.html html=content sanitize=true class="inline_toc" id="my_toc" h_min=2 h_max=3 %} |
| 34 | + |
| 35 | + Parameters: |
| 36 | + * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll |
| 37 | + |
| 38 | + Optional Parameters: |
| 39 | + * sanitize (bool) : false - when set to true, the headers will be stripped of any HTML in the TOC |
| 40 | + * class (string) : '' - a CSS class assigned to the TOC |
| 41 | + * id (string) : '' - an ID to assigned to the TOC |
| 42 | + * h_min (int) : 1 - the minimum TOC header level to use; any header lower than this value will be ignored |
| 43 | + * h_max (int) : 6 - the maximum TOC header level to use; any header greater than this value will be ignored |
| 44 | + * ordered (bool) : false - when set to true, an ordered list will be outputted instead of an unordered list |
| 45 | + * item_class (string) : '' - add custom class(es) for each list item; has support for '%level%' placeholder, which is the current heading level |
| 46 | + * submenu_class (string) : '' - add custom class(es) for each child group of headings; has support for '%level%' placeholder which is the current "submenu" heading level |
| 47 | + * base_url (string) : '' - add a base url to the TOC links for when your TOC is on another page than the actual content |
| 48 | + * anchor_class (string) : '' - add custom class(es) for each anchor element |
| 49 | + * skip_no_ids (bool) : false - skip headers that do not have an `id` attribute |
| 50 | + * flat_toc (bool) : false - when set to true, the TOC will be a single level list |
| 51 | + |
| 52 | + Output: |
| 53 | + An ordered or unordered list representing the table of contents of a markdown block. This snippet will only |
| 54 | + generate the table of contents and will NOT output the markdown given to it |
| 55 | + {% endcomment %} |
| 56 | + |
| 57 | + {% capture newline %} |
| 58 | + {% endcapture %} |
| 59 | + {% assign newline = newline | rstrip %} <!-- Remove the extra spacing but preserve the newline --> |
| 60 | + |
| 61 | + {% capture deprecation_warnings %}{% endcapture %} |
| 62 | + |
| 63 | + {% if include.baseurl %} |
| 64 | + {% capture deprecation_warnings %}{{ deprecation_warnings }}<!-- jekyll-toc :: "baseurl" has been deprecated, use "base_url" instead -->{{ newline }}{% endcapture %} |
| 65 | + {% endif %} |
| 66 | + |
| 67 | + {% if include.skipNoIDs %} |
| 68 | + {% capture deprecation_warnings %}{{ deprecation_warnings }}<!-- jekyll-toc :: "skipNoIDs" has been deprecated, use "skip_no_ids" instead -->{{ newline }}{% endcapture %} |
| 69 | + {% endif %} |
| 70 | + |
| 71 | + {% capture jekyll_toc %}{% endcapture %} |
| 72 | + {% assign orderedList = include.ordered | default: false %} |
| 73 | + {% assign flatToc = include.flat_toc | default: false %} |
| 74 | + {% assign baseURL = include.base_url | default: include.baseurl | default: '' %} |
| 75 | + {% assign skipNoIDs = include.skip_no_ids | default: include.skipNoIDs | default: false %} |
| 76 | + {% assign minHeader = include.h_min | default: 1 %} |
| 77 | + {% assign maxHeader = include.h_max | default: 6 %} |
| 78 | + {% assign nodes = include.html | strip | split: '<h' %} |
| 79 | + |
| 80 | + {% assign firstHeader = true %} |
| 81 | + {% assign currLevel = 0 %} |
| 82 | + {% assign lastLevel = 0 %} |
| 83 | + |
| 84 | + {% capture listModifier %}{% if orderedList %}ol{% else %}ul{% endif %}{% endcapture %} |
| 85 | + |
| 86 | + {% for node in nodes %} |
| 87 | + {% if node == "" %} |
| 88 | + {% continue %} |
| 89 | + {% endif %} |
| 90 | + |
| 91 | + {% assign currLevel = node | replace: '"', '' | slice: 0, 1 | times: 1 %} |
| 92 | + |
| 93 | + {% if currLevel < minHeader or currLevel > maxHeader %} |
| 94 | + {% continue %} |
| 95 | + {% endif %} |
| 96 | + |
| 97 | + {% assign _workspace = node | split: '</h' %} |
| 98 | + |
| 99 | + {% assign _idWorkspace = _workspace[0] | split: 'id="' %} |
| 100 | + {% assign _idWorkspace = _idWorkspace[1] | split: '"' %} |
| 101 | + {% assign htmlID = _idWorkspace[0] %} |
| 102 | + |
| 103 | + {% assign _classWorkspace = _workspace[0] | split: 'class="' %} |
| 104 | + {% assign _classWorkspace = _classWorkspace[1] | split: '"' %} |
| 105 | + {% assign htmlClass = _classWorkspace[0] %} |
| 106 | + |
| 107 | + {% if htmlClass contains "no_toc" %} |
| 108 | + {% continue %} |
| 109 | + {% endif %} |
| 110 | + |
| 111 | + {% if firstHeader %} |
| 112 | + {% assign minHeader = currLevel %} |
| 113 | + {% endif %} |
| 114 | + |
| 115 | + {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %} |
| 116 | + {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} |
| 117 | + |
| 118 | + {% if include.item_class and include.item_class != blank %} |
| 119 | + {% capture listItemClass %} class="{{ include.item_class | replace: '%level%', currLevel | split: '.' | join: ' ' }}"{% endcapture %} |
| 120 | + {% endif %} |
| 121 | + |
| 122 | + {% if include.submenu_class and include.submenu_class != blank %} |
| 123 | + {% assign subMenuLevel = currLevel | minus: 1 %} |
| 124 | + {% capture subMenuClass %} class="{{ include.submenu_class | replace: '%level%', subMenuLevel | split: '.' | join: ' ' }}"{% endcapture %} |
| 125 | + {% endif %} |
| 126 | + |
| 127 | + {% capture anchorBody %}{% if include.sanitize %}{{ header | strip_html }}{% else %}{{ header }}{% endif %}{% endcapture %} |
| 128 | + |
| 129 | + {% if htmlID %} |
| 130 | + {% capture anchorAttributes %} href="{% if baseURL %}{{ baseURL }}{% endif %}#{{ htmlID }}"{% endcapture %} |
| 131 | + |
| 132 | + {% if include.anchor_class %} |
| 133 | + {% capture anchorAttributes %}{{ anchorAttributes }} class="{{ include.anchor_class | split: '.' | join: ' ' }}"{% endcapture %} |
| 134 | + {% endif %} |
| 135 | + |
| 136 | + {% capture listItem %}<a{{ anchorAttributes }}>{{ anchorBody }}</a>{% endcapture %} |
| 137 | + {% elsif skipNoIDs == true %} |
| 138 | + {% continue %} |
| 139 | + {% else %} |
| 140 | + {% capture listItem %}{{ anchorBody }}{% endcapture %} |
| 141 | + {% endif %} |
| 142 | + |
| 143 | + {% if currLevel > lastLevel and flatToc == false %} |
| 144 | + {% capture jekyll_toc %}{{ jekyll_toc }}<{{ listModifier }}{{ subMenuClass }}>{% endcapture %} |
| 145 | + {% elsif currLevel < lastLevel and flatToc == false %} |
| 146 | + {% assign repeatCount = lastLevel | minus: currLevel %} |
| 147 | + |
| 148 | + {% for i in (1..repeatCount) %} |
| 149 | + {% capture jekyll_toc %}{{ jekyll_toc }}</li></{{ listModifier }}>{% endcapture %} |
| 150 | + {% endfor %} |
| 151 | + |
| 152 | + {% capture jekyll_toc %}{{ jekyll_toc }}</li>{% endcapture %} |
| 153 | + {% else %} |
| 154 | + {% capture jekyll_toc %}{{ jekyll_toc }}</li>{% endcapture %} |
| 155 | + {% endif %} |
| 156 | + |
| 157 | + {% capture jekyll_toc %}{{ jekyll_toc }}<li{{ listItemClass }}>{{ listItem }}{% endcapture %} |
| 158 | + |
| 159 | + {% assign lastLevel = currLevel %} |
| 160 | + {% assign firstHeader = false %} |
| 161 | + {% endfor %} |
| 162 | + |
| 163 | + {% if flatToc == true %} |
| 164 | + {% assign repeatCount = 1 %} |
| 165 | + {% else %} |
| 166 | + {% assign repeatCount = minHeader | minus: 1 %} |
| 167 | + {% assign repeatCount = lastLevel | minus: repeatCount %} |
| 168 | + {% endif %} |
| 169 | + |
| 170 | + {% for i in (1..repeatCount) %} |
| 171 | + {% capture jekyll_toc %}{{ jekyll_toc }}</li></{{ listModifier }}>{% endcapture %} |
| 172 | + {% endfor %} |
| 173 | + |
| 174 | + {% if jekyll_toc != '' %} |
| 175 | + {% assign rootAttributes = '' %} |
| 176 | + {% if include.class and include.class != blank %} |
| 177 | + {% capture rootAttributes %} class="{{ include.class | split: '.' | join: ' ' }}"{% endcapture %} |
| 178 | + {% endif %} |
| 179 | + |
| 180 | + {% if include.id and include.id != blank %} |
| 181 | + {% capture rootAttributes %}{{ rootAttributes }} id="{{ include.id }}"{% endcapture %} |
| 182 | + {% endif %} |
| 183 | + |
| 184 | + {% if rootAttributes %} |
| 185 | + {% assign nodes = jekyll_toc | split: '>' %} |
| 186 | + {% capture jekyll_toc %}<{{ listModifier }}{{ rootAttributes }}>{{ nodes | shift | join: '>' }}>{% endcapture %} |
| 187 | + {% endif %} |
| 188 | + {% endif %} |
| 189 | +{% endcapture %}{% assign tocWorkspace = '' %}{{ deprecation_warnings }}{{ jekyll_toc -}} |
0 commit comments