Commits

Anonymous committed c604e42

Add html-page-context event for customizing the template context.

Comments (0)

Files changed (7)

 * Defaults for configuration values can now be callables, which allows
   dynamic defaults.
 
+* The new ``html-page-context`` event can be used to include custom values
+  into the context used when rendering an HTML template.
+
+* Add document metadata to the values in the default template context.
+
 Bugs fixed
 ----------
 
     return sig
 
 
+event_sig_re = re.compile(r'([a-zA-Z-]+)\s*\((.*)\)')
+
+def parse_event(env, sig, signode):
+    m = event_sig_re.match(sig)
+    if not m:
+        signode += addnodes.desc_name(sig, sig)
+        return sig
+    name, args = m.groups()
+    signode += addnodes.desc_name(name, name)
+    plist = addnodes.desc_parameterlist()
+    for arg in args.split(','):
+        arg = arg.strip()
+        plist += addnodes.desc_parameter(arg, arg)
+    signode += plist
+    return name
+
+
 def setup(app):
     app.add_description_unit('directive', 'dir', 'pair: %s; directive', parse_directive)
     app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
     app.add_description_unit('confval', 'confval', 'pair: %s; configuration value')
+    app.add_description_unit('event', 'event', 'pair: %s; event', parse_event)

doc/ext/appapi.rst

 Sphinx core events
 ------------------
 
-These events are known to the core:
+These events are known to the core.  The arguments showed are given to the
+registered event handlers.
 
-.. tabularcolumns:: |l|L|L|
+.. event:: builder-inited ()
 
-====================== =================================== =========
-Event name             Emitted when                        Arguments
-====================== =================================== =========
-``'builder-inited'``   the builder object has been created -none-
-``'doctree-read'``     a doctree has been parsed and read  *doctree*
-                       by the environment, and is about to
-                       be pickled
-``'doctree-resolved'`` a doctree has been "resolved" by    *doctree*, *docname*
-                       the environment, that is, all
-                       references and TOCs have been
-                       inserted
-====================== =================================== =========
+   Emitted the builder object has been created.
+
+.. event:: doctree-read (doctree)
+
+   Emitted when a doctree has been parsed and read by the environment, and is
+   about to be pickled.
+
+.. event:: doctree-resolved (doctree, docname)
+
+   Emitted when a doctree has been "resolved" by the environment, that is, all
+   references and TOCs have been inserted.
+
+.. event:: page-context (pagename, templatename, context, doctree)
+
+   Emitted when the HTML builder has created a context dictionary to render a
+   template with -- this can be used to add custom elements to the context.
+
+   The *pagename* argument is the canonical name of the page being rendered,
+   that is, without ``.html`` suffix and using slashes as path separators.  The
+   *templatename* is the name of the template to render, this will be
+   ``'page.html'`` for all pages from reST documents.
+
+   The *context* argument is a dictionary of values that are given to the
+   template engine to render the page and can be modified to include custom
+   values.  Keys must be strings.
+
+   The *doctree* argument will be a doctree when the page is created from a reST
+   documents; it will be ``None`` when the page is created from an HTML template
+   alone.
+
+   .. versionadded:: 0.4
+
 
 .. _template-bridge:
 

sphinx/application.py

 events = {
     'builder-inited': '',
     'doctree-read' : 'the doctree before being pickled',
-    'doctree-resolved' : 'the doctree, the docname',
+    'doctree-resolved' : 'doctree, docname',
+    'html-page-context': 'pagename, context, doctree or None',
 }
 
 class Sphinx(object):

sphinx/builder.py

             show_sphinx = self.config.html_show_sphinx,
             builder = self.name,
             parents = [],
-            titles = {},
             logo = logo,
             len = len, # the built-in
         )
 
