New EPUB builder, other minor changes.
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 5 Jul 2021 09:47:09 +0000 (11:47 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 5 Jul 2021 09:47:09 +0000 (11:47 +0200)
79 files changed:
src/librarian/builders/__init__.py
src/librarian/builders/epub.py [new file with mode: 0644]
src/librarian/builders/pdf.py [new file with mode: 0644]
src/librarian/builders/txt.py
src/librarian/cover.py
src/librarian/document.py
src/librarian/elements/__init__.py
src/librarian/elements/base.py
src/librarian/elements/blocks/dedykacja.py
src/librarian/elements/blocks/dlugi_cytat.py
src/librarian/elements/blocks/nota.py
src/librarian/elements/blocks/poezja_cyt.py
src/librarian/elements/blocks/ramka.py
src/librarian/elements/comments/abstrakt.py
src/librarian/elements/comments/nota_red.py
src/librarian/elements/comments/uwaga.py
src/librarian/elements/drama/didask_tekst.py
src/librarian/elements/drama/didaskalia.py
src/librarian/elements/drama/kwestia.py
src/librarian/elements/drama/lista_osob.py
src/librarian/elements/drama/lista_osoba.py
src/librarian/elements/drama/miejsce_czas.py
src/librarian/elements/drama/naglowek_listy.py
src/librarian/elements/drama/naglowek_osoba.py
src/librarian/elements/drama/osoba.py
src/librarian/elements/figures/ilustr.py
src/librarian/elements/figures/kol.py
src/librarian/elements/figures/tabela.py
src/librarian/elements/figures/wiersz.py
src/librarian/elements/footnotes/__init__.py
src/librarian/elements/front/autor_utworu.py
src/librarian/elements/front/dzielo_nadrzedne.py
src/librarian/elements/front/motto.py
src/librarian/elements/front/motto_podpis.py
src/librarian/elements/front/nazwa_utworu.py
src/librarian/elements/front/podtytul.py
src/librarian/elements/headers/__init__.py
src/librarian/elements/headers/naglowek_czesc.py
src/librarian/elements/headers/naglowek_rozdzial.py
src/librarian/elements/headers/naglowek_scena.py [new file with mode: 0644]
src/librarian/elements/headers/podtytul_czesc.py
src/librarian/elements/headers/podtytul_podrozdzial.py
src/librarian/elements/headers/podtytul_rozdzial.py
src/librarian/elements/paragraphs/akap.py
src/librarian/elements/poetry/strofa.py
src/librarian/elements/poetry/wers.py
src/librarian/elements/poetry/wers_akap.py
src/librarian/elements/poetry/wers_cd.py
src/librarian/elements/poetry/wers_do_prawej.py
src/librarian/elements/poetry/wers_wciety.py
src/librarian/elements/separators/sekcja_asterysk.py
src/librarian/elements/separators/sekcja_swiatlo.py
src/librarian/elements/separators/separator_linia.py
src/librarian/elements/styles/indeks_dolny.py
src/librarian/elements/styles/mat.py
src/librarian/elements/styles/slowo_obce.py
src/librarian/elements/styles/tytul_dziela.py
src/librarian/elements/styles/wieksze_odstepy.py
src/librarian/elements/styles/wyroznienie.py
src/librarian/elements/themes/motyw.py
src/librarian/epub.py
src/librarian/epub/style.css
src/librarian/epub/xsltAnnotations.xsl
src/librarian/epub/xsltScheme.xsl
src/librarian/fonts.py [new file with mode: 0644]
src/librarian/fundraising.py [new file with mode: 0644]
src/librarian/html.py
src/librarian/pdf.py
src/librarian/pdf/wl.cls
src/librarian/pdf/wl2tex.xslt
src/librarian/res/BN.png [new file with mode: 0644]
src/librarian/res/MKIDN.jpg [new file with mode: 0644]
src/librarian/res/atrium-logo.png
src/librarian/res/dofinansowano.png [new file with mode: 0644]
src/librarian/text.py
src/librarian/xslt/book2html.xslt
tests/uat/main.xml
tests/uat/parent.xml [new file with mode: 0644]
tests/uat/part2.xml [new file with mode: 0644]

index dc5bdee..e359cd6 100644 (file)
@@ -3,6 +3,8 @@ from .txt import TxtBuilder
 from .html import HtmlBuilder, StandaloneHtmlBuilder, DaisyHtmlBuilder
 from .sanitize import Sanitizer
 from .daisy import DaisyBuilder
 from .html import HtmlBuilder, StandaloneHtmlBuilder, DaisyHtmlBuilder
 from .sanitize import Sanitizer
 from .daisy import DaisyBuilder
+from .epub import EpubBuilder
+from .pdf import PdfBuilder
 
 
 builders = OrderedDict([
 
 
 builders = OrderedDict([
@@ -12,4 +14,7 @@ builders = OrderedDict([
     ("html-daisy", DaisyHtmlBuilder),
     ("daisy", DaisyBuilder),
     ("sanitizer", Sanitizer),
     ("html-daisy", DaisyHtmlBuilder),
     ("daisy", DaisyBuilder),
     ("sanitizer", Sanitizer),
+
+    ("epub", EpubBuilder),
+    ("pdf", PdfBuilder),
 ])
 ])
diff --git a/src/librarian/builders/epub.py b/src/librarian/builders/epub.py
new file mode 100644 (file)
index 0000000..91405c3
--- /dev/null
@@ -0,0 +1,690 @@
+from datetime import date
+import os
+import tempfile
+from ebooklib import epub
+from lxml import etree
+import six
+from librarian import functions, OutputFile, get_resource, XHTMLNS
+from librarian.cover import make_cover
+from librarian.embeds.mathml import MathML
+import librarian.epub
+from librarian.fonts import strip_font
+from librarian.fundraising import FUNDRAISING
+
+
+
+
+class Xhtml:
+    def __init__(self):
+        self.element = etree.XML('''<html xmlns="http://www.w3.org/1999/xhtml"><head><link rel="stylesheet" href="style.css" type="text/css"/><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>WolneLektury.pl</title></head><body/></html>''')
+
+    @property
+    def title(self):
+        return self.element.find('.//' + XHTMLNS('title'))
+        
+    @property
+    def body(self):
+        return self.element.find('.//' + XHTMLNS('body'))
+
+
+class Builder:
+    file_extension = None
+
+    def __init__(self, base_url=None):
+        self._base_url = base_url or 'file:///home/rczajka/for/fnp/librarian/temp~/maly/img/'
+        self.footnotes = etree.Element('div', id='footnotes')
+
+        self.cursors = {
+#            None: None,
+#            'header': self.header,
+            'footnotes': self.footnotes,
+        }
+        self.current_cursors = []
+
+        self.toc_base = 0
+
+    @property
+    def cursor(self):
+        return self.current_cursors[-1]
+
+    def enter_fragment(self, fragment):
+        self.current_cursors.append(self.cursors[fragment])
+
+    def exit_fragment(self):
+        self.current_cursors.pop()
+
+    def create_fragment(self, name, element):
+        assert name not in self.cursors
+        self.cursors[name] = element
+
+    def forget_fragment(self, name):
+        del self.cursors[name]
+
+
+
+    @property
+    def base_url(self):
+        if self._base_url is not None:
+            return self._base_url
+        else:
+            return 'https://wolnelektury.pl/media/book/pictures/{}/'.format(self.document.meta.url.slug)
+
+
+    # Base URL should be on Document level, not builder.
+    def build(self, document, **kwargs):
+        """Should return an OutputFile with the output."""
+        raise NotImplementedError()
+
+
+class EpubBuilder(Builder):
+    file_extension = 'epub'
+
+    def __init__(self, *args, **kwargs):
+        self.chars = set()
+        self.fundr = 0
+        super().__init__(*args, **kwargs)
+    
+    def build(self, document, **kwargs):
+        # replace_characters -- nie, robimy to na poziomie elementów
+        
+        # hyphenator (\00ad w odp. miejscach) -- jeśli już, to też powinno to się dziać na poziomie elementów
+        # spójniki (\u00a0 po)-- jeśli już, to na poziomie elementów
+        # trick na dywizy: &#xad;&#8288;-
+
+        # do toc trafia:
+        #   początek z KAŻDEGO PLIKU xml
+        
+        # zliczamy zbiór użytych znaków
+
+        # flagi:
+        # mieliśmy taką flagę less-advertising, używaną tylko dla Prestigio; już nie używamy.
+
+        # @editors = document.editors() (jako str)
+        # @funders = join(meta.funders)
+        # @thanks = meta.thanks
+
+
+        self.output = output = epub.EpubBook()
+        self.document = document
+
+        self.set_metadata()
+        
+
+        self.add_cover()
+        
+        self.add_title_page()
+        self.add_toc()
+
+
+
+        self.start_chunk()
+
+        self.add_toc_entry(
+            None,
+            'Początek utworu', # i18n
+            0
+        )
+        self.output.guide.append({
+            "type": "text",
+            "title": "Początek",
+            "href": "part1.xhtml"
+        })
+
+
+        self.build_document(self.document)
+
+        
+        self.close_chunk()
+
+        self.add_annotations()
+        self.add_support_page()
+        self.add_last_page()
+
+
+        e = len(self.output.spine) - 3 - 3
+        nfunds = len(FUNDRAISING)
+        if e > 16:
+            nfunds *= 2
+
+        # COUNTING CHARACTERS?
+        for f in range(nfunds):
+            spine_index = int(4 + (f / nfunds * e) + f)
+
+            h = Xhtml()
+            h.body.append(
+                etree.XML('<div id="book-text"><div class="fundraising">' + FUNDRAISING[f % len(FUNDRAISING)] + '</div></div>')
+            )
+            self.add_html(h.element, file_name='fund%d.xhtml' % f, spine=spine_index)
+
+        self.add_fonts()
+
+        output_file = tempfile.NamedTemporaryFile(
+            prefix='librarian', suffix='.epub',
+            delete=False)
+        output_file.close()
+        epub.write_epub(output_file.name, output, {'epub3_landmark': False})
+        return OutputFile.from_filename(output_file.name)
+
+    def build_document(self, document):
+        self.toc_precedences = []
+
+        self.start_chunk()
+
+
+        document.tree.getroot().epub_build(self)
+        if document.meta.parts:
+            self.start_chunk()
+
+            self.start_element('div', {'class': 'title-page'})
+            self.start_element('h1', {'class': 'title'})
+            self.push_text(document.meta.title)
+            self.end_element()
+            self.end_element()
+
+            ######
+            # 160
+            # translators
+            # working copy?
+            # ta lektura
+            # tanks
+            # utwor opracowany
+            # isbn
+            # logo
+
+            for child in document.children:
+                self.start_chunk()
+                self.add_toc_entry(None, child.meta.title, 0)
+                self.build_document(child)
+
+        self.shift_toc_base()
+            
+    
+    def add_title_page(self):
+        html = Xhtml()
+        html.title.text = "Strona tytułowa"
+        bt = etree.SubElement(html.body, 'div', **{'class': 'book-text'})
+        tp = etree.SubElement(bt, 'div', **{'class': 'title-page'})
+
+        # Tak jak jest teraz – czy może być jednocześnie
+        # no „autor_utworu”
+        # i „dzieło nadrzędne”
+        # wcześniej mogło być dzieło nadrzędne,
+
+        e = self.document.tree.find('//autor_utworu')
+        if e is not None:
+            etree.SubElement(tp, 'h2', **{'class': 'author'}).text = e.raw_printable_text()
+        e = self.document.tree.find('//nazwa_utworu')
+        if e is not None:
+            etree.SubElement(tp, 'h1', **{'class': 'title'}).text = e.raw_printable_text()
+
+        if not len(tp):
+            for author in self.document.meta.authors:
+                etree.SubElement(tp, 'h2', **{'class': 'author'}).text = author.readable()
+            etree.SubElement(tp, 'h1', **{'class': 'title'}).text = self.document.meta.title
+
+#                <xsl:apply-templates select="//nazwa_utworu | //podtytul | //dzielo_nadrzedne" mode="poczatek"/>
+#        else:
+#                            <xsl:apply-templates select="//dc:creator" mode="poczatek"/>
+#                <xsl:apply-templates select="//dc:title | //podtytul | //dzielo_nadrzedne" mode="poczatek"/>
+
+        etree.SubElement(tp, 'p', **{"class": "info"}).text = '\u00a0'
+
+        if self.document.meta.translators:
+            p = etree.SubElement(tp, 'p', **{'class': 'info'})
+            p.text = 'tłum. ' + ', '.join(t.readable() for t in self.document.meta.translators)
+                
+        #<p class="info">[Kopia robocza]</p>
+
+        p = etree.XML("""<p class="info">
+              <a>Ta lektura</a>, podobnie jak tysiące innych, jest dostępna on-line na stronie
+              <a href="http://www.wolnelektury.pl/">wolnelektury.pl</a>.
+            </p>""")
+        p[0].attrib['href'] = str(self.document.meta.url)
+        tp.append(p)
+
+        if self.document.meta.thanks:
+            etree.SubElement(tp, 'p', **{'class': 'info'}).text = self.document.meta.thanks
+        
+        tp.append(etree.XML("""
+          <p class="info">
+            Utwór opracowany został w&#160;ramach projektu<a href="http://www.wolnelektury.pl/"> Wolne Lektury</a> przez<a href="http://www.nowoczesnapolska.org.pl/"> fundację Nowoczesna Polska</a>.
+          </p>
+        """))
+
+        if self.document.meta.isbn_epub:
+            etree.SubElement(tp, 'p', **{"class": "info"}).text = self.document.meta.isbn_epub
+
+        tp.append(etree.XML("""<p class="footer info">
+            <a href="http://www.wolnelektury.pl/"><img src="logo_wolnelektury.png" alt="WolneLektury.pl" /></a>
+        </p>"""))
+
+        self.add_html(
+            html.element,
+            file_name='title.xhtml',
+            spine=True,
+            toc='Strona tytułowa' # TODO: i18n
+        )
+
+        self.add_file(
+            get_resource('res/wl-logo-small.png'),
+            file_name='logo_wolnelektury.png',
+            media_type='image/png'
+        )
+    
+    def set_metadata(self):
+        self.output.set_identifier(
+            str(self.document.meta.url))
+        self.output.set_language(
+            functions.lang_code_3to2(self.document.meta.language)
+        )
+        self.output.set_title(self.document.meta.title)
+
+        for i, author in enumerate(self.document.meta.authors):
+            self.output.add_author(
+                author.readable(),
+                file_as=six.text_type(author),
+                uid='creator{}'.format(i)
+            )
+        for translator in self.document.meta.translators:
+            self.output.add_author(
+                translator.readable(),
+                file_as=six.text_type(translator),
+                role='trl',
+                uid='translator{}'.format(i)
+            )
+        for publisher in self.document.meta.publisher:
+            self.output.add_metadata("DC", "publisher", publisher)
+
+        self.output.add_metadata("DC", "date", self.document.meta.created_at)
+
+        
+
+
+    def add_toc(self):
+        item = epub.EpubNav()
+        self.output.add_item(item)
+        self.output.spine.append(item)
+        self.output.add_item(epub.EpubNcx())
+
+        self.output.toc.append(
+            epub.Link(
+                "nav.xhtml",
+                "Spis treści",
+                "nav"
+            )
+        )
+
+    
+
+    def add_support_page(self):
+        self.add_file(
+            get_resource('epub/support.xhtml'),
+            spine=True,
+            toc='Wesprzyj Wolne Lektury'
+        )
+
+        self.add_file(
+            get_resource('res/jedenprocent.png'),
+            media_type='image/png'
+        )
+        self.add_file(
+            get_resource('epub/style.css'),
+            media_type='text/css'
+        )
+
+
+    def add_file(self, path=None, content=None,
+                 media_type='application/xhtml+xml',
+                 file_name=None, uid=None,
+                 spine=False, toc=None):
+
+        # update chars?
+        # jakieś tam ścieśnianie białych znaków?
+
+        if content is None:
+            with open(path, 'rb') as f:
+                content = f.read()
+            if file_name is None:
+                file_name = path.rsplit('/', 1)[-1]
+
+        if uid is None:
+            uid = file_name.split('.', 1)[0]
+
+        item = epub.EpubItem(
+            uid=uid,
+            file_name=file_name,
+            media_type=media_type,
+            content=content
+        )
+
+        self.output.add_item(item)
+        if spine:
+            if spine is True:
+                self.output.spine.append(item)
+            else:
+                self.output.spine.insert(spine, item)
+
+        if toc:
+            self.output.toc.append(
+                epub.Link(
+                    file_name,
+                    toc,
+                    uid
+                )
+            )
+
+    def add_html(self, html_tree, **kwargs):
+        html = etree.tostring(
+            html_tree, pretty_print=True, xml_declaration=True,
+            encoding="utf-8",
+            doctype='<!DOCTYPE html>'
+        )
+
+        html = librarian.epub.squeeze_whitespace(html)
+
+        self.add_file(
+            content=html,
+            **kwargs
+        )
+            
+        
+    def add_fonts(self):
+        print("".join(sorted(self.chars)))
+        # TODO: optimizer
+        for fname in ('DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf',
+                      'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf'):
+            self.add_file(
+                content=strip_font(
+                    get_resource('fonts/' + fname),
+                    self.chars
+                ),
+                file_name=fname,
+                media_type='font/ttf'
+            )
+
+    def start_chunk(self):
+        if getattr(self, 'current_chunk', None) is not None:
+            if not len(self.current_chunk):
+                return
+            self.close_chunk()
+        self.current_chunk = etree.Element(
+            'div',
+            id="book-text"
+        )
+        self.cursors[None] = self.current_chunk
+        self.current_cursors.append(self.current_chunk)
+
+        self.section_number = 0
+        
+
+    def close_chunk(self):
+        assert self.cursor is self.current_chunk
+        ###### -- what if we're inside?
+
+        chunk_no = getattr(
+            self,
+            'chunk_counter',
+            1
+        )
+        self.chunk_counter = chunk_no + 1
+
+        html = Xhtml()
+        html.body.append(self.current_chunk)
+        
+        self.add_html(
+            ## html container from template.
+            #self.current_chunk,
+            html.element,
+            file_name='part%d.xhtml' % chunk_no,
+            spine=True,
+            
+        )
+        self.current_chunk = None
+        self.current_cursors.pop()
+
+    def start_element(self, tag, attr):
+        self.current_cursors.append(
+            etree.SubElement(self.cursor, tag, **attr)
+        )
+        
+    def end_element(self):
+        self.current_cursors.pop()
+        
+    def push_text(self, text):
+        self.chars.update(text)
+        if len(self.cursor):
+            self.cursor[-1].tail = (self.cursor[-1].tail or '') + text
+        else:
+            self.cursor.text = (self.cursor.text or '') + text
+
+
+    def assign_image_number(self):
+        image_number = getattr(self, 'image_number', 0)
+        self.image_number = image_number + 1
+        return image_number
+
+    def assign_footnote_number(self):
+        number = getattr(self, 'footnote_number', 1)
+        self.footnote_number = number + 1
+        return number
+
+    def assign_section_number(self):
+        number = getattr(self, 'section_number', 1)
+        self.section_number = number + 1
+        return number
+
+    def assign_mathml_number(self):
+        number = getattr(self, 'mathml_number', 0)
+        self.mathml_number = number + 1
+        return number
+
+    
+    def add_toc_entry(self, fragment, name, precedence):
+        if precedence:
+            while self.toc_precedences and self.toc_precedences[-1] >= precedence:
+                self.toc_precedences.pop()
+        else:
+            self.toc_precedences = []
+
+        real_level = self.toc_base + len(self.toc_precedences)
+        if precedence:
+            self.toc_precedences.append(precedence)
+        else:
+            self.toc_base += 1
+        
+        part_number = getattr(
+            self,
+            'chunk_counter',
+            1
+        )
+        filename = 'part%d.xhtml' % part_number
+        uid = filename.split('.')[0]
+        if fragment:
+            filename += '#' + fragment
+            uid += '-' + fragment
+
+        toc = self.output.toc
+        for l in range(1, real_level):
+            if isinstance(toc[-1], epub.Link):
+                toc[-1] = [toc[-1], []]
+            toc = toc[-1][1]
+
+        toc.append(
+            epub.Link(
+                filename,
+                name,
+                uid
+            )
+        )
+
+    def shift_toc_base(self):
+        self.toc_base -= 1
+        
+
+    def add_last_page(self):
+        html = Xhtml()
+        m = self.document.meta
+        
+        html.title.text = 'Strona redakcyjna'
+        d = etree.SubElement(html.body, 'div', id='book-text')
+
+        newp = lambda: etree.SubElement(d, 'p', {'class': 'info'})
+
+        p = newp()
+        if m.license:
+            p.text = """
+                      Ten utwór jest udostępniony na licencji
+                      """
+            etree.SubElement(p, 'a', href=m.license).text = m.license_description
+        else:
+            p.text = """
+                    Ten utwór nie jest objęty majątkowym prawem autorskim i znajduje się w domenie
+                    publicznej, co oznacza że możesz go swobodnie wykorzystywać, publikować
+                    i rozpowszechniać. Jeśli utwór opatrzony jest dodatkowymi materiałami
+                    (przypisy, motywy literackie etc.), które podlegają prawu autorskiemu, to
+                    te dodatkowe materiały udostępnione są na licencji
+                    """
+            a = etree.SubElement(p, "a", href="http://creativecommons.org/licenses/by-sa/3.0/")
+            a.text = """Creative Commons
+                    Uznanie Autorstwa – Na Tych Samych Warunkach 3.0 PL"""
+            a.tail = "."
+
+
+        p = newp()
+        p.text = 'Źródło: '
+        etree.SubElement(
+            p, 'a', href=str(m.url),
+            title=', '.join((
+                ', '.join(p.readable() for p in m.authors),
+                m.title
+            ))
+        ).text = str(m.url)
+
+        newp().text = 'Tekst opracowany na podstawie: ' + m.source_name
+
+        newp().text = """
+              Wydawca:
+              """ + ", ".join(p for p in m.publisher)
+
+        if m.description:
+            newp().text = m.description
+
+
+        if m.editors:
+            newp().text = 'Opracowanie redakcyjne i przypisy: %s.' % (
+                ', '.join(e.readable() for e in sorted(self.document.editors())))
+
+        if m.funders:
+            etree.SubElement(d, 'p', {'class': 'minor-info'}).text = '''Publikację wsparli i wsparły:
+            %s.''' % (', '.join(m.funders))
+
+        if m.cover_by:
+            p = newp()
+            p.text = 'Okładka na podstawie: '
+            if m.cover_source:
+                etree.SubElement(
+                    p,
+                    'a',
+                    href=m.cover_source
+                ).text = m.cover_by
+            else:
+                p.text += m.cover_by
+            
+        if m.isbn_epub:
+            newp().text = m.isbn_epub
+
+        newp().text = '\u00a0'
+
+        p = newp()
+        p.attrib['class'] = 'minor-info'
+        p.text = '''
+              Plik wygenerowany dnia '''
+        span = etree.SubElement(p, 'span', id='file_date')
+        span.text = str(date.today())
+        span.tail = '''.
+          '''
+        
+        self.add_html(
+            html.element,
+            file_name='last.xhtml',
+            toc='Strona redakcyjna',
+            spine=True
+        )
+
+
+    def add_annotations(self):
+        if not len(self.footnotes):
+            return
+
+        html = Xhtml()
+        html.title.text = 'Przypisy'
+        d = etree.SubElement(
+            etree.SubElement(
+                html.body,
+                'div',
+                id='book-text'
+            ),
+            'div',
+            id='footnotes'
+        )
+        
+        etree.SubElement(
+            d,
+            'h2',
+        ).text = 'Przypisy:'
+
+        d.extend(self.footnotes)
+        
+        self.add_html(
+            html.element,
+            file_name='annotations.xhtml',
+            spine=True,
+            toc='Przypisy'
+        )
+
+    def add_cover(self):
+        # TODO: allow other covers
+
+        cover_maker = make_cover
+
+        cover_file = six.BytesIO()
+        cover = cover_maker(self.document.meta)
+        cover.save(cover_file)
+        cover_name = 'cover.%s' % cover.ext()
+
+        self.output.set_cover(
+            file_name=cover_name,
+            content=cover_file.getvalue(),
+            create_page = False
+        )
+        ci = ('''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en" xml:lang="en">
+ <head>
+  <title>Okładka</title>
+  <style>
+    body { margin: 0em; padding: 0em; }
+    img { width: 100%%; }
+  </style>
+ </head>
+ <body>
+   <img src="cover.%s" alt="Okładka" />
+ </body>
+</html>''' % cover.ext()).encode('utf-8')
+        self.add_file(file_name='cover.xhtml', content=ci)
+
+        self.output.spine.append('cover')
+        self.output.guide.append({
+            'type': 'cover',
+            'href': 'cover.xhtml',
+            'title': 'Okładka'
+        })
+
+    def mathml(self, element):
+        name = "math%d.png" % self.assign_mathml_number()
+        self.add_file(
+            content=MathML(element).to_latex().to_png().data,
+            media_type='image/png',
+            file_name=name
+        )
+        return name
diff --git a/src/librarian/builders/pdf.py b/src/librarian/builders/pdf.py
new file mode 100644 (file)
index 0000000..6b2501e
--- /dev/null
@@ -0,0 +1,12 @@
+from librarian import OutputFile
+
+
+class PdfBuilder:
+    # Obowiązkowe
+    file_extension = 'pdf'
+    def build(self, document, mp3):
+        # stub
+        return OutputFile.from_bytes(b'')
+
+
+
index 3f19346..8dba4ae 100644 (file)
@@ -50,20 +50,40 @@ class TxtBuilder:
 
     default_license_description = {
         "pol": (
 
     default_license_description = {
         "pol": (
-            "Ten utwór nie jest objęty majątkowym prawem autorskim "
-            "i znajduje się w domenie publicznej, co oznacza że "
-            "możesz go swobodnie wykorzystywać, publikować "
-            "i rozpowszechniać. Jeśli utwór opatrzony jest "
-            "dodatkowymi materiałami (przypisy, motywy literackie "
-            "etc.), które podlegają prawu autorskiemu, to te "
-            "dodatkowe materiały udostępnione są na licencji "
-            "Creative Commons Uznanie Autorstwa – Na Tych Samych "
-            "Warunkach 3.0 PL "
-            "(http://creativecommons.org/licenses/by-sa/3.0/)"
+            "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+            "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+            "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n"
+            "Ten utwór jest w domenie publicznej. "
+            "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+            "udostępnione na Licencji Wolnej Sztuki 1.3 "
+            "(https://artlibre.org/licence/lal/pl/).\n"
+            "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+            "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+            "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, "
+            "należy pamiętać o zapisach licencji oraz zasadach, które "
+            "spisaliśmy w Zasadach wykorzystania Wolnych Lektur "
+            "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj "
+            "się z nimi, zanim udostępnisz dalej nasze książki."
         )
     }
     license_description = {
         )
     }
     license_description = {
-        "pol": "Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}",
+        "pol": (
+            #"Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}",
+            "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+            "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+            "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n"
+            "Ten utwór jest jest udostępniony na licencji {meta.license_description} ({meta.license}). "
+            "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+            "udostępnione na Licencji Wolnej Sztuki 1.3 "
+            "(https://artlibre.org/licence/lal/pl/).\n"
+            "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+            "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+            "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, "
+            "należy pamiętać o zapisach licencji oraz zasadach, które "
+            "spisaliśmy w Zasadach wykorzystania Wolnych Lektur "
+            "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj "
+            "się z nimi, zanim udostępnisz dalej nasze książki."
+        )
     }
 
     def __init__(self):
     }
 
     def __init__(self):
index 1873be9..7d7964d 100644 (file)
@@ -363,10 +363,10 @@ class WLCover(Cover):
         box_img = box.image()
 
         # Find box position.
         box_img = box.image()
 
         # Find box position.
-        if self.box_position == 'top':
-            box_top = metr.box_top_margin
-        elif self.box_position == 'bottom':
+        if self.box_position == 'bottom' or box_img.size[1] + metr.box_top_margin + metr.box_bottom_margin > metr.height:
             box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
             box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
+        elif self.box_position == 'top':
+            box_top = metr.box_top_margin
         else:   # Middle.
             box_top = (metr.height - box_img.size[1]) // 2
 
         else:   # Middle.
             box_top = (metr.height - box_img.size[1]) // 2
 
@@ -470,6 +470,7 @@ class WLNoBoxCover(WLCover):
 class LogoWLCover(WLCover):
     gradient_height = 90
     gradient_logo_height = 60
 class LogoWLCover(WLCover):
     gradient_height = 90
     gradient_logo_height = 60
+    gradient_logo_max_width = 1000
     gradient_logo_margin_right = 30
     gradient_logo_spacing = 40
     gradient_color = '#000'
     gradient_logo_margin_right = 30
     gradient_logo_spacing = 40
     gradient_color = '#000'
@@ -478,6 +479,8 @@ class LogoWLCover(WLCover):
         'res/wl-logo-white.png',
         'res/fnp-logo-white.png',
     ]
         'res/wl-logo-white.png',
         'res/fnp-logo-white.png',
     ]
+    annotation = None
+    annotation_height = 10
 
     def __init__(self, book_info, *args, **kwargs):
         super(LogoWLCover, self).__init__(book_info, *args, **kwargs)
 
     def __init__(self, book_info, *args, **kwargs):
         super(LogoWLCover, self).__init__(book_info, *args, **kwargs)
@@ -537,7 +540,10 @@ class LogoWLCover(WLCover):
             - 2 * metr.gradient_logo_margin_right
         )
         widths = [
             - 2 * metr.gradient_logo_margin_right
         )
         widths = [
-            logo.size[0] * metr.gradient_logo_height / logo.size[1]
+            min(
+                metr.gradient_logo_max_width,
+                logo.size[0] * metr.gradient_logo_height / logo.size[1]
+            )
             for logo in logos]
         taken_space = (
             sum(widths)
             for logo in logos]
         taken_space = (
             sum(widths)
@@ -553,13 +559,36 @@ class LogoWLCover(WLCover):
             logo = logo.resize(
                 (
                     int(round(widths[i] * logo_scale)),
             logo = logo.resize(
                 (
                     int(round(widths[i] * logo_scale)),
-                    int(round(metr.gradient_logo_height * logo_scale))
+                    int(round(
+                        logo.size[1] * widths[i] / logo.size[0] * logo_scale
+                    ))
                 ),
                 Image.ANTIALIAS)
             cursor -= logo.size[0]
                 ),
                 Image.ANTIALIAS)
             cursor -= logo.size[0]
-            img.paste(logo, (cursor, logo_top), mask=logo)
+            img.paste(
+                logo,
+                (
+                    cursor,
+                    int(round(logo_top + (metr.gradient_logo_height - logo.size[1]) * logo_scale / 2))
+                ),
+                mask=logo
+            )
             cursor -= int(round(metr.gradient_logo_spacing * logo_scale))
 
             cursor -= int(round(metr.gradient_logo_spacing * logo_scale))
 
+        if self.annotation:
+            img2 = Image.new('RGBA', (metr.height, metr.height), color=None)
+            draw = ImageDraw.Draw(img2)
+            author_font = ImageFont.truetype(
+                self.author_font_ttf, metr.annotation_height,
+                layout_engine=ImageFont.LAYOUT_BASIC)
+            draw.text((self.annotation_height, self.annotation_height), self.annotation, font=author_font, fill='#FFFFFF')
+            img2.show()
+            img2 = img2.rotate(90)
+            img2.show()
+            img.putalpha(0)
+            img.alpha_composite(img2, (0, 0))
+            img = img.convert('RGB')
+
         return img
 
 
         return img
 
 
@@ -676,11 +705,22 @@ class AtriumCover(LogoWLCover):
     ]
 
 
     ]
 
 
