1# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3#
4# This file is part of logilab-common.
5#
6# logilab-common is free software: you can redistribute it and/or modify it
7# under the terms of the GNU Lesser General Public License as published by the
8# Free Software Foundation, either version 2.1 of the License,
9# or (at your option) any later version.
10#
11# logilab-common is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
14# details.
15#
16# You should have received a copy of the GNU Lesser General Public License
17# along with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
18"""HTML formatting drivers for ureports"""
19__docformat__ = "restructuredtext en"
20
21
22from logilab.common.ureports import BaseWriter
23from logilab.common.ureports.nodes import (
24    Section,
25    Title,
26    Table,
27    List,
28    Paragraph,
29    Link,
30    VerbatimText,
31    Text,
32)
33from typing import Any
34
35
36class HTMLWriter(BaseWriter):
37    """format layouts as HTML"""
38
39    def __init__(self, snippet: int = None) -> None:
40        super(HTMLWriter, self).__init__()
41        self.snippet = snippet
42
43    def handle_attrs(self, layout: Any) -> str:
44        """get an attribute string from layout member attributes"""
45        attrs = ""
46        klass = getattr(layout, "klass", None)
47        if klass:
48            attrs += ' class="%s"' % klass
49        nid = getattr(layout, "id", None)
50        if nid:
51            attrs += ' id="%s"' % nid
52        return attrs
53
54    def begin_format(self, layout: Any) -> None:
55        """begin to format a layout"""
56        super(HTMLWriter, self).begin_format(layout)
57        if self.snippet is None:
58            self.writeln("<html>")
59            self.writeln("<body>")
60
61    def end_format(self, layout: Any) -> None:
62        """finished to format a layout"""
63        if self.snippet is None:
64            self.writeln("</body>")
65            self.writeln("</html>")
66
67    def visit_section(self, layout: Section) -> None:
68        """display a section as html, using div + h[section level]"""
69        self.section += 1
70        self.writeln("<div%s>" % self.handle_attrs(layout))
71        self.format_children(layout)
72        self.writeln("</div>")
73        self.section -= 1
74
75    def visit_title(self, layout: Title) -> None:
76        """display a title using <hX>"""
77        self.write("<h%s%s>" % (self.section, self.handle_attrs(layout)))
78        self.format_children(layout)
79        self.writeln("</h%s>" % self.section)
80
81    def visit_table(self, layout: Table) -> None:
82        """display a table as html"""
83        self.writeln("<table%s>" % self.handle_attrs(layout))
84        table_content = self.get_table_content(layout)
85        for i in range(len(table_content)):
86            row = table_content[i]
87            if i == 0 and layout.rheaders:
88                self.writeln('<tr class="header">')
89            elif i + 1 == len(table_content) and layout.rrheaders:
90                self.writeln('<tr class="header">')
91            else:
92                self.writeln('<tr class="%s">' % (i % 2 and "even" or "odd"))
93            for j in range(len(row)):
94                cell = row[j] or "&#160;"
95                if (
96                    (layout.rheaders and i == 0)
97                    or (layout.cheaders and j == 0)
98                    or (layout.rrheaders and i + 1 == len(table_content))
99                    or (layout.rcheaders and j + 1 == len(row))
100                ):
101                    self.writeln("<th>%s</th>" % cell)
102                else:
103                    self.writeln("<td>%s</td>" % cell)
104            self.writeln("</tr>")
105        self.writeln("</table>")
106
107    def visit_list(self, layout: List) -> None:
108        """display a list as html"""
109        self.writeln("<ul%s>" % self.handle_attrs(layout))
110        for row in list(self.compute_content(layout)):
111            self.writeln("<li>%s</li>" % row)
112        self.writeln("</ul>")
113
114    def visit_paragraph(self, layout: Paragraph) -> None:
115        """display links (using <p>)"""
116        self.write("<p>")
117        self.format_children(layout)
118        self.write("</p>")
119
120    def visit_span(self, layout):
121        """display links (using <p>)"""
122        self.write("<span%s>" % self.handle_attrs(layout))
123        self.format_children(layout)
124        self.write("</span>")
125
126    def visit_link(self, layout: Link) -> None:
127        """display links (using <a>)"""
128        self.write(' <a href="%s"%s>%s</a>' % (layout.url, self.handle_attrs(layout), layout.label))
129
130    def visit_verbatimtext(self, layout: VerbatimText) -> None:
131        """display verbatim text (using <pre>)"""
132        self.write("<pre>")
133        self.write(layout.data.replace("&", "&amp;").replace("<", "&lt;"))
134        self.write("</pre>")
135
136    def visit_text(self, layout: Text) -> None:
137        """add some text"""
138        data = layout.data
139        if layout.escaped:
140            data = data.replace("&", "&amp;").replace("<", "&lt;")
141        self.write(data)
142