-    def write_doc(self, docname, doctree):
-        destination = StringOutput(encoding='utf-8')
-        doctree.settings = self.docsettings
-
-        self.imgpath = relative_uri(self.get_target_uri(docname), '_images')
-        self.docwriter.write(doctree, destination)
-        self.docwriter.assemble_parts()
-
+    def get_doc_context(self, docname, body):
+        """Collect items for the template context of a page."""
+        # find out relations
         prev = next = None
         parents = []
         related = self.env.toctree_relations.get(docname)
                           # "back to index" link already
         parents.reverse()
 
+        # title rendered as HTML
         title = titles.get(docname)
-        if title:
-            title = self.render_partial(title)['title']
-        else:
-            title = ''
-        self.globalcontext['titles'][docname] = title
+        title = title and self.render_partial(title)['title'] or ''
+        # the name for the copied source
         sourcename = self.config.html_copy_source and docname + '.txt' or ''
-        ctx = dict(
+
+        # metadata for the document
+        meta = self.env.metadata.get(docname)
+
+        return dict(
+            parents = parents,
+            prev = prev,
+            next = next,
             title = title,
+            meta = meta,
+            body = body,
             sourcename = sourcename,
-            body = self.docwriter.parts['fragment'],
             toc = self.render_partial(self.env.get_toc_for(docname))['fragment'],
             # only display a TOC if there's more than one item to show
             display_toc = (self.env.toc_num_entries[docname] > 1),
-            parents = parents,
-            prev = prev,
-            next = next,
         )
 
-        self.index_page(docname, doctree, title)
-        self.handle_page(docname, ctx)
+    def write_doc(self, docname, doctree):
+        destination = StringOutput(encoding='utf-8')
+        doctree.settings = self.docsettings
+
+        self.imgpath = relative_uri(self.get_target_uri(docname), '_images')
+        self.docwriter.write(doctree, destination)
+        self.docwriter.assemble_parts()
+        body = self.docwriter.parts['fragment']
+
+        ctx = self.get_doc_context(docname, body)
+        self.index_page(docname, doctree, ctx.get('title', ''))
+        self.handle_page(docname, ctx, event_arg=doctree)
 
     def finish(self):
         self.info(bold('writing additional files...'), nonl=1)
         return docname + self.out_suffix
 
     def handle_page(self, pagename, addctx, templatename='page.html',
-                    outfilename=None):
+                    outfilename=None, event_arg=None):
         ctx = self.globalcontext.copy()
-        ctx['current_page_name'] = pagename
+        # current_page_name is backwards compatibility
+        ctx['pagename'] = ctx['current_page_name'] = pagename
 
         def pathto(otheruri, resource=False,
                    baseuri=self.get_target_uri(pagename)):
             return relative_uri(baseuri, otheruri)
         ctx['pathto'] = pathto
         ctx['hasdoc'] = lambda name: name in self.env.all_docs
-        sidebarfile = self.config.html_sidebars.get(pagename)
-        if sidebarfile:
-            ctx['customsidebar'] = sidebarfile
+        ctx['customsidebar'] = self.config.html_sidebars.get(pagename)
         ctx.update(addctx)
 
+        self.app.emit('html-page-context', pagename, templatename, ctx, event_arg)
+
         output = self.templates.render(templatename, ctx)
         if not outfilename:
             outfilename = path.join(self.outdir, os_path(pagename) + self.out_suffix)

sphinx/templates/layout.html

           {{ rendertemplate(customsidebar) }}
           {%- endif %}
           {%- block sidebarsearch %}
-          {%- if current_page_name != "search" %}
+          {%- if pagename != "search" %}
             <h3>{{ builder == 'web' and 'Keyword' or 'Quick' }} search</h3>
             <form class="search" action="{{ pathto('search') }}" method="get">
               <input type="text" name="q" size="18" /> <input type="submit" value="Go" />

sphinx/templates/web/settings.html

 {% extends "layout.html" %}
 {% set title = 'Settings' %}
-{% set current_page_name = 'settings' %}
+{% set pagename = 'settings' %}
 {% block body %}
   <h1>{{ project }} Documentation Settings</h1>
   <p>