Add an automatic TOC to pages that don't have no_toc in front-matter

This commit is contained in:
Misty Stanley-Jones 2017-01-30 15:34:25 -08:00
parent b547d91606
commit 8d3145ff3b
7 changed files with 150 additions and 115 deletions

View File

@ -5,6 +5,7 @@ kramdown:
html_to_native: true
hard_wrap: false
syntax_highlighter: rouge
toc_levels: 2..3
incremental: true
permalink: pretty
safe: false
@ -29,6 +30,8 @@ defaults:
layout: docs
defaultassignee: johndmulhausen
enginebranch: 1.13.x
toc_min: 2
toc_max: 3
- scope:
path: "compose"
values:

View File

@ -0,0 +1,70 @@
{% capture tocWorkspace %}
{% comment %}
"...like all things liquid - where there's a will, and ~36 hours to spare, there's usually a/some way" ~jaybe
Usage:
{% include toc_pure_liquid.html html=content sanitize=true class="inline_toc" id="my_toc" toc_min=2 toc_max=3 my_name="unnamed" %}
Variables:
* html (string) - the HTML of compiled markdown generated by kramdown in Jekyll
* sanitize (bool) - when set to true, the headers will be sanitized in the TOC
* class (string) - a CSS class assigned to the TOC
* id (string) - an ID to assigned to the TOC
* toc_min (int) - the minimum TOC header level to use (if not set, check page, then site, then default to 2)
* toc_max (int) - the maximum TOC header level to use (if not set, check page, then site, then default to 3)
* page_name (string) - the URL of the page
Output:
An unordered list representing the table of contents of a markdown block. This snippet will only generate the table of contents and will NOT output the markdown given to it
{% endcomment %}
{% capture my_toc %}{% endcapture %}
{% assign minHeader = include.toc_min | default: 2 %}
{% assign maxHeader = include.toc_max | default: 3 %}
{% assign my_name = include.page_name | default: "unnamed" %}
{% assign nodes = include.html | split: '<h' %}
{% for node in nodes %}
{% if node == "" %}
{% continue %}
{% endif %}
{% assign headerLevel = node | replace: '"', '' | slice: 0, 1 %}
{% assign headerLevel = headerLevel | times: 1 %}
{% assign indentAmount = headerLevel | minus: minHeader | add: 1 %}
{% assign _workspace = node | split: '</h' %}
{% unless headerLevel >= minHeader %}
{% continue %}
{% endunless %}
{% if headerLevel > maxHeader %}
{% continue %}
{% endif %}
{% assign _idWorkspace = _workspace[0] | split: '"' %}
{% assign html_id = _idWorkspace[1] %}
{% capture _hAttrToStrip %}{{ headerLevel }} id="{{ html_id }}">{% endcapture %}
{% assign header = _workspace[0] | replace: _hAttrToStrip, '' %}
{% assign space = '' %}
{% for i in (1..indentAmount) %}
{% assign space = space | prepend: ' ' %}
{% endfor %}
{% capture my_toc %}{{ my_toc }}
{{ space }}- [{% if include.sanitize %}{{ header | strip_html }}{% else %}{{ header }}{% endif %}]({{ my_name }}#{{ html_id }}){: class="nomunge" }{% endcapture %}
{% endfor %}
{% if include.class %}
{% capture my_toc %}{:.{{ include.class }}}
{{ my_toc | lstrip }}{% endcapture %}
{% endif %}
{% if include.id %}
{% capture my_toc %}{: #{{ include.id }}}
{{ my_toc | lstrip }}{% endcapture %}
{% endif %}
{% endcapture %}{% assign tocWorkspace = '' %}
{{ my_toc | markdownify }}

View File

@ -201,12 +201,12 @@ ng\:form {
</ul>
</div>
</div>
<div {% if page.notoc %} class="col-xs-12 col-sm-9 col-md-10" {% else %} class="col-xs-12 col-sm-9 col-md-8 col-xl-9" {% endif %} >
<div class="col-xs-12 col-sm-9 col-md-8 col-xl-9">
<section class="section" id="DocumentationText">
{% if page.title %}<h1>{{ page.title }}</h1>{% endif %}
{% if page.advisory %}<blockquote style="border-left: 6px solid #FFD601; background: -webkit-gradient(linear, left top, left bottom, from(#FBFCFC), to(#EBEDEF));">{{ site.data.advisories.texts[page.advisory] | markdownify }}</blockquote>{% endif %}
{% include read_time.html %}
{{ content }}
{{ content }}
{% if page.noratings != true %}
<div style="text-align: center; margin-top: 50px">
<img src="/images/chat.png" alt="chat icon" style="margin-right: 10px">
@ -252,26 +252,34 @@ ng\:form {
}
</script>
</div>
{% if page.notoc != true %}
<div class="hidden-xs hidden-sm col-md-2 col-xl-1 tableofcontents_section">
<section class="section" id="TableOfContentsSection">
<div class="hidden-xs hidden-sm col-md-2 col-xl-1 right_column_section">
<section class="section" id="RightColumnSection">
<span class="title_section">
<form class="search-form form-inline ng-pristine ng-valid" id="searchForm" action="/search/">
<div id="search-div">
<form class="search-form form-inline ng-pristine ng-valid" id="searchForm" action="/search/">
<input class="search-field form-control ds-input" id="st-search-input" value="" name="q" placeholder="Search the docs" type="search" autocomplete="off" spellcheck="false" dir="auto" style="position: relative; vertical-align: top;">
<div id="autocompleteContainer">
<div id="autocompleteResults"></div>
</div>
<button type="submit" class="search-submit btn btn-default">Search</button>
</form>
<button type="submit" class="search-submit btn btn-default">Search</button>
</form>
</div>
</span>
{% if edit_url != "" %}
<span><a href="{{ edit_url }}" class="button darkblue-btn nomunge" style="color:#FFFFFF; width:100%; margin: 0px;">Edit This Page</a></span>
{% endif %}
<nav id="TableOfContents">
</nav>
<div id="feedback-links">
<ul>
{% if edit_url != "" %}<li><a href="{{ edit_url }}">&#9998;&nbsp;Edit this page</a></li>{% endif %}
<li><a href="https://github.com/docker/docker.github.io/issues/new?title=Feedback for: {{ page.path }}&assignee={% if page.assignee %}{{ page.assignee }}{% else %}{{ page.defaultassignee }}{% endif %}&body=File: [{{ page.path }}](https://docs.docker.com{{ page.url }})" class="nomunge">&#10003;&nbsp;Request docs changes</a></li>
<li><a href="https://www.docker.com/docker-support-services">&#x0003F;&nbsp;Get support</a></li>
</ul>
</div>
{% unless page.notoc %}
{% assign my_min = page.toc_min | default: site.toc_min | default: 2 %}
{% assign my_max = page.toc_max | default: site.toc_max | default: 3 %}
{% assign my_name = page.url | default: "unnamed" %}
<div id="side-toc"><div id="side-toc-title">On this page:</div><div id="side-toc-contents">{% include toc_pure_liquid.html html=content sanitize=true class="inline_toc" id="my_toc" toc_min=my_min toc_max=my_max page_name=my_name %}</div></div>
{% endunless %}
</section>
</div>
{% endif %}<!-- end check for notoc != true -->
</div>
</div>
</div>

View File

@ -131,9 +131,10 @@
color: black;
}
#DocumentationText a,
#TableOfContentsSection a {
#RightColumnSection a {
color: #008AB5;
}
/* reset away from #008AB5 */
/* removed hard-coded color for button links pre new CSS from Design */
@ -303,7 +304,7 @@ div.docsidebarnav_section.affix ul {
}
/* TableOfContents */
.tableofcontents_section {
.right_column_section {
padding: 0;
}
.rating-msg {
@ -316,55 +317,15 @@ div.docsidebarnav_section.affix ul {
display: none !important;
}
#TableOfContents {
padding-top: 10px;
}
#TableOfContentsSection {
margin: 0;
#RightColumnSection {
padding: 0 !important;
background-color: #f5fdff;
}
#TableOfContents li a,
#TableOfContentsSection .heading {
font-size: 14px;
font-style: normal;
margin: 0;
padding: 10px 15px;
display: block !important;
line-height: 15px;
}
#TableOfContentsSection .heading {
background-color: #6db9d1;
color: #ffffff;
}
#TableOfContentsSection #TableOfContents {
background-color: #F5FDFF;
margin: 0;
padding: 15px;
}
#TableOfContentsSection #TableOfContents ul {
list-style: none;
padding: 0;
left: 0;
padding: 0;
width: 100%;
text-align: left;
overflow: hidden;
margin-left: 0;
padding-left: 0.30rem;
font-size: 14px;
}
#TableOfContentsSection #TableOfContents > ul {
padding-left: 0;
#RightColumnSection ul {
padding-top: 5px;
list-style: none;
margin-left: 0;
}
#TableOfContentsSection #TableOfContents > ul > li > ul {
padding-left: 0;
}
.advisory {
color: #F04124;
margin: -20px -20px 20px -20px;
@ -388,7 +349,6 @@ color: #F04124;
}
.search-form .algolia-autocomplete .search-field, #st-search-input {
width: 100%;
border: 1px solid lightgray;
}
.search-form{
max-width: 420px;
@ -451,3 +411,49 @@ span.reading-time-label {
img.with-border {
border: 1px solid #eaeaea;
}
#search-div {
margin-top: 10px;
border: 1px solid #2294ca;
}
#side-toc {
background-color: #f5fdff;
border: 1px solid #2294ca;
padding: 10px;
margin-top: 20px;
width: 100%;
}
#feedback-links {
border: 1px solid #2294ca;
padding: 10px;
margin-top: 20px;
width: 100%;
}
#side-toc-contents,
#feedback-links {
list-style-type: none;
font-size: 80%;
}
#side-toc-contents ul,
#feedback-links ul {
margin-bottom: 0;
}
#side-toc-contents li {
padding-bottom: 7px;
padding-top: 7px;
line-height: 1!important;
}
#side-toc-contents ul ul li {
padding-left: 14px;
}
#side-toc-title {
font-weight: bolder;
font-size: 90%;
color: #155A74;
padding-bottom: 5px;
}