+class BNCover(LogoWLCover):
+    gradient_logos = [
+        'res/dofinansowano.png',
+        'res/MKIDN.jpg',
+        'res/BN.png',
+        'res/wl-logo-white.png',
+    ]
+#    annotation = 'Zadanie „Udostępnienie publikacji w formatach cyfrowych” w ramach Narodowego Programu Rozwoju Czytelnictwa. Dofinansowano ze środków Ministra Kultury, Dziedzictwa Narodowego i Sportu.'
+
+
 COVER_CLASSES = {
     'default': LogoWLCover,
     'kmlu': KMLUCover,
     'mpw': MPWCover,
     'atrium': AtriumCover,
 COVER_CLASSES = {
     'default': LogoWLCover,
     'kmlu': KMLUCover,
     'mpw': MPWCover,
     'atrium': AtriumCover,
+    'bn': BNCover,
 }
 
 
 }
 
 
index 6e94ff2..0dbb14f 100644 (file)
@@ -4,12 +4,12 @@ import re
 from lxml import etree
 import six
 from .parser import parser
 from lxml import etree
 import six
 from .parser import parser
-from . import dcparser, DCNS
+from . import dcparser, DCNS, DirDocProvider
 from .functions import lang_code_3to2
 
 
 class WLDocument:
 from .functions import lang_code_3to2
 
 
 class WLDocument:
