diff --git a/manual/conf.py b/manual/conf.py index f1679b072f..79be525ea3 100644 --- a/manual/conf.py +++ b/manual/conf.py @@ -30,7 +30,7 @@ needs_sphinx = '1.2' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.addons.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'custom', 'sphinx.ext.viewcode'] +extensions = ['sphinx.ext.autodoc', 'custom', 'sidebar_toc', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['templates'] diff --git a/manual/sidebar_toc.py b/manual/sidebar_toc.py new file mode 100644 index 0000000000..b039dfc337 --- /dev/null +++ b/manual/sidebar_toc.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python2 +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +from docutils import nodes +from itertools import count + +id_counter = count() +ID = 'sidebar-collapsible-toc' + +CSS = r''' +ID li { + list-style: none; + margin-left: 0; + padding-left: 0.2em; + text-indent: -0.7em; +} + +ID li.leaf-node { + text-indent: 0; +} + +ID li input[type=checkbox] { + display: none; +} + +ID li > label { + cursor: pointer; +} + +ID li > input[type=checkbox] ~ ul > li { + display: none; +} + +ID li > input[type=checkbox]:checked ~ ul > li { + display: block; +} + +ID li > input[type=checkbox]:checked + label:before { + content: "\025bf"; +} + +ID li > input[type=checkbox]:not(:checked) + label:before { + content: "\025b8"; +} +'''.replace('ID', 'ul#' + ID) + + +class checkbox(nodes.Element): + pass + + +def visit_checkbox(self, node): + cid = node['ids'][0] + node['classes'] = [] + self.body.append('' + ''.format(cid)) + + +def modify_li(li): + if li.first_child_matching_class(nodes.bullet_list) is None: + if not li.get('classes'): + li['classes'] = [] + li['classes'].append('leaf-node') + else: + c = checkbox() + c['ids'] = ['collapse-checkbox-{}'.format(next(id_counter))] + li.insert(0, c) + + +def create_toc(app, pagename): + toctree = app.env.get_toc_for(pagename, app.builder) + if toctree is not None: + subtree = toctree[toctree.first_child_matching_class(nodes.list_item)] + bl = subtree.first_child_matching_class(nodes.bullet_list) + if bl is None: + return # Empty ToC + subtree = subtree[bl] + for li in subtree.traverse(nodes.list_item): + modify_li(li) + subtree['ids'] = [ID] + return '' + app.builder.render_partial( + subtree)['fragment'] + + +def add_html_context(app, pagename, templatename, context, *args): + if 'toc' in context: + context['toc'] = create_toc(app, pagename) or context['toc'] + + +def setup(app): + app.add_node(checkbox, html=(visit_checkbox, lambda *x: None)) + app.connect('html-page-context', add_html_context) diff --git a/manual/templates/localtoc.html b/manual/templates/localtoc.html new file mode 100644 index 0000000000..b47410ee2a --- /dev/null +++ b/manual/templates/localtoc.html @@ -0,0 +1,3 @@ +{%- if display_toc %} + {{ toc }} +{%- endif %}