diff options
Diffstat (limited to 'doc/sphinx/_exts/taler_sphinx_theme/__init__.py')
-rw-r--r-- | doc/sphinx/_exts/taler_sphinx_theme/__init__.py | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/doc/sphinx/_exts/taler_sphinx_theme/__init__.py b/doc/sphinx/_exts/taler_sphinx_theme/__init__.py new file mode 100644 index 0000000..2d3c61c --- /dev/null +++ b/doc/sphinx/_exts/taler_sphinx_theme/__init__.py | |||
@@ -0,0 +1,166 @@ | |||
1 | """Sphinx Guzzle theme.""" | ||
2 | |||
3 | import os | ||
4 | from os import path | ||
5 | import xml.etree.ElementTree as ET | ||
6 | |||
7 | from docutils import nodes | ||
8 | from sphinx.locale import admonitionlabels | ||
9 | from sphinx.writers.html import HTMLTranslator as SphinxHTMLTranslator | ||
10 | |||
11 | from pygments.style import Style | ||
12 | from pygments.token import Keyword, Name, Comment, String, Error, \ | ||
13 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal | ||
14 | |||
15 | |||
16 | def setup(app): | ||
17 | """Setup conntects events to the sitemap builder""" | ||
18 | app.connect('html-page-context', add_html_link) | ||
19 | app.connect('build-finished', create_sitemap) | ||
20 | app.set_translator('html', MyHTMLTranslator) | ||
21 | app.set_translator('html-linked', MyHTMLTranslator) | ||
22 | app.sitemap_links = [] | ||
23 | app.add_html_theme('taler_sphinx_theme', path.abspath(path.dirname(__file__) + "/guzzle_sphinx_theme")) | ||
24 | |||
25 | |||
26 | def add_html_link(app, pagename, templatename, context, doctree): | ||
27 | """As each page is built, collect page names for the sitemap""" | ||
28 | base_url = app.config['html_theme_options'].get('base_url', '') | ||
29 | if base_url: | ||
30 | app.sitemap_links.append(base_url + pagename + ".html") | ||
31 | |||
32 | |||
33 | def create_sitemap(app, exception): | ||
34 | """Generates the sitemap.xml from the collected HTML page links""" | ||
35 | if (not app.config['html_theme_options'].get('base_url', '') or | ||
36 | exception is not None or | ||
37 | not app.sitemap_links): | ||
38 | return | ||
39 | |||
40 | filename = app.outdir + "/sitemap.xml" | ||
41 | print("Generating sitemap.xml in %s" % filename) | ||
42 | |||
43 | root = ET.Element("urlset") | ||
44 | root.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") | ||
45 | |||
46 | for link in app.sitemap_links: | ||
47 | url = ET.SubElement(root, "url") | ||
48 | ET.SubElement(url, "loc").text = link | ||
49 | |||
50 | ET.ElementTree(root).write(filename) | ||
51 | |||
52 | |||
53 | def html_theme_path(): | ||
54 | return [os.path.dirname(os.path.abspath(__file__))] | ||
55 | |||
56 | |||
57 | class MyHTMLTranslator(SphinxHTMLTranslator): | ||
58 | """ | ||
59 | Handle translating to bootstrap structure. | ||
60 | """ | ||
61 | def visit_table(self, node, name=''): | ||
62 | """ | ||
63 | Override docutils default table formatter to not include a border | ||
64 | and to use Bootstrap CSS | ||
65 | See: http://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/writers/html4css1/__init__.py#l1550 | ||
66 | """ | ||
67 | self.context.append(self.compact_p) | ||
68 | self.compact_p = True | ||
69 | classes = 'table table-bordered ' + self.settings.table_style | ||
70 | classes = classes.strip() | ||
71 | self.body.append( | ||
72 | self.starttag(node, 'table', CLASS=classes)) | ||
73 | |||
74 | def depart_table(self, node): | ||
75 | """ | ||
76 | This needs overridin' too | ||
77 | """ | ||
78 | self.compact_p = self.context.pop() | ||
79 | self.body.append('</table>\n') | ||
80 | |||
81 | def visit_field(self, node): | ||
82 | pass | ||
83 | |||
84 | def depart_field(self, node): | ||
85 | pass | ||
86 | |||
87 | def visit_field_name(self, node): | ||
88 | atts = {} | ||
89 | if self.in_docinfo: | ||
90 | atts['class'] = 'docinfo-name' | ||
91 | else: | ||
92 | atts['class'] = 'field-name' | ||
93 | self.context.append('') | ||
94 | self.body.append(self.starttag(node, 'dt', '', **atts)) | ||
95 | |||
96 | def depart_field_name(self, node): | ||
97 | self.body.append('</dt>') | ||
98 | self.body.append(self.context.pop()) | ||
99 | |||
100 | def visit_field_body(self, node): | ||
101 | self.body.append(self.starttag(node, 'dd', '', CLASS='field-body')) | ||
102 | self.set_class_on_child(node, 'first', 0) | ||
103 | field = node.parent | ||
104 | if (self.compact_field_list or | ||
105 | isinstance(field.parent, nodes.docinfo) or | ||
106 | field.parent.index(field) == len(field.parent) - 1): | ||
107 | # If we are in a compact list, the docinfo, or if this is | ||
108 | # the last field of the field list, do not add vertical | ||
109 | # space after last element. | ||
110 | self.set_class_on_child(node, 'last', -1) | ||
111 | |||
112 | def depart_field_body(self, node): | ||
113 | self.body.append('</dd>\n') | ||
114 | |||
115 | def visit_field_list(self, node): | ||
116 | self.context.append((self.compact_field_list, self.compact_p)) | ||
117 | self.compact_p = None | ||
118 | if 'compact' in node['classes']: | ||
119 | self.compact_field_list = True | ||
120 | elif (self.settings.compact_field_lists | ||
121 | and 'open' not in node['classes']): | ||
122 | self.compact_field_list = True | ||
123 | if self.compact_field_list: | ||
124 | for field in node: | ||
125 | field_body = field[-1] | ||
126 | assert isinstance(field_body, nodes.field_body) | ||
127 | children = [n for n in field_body | ||
128 | if not isinstance(n, nodes.Invisible)] | ||
129 | if not (len(children) == 0 or | ||
130 | len(children) == 1 and | ||
131 | isinstance(children[0], | ||
132 | (nodes.paragraph, nodes.line_block))): | ||
133 | self.compact_field_list = False | ||
134 | break | ||
135 | self.body.append(self.starttag(node, 'dl', frame='void', | ||
136 | rules='none', | ||
137 | CLASS='docutils field-list')) | ||
138 | |||
139 | def depart_field_list(self, node): | ||
140 | self.body.append('</dl>\n') | ||
141 | self.compact_field_list, self.compact_p = self.context.pop() | ||
142 | |||
143 | def visit_container(self, node): | ||
144 | self.body.append(self.starttag(node, 'div', CLASS='docutils')) | ||
145 | |||
146 | def add_secnumber(self, node): | ||
147 | # type: (nodes.Element) -> None | ||
148 | if node.get('secnumber'): | ||
149 | numbers = list(map(str, node['secnumber'])) | ||
150 | if len(numbers) <= 3: | ||
151 | self.body.append('.'.join(numbers) + self.secnumber_suffix) | ||
152 | elif isinstance(node.parent, nodes.section): | ||
153 | if self.builder.name == 'singlehtml': | ||
154 | docname = self.docnames[-1] | ||
155 | anchorname = "%s/#%s" % (docname, node.parent['ids'][0]) | ||
156 | if anchorname not in self.builder.secnumbers: | ||
157 | anchorname = "%s/" % docname # try first heading which has no anchor | ||
158 | else: | ||
159 | anchorname = '#' + node.parent['ids'][0] | ||
160 | if anchorname not in self.builder.secnumbers: | ||
161 | anchorname = '' # try first heading which has no anchor | ||
162 | if self.builder.secnumbers.get(anchorname): | ||
163 | numbers = list(self.builder.secnumbers[anchorname]) | ||
164 | if len(numbers) <= 3: | ||
165 | self.body.append('.'.join(map(str, numbers)) + | ||
166 | self.secnumber_suffix) | ||