Commit 40ebfd6a authored by gijs's avatar gijs

Started on a browser

parent 7956f219
from glob import glob
import os.path, os
import re
from parse_tree import parse_tree
import csv
from jinja2 import Environment, FileSystemLoader, select_autoescape
TREE_DIR = 'trees'
TEMPLATE_DIR = 'templates'
OUTPUT_DIR = 'output'
env = Environment(
loader=FileSystemLoader(TEMPLATE_DIR),
autoescape=select_autoescape(['html', 'xml'])
)
filename_data_patt = re.compile('(.+)\+(.+)\+(.+)\.txt')
line_patt = re.compile('^(?:│|├|─|└|\s)*(.+)\s\((Q\d+)\)')
# (?:\│\s\s|\├\─\─|\└\─\─)*(.+)\s\((Q\d+)\)
def get_or_create (key, data):
if key not in data:
data[key] = {}
return data[key]
def slugify (inp):
if inp:
return re.subn(r'\W', '-', inp)[0]
def parse_simple (path):
with open(path, 'r') as source:
for line in source.readlines():
m = line_patt.match(line)
yield m.group(2), m.group(1)
trees = {}
translations = {}
languages = []
print('Importing structures')
for path in glob(os.path.join(TREE_DIR, '*Latin.txt')):
filename = os.path.basename(path)
m = filename_data_patt.match(filename)
if m:
genus = m.group(1)
trees[genus] = parse_tree(path)
print('Importing translations')
for path in glob(os.path.join(TREE_DIR, '*.txt')):
filename = os.path.basename(path)
m = filename_data_patt.match(filename)
if m:
language = m.group(3)
if language not in languages:
languages.append(language)
for identifier, label in parse_simple(path):
if identifier not in translations:
translations[identifier] = {}
translations[identifier][language] = label
with open('tree_genera.csv') as source:
reader = csv.reader(source)
for row in reader:
genus = row[0]
commonname = row[1]
identifier = row[2]
if identifier not in translations:
translations[identifier] = {}
translations[identifier]['commonname'] = commonname
languages.sort()
# print()
# print(data_per_language.keys())
# print(data_per_genus.keys())
# print(data_per_genus['Abies'])
# print('Generating templates')
def translate (identifier, language):
if identifier in translations:
if language in translations[identifier]:
return translations[identifier][language]
return '!!!'
"""
Walks through the tree and adds a url to all entries.
Replace tuple (genus, identifier, tree) → (genus, identifier, path, tree)
"""
def add_urls (tree):
def treat (leaf, prefix):
genus, identifier, subtree = leaf
basename = os.path.join(prefix, identifier) if prefix else identifier
path = '{}.html'.format(basename)
return (genus, identifier, path, walker(subtree, basename))
def walker (tree, prefix = None):
return [treat(leaf, prefix) for leaf in tree]
return walker(tree)
genera = []
leaf_template = env.get_template('names.html')
tree_template = env.get_template('tree.html')
def render_leaf(leaf):
genus, identifier, path, subtree = leaf
path = os.path.join(OUTPUT_DIR, path)
folder = os.path.dirname(path)
if genus:
names = [(language, translate(identifier, language)) for language in languages]
if folder and not os.path.exists(folder):
os.makedirs(folder)
leaf_template.stream(genus=genus, names=names, tree=subtree).dump(path)
if subtree:
[render_leaf(leaf) for leaf in subtree]
print('Generating output')
for tree in trees.values():
tree = add_urls(tree)
genus, identifier, path, _ = tree[0]
print(genus, identifier, commonname)
commonname = translate(identifier, 'commonname')
genera.append((genus, commonname, path))
[render_leaf(leaf) for leaf in tree]
# tree_template.stream(tree=tree).dump(os.path.join(OUTPUT_DIR, '{}-structure.html'.format(genus)))
index_template = env.get_template('index.html')
index_template.stream(genera=sorted(genera, key=lambda r: r[1])).dump(os.path.join(OUTPUT_DIR, 'index.html'))
import re
token_empty = '???'
name_pattern = re.compile(r'(.+)\s\((.+)\)')
token_branch = '├──' # Token to indicate a branch at the current level
token_branch_close = '└──' # Token to indicate the end of a branch
token_indent = '│ ' # Token to indicate this line holds a branch at a deeper level
def parse_line (line):
level = 0
offset = 0
end = False
# Detect at which level in the tree this
# line is placed
while line.startswith(token_indent, offset):
level += 1
offset += len(token_indent)
#
if line.startswith(token_branch_close, offset):
level += 1
offset += len(token_branch_close)
end = True
elif line.startswith(token_branch, offset):
level += 1
offset += len(token_branch)
m = name_pattern.match(line[offset:])
if m:
name = m.group(1)
code = m.group(2)
if name.startswith(token_empty):
name = None
return (name, code, level, end)
else:
print('Unrecognized line `{}`'.format(line[offset:]))
"""
Returns a tree strucutre:
shape Leaf = Array<label, identifier, Tree>
shape Tree = Array<Leaf>
"""
def parse_lines (lines, level = 0, tree = None):
if tree is None:
tree = []
while lines:
line = lines.pop(0)
name, code, line_level, is_end = parse_line(line)
leaf = (name, code, [])
if line_level > level:
if is_end:
tree[-1][2].append(leaf)
else:
subtree = parse_lines(lines, line_level, [leaf])
tree[-1][2].extend(subtree)
else:
tree.append(leaf)
if is_end:
return tree
return tree
def parse_tree (path):
with open(path, 'r') as source:
lines = list(source.readlines())
return parse_lines(lines, 0, [])
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ genus }}</title>
<link rel="stylesheet" href="/styles.css">
<style>
body {
overflow-y: hidden;
height: 100vh;
padding: 0;
margin: 0;
}
#root {
display: flex;
flex-direction: row;
height: 100vh;
}
.leaf {
overflow-y: auto;
flex: 1 0;
min-width: 50vw;
}
</style>
</head>
<body>
<section id="root">
<section class="leaf">
{% for genus, commonname, url in genera %}
<section class="entry">
<a href="{{ url }}">
<h2>{{ commonname }} ({{ genus }})</h2>
</a>
</section>
{% endfor %}
</section>
</section>
<script>
(function () {
function parseDOM (html) {
var parser = new DOMParser();
return parser.parseFromString(html, "text/html");
}
function loadHTML (url) {
return new Promise(function (resolve, reject) {
fetch(url, { method: 'GET'})
.then(function(response) {
if (response.status == 200) {
// success
response.text()
.then(function (text) {
resolve(parseDOM(text));
})
.catch(reject);
} else {
reject();
}
});
});
}
/**
* Returns the first container for the given panel
* @param {DOMElement} panel
*/
function parentQuerySelector(panel, selector) {
var parent = panel.parentElement;
if (parent) {
if (parent.matches(selector)) {
return parent;
} else {
return parentQuerySelector(parent, selector);
}
}
return null;
}
function addListeners (el) {
els = el.querySelectorAll('a');
for (let i = 0; i < els.length; i++) {
els[i].addEventListener('click', load);
}
}
function load (e) {
e.preventDefault();
// if nodes to the right of container: remove them
const container = parentQuerySelector(this, '.leaf');
while (container.nextElementSibling) {
container.nextElementSibling.remove();
}
// load new child
loadHTML(this.href)
.then(function (dom) {
const leaf = dom.querySelector('.leaf');
document.body.querySelector('#root').appendChild(leaf);
addListeners(leaf);
window.scrollTo({
top: 0,
left: document.body.scrollWidth - window.innerWidth
});
});
// strip wrapper
// insert
}
addListeners(document);
})();
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ genus }}</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<section class="leaf">
<h1>{{ genus }}</h1>
<section class="structure">
{% include 'partials/leaf.html' %}
</section>
{% for language, name in names %}
<section class="entry">
<h3>{{ language }}</h3>
{% if name %}
<h2>{{ name }}</h2>
{% endif %}
</section>
{% endfor %}
</section>
</body>
</html>
\ No newline at end of file
<ul>
{% for label, identifier, path, subtree in tree %}
<li>
<a href="/{{ path }}">{{ label }}</a>
<!-- {% if subtree %}
{% with tree = subtree %}
{% include 'partials/leaf.html' %}
{% endwith %}
{% endif %} -->
</li>
{% endfor %}
</ul>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ genus }}</title>
<link rel="stylesheet" href="/styles.css">
<style>
body {
display: flex;
flex-direction: row;
overflow-x: auto;
overflow-y: hidden;
height: 100vh;
padding: 0;
margin: 0;
}
.leaf {
overflow-y: auto;
flex: 1 0;
min-width: 50vw;
}
</style>
</head>
<body>
{% include 'partials/leaf.html' %}
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment