import os
from datetime import timedelta, date
from collections import defaultdict
from typing import Iterable, Dict, Union, Callable, Optional # noqa: F401
from . import diary
from .localization import Localization
from .simplepath import AbsolutePath, RelativePath
from .htmltags import article, header, head, h1, h4, ul, li, a, span, div, \
footer, meta, link, style, html, body, title, HTMLElement, HTMLContent
[docs]def wrap_page(body_content: HTMLContent, page_title: str = None,
encoding: str = 'utf-8', css_references: Iterable[str] = [],
inline_css: str = None) -> html:
h = head(
meta(charset=encoding),
meta(name='viewport',
content='width=device-width, initial-scale=1')
)
if page_title:
h.append(title(page_title))
for css in css_references:
h.append(link(href=css, rel="stylesheet"))
if inline_css:
h.append(style(inline_css))
return html(h, body(body_content))
[docs]def day_to_html(current: date, entry: Iterable[str],
localization: Localization,
link_to_id_fn: Callable[[Optional[str]], str] = None) \
-> HTMLElement:
day = article(_class='card', _id=str(path_for_date(current)))(
header(h4(localization.format_date(current)))
)
day_list = day.subelement(ul())
for e in entry:
if isinstance(e, str):
eli = li()
if link_to_id_fn:
tags_to_print = []
for token in diary.tokenize(e):
if token.type == diary.TokenType.Id:
eli.append(a(token.text,
href=link_to_id_fn(token.ref)))
elif token.type == diary.TokenType.Text:
eli.append(span(token.text))
elif token.type == diary.TokenType.Tag:
tags_to_print.append(token)
else:
raise NotImplementedError('Unknown TokenType')
for tag in tags_to_print:
eli.append(' ')
eli.append(span(tag.text, _class='tag'))
else:
eli.append(e)
day_list.append(eli)
return day
[docs]def wrap_html_page(content: HTMLContent, title: str = None, level: int = 0) \
-> html:
return wrap_page(
div(content, _class='content'),
page_title=title,
css_references=[('../'*level) + 'assets/css/picnic.min.css'],
inline_css='.content { max-width: 800px; margin: auto; '
'font-family: lato, sans-serif;}'
'.tag { background-color: #ffeeaa;}'
)
[docs]def diary_to_html(diary_instance: diary.Diary, fname: str) -> None:
entries = diary_instance.entries
content = div(h1('Entries'))
entries_html = content.subelement(div())
for entry in entries:
entries_html.append(day_to_html(entry.dt, entry.lines,
diary_instance.localization,
lambda ref: '#'))
wrap_html_page(content, title='Diary').write(fname)
[docs]def diary_to_html_folder(diary_instance: diary.Diary, folder: str) -> None:
root_path = AbsolutePath('/')
entries_path = AbsolutePath('/entries')
ids_path = AbsolutePath('/ids')
loc = diary_instance.localization
def folder_from_path(p: AbsolutePath) -> str:
return os.path.join(folder, str(p - root_path))
entries_ul = ul()
identifiers = defaultdict(list) # type: Dict[diary.Token, list]
for year, year_group in diary_instance.iter_entries_by_year_and_month():
year_path = entries_path + rel_path(year)
year_ul = ul()
for month, month_entries in year_group:
s_month = '{:02d}'.format(month)
month_path = year_path + rel_path(s_month)
month_html = div(h1('{} {}'.format(loc.get_month(month-1), year)))
month_ul = month_html.subelement(ul())
for entry in month_entries:
current = entry.dt
s_day = '{:02d}'.format(current.day)
day_path = month_path + rel_path(s_day)
day_folder = folder_from_path(day_path)
os.makedirs(day_folder, exist_ok=True)
def link_to_id_fn(sid: Optional[str]) -> str:
assert sid is not None, \
'Got invalid identifier {}'.format(sid)
return str(ids_path + rel_path(sid) - day_path)
day_html = day_to_html(current, entry.lines,
diary_instance.localization,
link_to_id_fn)
foot = div(_class='flex four')
day_html.append(footer(foot))
yesterday = current - timedelta(days=1)
foot.append(div(a('Yesterday ({})'.format(yesterday),
href=str(path_for_date(yesterday) - day_path)))
)
tomorrow = current + timedelta(days=1)
foot.append(div(a('Tomorrow ({})'.format(tomorrow),
href=str(path_for_date(tomorrow) -
day_path)),
_class='off-fourth'))
index_path = os.path.join(day_folder, 'index.html')
wrap_html_page(day_html, level=4).write(index_path)
append_li_a(month_ul, str(current), str(day_path - month_path))
for dt, e in entry.iter_lines():
for identifier in diary.find_ids(e):
identifiers[identifier].append(dt)
index_path = os.path.join(folder_from_path(month_path),
'index.html')
wrap_html_page(month_html, level=3).write(index_path)
append_li_a(year_ul, loc.get_month(month-1), s_month)
index_path = os.path.join(folder_from_path(year_path), 'index.html')
wrap_html_page(year_ul, level=2).write(index_path)
append_li_a(entries_ul, str(year), str(year))
index_path = os.path.join(folder_from_path(entries_path), 'index.html')
wrap_html_page(entries_ul, level=1).write(index_path)
ids_ul = ul()
for identifier, days in sorted(identifiers.items()):
assert identifier.ref is not None, \
'{} has broken ref'.format(identifier)
id_path = ids_path + rel_path(identifier.ref)
id_folder = folder_from_path(id_path)
os.makedirs(id_folder, exist_ok=True)
append_li_a(ids_ul, identifier.text, str(id_path - ids_path))
identifier_ul = ul()
for day in days:
append_li_a(identifier_ul, str(day), str(path_for_date(day) -
id_path))
index_path = os.path.join(id_folder, 'index.html')
wrap_html_page(identifier_ul, level=2).write(index_path)
index_path = os.path.join(folder_from_path(ids_path), 'index.html')
wrap_html_page(ids_ul, level=1).write(index_path)
import shutil
shutil.rmtree(os.path.join(folder, 'assets'), ignore_errors=True)
shutil.copytree(os.path.join(os.path.dirname(__file__), 'assets'),
os.path.join(folder, 'assets'))
[docs]def rel_path(spath: Union[date, str, int]) -> RelativePath:
return RelativePath(str(spath))
[docs]def path_for_date(dt: date) -> AbsolutePath:
return AbsolutePath('/entries/{}/{:02d}/{:02d}'.format(dt.year,
dt.month,
dt.day))
[docs]def append_li_a(ul: HTMLElement, text: str, href: str) -> None:
ul.append(li(a(text, href=href)))