First layout
parent
bbb902995a
commit
4f4d2802f0
@ -1,10 +1,55 @@
|
|||||||
#!/usr/bin/env/ python
|
#!/usr/bin/env/ python
|
||||||
|
|
||||||
from flask import Flask, render_template
|
from flask import Flask, render_template, request, Response
|
||||||
|
from weasyprint import HTML
|
||||||
|
from pagedjs import make_pdf
|
||||||
|
|
||||||
|
try:
|
||||||
|
from paseo import crear_camino
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
basepath = os.path.dirname(__file__)
|
||||||
|
|
||||||
BASEURL = ''
|
BASEURL = ''
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@app.route('{}/'.format(BASEURL))
|
@app.route('{}/'.format(BASEURL))
|
||||||
def index():
|
def index():
|
||||||
return 'Hello world'
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route('{}/book'.format(BASEURL), methods=['POST'])
|
||||||
|
def book():
|
||||||
|
fragment = max(0, min(1, int(request.form['fragment'])))
|
||||||
|
|
||||||
|
first_word = 'un'
|
||||||
|
|
||||||
|
if fragment == 0:
|
||||||
|
novel = os.path.join(basepath, '../data/emilia_prueba.txt')
|
||||||
|
author = 'Emilia Pardo Bazán'
|
||||||
|
title = 'La Madre Naturaleza'
|
||||||
|
else:
|
||||||
|
novel = os.path.join(basepath, '../data/prueba.txt')
|
||||||
|
author = 'Benito Pérez Gáldos'
|
||||||
|
title = 'Miau'
|
||||||
|
|
||||||
|
path = crear_camino(novel, first_word)
|
||||||
|
|
||||||
|
context = { 'title': title, 'author': author, 'path': path }
|
||||||
|
html = render_template('book.html', **context)
|
||||||
|
|
||||||
|
# pdf = HTML(string=html).write_pdf()
|
||||||
|
|
||||||
|
# Use pagedjs as weasyprint does not seem to support our layout.
|
||||||
|
pdf = make_pdf(html)
|
||||||
|
|
||||||
|
r = Response(pdf, mimetype='application/pdf')
|
||||||
|
|
||||||
|
r.headers.extend({
|
||||||
|
'Content-Disposition': 'attachment; filename="Paseo por arboles de madrid.pdf"'
|
||||||
|
})
|
||||||
|
|
||||||
|
return r
|
||||||
|
# return html
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
basepath = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
paged_bin = 'node_modules/pagedjs-cli/bin/paged'
|
||||||
|
|
||||||
|
def run_pagedjs (path_html, path_pdf, cwd=None, extra_scripts=[]):
|
||||||
|
args = [
|
||||||
|
paged_bin
|
||||||
|
]
|
||||||
|
|
||||||
|
for script in extra_scripts:
|
||||||
|
args.extend([
|
||||||
|
'--additional-script',
|
||||||
|
script
|
||||||
|
])
|
||||||
|
|
||||||
|
args.extend([
|
||||||
|
'-o', path_pdf,
|
||||||
|
path_html
|
||||||
|
])
|
||||||
|
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(args, cwd=cwd, stderr=subprocess.STDOUT).decode()
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
return 'Error:\n{}'.format(e.output.decode())
|
||||||
|
|
||||||
|
"""
|
||||||
|
Generate a PDF based on provided HTML using pagedjs and returns the contents of
|
||||||
|
the generated PDF.
|
||||||
|
|
||||||
|
If optional path_out is provided the PDF is written there and the function returns the path.
|
||||||
|
|
||||||
|
Optional extra_scripts is a list of strings with javascript.
|
||||||
|
Scripts are sent in the same order to paged.js
|
||||||
|
"""
|
||||||
|
def make_pdf (html, path_out=None, extra_scripts=[]):
|
||||||
|
with tempfile.TemporaryDirectory(prefix='algoliterary_publishing_house_') as tempdir:
|
||||||
|
with tempfile.NamedTemporaryFile(dir=tempdir, mode='w', suffix='.html', delete=False) as temphtml:
|
||||||
|
# Store html in a temporary file
|
||||||
|
temphtml.write(html)
|
||||||
|
temphtml.close()
|
||||||
|
|
||||||
|
name_in = temphtml.name
|
||||||
|
|
||||||
|
extra_scripts_tmp = []
|
||||||
|
|
||||||
|
for script in extra_scripts:
|
||||||
|
with tempfile.NamedTemporaryFile(dir=tempdir, mode='w', suffix='.js', delete=False) as tempjs:
|
||||||
|
tempjs.write(script)
|
||||||
|
tempjs.close()
|
||||||
|
extra_scripts_tmp.append(tempjs.name)
|
||||||
|
|
||||||
|
# Make a temporary file for the generated PDF
|
||||||
|
with tempfile.NamedTemporaryFile(dir=tempdir, mode='w', suffix='.pdf', delete=False) as temppdf:
|
||||||
|
temppdf.close()
|
||||||
|
name_out = temppdf.name
|
||||||
|
|
||||||
|
# Make the pdf
|
||||||
|
run_pagedjs(name_in, name_out, cwd=basepath, extra_scripts=extra_scripts_tmp)
|
||||||
|
|
||||||
|
if path_out:
|
||||||
|
import shutil
|
||||||
|
shutil.copy(name_out, path_out)
|
||||||
|
return path_out
|
||||||
|
else:
|
||||||
|
with open(name_out, 'rb') as generated_pdf:
|
||||||
|
return generated_pdf.read()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|
||||||
|
with open(os.path.join(basepath, 'index.html'), 'r') as file_input:
|
||||||
|
html = file_input.read()
|
||||||
|
|
||||||
|
with open(os.path.join(basepath, 'delayedLoading.js'), 'r') as js_input:
|
||||||
|
js = js_input.read()
|
||||||
|
|
||||||
|
make_pdf(html, os.path.join(basepath, 'generated.pdf'), [ js ])
|
||||||
|
|
||||||
|
|
@ -0,0 +1,173 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: 210mm 297mm;
|
||||||
|
margin: 10mm 10mm 15mm 10mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-picked] {
|
||||||
|
text-decoration: underline;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-picked]::after {
|
||||||
|
content: ' → ';
|
||||||
|
text-decoration: none;
|
||||||
|
position: absolute;
|
||||||
|
left: calc(100% + 1.5em);
|
||||||
|
top: 0;
|
||||||
|
height: 1.2em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.traces > :last-child [data-picked]::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: a4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page title {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page:left {
|
||||||
|
@bottom-left {
|
||||||
|
text-align: left;
|
||||||
|
content: counter(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@page:right {
|
||||||
|
@bottom-right {
|
||||||
|
text-align: right;
|
||||||
|
content: counter(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@page:empty {
|
||||||
|
@bottom-right {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@bottom-left {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@page title {
|
||||||
|
@bottom-right {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
@bottom-left {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
page: title;
|
||||||
|
color: white;
|
||||||
|
page-break-after: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.step {
|
||||||
|
page-break-before: always;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 252mm;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.traces {
|
||||||
|
list-style-type: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
line-height: 1.2em;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0 4em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options li {
|
||||||
|
line-height: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sentence {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
background: linear-gradient(to top, rgba(255,255,255,0), white 2.5em);
|
||||||
|
padding: 0.5em 20mm 3em 20mm;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tree {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
background: linear-gradient(to bottom, rgba(255,255,255,0), white 2.5em);
|
||||||
|
padding: 3em 20mm 0.5em 20mm;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Paseo por los árboles de Madrid con {{ author }} y {{ title }}</h1>
|
||||||
|
|
||||||
|
{% for sentence, previous_steps, tree, traces in path %}
|
||||||
|
<section class="step">
|
||||||
|
<section class="sentence">
|
||||||
|
{{ previous_steps }}
|
||||||
|
</section>
|
||||||
|
<ul class="traces">
|
||||||
|
{% for word, dice, options in traces %}
|
||||||
|
<li style="margin-top: calc({{ dice }} * -1.2em)">
|
||||||
|
<ul class="options">
|
||||||
|
{% for option in options %}
|
||||||
|
<li {% if loop.index0 == dice %}data-picked{% endif %}>
|
||||||
|
{{ option }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<!-- Rolled: {{ dice }} -->
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<section class="tree">
|
||||||
|
{{ tree.properties.NOMBRE_COMUN }} en {{ tree.properties.MINTDIRECCIONAUX }}
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1 +1,7 @@
|
|||||||
<h1>Hello world</h1>
|
<h1>Hello world</h1>
|
||||||
|
|
||||||
|
<form method="POST" action="/book">
|
||||||
|
<label><input type="radio" name="fragment" value="0" checked> Fragment 1</label><br />
|
||||||
|
<label><input type="radio" name="fragment" value="1"> Fragment 2</label><br />
|
||||||
|
<button type="submit">Generate</button>
|
||||||
|
</form>
|
Loading…
Reference in New Issue