MoinLight

moinformat/serialisers/html/moin.py

176:47af441b48bf
2018-11-26 Paul Boddie Support linking to stylesheets based on the collection of available files.
     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     45         # Generate attributes, joining them when preparing the tag.    46     47         l = []    48         out = l.append    49     50         if level:    51             out("level-%d" % level)    52     53         if indent:    54             out("indent-%d" % indent)    55     56         # NOTE: Encode type details for CSS.    57     58         out("type-%s" % escape_attr(type or "opaque"))    59     60         tag = self._region_tag(type)    61         self.out("<%s class='%s'>" % (tag, " ".join(l)))    62     63     def end_region(self, level, indent, type, extra):    64         tag = self._region_tag(type)    65         self.out("</%s>" % tag)    66     67     def start_block(self):    68         self.out("<p>")    69     70     def end_block(self):    71         self.out("</p>")    72     73     def start_defitem(self, pad, extra):    74         self.out("<dd>")    75     76     def end_defitem(self, pad, extra):    77         self.out("</dd>")    78     79     def start_defterm(self, pad, extra):    80         self.out("<dt>")    81     82     def end_defterm(self, pad, extra):    83         self.out("</dt>")    84     85     def start_emphasis(self):    86         self.out("<em>")    87     88     def end_emphasis(self):    89         self.out("</em>")    90     91     def start_heading(self, level, extra, pad, identifier):    92         self.out("<h%d id='%s'>" % (level, escape_attr(self.linker.make_id(identifier))))    93     94     def end_heading(self, level, pad, extra):    95         self.out("</h%d>" % level)    96     97     def start_larger(self):    98         self.out("<big>")    99    100     def end_larger(self):   101         self.out("</big>")   102    103     def start_linktext(self):   104         pass   105    106     def end_linktext(self):   107         pass   108    109     list_tags = {   110         "i" : "lower-roman",   111         "I" : "upper-roman",   112         "a" : "lower-latin",   113         "A" : "upper-latin",   114         }   115    116     def _get_list_tag(self, marker):   117         if marker:   118             if marker[0].isdigit():   119                 return "ol", "decimal"   120             style_type = self.list_tags.get(marker[0])   121             if style_type:   122                 return "ol", style_type   123    124         return "ul", None   125    126     def start_list(self, indent, marker, num):   127         tag, style_type = self._get_list_tag(marker)   128         style = style_type and ' style="list-style-type: %s"' % escape_attr(style_type) or ""   129         start = style_type and num is not None and ' start="%s"' % escape_attr(num) or ""   130         self.out("<%s%s%s>" % (tag, style, start))   131    132     def end_list(self, indent, marker, num):   133         tag, style = self._get_list_tag(marker)   134         self.out("</%s>" % tag)   135    136     def start_listitem(self, indent, marker, space, num):   137         self.out("<li>")   138    139     def end_listitem(self, indent, marker, space, num):   140         self.out("</li>")   141    142     def start_macro(self, name, args, nodes):   143         self.out("<span class='macro'>")   144    145         # Fallback case for when macros are not replaced.   146    147         if not nodes:   148             self.out(escape_text("<<"))   149             self.out("<span class='name'>%s</span>" % escape_text(name))   150             if args:   151                 self.out("(")   152             first = True   153             for arg in args:   154                 if not first:   155                     self.out(",")   156                 self.out("<span class='arg'>%s</span>" % escape_text(arg))   157                 first = False   158             if args:   159                 self.out(")")   160             self.out(escape_text(">>"))   161    162     def end_macro(self):   163         self.out("</span>")   164    165     def start_monospace(self):   166         self.out("<tt>")   167    168     def end_monospace(self):   169         self.out("</tt>")   170    171     def start_smaller(self):   172         self.out("<small>")   173    174     def end_smaller(self):   175         self.out("</small>")   176    177     def start_strikethrough(self):   178         self.out("<del>")   179    180     def end_strikethrough(self):   181         self.out("</del>")   182    183     def start_strong(self):   184         self.out("<strong>")   185    186     def end_strong(self):   187         self.out("</strong>")   188    189     def start_subscript(self):   190         self.out("<sub>")   191    192     def end_subscript(self):   193         self.out("</sub>")   194    195     def start_superscript(self):   196         self.out("<sup>")   197    198     def end_superscript(self):   199         self.out("</sup>")   200    201     def start_table(self):   202         self.out("<table>")   203    204     def end_table(self):   205         self.out("</table>")   206    207     def start_table_attrs(self):   208         pass   209    210     def end_table_attrs(self):   211         pass   212    213     def start_table_cell(self, attrs):   214         self.out("<td")   215    216         # Handle the attributes separately from their container.   217    218         if attrs and not attrs.empty():   219             for attr in attrs.nodes:   220                 attr.to_string(self)   221    222         self.out(">")   223    224     def end_table_cell(self):   225         self.out("</td>")   226    227     def start_table_row(self):   228         self.out("<tr>")   229    230     def end_table_row(self, trailing):   231         self.out("</tr>")   232    233     def start_underline(self):   234         self.out("<span style='text-decoration: underline'>")   235    236     def end_underline(self):   237         self.out("</span>")   238    239     def anchor(self, target):   240         self.out("<a name='%s' />" % escape_attr(self.linker.make_id(target)))   241    242     def break_(self):   243         pass   244    245     def comment(self, comment, extra):   246         pass   247    248     def directive(self, directive, extra):   249         pass   250    251     def linebreak(self):   252         self.out("<br />")   253    254     def _link(self, target, nodes, tag, attr):   255         label = None   256         if self.linker:   257             target, label = self.linker.translate(target)   258    259         self.out('<%s %s="%s"' % (tag, attr, escape_attr(target)))   260    261         if nodes:   262             for node in nodes[1:]:   263                 self.out(" ")   264                 node.to_string(self)   265    266         self.out(">")   267    268         if nodes:   269             nodes[0].to_string(self)   270         else:   271             self.out(escape_text(label or target))   272    273         self.out("</%s>" % tag)   274    275     def link(self, target, nodes):   276         self._link(target, nodes, "a", "href")   277    278     def link_label(self, nodes):   279         for node in nodes:   280             node.to_string(self)   281    282     def link_parameter(self, key_value):   283         if len(key_value) == 1:   284             self.out(key_value[0])   285         else:   286             key, value = key_value   287             self.out("%s='%s'" % (key, escape_attr(value)))   288    289     def rule(self, length):   290         self.out("<hr style='height: %dpt' />" % min(length, 10))   291    292     def table_attrs(self, nodes):   293    294         # Skip the attributes in their original form.   295    296         pass   297    298     def table_attr(self, name, value, concise, quote):   299         self.out(" %s%s" % (escape_text(name), value is not None and   300             "='%s'" % escape_attr(value) or ""))   301    302     def text(self, s):   303         self.out(escape_text(s))   304    305     def transclusion(self, target, nodes):   306         self._link(target, nodes, "img", "src")   307    308     def verbatim(self, s):   309         self.text(s)   310    311 serialiser = HTMLSerialiser   312    313 # vim: tabstop=4 expandtab shiftwidth=4