-    def __init__(self, filename=None, url=None):
+    def __init__(self, filename=None, url=None, provider=None):
         source = filename or six.moves.urllib.request.urlopen(url)
         tree = etree.parse(source, parser=parser)
         self.tree = tree
         source = filename or six.moves.urllib.request.urlopen(url)
         tree = etree.parse(source, parser=parser)
         self.tree = tree
@@ -18,6 +18,8 @@ class WLDocument:
             DCNS('language'): ["pol"],
         }, validate_required=False)
 
             DCNS('language'): ["pol"],
         }, validate_required=False)
 
+        self.provider = provider if provider is not None else DirDocProvider('.')
+
     @property
     def meta(self):
         # Allow metadata of the master element as document meta.
     @property
     def meta(self):
         # Allow metadata of the master element as document meta.
@@ -25,6 +27,15 @@ class WLDocument:
         return self.tree.getroot().meta
         return master.meta
 
         return self.tree.getroot().meta
         return master.meta
 
+    @property
+    def children(self):
+        for part_uri in self.meta.parts or []:
+            yield type(self)(
+                filename=self.provider.by_uri(part_uri),
+                provider=self.provider
+            )
+            
+    
     def build(self, builder, **kwargs):
         return builder().build(self, **kwargs)
 
     def build(self, builder, **kwargs):
         return builder().build(self, **kwargs)
 
@@ -66,3 +77,13 @@ class WLDocument:
                 _compat_assigns_section_ids_in_elem(child, idfier + '-')
         _compat_assigns_section_ids_in_elem(self.tree.getroot().master)
 
                 _compat_assigns_section_ids_in_elem(child, idfier + '-')
         _compat_assigns_section_ids_in_elem(self.tree.getroot().master)
 
