Source code for hyperdiary.htmltags
from typing import Iterable, Union
HTMLContent = Union['HTMLElement', str]
_escaped_attrs = ('id', 'class', 'type')
[docs]class HTMLElement(object):
tag = 'div' # type: str
render_compact = False # type: bool
def __init__(self, *content: HTMLContent, **attributes: str) -> None:
self.content = list(content)
self.attributes = attributes
for a in _escaped_attrs:
if '_' + a in self.attributes:
self.attributes[a] = self.attributes.pop('_' + a)
[docs] def append(self, *items: HTMLContent) -> 'HTMLElement':
self.content += items
return self
def __call__(self, *items: HTMLContent) -> 'HTMLElement':
return self.append(*items)
[docs] def subelement(self, item: 'HTMLElement') -> 'HTMLElement':
self.content.append(item)
return item
[docs] def lazy_render_attributes(self) -> Iterable[str]:
if self.attributes:
for k, v in self.attributes.items():
yield ' '
yield str(k)
yield '="'
yield str(v)
yield '"'
[docs] def lazy_render(self, indent: str = '', add_indent: str = '') \
-> Iterable[str]:
is_doc_root = self.tag.lower() == 'html'
if is_doc_root:
yield '<!DOCTYPE HTML>\n'
do_linebreak = not self.render_compact and self.content
yield indent
yield '<'
yield self.tag
yield from self.lazy_render_attributes()
yield '>'
if do_linebreak:
yield '\n'
child_indent = indent + add_indent if do_linebreak else ''
if not do_linebreak:
add_indent = ''
for child in self.content:
if isinstance(child, HTMLElement):
yield from child.lazy_render(child_indent, add_indent)
else:
yield '{}{}'.format(child_indent, child)
if do_linebreak:
yield '\n'
if do_linebreak:
yield indent
yield '</'
yield self.tag
yield '>'
if is_doc_root:
yield '\n'
def __str__(self) -> str:
'''Render element to string.
>>> str(a('Somewhere', href="#"))
'<a href="#">Somewhere</a>'
>>> str(p())
'<p></p>'
>>> str(div('Hello World'))
'<div>\\n Hello World\\n</div>'
>>> str(table())
'<table></table>'
'''
return ''.join(self.lazy_render(add_indent=' '))
[docs] def write(self, fname: str) -> None:
with open(fname, 'w') as f:
for s in self.lazy_render(add_indent=' '):
f.write(s)
# TAGS
[docs]class a (HTMLElement):
tag = 'a'
render_compact = True
[docs]class article (HTMLElement):
tag = 'article'
render_compact = False
[docs]class body (HTMLElement):
tag = 'body'
render_compact = False
[docs]class div (HTMLElement):
tag = 'div'
render_compact = False
[docs]class h1 (HTMLElement):
tag = 'h1'
render_compact = True
[docs]class h2 (HTMLElement):
tag = 'h2'
render_compact = True
[docs]class h3 (HTMLElement):
tag = 'h3'
render_compact = True
[docs]class h4 (HTMLElement):
tag = 'h4'
render_compact = True
[docs]class head (HTMLElement):
tag = 'head'
render_compact = False
[docs]class hr (HTMLElement):
tag = 'hr'
render_compact = False
[docs]class html (HTMLElement):
tag = 'html'
render_compact = False
[docs]class img (HTMLElement):
tag = 'img'
render_compact = False
[docs]class li (HTMLElement):
tag = 'li'
render_compact = True
[docs]class link (HTMLElement):
tag = 'link'
render_compact = False
[docs]class nav (HTMLElement):
tag = 'nav'
render_compact = False
[docs]class ol (HTMLElement):
tag = 'ol'
render_compact = False
[docs]class p (HTMLElement):
tag = 'p'
render_compact = True
[docs]class small (HTMLElement):
tag = 'small'
render_compact = True
[docs]class span (HTMLElement):
tag = 'span'
render_compact = True
[docs]class style (HTMLElement):
tag = 'style'
render_compact = False
[docs]class table (HTMLElement):
tag = 'table'
render_compact = False
[docs]class tbody (HTMLElement):
tag = 'tbody'
render_compact = False
[docs]class td (HTMLElement):
tag = 'td'
render_compact = True
[docs]class th (HTMLElement):
tag = 'th'
render_compact = False
[docs]class thead (HTMLElement):
tag = 'thead'
render_compact = False
[docs]class title (HTMLElement):
tag = 'title'
render_compact = True
[docs]class tr (HTMLElement):
tag = 'tr'
render_compact = False
[docs]class ul (HTMLElement):
tag = 'ul'
render_compact = False