1 # -*- coding: utf-8 -*-
3 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
8 from librarian.formats import Format
9 from librarian.output import OutputFile
10 from librarian.renderers import Register, TreeRenderer
11 from librarian.utils import Context, get_resource
12 from librarian import core
15 class HtmlFormat(Format):
19 renderers = Register()
21 def __init__(self, doc, standalone=False):
22 super(HtmlFormat, self).__init__(doc)
23 self.standalone = standalone
27 tmpl = get_resource("formats/html/res/html_standalone.html")
29 tmpl = get_resource("formats/html/res/html.html")
32 ctx = Context(format=self)
35 ctx.footnotes = Footnotes()
38 t.find('head/title').text = u"%s (%s)" % (self.doc.meta.title(), self.doc.meta.author())
40 t.find('.//div[@id="content"]').extend(
41 self.render(self.doc.edoc.getroot(), ctx))
42 t.find('.//div[@id="toc"]').append(ctx.toc.render())
43 t.find('.//div[@id="footnotes"]').extend(ctx.footnotes.output)
45 return OutputFile.from_string(etree.tostring(
46 t, encoding='utf-8', method="html"))
48 def render(self, element, ctx):
49 return self.renderers.get_for(element).render(element, ctx)
54 class NaturalText(TreeRenderer):
55 def render_text(self, text, ctx):
56 root, inner = self.text_container()
57 chunks = re.split('(?<=\s\w) ', text)
58 inner.text = chunks[0]
59 for chunk in chunks[1:]:
60 x = etree.Entity("nbsp")
66 class LiteralText(TreeRenderer):
70 class Footnotes(object):
73 self.output = etree.Element("_")
75 def append(self, item):
77 e = etree.Element("a",
78 href="#footnote-anchor-%d" % self.counter,
79 id="footnote-%d" % self.counter,
80 style="float:left;margin-right:1em")
81 e.text = "[%d]" % self.counter
84 self.output.extend(item)
85 anchor = etree.Element("a",
86 id="footnote-anchor-%d" % self.counter,
87 href="#footnote-%d" % self.counter)
88 anchor.text = "[%d]" % self.counter
97 def add(self, title, level=0):
99 self.items.append((level, title, self.counter))
103 out = etree.Element("ul", id="toc")
106 for level, title, counter in self.items:
107 while level > curr_level:
108 ins = etree.Element("ul")
112 while level < curr_level:
113 cursor = cursor.getparent()
115 ins = etree.Element("li")
116 ins.append(etree.Element("a", href="#sect%d" % counter))
124 HtmlFormat.renderers.register(core.Aside, None, NaturalText('aside'))
126 class AsideFootnote(NaturalText):
127 def render(self, element, ctx):
128 output = super(AsideFootnote, self).render(element, ctx)
129 anchor = ctx.footnotes.append(output)
130 root, inner = self.container()
133 HtmlFormat.renderers.register(core.Aside, 'footnote', AsideFootnote())
136 HtmlFormat.renderers.register(core.Header, None, NaturalText('h1'))
139 HtmlFormat.renderers.register(core.Div, None, NaturalText('div'))
140 HtmlFormat.renderers.register(core.Div, 'item', NaturalText('li'))
141 HtmlFormat.renderers.register(core.Div, 'list', NaturalText('ul'))
142 HtmlFormat.renderers.register(core.Div, 'p', NaturalText('p'))
145 class Section(NaturalText):
146 def subcontext(self, element, ctx):
147 return Context(ctx, toc_level=ctx.toc_level + 1)
149 def render(self, element, ctx):
150 counter = ctx.toc.add(element.meta.title(), ctx.toc_level)
151 root = super(Section, self).render(element, ctx)
152 root[0].set("id", "sect%d" % counter)
154 HtmlFormat.renderers.register(core.Section, None, Section('section'))
157 HtmlFormat.renderers.register(core.Span, None, NaturalText('span'))
158 HtmlFormat.renderers.register(core.Span, 'cite', NaturalText('cite'))
159 HtmlFormat.renderers.register(core.Span, 'cite.code', LiteralText('code'))
160 HtmlFormat.renderers.register(core.Span, 'emph', NaturalText('em'))
162 class SpanUri(LiteralText):
163 def render(self, element, ctx):
164 root = super(SpanUri, self).render(element, ctx)
165 root[0].attrib['href'] = element.text
167 HtmlFormat.renderers.register(core.Span, 'uri', SpanUri('a'))