1 # Author: David Goodger |
|
2 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
4 # |
|
5 # This file is part of CubicWeb. |
|
6 # |
|
7 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
8 # terms of the GNU Lesser General Public License as published by the Free |
|
9 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
10 # any later version. |
|
11 # |
|
12 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
15 # details. |
|
16 # |
|
17 # You should have received a copy of the GNU Lesser General Public License along |
|
18 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
19 """ |
|
20 |
|
21 """ |
|
22 # Contact: goodger@users.sourceforge.net |
|
23 # Revision: $Revision: 1.2 $ |
|
24 # Date: $Date: 2005-07-04 16:36:50 $ |
|
25 # Copyright: This module has been placed in the public domain. |
|
26 |
|
27 """ |
|
28 Simple HyperText Markup Language document tree Writer. |
|
29 |
|
30 The output conforms to the HTML 4.01 Transitional DTD and to the Extensible |
|
31 HTML version 1.0 Transitional DTD (*almost* strict). The output contains a |
|
32 minimum of formatting information. A cascading style sheet ("default.css" by |
|
33 default) is required for proper viewing with a modern graphical browser. |
|
34 |
|
35 http://cvs.zope.org/Zope/lib/python/docutils/writers/Attic/html4zope.py?rev=1.1.2.2&only_with_tag=ajung-restructuredtext-integration-branch&content-type=text/vnd.viewcvs-markup |
|
36 """ |
|
37 |
|
38 __docformat__ = 'reStructuredText' |
|
39 |
|
40 import os |
|
41 |
|
42 from logilab.mtconverter import xml_escape |
|
43 |
|
44 from docutils import nodes |
|
45 from docutils.writers.html4css1 import Writer as CSS1Writer |
|
46 from docutils.writers.html4css1 import HTMLTranslator as CSS1HTMLTranslator |
|
47 |
|
48 default_level = int(os.environ.get('STX_DEFAULT_LEVEL', 3)) |
|
49 |
|
50 class Writer(CSS1Writer): |
|
51 """css writer using our html translator""" |
|
52 def __init__(self, base_url): |
|
53 CSS1Writer.__init__(self) |
|
54 self.translator_class = URLBinder(base_url, HTMLTranslator) |
|
55 |
|
56 def apply_template(self): |
|
57 """overriding this is necessary with docutils >= 0.5""" |
|
58 return self.visitor.astext() |
|
59 |
|
60 class URLBinder: |
|
61 def __init__(self, url, klass): |
|
62 self.base_url = url |
|
63 self.translator_class = HTMLTranslator |
|
64 |
|
65 def __call__(self, document): |
|
66 translator = self.translator_class(document) |
|
67 translator.base_url = self.base_url |
|
68 return translator |
|
69 |
|
70 class HTMLTranslator(CSS1HTMLTranslator): |
|
71 """ReST tree to html translator""" |
|
72 |
|
73 def astext(self): |
|
74 """return the extracted html""" |
|
75 return ''.join(self.body) |
|
76 |
|
77 def visit_title(self, node): |
|
78 """Only 6 section levels are supported by HTML.""" |
|
79 if isinstance(node.parent, nodes.topic): |
|
80 self.body.append( |
|
81 self.starttag(node, 'p', '', CLASS='topic-title')) |
|
82 if node.parent.hasattr('id'): |
|
83 self.body.append( |
|
84 self.starttag({}, 'a', '', name=node.parent['id'])) |
|
85 self.context.append('</a></p>\n') |
|
86 else: |
|
87 self.context.append('</p>\n') |
|
88 elif self.section_level == 0: |
|
89 # document title |
|
90 self.head.append('<title>%s</title>\n' |
|
91 % self.encode(node.astext())) |
|
92 self.body.append(self.starttag(node, 'h%d' % default_level, '', |
|
93 CLASS='title')) |
|
94 self.context.append('</h%d>\n' % default_level) |
|
95 else: |
|
96 self.body.append( |
|
97 self.starttag(node, 'h%s' % ( |
|
98 default_level+self.section_level-1), '')) |
|
99 atts = {} |
|
100 if node.hasattr('refid'): |
|
101 atts['class'] = 'toc-backref' |
|
102 atts['href'] = '%s#%s' % (self.base_url, node['refid']) |
|
103 self.body.append(self.starttag({}, 'a', '', **atts)) |
|
104 self.context.append('</a></h%s>\n' % ( |
|
105 default_level+self.section_level-1)) |
|
106 |
|
107 def visit_subtitle(self, node): |
|
108 """format a subtitle""" |
|
109 if isinstance(node.parent, nodes.sidebar): |
|
110 self.body.append(self.starttag(node, 'p', '', |
|
111 CLASS='sidebar-subtitle')) |
|
112 self.context.append('</p>\n') |
|
113 else: |
|
114 self.body.append( |
|
115 self.starttag(node, 'h%s' % (default_level+1), '', |
|
116 CLASS='subtitle')) |
|
117 self.context.append('</h%s>\n' % (default_level+1)) |
|
118 |
|
119 def visit_document(self, node): |
|
120 """syt: i don't want the enclosing <div class="document">""" |
|
121 def depart_document(self, node): |
|
122 """syt: i don't want the enclosing <div class="document">""" |
|
123 |
|
124 def visit_reference(self, node): |
|
125 """syt: i want absolute urls""" |
|
126 if 'refuri' in node: |
|
127 href = node['refuri'] |
|
128 if ( self.settings.cloak_email_addresses |
|
129 and href.startswith('mailto:')): |
|
130 href = self.cloak_mailto(href) |
|
131 self.in_mailto = 1 |
|
132 else: |
|
133 assert 'refid' in node, \ |
|
134 'References must have "refuri" or "refid" attribute.' |
|
135 href = '%s#%s' % (self.base_url, node['refid']) |
|
136 atts = {'href': href, 'class': 'reference'} |
|
137 if not isinstance(node.parent, nodes.TextElement): |
|
138 assert len(node) == 1 and isinstance(node[0], nodes.image) |
|
139 atts['class'] += ' image-reference' |
|
140 self.body.append(self.starttag(node, 'a', '', **atts)) |
|
141 |
|
142 ## override error messages to avoid XHTML problems ######################## |
|
143 def visit_problematic(self, node): |
|
144 pass |
|
145 |
|
146 def depart_problematic(self, node): |
|
147 pass |
|
148 |
|
149 def visit_system_message(self, node): |
|
150 backref_text = '' |
|
151 if len(node['backrefs']): |
|
152 backrefs = node['backrefs'] |
|
153 if len(backrefs) == 1: |
|
154 backref_text = '; <em>backlink</em>' |
|
155 else: |
|
156 i = 1 |
|
157 backlinks = [] |
|
158 for backref in backrefs: |
|
159 backlinks.append(str(i)) |
|
160 i += 1 |
|
161 backref_text = ('; <em>backlinks: %s</em>' |
|
162 % ', '.join(backlinks)) |
|
163 if node.hasattr('line'): |
|
164 line = ', line %s' % node['line'] |
|
165 else: |
|
166 line = '' |
|
167 a_start = a_end = '' |
|
168 error = u'System Message: %s%s/%s%s (%s %s)%s</p>\n' % ( |
|
169 a_start, node['type'], node['level'], a_end, |
|
170 self.encode(node['source']), line, backref_text) |
|
171 self.body.append(u'<div class="system-message"><b>ReST / HTML errors:</b>%s</div>' % xml_escape(error)) |
|
172 |
|
173 def depart_system_message(self, node): |
|
174 pass |
|