1 #!/usr/bin/env python 2 3 """ 4 HTML serialiser. 5 6 Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from moinformat.serialisers.common import escape_attr, escape_text, Serialiser 23 24 class HTMLSerialiser(Serialiser): 25 26 "Serialisation of the page." 27 28 format = "html" 29 30 def _region_tag(self, type): 31 32 # NOTE: Need to support types in general. 33 34 type = type and type.split()[0] 35 36 if type == "inline": 37 return "tt" 38 elif type in (None, "python"): 39 return "pre" 40 else: 41 return "span" 42 43 def start_region(self, level, indent, type, extra): 44 l = [] 45 out = l.append 46 if level: 47 out("level-%d" % level) 48 49 if indent: 50 out("indent-%d" % indent) 51 52 # NOTE: Encode type details for CSS. 53 54 out("type-%s" % escape_attr(type or "opaque")) 55 56 tag = self._region_tag(type) 57 self.out("<%s class='%s'>" % (tag, " ".join(l))) 58 59 def end_region(self, level, indent, type, extra): 60 tag = self._region_tag(type) 61 self.out("</%s>" % tag) 62 63 def start_block(self): 64 self.out("<p>") 65 66 def end_block(self): 67 self.out("</p>") 68 69 def start_defitem(self, pad, extra): 70 self.out("<dd>") 71 72 def end_defitem(self, pad, extra): 73 self.out("</dd>") 74 75 def start_defterm(self, pad): 76 self.out("<dt>") 77 78 def end_defterm(self, pad): 79 self.out("</dt>") 80 81 def start_emphasis(self): 82 self.out("<em>") 83 84 def end_emphasis(self): 85 self.out("</em>") 86 87 def start_heading(self, level, extra, pad): 88 self.out("<h%d>" % level) 89 90 def end_heading(self, level, pad, extra): 91 self.out("</h%d>" % level) 92 93 def start_larger(self): 94 self.out("<big>") 95 96 def end_larger(self): 97 self.out("</big>") 98 99 def start_link(self, target): 100 self.out('<a href="%s">' % escape_attr(target)) 101 102 def end_link(self): 103 self.out("</a>") 104 105 def start_linktext(self): 106 pass 107 108 def end_linktext(self): 109 pass 110 111 list_tags = { 112 "i" : "lower-roman", 113 "I" : "upper-roman", 114 "a" : "lower-latin", 115 "A" : "upper-latin", 116 } 117 118 def _get_list_tag(self, marker): 119 if marker: 120 if marker[0].isdigit(): 121 return "ol", "decimal" 122 style_type = self.list_tags.get(marker[0]) 123 if style_type: 124 return "ol", style_type 125 126 return "ul", None 127 128 def start_list(self, indent, marker, num): 129 tag, style_type = self._get_list_tag(marker) 130 style = style_type and ' style="list-style-type: %s"' % escape_attr(style_type) or "" 131 start = style_type and num is not None and ' start="%s"' % escape_attr(num) or "" 132 self.out("<%s%s%s>" % (tag, style, start)) 133 134 def end_list(self, indent, marker, num): 135 tag, style = self._get_list_tag(marker) 136 self.out("</%s>" % tag) 137 138 def start_listitem(self, indent, marker, space, num): 139 self.out("<li>") 140 141 def end_listitem(self, indent, marker, space, num): 142 self.out("</li>") 143 144 def start_monospace(self): 145 self.out("<tt>") 146 147 def end_monospace(self): 148 self.out("</tt>") 149 150 def start_smaller(self): 151 self.out("<small>") 152 153 def end_smaller(self): 154 self.out("</small>") 155 156 def start_strikethrough(self): 157 self.out("<del>") 158 159 def end_strikethrough(self): 160 self.out("</del>") 161 162 def start_strong(self): 163 self.out("<strong>") 164 165 def end_strong(self): 166 self.out("</strong>") 167 168 def start_subscript(self): 169 self.out("<sub>") 170 171 def end_subscript(self): 172 self.out("</sub>") 173 174 def start_superscript(self): 175 self.out("<sup>") 176 177 def end_superscript(self): 178 self.out("</sup>") 179 180 def start_table(self): 181 self.out("<table>") 182 183 def end_table(self): 184 self.out("</table>") 185 186 def start_table_attrs(self): 187 pass 188 189 def end_table_attrs(self): 190 pass 191 192 def start_table_cell(self, attrs): 193 self.out("<td") 194 if attrs and not attrs.empty(): 195 attrs.to_string(self) 196 self.out(">") 197 198 def end_table_cell(self): 199 self.out("</td>") 200 201 def start_table_row(self): 202 self.out("<tr>") 203 204 def end_table_row(self, trailing): 205 self.out("</tr>") 206 207 def start_underline(self): 208 self.out("<span style='text-decoration: underline'>") 209 210 def end_underline(self): 211 self.out("</span>") 212 213 def break_(self): 214 pass 215 216 def macro(self, name, args): 217 218 # NOTE: Special case. 219 220 if name == "BR": 221 self.out("<br />") 222 return 223 224 # Fallback case. 225 226 self.out("<span class='macro'>") 227 self.out(escape_text("<<")) 228 self.out("<span class='name'>%s</span>" % escape_text(name)) 229 if args: 230 self.out("(") 231 first = True 232 for arg in args: 233 if not first: 234 self.out(",") 235 self.out("<span class='arg'>%s</span>" % escape_text(arg)) 236 first = False 237 if args: 238 self.out(")") 239 self.out(escape_text(">>")) 240 self.out("</span>") 241 242 def rule(self, length): 243 self.out("<hr style='height: %dpt' />" % min(length, 10)) 244 245 def table_attr(self, name, value, concise, quote): 246 self.out(" %s%s" % (escape_text(name), value is not None and 247 "='%s'" % escape_attr(value) or "")) 248 249 def text(self, s): 250 self.out(escape_text(s)) 251 252 serialiser = HTMLSerialiser 253 254 # vim: tabstop=4 expandtab shiftwidth=4