+
+    def editors(self):
+        persons = set(self.meta.editors
+                      + self.meta.technical_editors)
+        #for child in self.parts():
+        #    persons.update(child.editors())
+        #if None in persons:
+        #    persons.remove(None)
+        return persons
+
index f3a8521..c3a55fb 100644 (file)
@@ -82,7 +82,7 @@ WL_ELEMENTS = {
 
     "naglowek_czesc": headers.NaglowekCzesc,
     "naglowek_akt": headers.NaglowekCzesc,
 
     "naglowek_czesc": headers.NaglowekCzesc,
     "naglowek_akt": headers.NaglowekCzesc,
-    "naglowek_scena": headers.NaglowekRozdzial,
+    "naglowek_scena": headers.NaglowekScena,
     "naglowek_rozdzial": headers.NaglowekRozdzial,
     "naglowek_podrozdzial": headers.NaglowekPodrozdzial,
     "srodtytul": headers.NaglowekCzesc,
     "naglowek_rozdzial": headers.NaglowekRozdzial,
     "naglowek_podrozdzial": headers.NaglowekPodrozdzial,
     "srodtytul": headers.NaglowekCzesc,
index b9df185..5317268 100644 (file)
@@ -3,10 +3,13 @@
 import re
 from lxml import etree
 from librarian import dcparser, RDFNS
 import re
 from lxml import etree
 from librarian import dcparser, RDFNS
+from librarian.html import raw_printable_text
 from librarian.util import get_translation
 
 
 class WLElement(etree.ElementBase):
 from librarian.util import get_translation
 
 
 class WLElement(etree.ElementBase):
+    SECTION_PRECEDENCE = None
+
     TXT_TOP_MARGIN = 0
     TXT_BOTTOM_MARGIN = 0
     TXT_PREFIX = ""
     TXT_TOP_MARGIN = 0
     TXT_BOTTOM_MARGIN = 0
     TXT_PREFIX = ""
@@ -15,17 +18,24 @@ class WLElement(etree.ElementBase):
     HTML_TAG = None
     HTML_ATTR = {}
     HTML_CLASS = None
     HTML_TAG = None
     HTML_ATTR = {}
     HTML_CLASS = None
-    
+
+    EPUB_TAG = None
+    EPUB_ATTR = {}
+    EPUB_CLASS = None
+    EPUB_START_CHUNK = False
+   
     CAN_HAVE_TEXT = True
     STRIP = False
 
     text_substitutions = [
         (u'---', u'—'),
         (u'--', u'–'),
     CAN_HAVE_TEXT = True
     STRIP = False
 
     text_substitutions = [
         (u'---', u'—'),
         (u'--', u'–'),
-        (u'...', u'…'),
+        #(u'...', u'…'),  # Temporary turnoff for epub
         (u',,', u'„'),
         (u'"', u'”'),
         ('\ufeff', ''),
         (u',,', u'„'),
         (u'"', u'”'),
         ('\ufeff', ''),
+
+        ("'", "\u2019"),    # This was enabled for epub.
     ]
 
     @property
     ]
 
     @property
@@ -52,11 +62,25 @@ class WLElement(etree.ElementBase):
     def gettext(self):
         return get_translation(self.meta.language).gettext
 
     def gettext(self):
         return get_translation(self.meta.language).gettext
 
+    def raw_printable_text(self):
+        # TODO: podtagi, wyroznienia, etc
+        t = ''
+        t += self.normalize_text(self.text)
+        for c in self:
+            if c.tag not in ('pe', 'pa', 'pt', 'pr', 'motyw'):
+                t += c.raw_printable_text()
+            t += self.normalize_text(c.tail)
+        return t
+    
     def normalize_text(self, text):
         text = text or ''
         for e, s in self.text_substitutions:
             text = text.replace(e, s)
     def normalize_text(self, text):
         text = text or ''
         for e, s in self.text_substitutions:
             text = text.replace(e, s)
-        text = re.sub(r'\s+', ' ', text)
+            # FIXME: TEmporary turnoff
+#        text = re.sub(r'\s+', ' ', text)
+### TODO: Added now for epub
+        text = re.sub(r'(?<=\s\w)\s+', u'\u00A0', text)
+
         return text
 
     def _build_inner(self, builder, build_method):
         return text
 
     def _build_inner(self, builder, build_method):
@@ -118,6 +142,48 @@ class WLElement(etree.ElementBase):
         if self.HTML_TAG:
             builder.end_element()
 
         if self.HTML_TAG:
             builder.end_element()
 
+    def _epub_build_inner(self, builder):
+        self._build_inner(builder, 'epub_build')
+
+    def get_epub_attr(self, builder):
+        attr = self.EPUB_ATTR.copy()
+        if self.EPUB_CLASS:
+            attr['class'] = self.EPUB_CLASS
+        return attr
+
+    def epub_build(self, builder):
+        # TEMPORARY
+        self.CAN_HAVE_TEXT = True
+        self.STRIP = False
+        
+        if self.EPUB_START_CHUNK:
+            builder.start_chunk()
+
+        fragment = None
+        if self.SECTION_PRECEDENCE:
+            if not self.EPUB_START_CHUNK:
+                fragment = 'sub%d' % builder.assign_section_number()
+                self.attrib['id'] = fragment
+
+            builder.add_toc_entry(
+                fragment,
+                self.raw_printable_text(),
+                self.SECTION_PRECEDENCE
+            )
+            
+        if self.EPUB_TAG:
+            attr = self.get_epub_attr(builder)
+            if fragment:
+                attr['id'] = fragment
+            builder.start_element(
+                self.EPUB_TAG,
+                attr
+            )
+
+        self._epub_build_inner(builder)
+        if self.EPUB_TAG:
+            builder.end_element()
+            
     def sanitize(self):
         # TODO: Remove insanity here.
         for e in self:
     def sanitize(self):
         # TODO: Remove insanity here.
         for e in self:
index 5436271..7ac809d 100644 (file)
@@ -4,5 +4,5 @@ from ..base import WLElement
 class Dedykacja(WLElement):
     TXT_LEGACY_TOP_MARGIN = 2
 
 class Dedykacja(WLElement):
     TXT_LEGACY_TOP_MARGIN = 2
 
-    HTML_TAG = "div"
-    HTML_CLASS = "dedication"
+    EPUB_TAG = HTML_TAG = "div"
+    EPUB_CLASS = HTML_CLASS = "dedication"
index c660583..22e98dd 100644 (file)
@@ -10,3 +10,6 @@ class DlugiCytat(WLElement):
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'blockquote'
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'blockquote'
+
+    EPUB_TAG = 'div'
+    EPUB_CLASS = 'block'
index a01bf29..0e3f61f 100644 (file)
@@ -4,5 +4,5 @@ from ..base import WLElement
 class Nota(WLElement):
     CAN_HAVE_TEXT = False
 
 class Nota(WLElement):
     CAN_HAVE_TEXT = False
 
-    HTML_TAG = "div"
-    HTML_CLASS = "note"
+    EPUB_TAG = HTML_TAG = "div"
+    EPUB_CLASS = HTML_CLASS = "note"
index 0c103b1..14cd539 100644 (file)
@@ -10,3 +10,6 @@ class PoezjaCyt(WLElement):
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'blockquote'
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'blockquote'
+
+    EPUB_TAG = 'div'
+    EPUB_CLASS = 'block'
index d8dd5f0..b85f83f 100644 (file)
@@ -5,3 +5,5 @@ class Ramka(WLElement):
     HTML_TAG = "div"
     HTML_CLASS = "ramka"
 
     HTML_TAG = "div"
     HTML_CLASS = "ramka"
 
+    EPUB_TAG = "div"
+    EPUB_CLASS = "frame"
index 9b43dc3..887712b 100644 (file)
@@ -7,3 +7,6 @@ class Abstrakt(WLElement):
 
     def html_build(self, builder):
         pass
 
     def html_build(self, builder):
         pass
+
+    def epub_build(self, builder):
+        pass
index faa5dd1..0ce970e 100644 (file)
@@ -9,3 +9,6 @@ class NotaRed(WLElement):
         builder.enter_fragment('nota_red')
         super(NotaRed, self).html_build(builder)
         builder.exit_fragment()
         builder.enter_fragment('nota_red')
         super(NotaRed, self).html_build(builder)
         builder.exit_fragment()
+
+    def epub_build(self, builder):
+        pass
index adf908b..1bdeb39 100644 (file)
@@ -7,3 +7,6 @@ class Uwaga(WLElement):
 
     def html_build(self, builder):
         pass
 
     def html_build(self, builder):
         pass
+
+    def epub_build(self, builder):
+        pass
index 7227c17..088e373 100644 (file)
@@ -5,5 +5,5 @@ class DidaskTekst(WLElement):
     TXT_PREFIX = "/ "
     TXT_SUFFIX = " /"
 
     TXT_PREFIX = "/ "
     TXT_SUFFIX = " /"
 
-    HTML_TAG = "em"
-    HTML_CLASS = "didaskalia"
+    EPUB_TAG = HTML_TAG = "em"
+    EPUB_CLASS = HTML_CLASS = "didaskalia"
index af0520f..bf81b69 100644 (file)
@@ -9,5 +9,5 @@ class Didaskalia(WLElement):
     TXT_PREFIX = "/ "
     TXT_SUFFIX = " /"
 
     TXT_PREFIX = "/ "
     TXT_SUFFIX = " /"
 
-    HTML_TAG = "div"
-    HTML_CLASS = "didaskalia"
+    EPUB_TAG =_HTML_TAG = "div"
+    EPUB_CLASS = HTML_CLASS = "didaskalia"
index 27dca30..56463d6 100644 (file)
@@ -4,5 +4,5 @@ from ..base import WLElement
 class Kwestia(WLElement):
     CAN_HAVE_TEXT = False
 
 class Kwestia(WLElement):
     CAN_HAVE_TEXT = False
 
-    HTML_TAG = "div"
-    HTML_CLASS = "kwestia"
+    EPUB_TAG = HTML_TAG = "div"
+    EPUB_CLASS = HTML_CLASS = "kwestia"
index 5beca64..269b05c 100644 (file)
@@ -19,3 +19,10 @@ class ListaOsob(WLElement):
         super(ListaOsob, self)._html_build_inner(builder)
         builder.cursor.append(ol)
         builder.forget_fragment('list')
         super(ListaOsob, self)._html_build_inner(builder)
         builder.cursor.append(ol)
         builder.forget_fragment('list')
+
+    def _epub_build_inner(self, builder):
+        ol = etree.Element('ol')
+        builder.create_fragment('list', ol)
+        super(ListaOsob, self)._epub_build_inner(builder)
+        builder.cursor.append(ol)
+        builder.forget_fragment('list')
index fe55838..c5770ee 100644 (file)
@@ -8,10 +8,14 @@ class ListaOsoba(WLElement):
     TXT_LEGACY_BOTTOM_MARGIN = 0
     TXT_PREFIX = " * "
 
     TXT_LEGACY_BOTTOM_MARGIN = 0
     TXT_PREFIX = " * "
 
-    HTML_TAG = "li"
+    EPUB_TAG = HTML_TAG = "li"
 
     def html_build(self, builder):
         builder.enter_fragment('list')
         super(ListaOsoba, self).html_build(builder)
         builder.exit_fragment()
         
 
     def html_build(self, builder):
         builder.enter_fragment('list')
         super(ListaOsoba, self).html_build(builder)
         builder.exit_fragment()
         
+    def epub_build(self, builder):
+        builder.enter_fragment('list')
+        super(ListaOsoba, self).epub_build(builder)
+        builder.exit_fragment()
index a4e9453..cf47ed2 100644 (file)
@@ -2,4 +2,7 @@ from ..paragraphs import Akap
 
 
 class MiejsceCzas(Akap):
 
 
 class MiejsceCzas(Akap):
-    HTML_CLASS = 'place-and-time'
+    EPUB_CLASS = HTML_CLASS = 'place-and-time'
+
+    EPUB_TAG = "div"
+    
index 4db9111..1f164a4 100644 (file)
@@ -3,3 +3,6 @@ from ..base import WLElement
 
 class NaglowekListy(WLElement):
     HTML_TAG = "h3"
 
 class NaglowekListy(WLElement):
     HTML_TAG = "h3"
+
+    EPUB_TAG = "div"
+    EPUB_CLASS = "h3"
index 5ab78fd..afa16ce 100644 (file)
@@ -8,3 +8,6 @@ class NaglowekOsoba(WLElement):
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = "h4"
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = "h4"
+
+    EPUB_TAG = "h2"
+    EPUB_CLASS = "h4"
index b0fb793..ffd9494 100644 (file)
@@ -2,6 +2,6 @@ from ..base import WLElement
 
 
 class Osoba(WLElement):
 
 
 class Osoba(WLElement):
-    HTML_TAG = "em"
-    HTML_CLASS = "person"
+    EPUB_TAG = HTML_TAG = "em"
+    EPUB_CLASS = HTML_CLASS = "person"
 
 
index 3c3026c..ab7c2b7 100644 (file)
@@ -1,12 +1,51 @@
+import six.moves
+from PIL import Image
 from ..base import WLElement
 
 
 class Ilustr(WLElement):
 from ..base import WLElement
 
 
 class Ilustr(WLElement):
-    HTML_TAG = 'img'
+    EPUB_TAG = HTML_TAG = 'img'
 
     def get_html_attr(self, builder):
 
     def get_html_attr(self, builder):
+        ## TODO: thumbnail.
+
+        url = six.moves.urllib.parse.urljoin(
+            builder.base_url,
+            self.get('src')
+        )
+        
+        imgfile = six.moves.urllib.request.urlopen(url)
+        img = Image.open(imgfile)
+        th_format, ext, media_type = {
+            'GIF': ('GIF', 'gif', 'image/gif'),
+            'PNG': ('PNG', 'png', 'image/png'),
+        }.get(img.format, ('JPEG', 'jpg', 'image/jpeg'))
+
+        width = 1200
+        if img.size[0] < width:
+            th = img
+        else:
+            th = img.resize((width, round(width * img.size[1] / img.size[0])))
+
+        imgfile.close()
+        buffer = six.BytesIO()
+        th.save(buffer, format=th_format)
+        ## TODO: Counter
+        file_name = 'image%d.%s' % (
+            builder.assign_image_number(),
+            ext
+        )
+
+        builder.add_file(
+            content=buffer.getvalue(),
+            file_name=file_name,
+            media_type=media_type,
+        )
+        
         return {
         return {
-            'src': builder.base_url + self.attrib['src'],
+            'src': file_name,
             'alt': self.attrib['alt'],
             'title': self.attrib['alt'],
         }
             'alt': self.attrib['alt'],
             'title': self.attrib['alt'],
         }
+
+    get_epub_attr = get_html_attr
index e0dae02..c94f20d 100644 (file)
@@ -2,4 +2,4 @@ from ..base import WLElement
 
 
 class Kol(WLElement):
 
 
 class Kol(WLElement):
-    HTML_TAG = 'td'
+    EPUB_TAG = HTML_TAG = 'td'
index af4a436..7da7877 100644 (file)
@@ -2,7 +2,7 @@ from ..base import WLElement
 
 
 class Tabela(WLElement):
 
 
 class Tabela(WLElement):
-    HTML_TAG = 'table'
+    EPUB_TAG = HTML_TAG = 'table'
 
     def get_html_attr(self, builder):
         if self.attrib.get('ramka', '') == '1':
 
     def get_html_attr(self, builder):
         if self.attrib.get('ramka', '') == '1':
@@ -10,3 +10,7 @@ class Tabela(WLElement):
                 'class': 'border'
             }
         return {}
                 'class': 'border'
             }
         return {}
+
+    get_epub_attr = get_html_attr
+
+                
index bc61f9d..2c7d91a 100644 (file)
@@ -2,4 +2,4 @@ from ..base import WLElement
 
 
 class Wiersz(WLElement):
 
 
 class Wiersz(WLElement):
-    HTML_TAG = 'tr'
+    EPUB_TAG = HTML_TAG = 'tr'
index 0f30747..433e881 100644 (file)
@@ -49,6 +49,49 @@ class Footnote(WLElement):
         builder.end_element()
         builder.exit_fragment()
 
         builder.end_element()
         builder.exit_fragment()
 
+    def epub_build(self, builder):
+        fn_no = builder.assign_footnote_number()
+        part_number = getattr(
+            builder,
+            'chunk_counter',
+            1
+        )
+
+        builder.start_element(
+            'a',
+            {
+                'class': 'anchor',
+                'id': f'anchor-{fn_no}',
+                'href': f'annotations.xhtml#annotation-{fn_no}',
+            }
+        )
+        builder.start_element('sup', {})
+        builder.push_text(str(fn_no))
+        builder.end_element()
+        builder.end_element()
+
+        
+        builder.enter_fragment('footnotes')
+        builder.start_element('p', {
+            'id': f'annotation-{fn_no}',
+            'class': "annotation"
+        })
+        builder.start_element('a', {
+            'href': f"part{part_number}.xhtml#anchor-{fn_no}"
+        })
+        builder.push_text(str(fn_no))
+        builder.end_element()
+        builder.push_text('. ')
+
+        super().epub_build(builder)
+        builder.push_text(' [' + self.qualifier + ']')
+        builder.end_element()
+
+        builder.push_text('\n')
+
+        builder.exit_fragment()
+
+        
 
 class PA(Footnote):
     """Przypis autorski."""
 
 class PA(Footnote):
     """Przypis autorski."""
index fd6b2e8..736a24c 100644 (file)
@@ -6,3 +6,6 @@ class AutorUtworu(HeaderElement):
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
     HTML_CLASS = 'author'
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
     HTML_CLASS = 'author'
+
+    def epub_build(self, builder):
+        return
index a034ae7..5f114bc 100644 (file)
@@ -6,3 +6,6 @@ class DzieloNadrzedne(HeaderElement):
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = "collection"
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = "collection"
+
+    def epub_build(self, builder):
+        return
index 98c7334..7f23ea6 100644 (file)
@@ -5,5 +5,5 @@ class Motto(WLElement):
     TXT_LEGACY_TOP_MARGIN = 4
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
     TXT_LEGACY_TOP_MARGIN = 4
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
-    HTML_TAG = "div"
-    HTML_CLASS = "motto"
+    EPUB_TAG = HTML_TAG = "div"
+    EPUB_CLASS = HTML_CLASS = "motto"
index 58fc9db..8fee127 100644 (file)
@@ -3,5 +3,7 @@ from ..base import WLElement
 
 class MottoPodpis(WLElement):
     HTML_TAG = "p"
 
 class MottoPodpis(WLElement):
     HTML_TAG = "p"
-    HTML_CLASS = "motto_podpis"
+    EPUB_CLASS = HTML_CLASS = "motto_podpis"
 
 
+    EPUB_TAG = "div"
+    
index aa68082..4d06b47 100644 (file)
@@ -6,3 +6,6 @@ class NazwaUtworu(HeaderElement):
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = 'title'
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = 'title'
+
+    EPUB_TAG = 'h2'
+    EPUB_CLASS = 'intitle'
index 4431bc2..71e28a8 100644 (file)
@@ -6,3 +6,7 @@ class Podtytul(HeaderElement):
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = 'subtitle'
     TXT_LEGACY_BOTTOM_MARGIN = 1
 
     HTML_CLASS = 'subtitle'
+
+    EPUB_TAG = 'h2'
+    EPUB_CLASS = 'insubtitle'
+
index 3389eec..f3bda2b 100644 (file)
@@ -1,6 +1,9 @@
 from .naglowek_czesc import NaglowekCzesc
 from .naglowek_podrozdzial import NaglowekPodrozdzial
 from .naglowek_rozdzial import NaglowekRozdzial
 from .naglowek_czesc import NaglowekCzesc
 from .naglowek_podrozdzial import NaglowekPodrozdzial
 from .naglowek_rozdzial import NaglowekRozdzial
