|
|
<!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>Grafted trees</title>
|
|
|
<style>
|
|
|
body {
|
|
|
display: grid;
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
margin: 0;
|
|
|
padding: 0;
|
|
|
height: 100vh;
|
|
|
font-family: Arial, Helvetica, sans-serif;
|
|
|
font-size: 12pt;
|
|
|
line-height: 18pt;
|
|
|
}
|
|
|
|
|
|
main {
|
|
|
grid-column: 1;
|
|
|
overflow-y: auto;
|
|
|
padding: 32pt 32pt 32pt 16pt;
|
|
|
}
|
|
|
|
|
|
aside {
|
|
|
grid-column: 2;
|
|
|
overflow-y: auto;
|
|
|
padding: 32pt 16pt;
|
|
|
}
|
|
|
|
|
|
[data-message] {
|
|
|
display: none;
|
|
|
font-size: var(--font-size-smaller);
|
|
|
line-height: var(--line-height--smaller);
|
|
|
font-style: italic;
|
|
|
margin: var(--line-height--smaller) 0;
|
|
|
}
|
|
|
|
|
|
[data-message][data-active] {
|
|
|
display: block;
|
|
|
}
|
|
|
|
|
|
button {
|
|
|
font: inherit;
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<main>
|
|
|
<h1>Grafted trees</h1>
|
|
|
<p>
|
|
|
‘Grafted trees’ takes quotes about trees from existing works. Each graft is defined by its gardener, who is present with a short biography scraped from Wikipedia. The reader chooses the amount of seasons the graft will grow. A random noun is picked and defined as a 'bud' from which a new branch grows by replacing the word by its definition. The algorithm is inspired by Oulipo's constraint of 'Littérature définitionnelle', invented by Marcel Bénabou in 1966: in a given phrase, one replaces every significant element (noun, adjective, verb, adverb) by one of its definitions in a given dictionary; one reiterates the operation on the newly received phrase, and again.
|
|
|
</p>
|
|
|
</main>
|
|
|
<aside>
|
|
|
<p>
|
|
|
<form action="{{ BASEURL }}/graft" method="POST">
|
|
|
Graft a tree for <input type="number" name="years" value="3" max="25" min="0" size="4" /> years.<br /><br />
|
|
|
<button type="submit">Graft & download</button>
|
|
|
</form>
|
|
|
</p>
|
|
|
<p data-message="working">
|
|
|
Grafting your tree. This might take a while.
|
|
|
</p>
|
|
|
<p data-message="error">
|
|
|
Something went wrong.
|
|
|
</p>
|
|
|
</aside>
|
|
|
<script>
|
|
|
function getFilename (headers, fallback) {
|
|
|
if (headers.has('Content-Disposition')) {
|
|
|
header = headers.get('Content-Disposition')
|
|
|
matches = header.match(/filename="(.+)"/)
|
|
|
|
|
|
if (matches.length == 2) {
|
|
|
return matches[1]
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return fallback;
|
|
|
}
|
|
|
|
|
|
(function () {
|
|
|
if (fetch) {
|
|
|
var form = document.querySelector('form'),
|
|
|
button = form.querySelector('button'),
|
|
|
messageWorking = document.querySelector('[data-message="working"]'),
|
|
|
messageError = document.querySelector('[data-message="error"]');
|
|
|
|
|
|
form.addEventListener('submit', function (e) {
|
|
|
e.preventDefault();
|
|
|
button.disabled = true;
|
|
|
delete messageError.dataset.active;
|
|
|
messageWorking.dataset.active = true;
|
|
|
const data = new FormData(form);
|
|
|
|
|
|
fetch(form.action, {
|
|
|
method: "POST",
|
|
|
body: data
|
|
|
}).then(function (r) {
|
|
|
console.log(r);
|
|
|
r.blob().then(function (blob) {
|
|
|
var filename = getFilename(r.headers, 'Grafted-tree.pdf');
|
|
|
const a = document.createElement('a');
|
|
|
a.setAttribute('href', URL.createObjectURL(blob));
|
|
|
a.setAttribute('download', filename);
|
|
|
|
|
|
if (document.createEvent) {
|
|
|
const event = document.createEvent('MouseEvents');
|
|
|
event.initEvent('click', true, true);
|
|
|
a.dispatchEvent(event);
|
|
|
}
|
|
|
else {
|
|
|
a.click();
|
|
|
}
|
|
|
delete messageWorking.dataset.active;
|
|
|
button.disabled = false;
|
|
|
});
|
|
|
}).catch(function() {
|
|
|
delete messageWorking.dataset.active;
|
|
|
messageError.dataset.active = true;
|
|
|
button.disabled = false;
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
})();
|
|
|
</script>
|
|
|
</body>
|
|
|
</html> |