View File

@ -8,11 +8,6 @@ title: Post-installation steps for Linux
This section contains optional procedures for configuring Linux hosts to work
better with Docker.
* [Manage Docker as a non-root user](#manage-docker-as-a-non-root-user)
* [Configure Docker to start on boot](#configure-docker-to-start-on-boot)
* [Allow access to the remote API through a firewall](#allow-access-to-the-remote-api-through-a-firewall)
* [Troubleshooting](#troubleshooting)
## Manage Docker as a non-root user
The `docker` daemon binds to a Unix socket instead of a TCP port. By default
@ -213,7 +208,7 @@ at `/etc/docker/daemon.json`.
2. Add a `dns` key with one or more IP addresses as values. If the file has
existing contents, you only need to add or edit the `dns` line.
```json
{
"dns": ["8.8.8.8", "8.8.4.4"]

View File

@ -3,6 +3,7 @@ description: Home page for Docker's documentation
keywords: Docker, documentation, manual, guide, reference, api
layout: docs
title: Docker Documentation
notoc: true
---
Docker packages your app with its dependencies, freeing you from worrying about your

View File

@ -199,52 +199,4 @@ jQuery(document).ready(function(){
metadata = data;
hookupTOCEvents();
});
$("#TableOfContents ul").empty();
var prevH2Item = null;
var prevH2List = null;
var index = 0;
var currentHeader = 0, lastHeader = 0;
var output = "<ul>";
$("h1, h2, h3, h4").each(function() {
var li= "<li><a href='" + window.location + "#" + $(this).attr('id') + "'>" + $(this).text().replace("¶","") + "</a></li>";
if( $(this).is("h2") ){
// h2
currentHeader = 2;
} else if( $(this).is("h3") ){
// h3
currentHeader = 3;
} else if( $(this).is("h4") ) {
// h4
currentHeader = 4;
}
//console.log("currentHeader ",currentHeader, "lastHeader ",lastHeader, "text ", $(this).text());
if (currentHeader > lastHeader) {
// nest further
output += "<ul>"
}
if (currentHeader < lastHeader && lastHeader > 0) {
// close nesting
//console.log("Closing nesting because ", lastHeader, "is <", currentHeader);
for (i=0; i < (lastHeader - currentHeader); i++)
{
output += "</ul>"
}
}
output += li;
lastHeader = currentHeader;
/*
if( $(this).is("h2") ){
prevH2List = $("<ul></ul>");
prevH2Item = $(li);
prevH2Item.append(prevH2List);
prevH2Item.appendTo("#TableOfContents ul");
} else {
prevH2List.append(li);
}
index++;*/
});
output += "</ul>";
$("#TableOfContents").html(output);
});