+from .naglowek_scena import NaglowekScena
 from .podtytul_czesc import PodtytulCzesc
 from .podtytul_rozdzial import PodtytulRozdzial
 from .podtytul_podrozdzial import PodtytulPodrozdzial
 from .podtytul_czesc import PodtytulCzesc
 from .podtytul_rozdzial import PodtytulRozdzial
 from .podtytul_podrozdzial import PodtytulPodrozdzial
+
+
index c7b2d9e..829e4f4 100644 (file)
@@ -2,9 +2,14 @@ from ..base import WLElement
 
 
 class NaglowekCzesc(WLElement):
 
 
 class NaglowekCzesc(WLElement):
+    SECTION_PRECEDENCE = 1
+    
     TXT_TOP_MARGIN = 5
     TXT_BOTTOM_MARGIN = 2
     TXT_LEGACY_TOP_MARGIN = 5
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     TXT_TOP_MARGIN = 5
     TXT_BOTTOM_MARGIN = 2
     TXT_LEGACY_TOP_MARGIN = 5
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
-    HTML_TAG = "h2"
+    EPUB_TAG = HTML_TAG = "h2"
+
+    EPUB_CLASS = "h2"
+    EPUB_START_CHUNK = True
index ded615f..33ff355 100644 (file)
@@ -2,9 +2,15 @@ from ..base import WLElement
 
 
 class NaglowekRozdzial(WLElement):
 
 
 class NaglowekRozdzial(WLElement):
+    SECTION_PRECEDENCE = 2
+    
     TXT_TOP_MARGIN = 4
     TXT_BOTTOM_MARGIN = 2
     TXT_LEGACY_TOP_MARGIN = 4
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'h3'
     TXT_TOP_MARGIN = 4
     TXT_BOTTOM_MARGIN = 2
     TXT_LEGACY_TOP_MARGIN = 4
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     HTML_TAG = 'h3'
+
+    EPUB_TAG = 'h2'
+    EPUB_CLASS = 'h3'
+    EPUB_START_CHUNK = True
diff --git a/src/librarian/elements/headers/naglowek_scena.py b/src/librarian/elements/headers/naglowek_scena.py
new file mode 100644 (file)
index 0000000..8a52ca2
--- /dev/null
@@ -0,0 +1,17 @@
+from ..base import WLElement
+
+
+class NaglowekScena(WLElement):
+    SECTION_PRECEDENCE = 2
+
+    TXT_TOP_MARGIN = 4
+    TXT_BOTTOM_MARGIN = 2
+    TXT_LEGACY_TOP_MARGIN = 4
+    TXT_LEGACY_BOTTOM_MARGIN = 0
+
+    HTML_TAG = 'h3'
+
+    EPUB_TAG = 'h2'
+    EPUB_CLASS = 'h3'
+    EPUB_START_CHUNK = False
+
index 9825211..df8fd5c 100644 (file)
@@ -7,3 +7,11 @@ class PodtytulCzesc(WLElement):
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle2"
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle2"
+
+    EPUB_TAG = "h2"
+    EPUB_CLASS = "h2"
+
+    def _epub_build_inner(self, builder):
+        builder.start_element('small', {})
+        super()._epub_build_inner(builder)
+        builder.end_element()
index 74aef13..cc00207 100644 (file)
@@ -7,3 +7,11 @@ class PodtytulPodrozdzial(WLElement):
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle4"
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle4"
+
+    EPUB_TAG = "h2"
+    EPUB_CLASS = "h4"
+
+    def _epub_build_inner(self, builder):
+        builder.start_element('small', {})
+        super()._epub_build_inner(builder)
+        builder.end_element()
index 675e19b..f8db548 100644 (file)
@@ -7,3 +7,11 @@ class PodtytulRozdzial(WLElement):
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle3"
 
     HTML_TAG = "div"
     HTML_CLASS = "subtitle3"
+
+    EPUB_TAG = "h2"
+    EPUB_CLASS = "h3"
+
+    def _epub_build_inner(self, builder):
+        builder.start_element('small', {})
+        super()._epub_build_inner(builder)
+        builder.end_element()
index 0a76c52..b0c0329 100644 (file)
@@ -9,5 +9,5 @@ class Akap(WLElement):
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
-    HTML_TAG = 'p'
-    HTML_CLASS = 'paragraph'
+    EPUB_TAG = HTML_TAG = 'p'
+    EPUB_CLASS = HTML_CLASS = 'paragraph'
index 7df549f..a843d20 100644 (file)
@@ -1,4 +1,5 @@
 from copy import copy
 from copy import copy
+import re
 from ..base import WLElement
 from .wers import Wers
 
 from ..base import WLElement
 from .wers import Wers
 
@@ -9,8 +10,19 @@ class Strofa(WLElement):
     TXT_LEGACY_TOP_MARGIN = 1
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     TXT_LEGACY_TOP_MARGIN = 1
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
-    HTML_TAG = 'div'
-    HTML_CLASS = 'stanza'
+    EPUB_TAG = HTML_TAG = 'div'
+    EPUB_CLASS = HTML_CLASS = 'stanza'
+
+    def epub_build(self, builder):
+        super().epub_build(builder)
+        builder.start_element(
+            'div',
+            {
+                'class': 'stanza-spacer'
+            }
+        )
+        builder.push_text('\u00a0');
+        builder.end_element()
     
     def get_verses(self):
         from librarian.parser import parser
     
     def get_verses(self):
         from librarian.parser import parser
@@ -20,7 +32,7 @@ class Strofa(WLElement):
         ]
         if self.text:
             # Before any tags. These are text-only verses.
         ]
         if self.text:
             # Before any tags. These are text-only verses.
-            pieces = self.text.split('/')
+            pieces = re.split(r"/\s+", self.text)
             for piece in pieces[:-1]:
                 verses[-1].text = piece
                 verses.append(parser.makeelement('wers'))
             for piece in pieces[:-1]:
                 verses[-1].text = piece
                 verses.append(parser.makeelement('wers'))
@@ -28,7 +40,7 @@ class Strofa(WLElement):
 
         for child in self:
             if child.tail:
 
         for child in self:
             if child.tail:
-                pieces = child.tail.split('/')
+                pieces = re.split(r"/\s+", child.tail)
                 child_copy = copy(child)
                 child_copy.tail = pieces[0]
                 verses[-1].append(child_copy)
                 child_copy = copy(child)
                 child_copy.tail = pieces[0]
                 verses[-1].append(child_copy)
index 5c28058..55cf537 100644 (file)
@@ -9,11 +9,16 @@ class Wers(WLElement):
     TXT_LEGACY_TOP_MARGIN = 1
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
     TXT_LEGACY_TOP_MARGIN = 1
     TXT_LEGACY_BOTTOM_MARGIN = 0
 
-    HTML_TAG = 'div'
-    HTML_CLASS = 'verse'
+    EPUB_TAG = HTML_TAG = 'div'
+    EPUB_CLASS = HTML_CLASS = 'verse'
 
     @property
     def meta(self):
         if hasattr(self, 'stanza'):
             return self.stanza.meta
         return super(Wers, self).meta
 
     @property
     def meta(self):
         if hasattr(self, 'stanza'):
             return self.stanza.meta
         return super(Wers, self).meta
+
+    def _epub_build_inner(self, builder):
+        super()._epub_build_inner(builder)
+        builder.push_text('''\u00a0''')
+
index 03b8187..c0d70f4 100644 (file)
@@ -7,3 +7,7 @@ class WersAkap(Wers):
     HTML_ATTR = {
         "style": "padding-left: 1em"
     }
     HTML_ATTR = {
         "style": "padding-left: 1em"
     }
+
+    EPUB_ATTR = {
+        "style": "margin-left: 1em"
+    }
index a61d5bc..df1f563 100644 (file)
@@ -8,3 +8,7 @@ class WersCd(Wers):
     HTML_ATTR = {
         "style": "padding-left: 12em",
     }
     HTML_ATTR = {
         "style": "padding-left: 12em",
     }
+
+    EPUB_ATTR = {
+        "style": "margin-left: 12em",
+    }
index 9ab5ff0..81af0d6 100644 (file)
@@ -4,6 +4,6 @@ from .wers import Wers
 class WersDoPrawej(Wers):
     TXT_PREFIX = '                       '
 
 class WersDoPrawej(Wers):
     TXT_PREFIX = '                       '
 
-    HTML_ATTR = {
+    EPUB_ATTR = HTML_ATTR = {
         "style": "text-align: right",
     }
         "style": "text-align: right",
     }
index 8ac2bb3..662e57a 100644 (file)
@@ -18,3 +18,8 @@ class WersWciety(Wers):
         attr = super(WersWciety, self).get_html_attr(builder)
         attr['style'] = "padding-left: {}em".format(self.typ)
         return attr
         attr = super(WersWciety, self).get_html_attr(builder)
         attr['style'] = "padding-left: {}em".format(self.typ)
         return attr
+
+    def get_epub_attr(self, builder):
+        attr = super(WersWciety, self).get_html_attr(builder)
+        attr['style'] = "margin-left: {}em".format(self.typ)
+        return attr
index e68430d..46be85b 100644 (file)
@@ -7,8 +7,8 @@ class SekcjaAsterysk(WLElement):
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
-    HTML_TAG = "p"
-    HTML_CLASS = "spacer-asterisk"
+    EPUB_TAG = HTML_TAG = "p"
+    HTML_CLASS = HTML_CLASS = "spacer-asterisk"
 
     def _txt_build_inner(self, builder):
         builder.push_text('*')
 
     def _txt_build_inner(self, builder):
         builder.push_text('*')
@@ -16,3 +16,5 @@ class SekcjaAsterysk(WLElement):
     def _html_build_inner(self, builder):
         builder.push_text("*")
 
     def _html_build_inner(self, builder):
         builder.push_text("*")
 
+    _epub_build_inner = _html_build_inner
+
index 7d950da..28ba6e5 100644 (file)
@@ -7,3 +7,9 @@ class SekcjaSwiatlo(WLElement):
 
     HTML_TAG = "hr"
     HTML_CLASS = "spacer"
 
     HTML_TAG = "hr"
     HTML_CLASS = "spacer"
+
+    EPUB_TAG = 'p'
+    EPUB_CLASS = 'spacer'
+
+    def _epub_build_inner(self, builder):
+        builder.push_text("\u00a0")
index 5249691..49ea17f 100644 (file)
@@ -7,8 +7,8 @@ class SeparatorLinia(WLElement):
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
     TXT_LEGACY_TOP_MARGIN = 2
     TXT_LEGACY_BOTTOM_MARGIN = 2
 
-    HTML_TAG = "hr"
-    HTML_CLASS = "spacer-line"
+    EPUB_TAG = HTML_TAG = "hr"
+    EPUB_CLASS = HTML_CLASS = "spacer-line"
     
     def _txt_build_inner(self, builder):
         builder.push_text('-' * 48)
     
     def _txt_build_inner(self, builder):
         builder.push_text('-' * 48)
index 5d19a44..bac93c0 100644 (file)
@@ -4,4 +4,4 @@ from ..base import WLElement
 class IndeksDolny(WLElement):
     TXT_PREFIX = "_"
 
 class IndeksDolny(WLElement):
     TXT_PREFIX = "_"
 
-    HTML_TAG = "sub"
+    EPUB_TAG = HTML_TAG = "sub"
index f284695..fa353f9 100644 (file)
@@ -8,3 +8,7 @@ class Mat(WLElement):
         e.tag = 'math'
         e.attrib['xmlns'] = 'http://www.w3.org/1998/Math/MathML'
         builder.cursor.append(e)
         e.tag = 'math'
         e.attrib['xmlns'] = 'http://www.w3.org/1998/Math/MathML'
         builder.cursor.append(e)
+
+    def epub_build(self, builder):
+        builder.start_element('img', {"src": builder.mathml(self)})
+        builder.end_element()
index 3592a1e..5848aa6 100644 (file)
@@ -2,5 +2,5 @@ from ..base import WLElement
 
 
 class SlowoObce(WLElement):
 
 
 class SlowoObce(WLElement):
-    HTML_TAG = 'em'
-    HTML_CLASS = 'foreign-word'
+    EPUB_TAG = HTML_TAG = 'em'
+    EPUB_CLASS = HTML_CLASS = 'foreign-word'
index ef3618c..906d98c 100644 (file)
@@ -3,8 +3,8 @@ from ..base import WLElement
 
 
 class TytulDziela(WLElement):
 
 
 class TytulDziela(WLElement):
-    HTML_TAG = 'em'
-    HTML_CLASS = 'book-title'
+    EPUB_TAG = HTML_TAG = 'em'
+    EPUB_CLASS = HTML_CLASS = 'book-title'
 
     def normalize_text(self, text):
         txt = super(TytulDziela, self).normalize_text(text)
 
     def normalize_text(self, text):
         txt = super(TytulDziela, self).normalize_text(text)
index 3229402..953e797 100644 (file)
@@ -5,5 +5,5 @@ class WiekszeOdstepy(WLElement):
     TXT_PREFIX = "*"
     TXT_SUFFIX = "*"
 
     TXT_PREFIX = "*"
     TXT_SUFFIX = "*"
 
-    HTML_TAG = "em"
-    HTML_CLASS = "wieksze-odstepy"
+    EPUB_TAG = HTML_TAG = "em"
+    EPUB_CLASS = HTML_CLASS = "wieksze-odstepy"
index c76b4cf..2a71a29 100644 (file)
@@ -5,5 +5,5 @@ class Wyroznienie(WLElement):
     TXT_PREFIX = "*"
     TXT_SUFFIX = "*"
 
     TXT_PREFIX = "*"
     TXT_SUFFIX = "*"
 
