1. Robert Lehmann
  2. sphinx-sidebar

Commits

Robert Lehmann  committed c3fb035

Added sidebar extension.

  • Participants
  • Parent commits 3f9cc5b
  • Branches default

Comments (0)

Files changed (2)

File sphinx/ext/sidebar.py

View file
+# -*- coding: utf-8 -*-
+"""
+    sphinx.ext.sidebar
+    ~~~~~~~~~~~~~~~~~~
+
+    Build a table of contents HTML document suitable for use as a
+    Mozilla/Netscape sidebar.
+
+    :copyright: Copyright 2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+
+from sphinx.util.console import bold, purple, darkgreen, term_width_line
+
+def env_updated(app, env):
+    """Search the master document for a TOC tree and examine every top-level
+    node ("sections") if it qualifies for a Mozilla panel. Sections are
+    considered fit for inclusion into the sidebar if they have references to
+    other documents in their table of contents (``toctree``) or if
+    *sidebar_all* is set. Individual documents can be excluded by listing them
+    in *sidebar_excludes*.
+
+    """
+    app.info()
+
+    def refuri(node):
+        "Return raw section name, with no anchors or ``.html`` suffix."
+        return node['refuri'].split('#')[0][:-len(app.builder.out_suffix)]
+    def refname(node):
+        "Return canonical section name."
+        name = refuri(node)
+        if name.endswith('/index'):
+            name = name[:-6]
+        return name
+    def issection(node):
+        "Find top-level sections."
+        return isinstance(node, nodes.list_item) and \
+            'toctree-l1' in node['classes']
+
+    tocdoc = env.get_and_resolve_doctree(
+             app.config.master_doc, app.builder, prune_toctrees=False)
+
+    # every section with a TOC has at least:
+    # <compact_paragraph>
+    #   <reference refuri="section.html">Section Title</reference>
+    # <bullet_list>
+    #   <list_item>
+    #   ...
+    # needs to retain order also
+    all_sections = [(node[0][0], node[1]) for node in
+                    tocdoc.traverse(issection) if len(node) == 2]
+    sections = [] # subset of all_sections
+
+    if app.config.sidebar_all:
+        sections = all_sections
+    else:
+        # build only section TOCs which have links to *other* documents
+        # amazingly, this is blazing fast
+        app.info(bold("collecting top-level sections... "), nonl=1)
+        for refnode, chapters in all_sections:
+            ref = refuri(refnode)
+            if refname(refnode) in app.config.sidebar_excludes:
+                continue
+            for chapter in chapters.traverse(nodes.reference):
+                if refuri(chapter) != ref: # inter-document link found
+                    sections.append((refnode, chapters))
+                    break
+        app.info("done", nonl=1) # build process emits newline
+
+    # (refnode, chapters, infile, outfile, title, relname)
+    env.sections = [(ref, chapters, refuri(ref),
+                    'toc-%s' % refname(ref).replace('/', '_'),
+                    ref.astext(),
+                    app.config.sidebar_abbrev.get(refname(ref), refname(ref))
+                   ) for ref, chapters in sections]
+    # section/subsection/index.html ends up in document toc-section_subsection
+
+def page_context(app, pagename, templatename, context, doctree):
+    """Add sidebar rellink to sections."""
+    for _, _, infile, href, _, _ in app.env.sections:
+        if infile == pagename:
+            context['has_sidebar'] = True
+            context['sidebar_uri'] = href
+            if app.config.sidebar_rellink:
+                context['rellinks'].append((href, 'addsidebar', '', 'toc'))
+                context['script_files'].append('_static/sidebar.js')
+            break
+
+def collect_pages(app):
+    """Every section grows its own panel at ``$BUILDDIR/toc-$DOCNAME.html``
+    (with additional preprocessing applied to the document name so as not to
+    end up in a subdirectory).
+
+    TOC trees can be collapsed at a certain depth by setting *sidebar_tocdepth*
+    with 0 meaning no pruning at all.
+
+    All sections are interlinked with each other in the template's relbar and
+    can be assigned individual shorthand names through *sidebar_abbrev*.
+
+    """
+    app.info()
+
+    def needscollapse(node):
+        "Find nodes requiring collapse."
+        return isinstance(node, nodes.list_item) and \
+            len(node) == 2 and \
+            'toctree-l%d' % (app.config.sidebar_tocdepth+1) in node['classes']
+
+    sections = app.env.sections
+    rellinks = [(outfile, title, '', relname)
+                for _, _, _, outfile, title, relname in sections]
+
+    for _, chapters, _, outfile, title, _ in app.builder.status_iterator(
+            sections, "building sidebar tocs... ",
+            lambda data:darkgreen(data[3]), len(sections)):
+        # collapse TOCs at maximum depth
+        for chapter in chapters.traverse(needscollapse):
+            chapter.pop()
+        # build new page
+        ctx = dict(
+            embedded = True,
+            rellinks = rellinks,
+            shorttitle = '',
+            reldelim1 = '&nbsp;',
+            body = "<h1>%s</h1>\n\n%s" % (title,
+                app.builder.render_partial(chapters)['fragment']),
+        )
+        yield outfile, ctx, 'page.html'
+
+    app.info(bold("writing additional files... "), nonl=1)
+
+def setup(app):
+    app.connect('env-updated', env_updated)
+    app.connect('html-page-context', page_context)
+    app.connect('html-collect-pages', collect_pages)
+    app.add_config_value('sidebar_all', False, 'html')
+    app.add_config_value('sidebar_excludes', [], 'html')
+    app.add_config_value('sidebar_rellink', True, 'html')
+    # Those configuration values /really/ taint the HTML build process but
+    # ordinary documents need not be rebuilt.
+    app.add_config_value('sidebar_abbrev', {}, None) # docname -> rellink
+    app.add_config_value('sidebar_tocdepth', 2, None)

File sphinx/themes/basic/sidebar.js

View file
+$(document).ready(function() {
+  if ((typeof window.sidebar == "object") && (typeof window.sidebar.addPanel == "function")) {
+    $('a[title=addsidebar]').click(function(event) {
+      event.preventDefault();
+      window.sidebar.addPanel("Python Sidebar", this.href, "");
+    });
+  }
+});