Website: add template and basic stylesheet with menu. Update buildhtml.py (and theref...
[docutils.git] / sandbox / gitpull / web_stylesheet_and_menu / docutils / transforms / parts.py
blob91acf1efadd594f87c6cf5ec256dcf4ce99a19d8
1 # $Id$
2 # Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer; Dmitry Jemerov
3 # Copyright: This module has been placed in the public domain.
5 """
6 Transforms related to document parts.
7 """
9 __docformat__ = 'reStructuredText'
12 import re
13 import sys
14 from docutils import nodes, utils
15 from docutils.transforms import TransformError, Transform
18 class SectNum(Transform):
20 """
21 Automatically assigns numbers to the titles of document sections.
23 It is possible to limit the maximum section level for which the numbers
24 are added. For those sections that are auto-numbered, the "autonum"
25 attribute is set, informing the contents table generator that a different
26 form of the TOC should be used.
27 """
29 default_priority = 710
30 """Should be applied before `Contents`."""
32 def apply(self):
33 self.maxdepth = self.startnode.details.get('depth', None)
34 self.startvalue = self.startnode.details.get('start', 1)
35 self.prefix = self.startnode.details.get('prefix', '')
36 self.suffix = self.startnode.details.get('suffix', '')
37 self.startnode.parent.remove(self.startnode)
38 if self.document.settings.sectnum_xform:
39 if self.maxdepth is None:
40 self.maxdepth = sys.maxint
41 self.update_section_numbers(self.document)
42 else: # store details for eventual section numbering by the writer
43 self.document.settings.sectnum_depth = self.maxdepth
44 self.document.settings.sectnum_start = self.startvalue
45 self.document.settings.sectnum_prefix = self.prefix
46 self.document.settings.sectnum_suffix = self.suffix
48 def update_section_numbers(self, node, prefix=(), depth=0):
49 depth += 1
50 if prefix:
51 sectnum = 1
52 else:
53 sectnum = self.startvalue
54 for child in node:
55 if isinstance(child, nodes.section):
56 numbers = prefix + (str(sectnum),)
57 title = child[0]
58 # Use &nbsp; for spacing:
59 generated = nodes.generated(
60 '', (self.prefix + '.'.join(numbers) + self.suffix
61 + u'\u00a0' * 3),
62 classes=['sectnum'])
63 title.insert(0, generated)
64 title['auto'] = 1
65 if depth < self.maxdepth:
66 self.update_section_numbers(child, numbers, depth)
67 sectnum += 1
70 class Contents(Transform):
72 """
73 This transform generates a table of contents from the entire document tree
74 or from a single branch. It locates "section" elements and builds them
75 into a nested bullet list, which is placed within a "topic" created by the
76 contents directive. A title is either explicitly specified, taken from
77 the appropriate language module, or omitted (local table of contents).
78 The depth may be specified. Two-way references between the table of
79 contents and section titles are generated (requires Writer support).
81 This transform requires a startnode, which contains generation
82 options and provides the location for the generated table of contents (the
83 startnode is replaced by the table of contents "topic").
84 """
86 default_priority = 720
88 def apply(self):
89 try: # let the writer (or output software) build the contents list?
90 toc_by_writer = self.document.settings.use_latex_toc
91 except AttributeError:
92 toc_by_writer = False
93 details = self.startnode.details
94 if 'local' in details:
95 startnode = self.startnode.parent.parent
96 while not (isinstance(startnode, nodes.section)
97 or isinstance(startnode, nodes.document)):
98 # find the ToC root: a direct ancestor of startnode
99 startnode = startnode.parent
100 else:
101 startnode = self.document
102 self.toc_id = self.startnode.parent['ids'][0]
103 if 'backlinks' in details:
104 self.backlinks = details['backlinks']
105 else:
106 self.backlinks = self.document.settings.toc_backlinks
107 if toc_by_writer:
108 # move customization settings to the parent node
109 self.startnode.parent.attributes.update(details)
110 self.startnode.parent.remove(self.startnode)
111 else:
112 contents = self.build_contents(startnode)
113 if len(contents):
114 self.startnode.replace_self(contents)
115 else:
116 self.startnode.parent.parent.remove(self.startnode.parent)
118 def build_contents(self, node, level=0):
119 level += 1
120 sections = [sect for sect in node if isinstance(sect, nodes.section)]
121 entries = []
122 autonum = 0
123 depth = self.startnode.details.get('depth', sys.maxint)
124 for section in sections:
125 title = section[0]
126 auto = title.get('auto') # May be set by SectNum.
127 entrytext = self.copy_and_filter(title)
128 reference = nodes.reference('', '', refid=section['ids'][0],
129 *entrytext)
130 ref_id = self.document.set_id(reference)
131 entry = nodes.paragraph('', '', reference)
132 item = nodes.list_item('', entry)
133 if ( self.backlinks in ('entry', 'top')
134 and title.next_node(nodes.reference) is None):
135 if self.backlinks == 'entry':
136 title['refid'] = ref_id
137 elif self.backlinks == 'top':
138 title['refid'] = self.toc_id
139 if level < depth:
140 subsects = self.build_contents(section, level)
141 item += subsects
142 entries.append(item)
143 if entries:
144 contents = nodes.bullet_list('', *entries)
145 if auto:
146 contents['classes'].append('auto-toc')
147 return contents
148 else:
149 return []
151 def copy_and_filter(self, node):
152 """Return a copy of a title, with references, images, etc. removed."""
153 visitor = ContentsFilter(self.document)
154 node.walkabout(visitor)
155 return visitor.get_entry_text()
158 class ContentsFilter(nodes.TreeCopyVisitor):
160 def get_entry_text(self):
161 return self.get_tree_copy().children
163 def visit_citation_reference(self, node):
164 raise nodes.SkipNode
166 def visit_footnote_reference(self, node):
167 raise nodes.SkipNode
169 def visit_image(self, node):
170 if node.hasattr('alt'):
171 self.parent.append(nodes.Text(node['alt']))
172 raise nodes.SkipNode
174 def ignore_node_but_process_children(self, node):
175 raise nodes.SkipDeparture
177 visit_interpreted = ignore_node_but_process_children
178 visit_problematic = ignore_node_but_process_children
179 visit_reference = ignore_node_but_process_children
180 visit_target = ignore_node_but_process_children