-    HTML_TAG = "em"
-    HTML_CLASS = "author-emphasis"
+    EPUB_TAG = HTML_TAG = "em"
+    EPUB_CLASS = HTML_CLASS = "author-emphasis"
index f9ab197..25369a7 100644 (file)
@@ -18,3 +18,6 @@ class Motyw(WLElement):
             "fid": fid,
             "name": "m" + fid,
         }
             "fid": fid,
             "name": "m" + fid,
         }
+
+    def epub_build(self, builder):
+        pass
index e2cdae7..0fb91e5 100644 (file)
@@ -30,6 +30,7 @@ functions.reg_person_name()
 
 
 def squeeze_whitespace(s):
 
 
 def squeeze_whitespace(s):
+    return s
     return re.sub(b'\\s+', b' ', s)
 
 
     return re.sub(b'\\s+', b' ', s)
 
 
@@ -62,33 +63,6 @@ def hyphenate_and_fix_conjunctions(source_tree, hyph):
             parent.tail = newt
 
 
             parent.tail = newt
 
 
-def inner_xml(node):
-    """ returns node's text and children as a string
-
-    >>> print(inner_xml(etree.fromstring('<a>x<b>y</b>z</a>')))
-    x<b>y</b>z
-    """
-
-    nt = node.text if node.text is not None else ''
-    return ''.join(
-        [nt] + [etree.tostring(child, encoding='unicode') for child in node]
-    )
-
-
-def set_inner_xml(node, text):
-    """ sets node's text and children from a string
-
-    >>> e = etree.fromstring('<a>b<b>x</b>x</a>')
-    >>> set_inner_xml(e, 'x<b>y</b>z')
-    >>> print(etree.tostring(e, encoding='unicode'))
-    <a>x<b>y</b>z</a>
-    """
-
-    p = etree.fromstring('<x>%s</x>' % text)
-    node.text = p.text
-    node[:] = p[:]
-
-
 def node_name(node):
     """ Find out a node's name
 
 def node_name(node):
     """ Find out a node's name
 
@@ -377,17 +351,8 @@ def remove_empty_lists_from_toc(toc):
                 toc[i] = e[0]
 
 
                 toc[i] = e[0]
 
 
-def transform(wldoc, verbose=False, style=None,
-              sample=None, cover=None, flags=None, hyphenate=False,
-              base_url='file://./', output_type='epub'):
-    """ produces a EPUB file
-
-    sample=n: generate sample e-book (with at least n paragraphs)
-    cover: a cover.Cover factory or True for default
-    flags: less-advertising, without-fonts, working-copy
-    """
 
 
-    def transform_file(wldoc, chunk_counter=1, first=True, sample=None):
+def transform_file(wldoc, chunk_counter=1, first=True, sample=None, hyphenate=False, output_type='epub', spine=None, output=None, annotations=None):
         """ processes one input file and proceeds to its children """
 
         replace_characters(wldoc.edoc.getroot())
         """ processes one input file and proceeds to its children """
 
         replace_characters(wldoc.edoc.getroot())
@@ -518,12 +483,27 @@ def transform(wldoc, verbose=False, style=None,
 
         for child in wldoc.parts():
             child_toc, chunk_counter, chunk_chars, sample = transform_file(
 
         for child in wldoc.parts():
             child_toc, chunk_counter, chunk_chars, sample = transform_file(
-                child, chunk_counter, first=False, sample=sample)
+                child, chunk_counter, first=False, sample=sample,
+                hyphenate=hyphenate, output_type=output_type,
+                spine=spine, output=output, annotations=annotations,
+            )
             toc[-1][1].extend(child_toc)
             chars = chars.union(chunk_chars)
 
         return toc, chunk_counter, chars, sample
 
             toc[-1][1].extend(child_toc)
             chars = chars.union(chunk_chars)
 
         return toc, chunk_counter, chars, sample
 
+                
+def transform(wldoc, verbose=False, style=None,
+              sample=None, cover=None, flags=None, hyphenate=False,
+              base_url='file://./', output_type='epub'):
+    """ produces a EPUB file
+
+    sample=n: generate sample e-book (with at least n paragraphs)
+    cover: a cover.Cover factory or True for default
+    flags: less-advertising, without-fonts, working-copy
+    """
+
+
     document = deepcopy(wldoc)
     del wldoc
 
     document = deepcopy(wldoc)
     del wldoc
 
@@ -584,8 +564,8 @@ def transform(wldoc, verbose=False, style=None,
             base_url,
             ilustr.get('src')
         )
             base_url,
             ilustr.get('src')
         )
-        with six.moves.urllib.request.urlopen(url) as imgfile:
-            img = Image.open(imgfile)
+        imgfile = six.moves.urllib.request.urlopen(url)
+        img = Image.open(imgfile)
 
         th_format, ext, media_type = {
             'GIF': ('GIF', 'gif', 'image/gif'),
 
         th_format, ext, media_type = {
             'GIF': ('GIF', 'gif', 'image/gif'),
@@ -598,6 +578,8 @@ def transform(wldoc, verbose=False, style=None,
         else:
             th = img.resize((width, round(width * img.size[1] / img.size[0])))
 
         else:
             th = img.resize((width, round(width * img.size[1] / img.size[0])))
 
+        imgfile.close()
+            
         buffer = six.BytesIO()
         th.save(buffer, format=th_format)
 
         buffer = six.BytesIO()
         th.save(buffer, format=th_format)
 
@@ -677,7 +659,11 @@ def transform(wldoc, verbose=False, style=None,
 
     annotations = etree.Element('annotations')
 
 
     annotations = etree.Element('annotations')
 
-    toc, chunk_counter, chars, sample = transform_file(document, sample=sample)
+    toc, chunk_counter, chars, sample = transform_file(
+        document, sample=sample,
+        hyphenate=hyphenate, output_type=output_type,
+        spine=spine, output=output, annotations=annotations
+    )
     output.toc = toc[0][1]
 
     # Last modifications in container files and EPUB creation
     output.toc = toc[0][1]
 
     # Last modifications in container files and EPUB creation
@@ -786,6 +772,7 @@ def transform(wldoc, verbose=False, style=None,
             os.chdir(cwd)
 
     remove_empty_lists_from_toc(output.toc)
             os.chdir(cwd)
 
     remove_empty_lists_from_toc(output.toc)
+    print(output.toc)
 
     output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub',
                                      delete=False)
 
     output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub',
                                      delete=False)
index 82ad4b9..a740f85 100644 (file)
@@ -387,4 +387,13 @@ table.border th, table.border td {
 
 th, td {
     vertical-align: top;
 
 th, td {
     vertical-align: top;
-}
\ No newline at end of file
+}
+
+.fundraising {
+       margin: 2em 1em 0;
+       border: 2px solid black;
+       padding: 2em 2em;
+       text-align: center;
+       font-size: 1.3em;
+       line-height: 1.4em;
+}
index cd22462..90f038e 100644 (file)
@@ -15,7 +15,7 @@
         <div id="book-text" xmlns="http://www.w3.org/1999/xhtml">
           <div id="footnotes" xmlns="http://www.w3.org/1999/xhtml">
             <h2 xmlns="http://www.w3.org/1999/xhtml">
         <div id="book-text" xmlns="http://www.w3.org/1999/xhtml">
           <div id="footnotes" xmlns="http://www.w3.org/1999/xhtml">
             <h2 xmlns="http://www.w3.org/1999/xhtml">
-              Przypisy:
+              <xsl:text>Przypisy:</xsl:text>
             </h2>
             <xsl:apply-templates mode="przypis" />
           </div>
             </h2>
             <xsl:apply-templates mode="przypis" />
           </div>
@@ -29,7 +29,7 @@
   </xsl:template>
 
   <xsl:template match="pa|pe|pr|pt" mode="przypis">
   </xsl:template>
 
   <xsl:template match="pa|pe|pr|pt" mode="przypis">
-    <p id="annotation-{@number}" class="annotation" xmlns="http://www.w3.org/1999/xhtml"><a href="part{@part}.xhtml#anchor-{@number}" xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@number" /></a>. <xsl:apply-templates /><xsl:if test="name()='pa'"> [przypis autorski]</xsl:if><xsl:if test="name()='pt'"> [przypis tłumacza]</xsl:if><xsl:if test="name()='pr'"> [przypis redakcyjny]</xsl:if><xsl:if test="name()='pe'"> [przypis edytorski]</xsl:if></p>
+    <p class="annotation" id="annotation-{@number}" xmlns="http://www.w3.org/1999/xhtml"><a href="part{@part}.xhtml#anchor-{@number}" xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@number" /></a>. <xsl:apply-templates /><xsl:if test="name()='pa'"> [przypis autorski]</xsl:if><xsl:if test="name()='pt'"> [przypis tłumacza]</xsl:if><xsl:if test="name()='pr'"> [przypis redakcyjny]</xsl:if><xsl:if test="name()='pe'"> [przypis edytorski]</xsl:if></p>
     <xsl:text>&#xa;</xsl:text>
   </xsl:template>
 
     <xsl:text>&#xa;</xsl:text>
   </xsl:template>
 
index 93767cf..0fae871 100644 (file)
@@ -7,9 +7,7 @@
       <xsl:element name="head">
         <link rel="stylesheet" href="style.css" type="text/css" />
         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
       <xsl:element name="head">
         <link rel="stylesheet" href="style.css" type="text/css" />
         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-        <title>
-          WolneLektury.pl
-        </title>
+        <title>WolneLektury.pl</title>
       </xsl:element>
       <xsl:element name="body" xmlns="http://www.w3.org/1999/xhtml">
         <xsl:element name="div" xmlns="http://www.w3.org/1999/xhtml">
       </xsl:element>
       <xsl:element name="body" xmlns="http://www.w3.org/1999/xhtml">
         <xsl:element name="div" xmlns="http://www.w3.org/1999/xhtml">
 
   <xsl:template match="ilustr">
     <img>
 
   <xsl:template match="ilustr">
     <img>
-      <xsl:attribute name="src">
-        <xsl:value-of select="@src" />
-      </xsl:attribute>
       <xsl:attribute name="alt">
         <xsl:value-of select="@alt" />
       </xsl:attribute>
       <xsl:attribute name="alt">
         <xsl:value-of select="@alt" />
       </xsl:attribute>
+      <xsl:attribute name="src">
+        <xsl:value-of select="@src" />
+      </xsl:attribute>
       <xsl:attribute name="title">
         <xsl:value-of select="@alt" />
       </xsl:attribute>
       <xsl:attribute name="title">
         <xsl:value-of select="@alt" />
       </xsl:attribute>
   <xsl:template match="extra" />
 
   <xsl:template match="pe|pa|pr|pt" >
   <xsl:template match="extra" />
 
   <xsl:template match="pe|pa|pr|pt" >
-    <a class="anchor" id="anchor-{.}" href="annotations.xhtml#annotation-{.}"
+    <a class="anchor" href="annotations.xhtml#annotation-{.}" id="anchor-{.}"
        xmlns="http://www.w3.org/1999/xhtml"><sup xmlns="http://www.w3.org/1999/xhtml"><xsl:apply-templates /></sup></a>
   </xsl:template>
 
        xmlns="http://www.w3.org/1999/xhtml"><sup xmlns="http://www.w3.org/1999/xhtml"><xsl:apply-templates /></sup></a>
   </xsl:template>
 
diff --git a/src/librarian/fonts.py b/src/librarian/fonts.py
new file mode 100644 (file)
index 0000000..adaeae4
--- /dev/null
@@ -0,0 +1,38 @@
+import os
+from shutil import rmtree
+import subprocess
+from tempfile import mkdtemp
+
+
+def strip_font(path, chars, verbose=False):
+    tmpdir = mkdtemp('-librarian-epub')
+    try:
+        cwd = os.getcwd()
+    except OSError:
+        cwd = None
+
+    os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                          'font-optimizer'))
+    optimizer_call = [
+        'perl', 'subset.pl', '--chars',
+        ''.join(chars).encode('utf-8'),
+        path,
+        os.path.join(tmpdir, 'font.ttf')
+    ]
+    env = {"PERL_USE_UNSAFE_INC": "1"}
+    if verbose:
+        print("Running font-optimizer")
+        subprocess.check_call(optimizer_call, env=env)
+    else:
+        dev_null = open(os.devnull, 'w')
+        subprocess.check_call(optimizer_call, stdout=dev_null,
+                              stderr=dev_null, env=env)
+    with open(os.path.join(tmpdir, 'font.ttf'), 'rb') as f:
+        content = f.read()
+
+    rmtree(tmpdir)
+
+    if cwd is not None:
+        os.chdir(cwd)
+
+    return content
diff --git a/src/librarian/fundraising.py b/src/librarian/fundraising.py
new file mode 100644 (file)
index 0000000..18d7774
--- /dev/null
@@ -0,0 +1,13 @@
+FUNDRAISING = [
+        'Przyjaciele Wolnych Lektur otrzymują dostęp do nowych tekstów współczesnych autorek i autorów wcześniej niż inni. <a href="https://wolnelektury.pl/towarzystwo/">Kliknij, by przejść do strony płatności.</a> Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur.',
+        'Czytaj teksty współczesnych autorek i autorów wcześniej niż inni. Ty decydujesz, ile płacisz! <a href="https://wolnelektury.pl/towarzystwo/">Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur</a>.',
+        'Informacje o nowościach w naszej bibliotece w Twojej skrzynce mailowej? Nic prostszego, zapisz się do newslettera.<br/><a href="https://wolnelektury.pl/newsletter/">Kliknij, by pozostawić swój adres e-mail</a>.',
+        '''Przekaż 1% podatku na Wolne Lektury.<br/>
+KRS: 0000070056<br/>
+Nazwa organizacji: Fundacja Nowoczesna Polska<br/>
+<br/>
+Możesz to zrobić w swoim formularzu PIT dostępnym od 15 lutego na stronie: <a href="https://www.podatki.gov.pl/pit">www.podatki.gov.pl/pit</a>.<br/>
+<br/>
+Każda wpłacona kwota zostanie przeznaczona na rozwój Wolnych Lektur.<br/>
+Dziękujemy, że jesteście z nami!''',
+]
index 363286c..f0f11db 100644 (file)
@@ -58,9 +58,8 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url):
         rel_path = ilustr.attrib['src']
         img_url = six.moves.urllib.parse.urljoin(base_url, rel_path)
 
         rel_path = ilustr.attrib['src']
         img_url = six.moves.urllib.parse.urljoin(base_url, rel_path)
 
-        with six.moves.urllib.request.urlopen(img_url) as f:
-            img = Image.open(f)
-
+        f = six.moves.urllib.request.urlopen(img_url)
+        img = Image.open(f)
         ext = {'GIF': 'gif', 'PNG': 'png'}.get(img.format, 'jpg')
 
         srcset = []
         ext = {'GIF': 'gif', 'PNG': 'png'}.get(img.format, 'jpg')
 
         srcset = []
@@ -75,10 +74,12 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url):
         ]
         largest = None
         for w in widths:
         ]
         largest = None
         for w in widths:
