Commit | Line | Data |
---|---|---|
62551769 FT |
1 | import xml.dom.minidom, io |
2 | from . import cons as _cons | |
3 | from . import util | |
ff79cdbf FT |
4 | dom = xml.dom.minidom.getDOMImplementation() |
5 | ||
62551769 FT |
6 | ns = "http://www.w3.org/1999/xhtml" |
7 | doctype = "-//W3C//DTD XHTML 1.1//EN" | |
8 | dtd = "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" | |
ff79cdbf FT |
9 | |
10 | class htmlelement(_cons.element): | |
11 | def __todoc__(self): | |
12 | doc = dom.createDocument(None, None, None) | |
13 | doc.appendChild(dom.createDocumentType("html", doctype, dtd)) | |
14 | doc.appendChild(self.__todom__(doc)) | |
15 | return doc | |
16 | ||
a573465e | 17 | class xhtmlcontext(_cons.context): |
26648796 | 18 | attrmap = {"klass": "class"} |
a573465e FT |
19 | |
20 | def addattr(self, node, k, v): | |
26648796 | 21 | k = str(k) |
d38b2004 | 22 | super().addattr(node, self.attrmap.get(k, k), v) |
a573465e | 23 | |
ff79cdbf | 24 | def cons(ctx=None): |
a573465e | 25 | if ctx is None: ctx = xhtmlcontext() |
ff79cdbf FT |
26 | return _cons.constructor(ns, htmlelement, ctx) |
27 | ||
28 | def head(title=None, css=None): | |
29 | h = cons() | |
30 | head = h.head | |
31 | if title: | |
32 | head(h.title(title)) | |
62551769 | 33 | if isinstance(css, str) or isinstance(css, bytes): |
ff79cdbf FT |
34 | head(h.link(rel="stylesheet", type="text/css", href=css)) |
35 | elif css: | |
36 | for ss in css: | |
37 | head(h.link(rel="stylesheet", type="text/css", href=ss)) | |
38 | return head | |
39 | ||
40 | class htmlformatter(util.formatter): | |
919b8a4f | 41 | allowshort = {"br", "hr", "img", "input", "meta", "link"} |
fb5f9f27 | 42 | def shorttag(self, el): |
ff79cdbf | 43 | if el.name in self.allowshort: |
919b8a4f | 44 | super().shorttag(el) |
ff79cdbf | 45 | else: |
7e9080af FT |
46 | self.handle(">", el) |
47 | self.handle("<", el) | |
ff79cdbf | 48 | |
fb5f9f27 | 49 | class htmlindenter(util.textindenter, htmlformatter): |
ff79cdbf FT |
50 | pass |
51 | ||
52 | def forreq(req, tree): | |
53 | # XXX: Use proper Content-Type for clients accepting it. | |
54 | req.ohead["Content-Type"] = "text/html; charset=utf-8" | |
dc437c45 | 55 | buf = io.BytesIO() |
ff79cdbf | 56 | htmlindenter.output(buf, tree, doctype=(doctype, dtd), charset="utf-8") |
a7b35f84 FT |
57 | ret = buf.getvalue() |
58 | req.ohead["Content-Length"] = len(ret) | |
59 | return [ret] | |
ff79cdbf FT |
60 | |
61 | def xhtmlresp(callable): | |
62 | def wrapper(req): | |
63 | return forreq(req, callable(req)) | |
d22f3483 | 64 | wrapper.__wrapped__ = callable |
ff79cdbf | 65 | return wrapper |