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

This commit is contained in:
Georg Brandl 2008-05-31 16:14:36 +00:00
parent 2dfad25fd0
commit 2b0e015fcc
7 changed files with 98 additions and 45 deletions

View File

@ -28,6 +28,11 @@ New features added
* Defaults for configuration values can now be callables, which allows * Defaults for configuration values can now be callables, which allows
dynamic defaults. 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 Bugs fixed
---------- ----------

View File

@ -162,7 +162,25 @@ def parse_role(env, sig, signode):
return sig 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): def setup(app):
app.add_description_unit('directive', 'dir', 'pair: %s; directive', parse_directive) 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('role', 'role', 'pair: %s; role', parse_role)
app.add_description_unit('confval', 'confval', 'pair: %s; configuration value') app.add_description_unit('confval', 'confval', 'pair: %s; configuration value')
app.add_description_unit('event', 'event', 'pair: %s; event', parse_event)

View File

@ -162,22 +162,43 @@ package.
Sphinx core events 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 ()
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
====================== =================================== =========
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
====================== =================================== =========
.. _template-bridge: .. _template-bridge:

View File

@ -49,7 +49,8 @@ class ExtensionError(Exception):
events = { events = {
'builder-inited': '', 'builder-inited': '',
'doctree-read' : 'the doctree before being pickled', '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): class Sphinx(object):

View File

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

View File

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

View File

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