-            height = round(img.size[1] * w / img.size[0])
-            th = img.resize((w, height))
             fname = '%d.W%d.%s' % (i, w, ext)
             fname = '%d.W%d.%s' % (i, w, ext)
-            th.save(gallery_path + fname)
+            fpath = gallery_path + fname
+            if not os.path.exists(fpath):
+                height = round(img.size[1] * w / img.size[0])
+                th = img.resize((w, height))
+                th.save(fpath)
             th_url = gallery_url + fname
             srcset.append(" ".join((
                 th_url,
             th_url = gallery_url + fname
             srcset.append(" ".join((
                 th_url,
@@ -88,6 +89,8 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url):
         ilustr.attrib['srcset'] = ", ".join(srcset)
         ilustr.attrib['src'] = largest_url
 
         ilustr.attrib['srcset'] = ", ".join(srcset)
         ilustr.attrib['src'] = largest_url
 
+        f.close()
+
 
 def transform(wldoc, stylesheet='legacy', options=None, flags=None, css=None, gallery_path='img/', gallery_url='img/', base_url='file://./'):
     """Transforms the WL document to XHTML.
 
 def transform(wldoc, stylesheet='legacy', options=None, flags=None, css=None, gallery_path='img/', gallery_url='img/', base_url='file://./'):
     """Transforms the WL document to XHTML.
index cad66a4..a025b9b 100644 (file)
@@ -320,8 +320,8 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
                 base_url,
                 ilustr.get('src')
             )
                 base_url,
                 ilustr.get('src')
             )
-            with six.moves.urllib.request.urlopen(url) as imgfile:
-                img = Image.open(imgfile)
+            imgfile = six.moves.urllib.request.urlopen(url)
+            img = Image.open(imgfile)
 
             th_format, ext, media_type = {
                 'GIF': ('GIF', 'gif', 'image/gif'),
 
             th_format, ext, media_type = {
                 'GIF': ('GIF', 'gif', 'image/gif'),
@@ -338,6 +338,8 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
             th.save(os.path.join(temp, file_name))
             ilustr.set('src', file_name)
 
             th.save(os.path.join(temp, file_name))
             ilustr.set('src', file_name)
 
+            imgfile.close()
+
         for sponsor in book_info.sponsors:
             ins = etree.Element("data-sponsor", name=sponsor)
             logo = sponsor_logo(sponsor)
         for sponsor in book_info.sponsors:
             ins = etree.Element("data-sponsor", name=sponsor)
             logo = sponsor_logo(sponsor)
index f8b7731..c46a0ec 100644 (file)
 \usepackage{unicode-math}
 \setmathfont{Latin Modern Math}
 
 \usepackage{unicode-math}
 \setmathfont{Latin Modern Math}
 
+\usepackage{wrapfig}
+
 \usepackage[overload]{textcase}
 \usepackage{scalefnt}
 \usepackage[colorlinks=true,linkcolor=black,setpagesize=false,urlcolor=black,xetex]{hyperref}
 \usepackage[overload]{textcase}
 \usepackage{scalefnt}
 \usepackage[colorlinks=true,linkcolor=black,setpagesize=false,urlcolor=black,xetex]{hyperref}
index 43a3274..820033d 100644 (file)
 </xsl:template>
 
 <xsl:template match="ilustr">
 </xsl:template>
 
 <xsl:template match="ilustr">
-    <cmd name="ilustr">
+  <xsl:choose>
+    <xsl:when test="@oblew = 'true'">
+      <cmd name="par"/>
+      <env name="wrapfigure">
+        <parm>R</parm>
+        <parm>5cm</parm>
+        <cmd name="includegraphics">
+          <opt>width=<cmd name="linewidth"/></opt>
+          <parm><xsl:value-of select="@src"/></parm>
+        </cmd>
+      </env>
+    </xsl:when>
+    <xsl:otherwise>
+      <cmd name="ilustr">
         <parm><xsl:value-of select="@src" /></parm>
         <parm><xsl:value-of select="@alt" /></parm>
         <parm><xsl:value-of select="@src" /></parm>
         <parm><xsl:value-of select="@alt" /></parm>
-    </cmd>
+      </cmd>
+    </xsl:otherwise>
+  </xsl:choose>
 </xsl:template>
 
 <!-- ========================================== -->
 </xsl:template>
 
 <!-- ========================================== -->
diff --git a/src/librarian/res/BN.png b/src/librarian/res/BN.png
new file mode 100644 (file)
index 0000000..2e6df23
Binary files /dev/null and b/src/librarian/res/BN.png differ
diff --git a/src/librarian/res/MKIDN.jpg b/src/librarian/res/MKIDN.jpg
new file mode 100644 (file)
index 0000000..373062c
Binary files /dev/null and b/src/librarian/res/MKIDN.jpg differ
index 35af904..4555c55 100644 (file)
Binary files a/src/librarian/res/atrium-logo.png and b/src/librarian/res/atrium-logo.png differ
diff --git a/src/librarian/res/dofinansowano.png b/src/librarian/res/dofinansowano.png
new file mode 100644 (file)
index 0000000..80c531b
Binary files /dev/null and b/src/librarian/res/dofinansowano.png differ
index e425552..5b03525 100644 (file)
@@ -51,27 +51,39 @@ def transform(wldoc, flags=None, **options):
             description = parsed_dc.description
             url = document.book_info.url
 
             description = parsed_dc.description
             url = document.book_info.url
 
-            license_description = parsed_dc.license_description
+            license_name = parsed_dc.license_description
             license = parsed_dc.license
             license = parsed_dc.license
+            license_description = [
+                (
+                    "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+                    "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+                    "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur."
+                )
+            ]
+
             if license:
             if license:
-                license_description = (
-                    u"Ten utwór jest udostępniony na licencji %s: \n%s" % (
-                        license_description, license
+                license_description.append(
+                    "Ten utwór jest udostępniony na licencji %s: %s" % (
+                        license_name, license
                     )
                 )
             else:
                     )
                 )
             else:
-                license_description = (
-                    "Ten utwór nie jest objęty majątkowym prawem autorskim "
-                    "i znajduje się w domenie publicznej, co oznacza że "
-                    "możesz go swobodnie wykorzystywać, publikować "
-                    "i rozpowszechniać. Jeśli utwór opatrzony jest "
-                    "dodatkowymi materiałami (przypisy, motywy literackie "
-                    "etc.), które podlegają prawu autorskiemu, to te "
-                    "dodatkowe materiały udostępnione są na licencji "
-                    "Creative Commons Uznanie Autorstwa – Na Tych Samych "
-                    "Warunkach 3.0 PL "
-                    "(http://creativecommons.org/licenses/by-sa/3.0/)"
+                license_description.append(
+                    "Ten utwór jest w domenie publicznej."
                 )
                 )
+            license_description.append(
+                "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+                "udostępnione na Licencji Wolnej Sztuki 1.3: "
+                "https://artlibre.org/licence/lal/pl/\n"
+                "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+                "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+                "i prawach pokrewnych.\nWykorzystując zasoby z Wolnych Lektur, "
+                "należy pamiętać o zapisach licencji oraz zasadach, które "
+                "spisaliśmy w Zasadach wykorzystania Wolnych Lektur: "
+                "https://wolnelektury.pl/info/zasady-wykorzystania/\nZapoznaj "
+                "się z nimi, zanim udostępnisz dalej nasze książki"
+            )
+            license_description = "\n".join(license_description)
 
             source = parsed_dc.source_name
             if source:
 
             source = parsed_dc.source_name
             if source:
index 04e2658..54f522e 100644 (file)
                                <xsl:value-of select="$css" />
                        </xsl:attribute>
                </link>
                                <xsl:value-of select="$css" />
                        </xsl:attribute>
                </link>
+               <style>
+                 .ilustr.prawo img {
+                 float: right;
+                 }
+                 .ilustr.lewo img {
+                 float: left;
+                 }
+                 .ilustr.srodek {
+                 text-align: center;
+                 }
+                 .ilustr .stop {
+                 clear: both;
+                 }
+                 .ilustr.oblew .stop {
+                 clear: none;
+                 }
+
+                  .ilustr.oblew img {
+                    margin-bottom: 1em;
+                  }
+                  .ilustr.oblew.lewo img {
+                    margin-right: 2em;
+                    }
+                    .ilustr.oblew.prawo img {
+                    margin-left: 2em;
+                    }
+
+
+                    .ilustr img {
+                    min-width: 200px !important;
+                    }
+                    @media screen and (max-width: 320px) {
+                    .ilustr img {
+                    width: 100% !important;
+                    min-width: auto !important;
+                    }
+                    .ilustr.lewo img {
+                    float: none;
+                    }
+                    .ilustr.prawo img {
+                    float:none;
+                    }
+                    .ilustr.oblew.prawo img {
+                    margin-left: 0;
+                    }
+                    .ilustr.oblew.lewo img{
+                    margin-right: 0;
+                    }
+                    .ilustr .stop {
+                   clear: none;
+                    }
+
+                    }
+               </style>
            </head>
             <body>
               <xsl:call-template name="book-text" />
            </head>
             <body>
               <xsl:call-template name="book-text" />
 </xsl:template>
 
 <xsl:template match="ilustr">
 </xsl:template>
 
 <xsl:template match="ilustr">
+  <div>
+
+    <xsl:attribute name="class">
+      <xsl:text>ilustr </xsl:text>
+      <xsl:value-of select="@wyrownanie"/>
+      <xsl:if test="@oblew">
+        <xsl:text> oblew</xsl:text>
+      </xsl:if>
+    </xsl:attribute>
+    
     <img>
     <img>
-        <xsl:attribute name="src">
-            <xsl:value-of select="@src" />
-        </xsl:attribute>
-        <xsl:attribute name="srcset">
-          <xsl:value-of select="@srcset" />
-        </xsl:attribute>
-        <xsl:attribute name="sizes">
-          (min-width: 718px) 600px,
-          (min-width: 600px) calc(100vw - 118px),
-          (min-width: 320px) calc(100vw - 75px),
-          (min-width: 15em) calc(100wv - 60px),
-          calc(100wv - 40px)
-        </xsl:attribute>
-        <xsl:attribute name="alt">
-            <xsl:value-of select="@alt" />
-        </xsl:attribute>
-        <xsl:attribute name="title">
-            <xsl:value-of select="@alt" />
+      <xsl:attribute name="src">
+        <xsl:value-of select="@src" />
+      </xsl:attribute>
+      <xsl:attribute name="srcset">
+        <xsl:value-of select="@srcset" />
+      </xsl:attribute>
+      <xsl:attribute name="sizes">
+        (min-width: 718px) 600px,
+        (min-width: 600px) calc(100vw - 118px),
+        (min-width: 320px) calc(100vw - 75px),
+        (min-width: 15em) calc(100wv - 60px),
+        calc(100wv - 40px)
+      </xsl:attribute>
+      <xsl:attribute name="alt">
+        <xsl:value-of select="@alt" />
+      </xsl:attribute>
+      <xsl:attribute name="title">
+        <xsl:value-of select="@alt" />
+      </xsl:attribute>
+
+      <xsl:if test="@szer">
+        <xsl:attribute name="style">
+          <xsl:text>width: </xsl:text>
+          <xsl:value-of select="@szer"/>
         </xsl:attribute>
         </xsl:attribute>
+      </xsl:if>
     </img>
     </img>
+
+    <div class="stop"></div>
+  </div>
 </xsl:template>
 
 <xsl:template match="animacja">
 </xsl:template>
 
 <xsl:template match="animacja">
index 4b77300..ceae2e7 100644 (file)
@@ -6,28 +6,29 @@
       <dc:date>2020-01-08</dc:date>
       <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
       <dc:language>pol</dc:language>
       <dc:date>2020-01-08</dc:date>
       <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
       <dc:language>pol</dc:language>
-      <dc:identifier.url>wl-test</dc:identifier.url>
+      <dc:identifier.url>main</dc:identifier.url>
       <dc:rights>gnu gpl</dc:rights>
     </rdf:Description>
   </rdf:RDF>
 
   <opowiadanie>
 
       <dc:rights>gnu gpl</dc:rights>
     </rdf:Description>
   </rdf:RDF>
 
   <opowiadanie>
 
-<autor_utworu>Wolne Lektury</autor_utworu>
-<nazwa_utworu>Testy</nazwa_utworu>
-<podtytul>Podtytuł</podtytul>
-
+    <dzielo_nadrzedne>Dzieło nadrzędne<pa>Przypis w dziele nadrzędnym</pa></dzielo_nadrzedne>
+    <autor_utworu>Wolne<pa>Przypis w nazwie utworu</pa> Lektury</autor_utworu>
+    <nazwa_utworu>Testy<pa>Przypis w tytule utworu</pa></nazwa_utworu>
+    <podtytul>Podtytuł<pa>Przypis w podtytule</pa></podtytul>
+    
     <naglowek_czesc>Testy struktury</naglowek_czesc>
     <naglowek_czesc>Testy struktury</naglowek_czesc>
-
+    
     <naglowek_czesc>Nagłówek części</naglowek_czesc>
     <podtytul_czesc>Podtytuł części</podtytul_czesc>
     <naglowek_czesc>Nagłówek części</naglowek_czesc>
     <podtytul_czesc>Podtytuł części</podtytul_czesc>
-
+    
     <naglowek_rozdzial>Nagłówek rozdziału</naglowek_rozdzial>
     <podtytul_rozdzial>Podtytuł rozdziału</podtytul_rozdzial>
     <naglowek_rozdzial>Nagłówek rozdziału</naglowek_rozdzial>
     <podtytul_rozdzial>Podtytuł rozdziału</podtytul_rozdzial>
-
+    
     <naglowek_podrozdzial>Nagłówek podrozdziału</naglowek_podrozdzial>
     <podtytul_podrozdzial>Podtytuł podrozdziału</podtytul_podrozdzial>
     <naglowek_podrozdzial>Nagłówek podrozdziału</naglowek_podrozdzial>
     <podtytul_podrozdzial>Podtytuł podrozdziału</podtytul_podrozdzial>
-
+    
     <naglowek_akt>Nagłówek aktu</naglowek_akt>
     <podtytul_akt>Podtytuł aktu</podtytul_akt>
     
     <naglowek_akt>Nagłówek aktu</naglowek_akt>
     <podtytul_akt>Podtytuł aktu</podtytul_akt>
     
     <srodtytul>Śródtytuł</srodtytul>
 
     <akap>Nagłówki powinny tworzyć prawidłową strukturę. Użyte elementy: tytuły i podtytuły części, rozdziału, podrozdziału, aktu i sceny, oraz śródtytuł.</akap>
     <srodtytul>Śródtytuł</srodtytul>
 
     <akap>Nagłówki powinny tworzyć prawidłową strukturę. Użyte elementy: tytuły i podtytuły części, rozdziału, podrozdziału, aktu i sceny, oraz śródtytuł.</akap>
+
+
+
+    <naglowek_czesc>Akapity</naglowek_czesc>
+
+    <akap>Zwykły akapit.</akap>
+
+    <akap_cd>Kontynuacja akapitu.</akap_cd>
+
+    <akap_dialog>--- Akapit dialogowy.</akap_dialog>
+
+    <akap>Zastępnik wersu w akapicie:</akap>
+    <akap><zastepnik_wersu>. . . . . . . .</zastepnik_wersu></akap>
+
+    <akap>Poezja cytowana w akapicie dialogowym (?):</akap>
+    <akap_dialog><poezja_cyt><strofa>--- Cytat</strofa></poezja_cyt></akap_dialog>
+    
+
+
+
+
+
+    <naglowek_czesc>Dramat</naglowek_czesc>
+
+    <lista_osob>
+      <naglowek_listy>
+       Lista osób
+      </naglowek_listy>
+      <lista_osoba>
+       <osoba>Pustelnik</osoba> --- pustelnik
+      </lista_osoba>
+      <lista_osoba>
+       <osoba>Hesia</osoba> --- Hesia
+      </lista_osoba>
+      
+    </lista_osob>
+
+    <miejsce_czas>
+    </miejsce_czas>
+    
+    <naglowek_osoba>PUSTELNIK</naglowek_osoba>
+
+    <kwestia>
+      <strofa>
+       Więc jako dawniej czynili mocarze,/
+       Z Lechem się mieniał Scyta na obrączki;/
+       A pokochawszy mocniej sercem, w darze/
+       Dał mu koronę... stąd nasza korona./
+       Zbawiciel niegdyś wyciągając rączki/
+       Szedł do niej z matki zadumanej łona/
+       I ku rubinom podawał się cały/
+       Jako różyczka z liści wychylona,/
+       I wołał: caca! i na brylant biały/
+       Różanych ustek perełkami świecił.
+      </strofa>
+    </kwestia>
+
+    <didaskalia>Słychać głos Hesi.</didaskalia>
+    
+    <naglowek_osoba>GŁOS HESI</naglowek_osoba>
+
+    <kwestia>
+      <akap>
+       Mamuńciu, tak zimno! troszkę ciepłej wody...
+      </akap>
+    </kwestia>
+
+    <naglowek_osoba>DULSKA</naglowek_osoba>
+
+    <kwestia>
+      <akap>
+       Jeszcze czego? Hartujcie się... Felicjan! wstajesz? Wiesz? ten błazen, twój syn, nie wrócił jeszcze do domu! Co? nic nie mówisz? naturalnie. 
+       Ojciec toleruje. Niedaleko padło jabłko od jabłoni. Ale jak będą dłużki małe --- nie zapłacę.
+      </akap>
+    </kwestia>
+    
+
+
+    
+    <naglowek_czesc>Wyróżnienia</naglowek_czesc>
+    
+    <akap>Wyróżnienia:
+    <didask_tekst>didaskalia tekstowe</didask_tekst>,
+    <didaskalia>didaskalia</didaskalia>,
+    <indeks_dolny>indeks dolny</indeks_dolny>,
+    <osoba>osoba</osoba>,
+    <slowo_obce>słowo obce</slowo_obce>,
+    <tytul_dziela>tytuł dzieła</tytul_dziela>,
+    <wieksze_odstepy>większe odstępny</wieksze_odstepy>,
+    <wyroznienie>wyróżnienie</wyroznienie>,
+    <www>https://wolnelektury.pl/</www>.
+    </akap>
+    
+
+
+
+    <naglowek_czesc>Grupy</naglowek_czesc>
+
+    <akap>Długi cytat:</akap>
+    
+    <dlugi_cytat>
+      <akap>Długi cytat, akapit.</akap>
+      <akap_cd>Kontynuacja akapitu.</akap_cd>
+      <akap_dialog>--- Akapit dialogowy</akap_dialog>
+
+      <strofa>Strofa/ w/ cytacie</strofa>
+
+      <didaskalia>Didaskalia (czy tak?)</didaskalia>
+
+      <dlugi_cytat>
+       <akap>Cytat w cytacie!</akap>
+       <akap_cd>Kontynuacja akapitu w cytacie</akap_cd>
+       <akap_dialog>--- Akapit dialogowy w cytacie</akap_dialog>
+      </dlugi_cytat>
+
+      
+      <poezja_cyt>
+       <strofa>Poezja/ cytowana/ w cytacie</strofa>
+      </poezja_cyt>
+
+      
+      <naglowek_osoba>
+      </naglowek_osoba>
+      <kwestia>
+       ...
+      </kwestia>
+
+
+      <naglowek_rozdzial>Rozdział w cytacie</naglowek_rozdzial>
+      <naglowek_podrozdzial>Podrozdział w cytacie</naglowek_podrozdzial>
+      <srodtytul>Śródtytuł w cytacie</srodtytul>
+
+      <motto_podpis>
+      </motto_podpis>
+
+      <nota>
+       <akap>Nota w cytacie</akap>
+      </nota>
+
+      <akap>Asterysk:</akap>
+      <sekcja_asterysk/>
+
+      <akap>Światło:</akap>
+      <sekcja_swiatlo/>
+
+      <akap>Separator linia:</akap>
+      <separator_linia/>
+
+      <akap>Koniec cytatu.</akap>
+
+    </dlugi_cytat>
+
+    <akap>Tekst za cytatem.</akap>
+
+
+    <akap>Cytat poetycki:</akap>
+    
+    <poezja_cyt>
+      <naglowek_rozdzial>Nagłówek rozdziału</naglowek_rozdzial>
+      <naglowek_podrozdzial>Nagłówek podrozdziału</naglowek_podrozdzial>
+      <srodtytul>Śródtytuł</srodtytul>
+      <naglowek_osoba>Nagłówek: osoba</naglowek_osoba>
+
+      <nota>
+       <akap>
+         Nota
+       </akap>
+      </nota>
+      
+      <akap>Akapit</akap>
+
+      <strofa>Strofa/ w/ cytacie</strofa>
+      
+      <didaskalia>didaskalia?</didaskalia>
+
+      <kwestia>
+       <strofa>
+         Strofa/ w/ kwestii/ w cytacie.
+       </strofa>
+      </kwestia>
+
+      <motto_podpis>
+       Motto-podpis
+      </motto_podpis>
+
+      <poezja_cyt>
+       <strofa>
+         Poezja/
+         cytowana/
+         w cytacie/
+         poetyckim
+       </strofa>
+      </poezja_cyt>
+
+      <akap>Asterysk:</akap>
+      <sekcja_asterysk/>
+
+      
+      
+    </poezja_cyt>
+
+
+    
+    
     
     
     <naglowek_czesc>Strofa w przypisie</naglowek_czesc>
     
     
     <naglowek_czesc>Strofa w przypisie</naglowek_czesc>
     </akap>
 
 
     </akap>
 
 
+
+
+
+
+    <naglowek_czesc>Wzory</naglowek_czesc>
+
+    <akap>
+      Wzór:
+      <mat><mrow>
+       <mi>δ</mi>
+       <mo>=</mo>
+       <mfrac>
+         <mrow>
+           <mi>e</mi>
+           <mo>⁢</mo>
+           <mi>F</mi>
+           <mo>⁢</mo>
+           <mi>l</mi>
+           <mo>×</mo>
+           <mfenced><mrow>
+             <mfrac>
+               <mi>l</mi>
+               <mn>2</mn>
+             </mfrac>
+             <mo>+</mo>
+             <mi>h</mi>
+           </mrow>
+           </mfenced>
+         </mrow>
+         <mrow>
+           <mi>m</mi>
+           <mo>⁢</mo>
+           <msup>
+             <mi>v</mi>
+             <mn>2</mn>
+           </msup>
+         </mrow>
+       </mfrac>
+      </mrow></mat>
+    </akap>
+
+
+
+
+    
+    <naglowek_czesc>Separatory</naglowek_czesc>
+
+    
+    <akap>Asterysk:</akap>
+    <sekcja_asterysk/>
+
+    <akap>Światło:</akap>
+    <sekcja_swiatlo/>
+
+    <akap>Separator linia:</akap>
+    <separator_linia/>
+
+
+    
+
+    <naglowek_czesc>Tabele</naglowek_czesc>
+
+    <akap>Tabela bez ramek:</akap>
+    
+    <tabela>
+      <wiersz>
+       <kol>
+         Komórka 1
+       </kol>
+       <kol>
+         Komórka 2
+       </kol>
+      </wiersz>
+      <wiersz>
+       <kol>
+         Komórka 3
+       </kol>
+       <kol>
+         Komórka 4
+       </kol>
+      </wiersz>
+    </tabela>
+
+    <akap>Tabela z ramkami:</akap>
+         
+
+    <tabela ramka="1">
+      <wiersz>
+       <kol>
+         Komórka 1
+       </kol>
+       <kol>
+         Komórka 2
+       </kol>
+      </wiersz>
+      <wiersz>
+       <kol>
+         Komórka 3
+       </kol>
+       <kol>
+         Komórka 4
+       </kol>
+      </wiersz>
+    </tabela>
+
+    <naglowek_czesc>Ilustracje</naglowek_czesc>
+
+    
     
   </opowiadanie>
 </utwor>
     
   </opowiadanie>
 </utwor>
diff --git a/tests/uat/parent.xml b/tests/uat/parent.xml
new file mode 100644 (file)
index 0000000..544032a
--- /dev/null
@@ -0,0 +1,15 @@
+<utwor>
+  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+    <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
+      <dc:creator>Radek Czajka</dc:creator>
+      <dc:title>Test Parent Document</dc:title>
+      <dc:date>2020-01-08</dc:date>
+      <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
+      <dc:language>pol</dc:language>
+      <dc:identifier.url>wl-test-parent</dc:identifier.url>
+      <dc:rights>gnu agpl</dc:rights>
+      <dc:relation.hasPart>main</dc:relation.hasPart>
+      <dc:relation.hasPart>part2</dc:relation.hasPart>
+    </rdf:Description>
+  </rdf:RDF>
+</utwor>
diff --git a/tests/uat/part2.xml b/tests/uat/part2.xml
new file mode 100644 (file)
index 0000000..2459748
--- /dev/null
@@ -0,0 +1,25 @@
+<utwor>
+  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+    <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
+      <dc:creator>Radek Czajka</dc:creator>
+      <dc:title>Test Document, Part 2</dc:title>
+      <dc:date>2020-01-08</dc:date>
+      <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
+      <dc:language>pol</dc:language>
+      <dc:identifier.url>part2</dc:identifier.url>
+      <dc:rights>gnu gpl</dc:rights>
+    </rdf:Description>
+  </rdf:RDF>
+
+  <opowiadanie>
+
+<autor_utworu>Wolne Lektury</autor_utworu>
+<nazwa_utworu>Testy</nazwa_utworu>
+<podtytul>Podtytuł</podtytul>
+
+<akap>
+       Druga część. Powinna być widoczna
+</akap>
+
+  </opowiadanie>
+</utwor>