Mercurial > jouvence
changeset 9:a5488b474c6b
Add HTML renderer.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 04 Jan 2017 02:56:08 -0800 |
parents | 02d2e4d8b0c1 |
children | 2cea36073188 |
files | .hgignore fontaine/html.py fontaine/resources/html_footer.html fontaine/resources/html_header.html fontaine/resources/html_styles.css fontaine/resources/html_styles.scss scripts/fontaine |
diffstat | 7 files changed, 211 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Wed Jan 04 02:55:20 2017 -0800 +++ b/.hgignore Wed Jan 04 02:56:08 2017 -0800 @@ -2,4 +2,6 @@ __pycache__ venv .cache +.sass-cache +*.css.map *.pyc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontaine/html.py Wed Jan 04 02:56:08 2017 -0800 @@ -0,0 +1,110 @@ +import os.path +from markupsafe import escape +from .renderer import BaseDocumentRenderer, BaseTextRenderer + + +def _elem(out, elem_name, class_name, contents): + f = out.write + f('<%s' % elem_name) + if class_name: + f(' class="fontaine-%s"' % class_name) + f('>') + f(contents) + f('</%s>\n' % elem_name) + + +def _br(text, strip_first=False): + lines = text.split('\n') + if strip_first and lines[0].strip() == '': + lines = lines[1:] + return '<br/>\n'.join(lines) + + +def _res(filename): + path = os.path.join(os.path.dirname(__file__), 'resources', filename) + with open(path, 'r') as fp: + return fp.read() + + +class HtmlDocumentRenderer(BaseDocumentRenderer): + def __init__(self, standalone=True): + super().__init__(HtmlTextRenderer()) + self.standalone = standalone + + def get_css(self): + return _res('html_styles.css') + + def write_header(self, doc, out): + if self.standalone: + meta = doc.title_values.get + data = { + # TODO: need a "strip formatting" to have a clean title. + 'title': meta('title', "Fountain Screenplay"), + 'description': meta('description', ''), + 'css': self.get_css() + } + out.write(_res('html_header.html') % data) + out.write('<div class="fontaine-doc">\n') + + def write_footer(self, doc, out): + out.write('</div>\n') + if self.standalone: + out.write(_res('html_footer.html')) + + def write_title_page(self, values, out): + out.write('<div class="fontaine-title-page">\n') + + _elem(out, 'h1', None, _br(values['title'])) + _elem(out, 'p', 'title-page-heading', _br(values['credit'])) + _elem(out, 'p', 'title-page-heading', _br(values['author'])) + + ddate = values.get('date') or values.get('draft date') + if ddate: + _elem(out, 'p', 'title-page-footer', _br(ddate)) + contact = values.get('contact') + if contact: + _elem(out, 'p', 'title-page-footer', _br(contact)) + + out.write('</div>\n') + self.write_pagebreak(out) + + def write_scene_heading(self, text, out): + _elem(out, 'p', 'scene-heading', text) + + def write_action(self, text, out): + _elem(out, 'p', 'action', _br(text, True)) + + def write_centeredaction(self, text, out): + _elem(out, 'p', 'action-centered', _br(text, True)) + + def write_character(self, text, out): + _elem(out, 'p', 'character', text) + + def write_dialog(self, text, out): + _elem(out, 'p', 'dialog', _br(text)) + + def write_parenthetical(self, text, out): + _elem(out, 'p', 'parenthetical', text) + + def write_transition(self, text, out): + _elem(out, 'p', 'transition', text) + + def write_lyrics(self, text, out): + _elem(out, 'p', 'lyrics', _br(text, True)) + + def write_pagebreak(self, out): + out.write('<hr/>\n') + + +class HtmlTextRenderer(BaseTextRenderer): + def render_text(self, text): + return super().render_text(escape(text)) + + def make_italics(self, text): + return '<em>%s</em>' % text + + def make_bold(self, text): + return '<strong>%s</strong>' % text + + def make_underline(self, text): + return '<u>%s</u>' % text
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontaine/resources/html_footer.html Wed Jan 04 02:56:08 2017 -0800 @@ -0,0 +1,3 @@ + <p class="footer">Generated with <a href="https://bolt80.com/fontaine">Fontaine</a></p> + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontaine/resources/html_header.html Wed Jan 04 02:56:08 2017 -0800 @@ -0,0 +1,40 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <meta http-equiv="x-ua-compatible" content="ie=edge"> + <title>%(title)s</title> + <meta name="description" content="%(description)s"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <link rel="apple-touch-icon" href="apple-touch-icon.png"> + <!-- Place favicon.ico in the root directory --> + + <style> + body { + margin: 1em 3em; + background-color: #666; + } + .fontaine-doc { + background-color: #fff; + padding: 2em; + box-shadow: #111 0px 0.5em 2em; + } + p.footer { + text-align: center; + text-transform: uppercase; + font-size: 0.9em; + font-family: "Times New Roman", "Times", serif; + color: #333; + padding: 1em; + } + p.footer a:link, p.footer a:visited, p.footer a:active { + color: #222; + } + p.footer a:hover { + color: #227; + } + </style> + <style>%(css)s</style> + </head> + <body>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontaine/resources/html_styles.css Wed Jan 04 02:56:08 2017 -0800 @@ -0,0 +1,16 @@ +.fontaine-doc { + font-family: "Courier Prime", "Courier New", Courier, sans-serif; } + .fontaine-doc h1, .fontaine-doc .fontaine-title-page-heading { + text-align: center; } + .fontaine-doc .fontaine-scene-heading { + font-weight: bold; } + .fontaine-doc .fontaine-character { + margin: auto 12rem 0 12rem; } + .fontaine-doc .fontaine-parenthetical { + margin: 0 8rem 0 8rem; } + .fontaine-doc .fontaine-dialog { + margin: 0 4rem 0 4rem; } + .fontaine-doc .fontaine-action-centered { + text-align: center; } + +/*# sourceMappingURL=html_styles.css.map */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fontaine/resources/html_styles.scss Wed Jan 04 02:56:08 2017 -0800 @@ -0,0 +1,30 @@ +.fontaine-doc { + font-family: "Courier Prime", "Courier New", Courier, sans-serif; + + h1, .fontaine-title-page-heading { + text-align: center; + } + + .fontaine-scene-heading { + font-weight: bold; + } + + .fontaine-transition { + } + + .fontaine-character { + margin: auto 3 * 4rem 0 3 * 4rem; + } + + .fontaine-parenthetical { + margin: 0 2 * 4rem 0 2 * 4rem; + } + + .fontaine-dialog { + margin: 0 4rem 0 4rem; + } + + .fontaine-action-centered { + text-align: center; + } +}
--- a/scripts/fontaine Wed Jan 04 02:55:20 2017 -0800 +++ b/scripts/fontaine Wed Jan 04 02:56:08 2017 -0800 @@ -11,15 +11,22 @@ parser = argparse.ArgumentParser( description='Fontaine command line utility') parser.add_argument('script') + parser.add_argument('out_file', nargs='?') args = parser.parse_args() from fontaine.parser import FontaineParser - from fontaine.console import ConsoleDocumentRenderer p = FontaineParser() doc = p.parse(args.script) - rdr = ConsoleDocumentRenderer() - rdr.render_doc(doc) + if not args.out_file: + from fontaine.console import ConsoleDocumentRenderer + rdr = ConsoleDocumentRenderer() + rdr.render_doc(doc, sys.stdout) + else: + from fontaine.html import HtmlDocumentRenderer + rdr = HtmlDocumentRenderer() + with open(args.out_file, 'w') as fp: + rdr.render_doc(doc, fp) if __name__ == '__main__': main()