|
|
@ -1,45 +1,71 @@ |
|
|
|
from panflute import * |
|
|
|
from whitespace import NBSP |
|
|
|
|
|
|
|
from transform import FQuoted |
|
|
|
|
|
|
|
def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str: |
|
|
|
|
|
|
|
if isinstance(e, ListContainer): |
|
|
|
return ''.join([html(child, indent_level, indent_str) for child in e]) |
|
|
|
|
|
|
|
tag = e.tag.lower() |
|
|
|
attributes = "" |
|
|
|
content_foot = "" |
|
|
|
content_head = "" |
|
|
|
|
|
|
|
tags = { |
|
|
|
BulletList: "ul", |
|
|
|
Doc: "main", |
|
|
|
Emph: "em", |
|
|
|
Caption: "figcaption", |
|
|
|
Para: "p", |
|
|
|
Header: "h"+str(e.level) if hasattr(e, "level") else "", |
|
|
|
LineBlock: "p", |
|
|
|
ListItem: "li", |
|
|
|
SmallCaps: "span", |
|
|
|
Strikeout: "strike", |
|
|
|
Subscript: "sub", |
|
|
|
Superscript: "sup", |
|
|
|
Underline: "u", |
|
|
|
TableBody: "tbody", |
|
|
|
TableHead: "thead", |
|
|
|
TableFoot: "tfoot", |
|
|
|
TableRow: "tr", |
|
|
|
TableCell: "td", |
|
|
|
} |
|
|
|
if type(e) in tags: |
|
|
|
tag = tags[type(e)] |
|
|
|
|
|
|
|
not_implemented = { |
|
|
|
Citation: True, |
|
|
|
Cite: True, |
|
|
|
Definition: True, |
|
|
|
DefinitionItem: True, |
|
|
|
DefinitionList: True |
|
|
|
} |
|
|
|
if type(e) in not_implemented: |
|
|
|
return f'<!-- FIXME: {type(e)}s not implemented -->' |
|
|
|
|
|
|
|
simple_string = { |
|
|
|
NBSP: " ", |
|
|
|
Space: " ", |
|
|
|
Null: "", |
|
|
|
LineBreak: f"\n{indent_level*indent_str}<br>\n{indent_level*indent_str}", |
|
|
|
SoftBreak: f"\n{indent_level*indent_str}<br>\n{indent_level*indent_str}", |
|
|
|
HorizontalRule: f"{indent_level*indent_str}<hr>\n" |
|
|
|
} |
|
|
|
if type(e) in simple_string: |
|
|
|
return simple_string[type(e)] |
|
|
|
|
|
|
|
if hasattr(e, "identifier") and e.identifier != "": |
|
|
|
attributes += f' id="{e.identifier}"' |
|
|
|
|
|
|
|
if hasattr(e, "classes") and len(e.classes) != 0: |
|
|
|
attributes += f' class="{" ".join(e.classes)}"' |
|
|
|
|
|
|
|
if isinstance(e, BulletList): |
|
|
|
tag = "ul" |
|
|
|
|
|
|
|
if isinstance(e, Citation): |
|
|
|
return "TODO: " + e.tag |
|
|
|
|
|
|
|
if isinstance(e, Cite): |
|
|
|
return "TODO: " + e.tag |
|
|
|
|
|
|
|
if isinstance(e, CodeBlock): |
|
|
|
# TODO: Syntax highlighting |
|
|
|
tag = "pre" |
|
|
|
|
|
|
|
if isinstance(e, Definition): |
|
|
|
return "TODO: " + e.tag |
|
|
|
|
|
|
|
if isinstance(e, DefinitionItem): |
|
|
|
return "TODO: " + e.tag |
|
|
|
|
|
|
|
if isinstance(e, DefinitionList): |
|
|
|
return "TODO: " + e.tag |
|
|
|
|
|
|
|
if isinstance(e, Emph): |
|
|
|
tag = "em" |
|
|
|
|
|
|
|
if isinstance(e, Figure): |
|
|
|
content_foot = html(e.caption, indent_level+1, indent_str) |
|
|
|
|
|
|
@ -47,15 +73,8 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str: |
|
|
|
tag = "figcaption" |
|
|
|
|
|
|
|
if isinstance(e, Image): |
|
|
|
tag = "img" |
|
|
|
# TODO: Finish this |
|
|
|
# TODO: Image processing |
|
|
|
|
|
|
|
if isinstance(e, LineBreak): |
|
|
|
return f"\n{indent_level*indent_str}<br>\n{indent_level*indent_str}" |
|
|
|
|
|
|
|
if isinstance(e, Para): |
|
|
|
tag = "p" |
|
|
|
return f'<img src="{e.url}" alt="{e.title or html(e.content, 0, "")}">' |
|
|
|
|
|
|
|
if isinstance(e, Header): |
|
|
|
tag = "h"+str(e.level) |
|
|
@ -63,29 +82,86 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str: |
|
|
|
if isinstance(e, Link): |
|
|
|
tag = "a" |
|
|
|
attributes += f' href="{e.url}"' |
|
|
|
if len(e.title) != 0: |
|
|
|
if e.title: |
|
|
|
attributes += f' title="{e.title}"' |
|
|
|
|
|
|
|
if isinstance(e, LineItem): |
|
|
|
return indent_level*indent_str + html(e.content) + "<br>\n" |
|
|
|
|
|
|
|
if isinstance(e, Note): |
|
|
|
content_head = "(" |
|
|
|
content_foot = ")" |
|
|
|
if len(e.content) == 1 and isinstance(e.content[0], Para): |
|
|
|
return f' <note>({html(e.content[0].content, 0, "")})</note>' |
|
|
|
|
|
|
|
if isinstance(e, OrderedList): |
|
|
|
tag = "ol" |
|
|
|
if e.start and e.start != 1: |
|
|
|
attributes += f' start="{e.start}"' |
|
|
|
html_styles = { |
|
|
|
"Decimal": "1", |
|
|
|
"LowerRoman": "i", |
|
|
|
"UpperRoman:": "I", |
|
|
|
"LowerAlpha": "a", |
|
|
|
"UpperAlpha": "A" |
|
|
|
} |
|
|
|
if e.style and e.style != "DefaultStyle": |
|
|
|
attributes += f' type="{html_styles[e.style]}"' |
|
|
|
# FIXME: Delimeter styles |
|
|
|
|
|
|
|
if isinstance(e, Table): |
|
|
|
content_head = html(e.head, indent_level+1, indent_str) |
|
|
|
content_foot = html(e.foot, indent_level+1, indent_str) |
|
|
|
# FIXME: Fancy pandoc tables, using colspec |
|
|
|
|
|
|
|
if isinstance(e, TableCell): |
|
|
|
tag = "td" |
|
|
|
if e.colspan != 1: |
|
|
|
attributes += f' colspan="{e.colspan}"' |
|
|
|
if e.rowspan != 1: |
|
|
|
attributes += f' rowspan="{e.rowspan}"' |
|
|
|
aligns = { |
|
|
|
"AlignLeft": "left", |
|
|
|
"AlignRight": "right", |
|
|
|
"AlignCenter": "center" |
|
|
|
} |
|
|
|
if e.alignment and e.alignment != "AlignDefault": |
|
|
|
attributes += f' style="text-align: {aligns[e.alignment]}"' |
|
|
|
|
|
|
|
if isinstance(e, FQuoted): |
|
|
|
if e.style == "cs": |
|
|
|
if e.quote_type == "SingleQuote": |
|
|
|
return f'‚{html(e.content, 0, "")}‘' |
|
|
|
elif e.quote_type == "DoubleQuote": |
|
|
|
return f'„{html(e.content, 0, "")}“' |
|
|
|
elif e.style == "en": |
|
|
|
if e.quote_type == "SingleQuote": |
|
|
|
return f'‘{html(e.content, 0, "")}’' |
|
|
|
elif e.quote_type == "DoubleQuote": |
|
|
|
return f'“{html(e.content, 0, "")}”' |
|
|
|
else: |
|
|
|
if e.quote_type == "SingleQuote": |
|
|
|
return f'\'{html(e.content, 0, "")}\'' |
|
|
|
elif e.quote_type == "DoubleQuote": |
|
|
|
return f'"{html(e.content, 0, "")}"' |
|
|
|
else: |
|
|
|
return f'"{html(e.content, 0, "")}"' |
|
|
|
|
|
|
|
if isinstance(e, Str): |
|
|
|
return e.text |
|
|
|
|
|
|
|
if isinstance(e, NBSP): |
|
|
|
return " " |
|
|
|
|
|
|
|
if isinstance(e, Space): |
|
|
|
return " " |
|
|
|
|
|
|
|
if isinstance(e, Null): |
|
|
|
return "" |
|
|
|
return e.text.replace(" ", " ") |
|
|
|
|
|
|
|
if isinstance(e, Math): |
|
|
|
# TODO |
|
|
|
return "TODO: MATH" |
|
|
|
|
|
|
|
if isinstance(e, RawInline): |
|
|
|
if isinstance(e, RawInline) and e.format == "html": |
|
|
|
return e.text |
|
|
|
|
|
|
|
if isinstance(e, RawBlock) and e.format == "html": |
|
|
|
return f'{e.text}\n' |
|
|
|
|
|
|
|
if isinstance(e, Inline): |
|
|
|
return f"<{tag}{attributes}> {content_head} {''.join([html(child, 0, '') for child in e.content])} {content_foot} </{tag}>" |
|
|
|
return f"<{tag}{attributes}>{content_head}{html(e.content, 0, '')}{content_foot}</{tag}>" |
|
|
|
|
|
|
|
out_str = "" |
|
|
|
if not isinstance(e, Plain): |
|
|
@ -94,8 +170,7 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str: |
|
|
|
if hasattr(e, "_content"): |
|
|
|
if len(e.content) > 0 and isinstance(e.content[0], Inline): |
|
|
|
out_str += (indent_level+1)*indent_str |
|
|
|
for child in e.content: |
|
|
|
out_str += html(child, indent_level+1, indent_str) |
|
|
|
out_str += html(e.content, indent_level+1, indent_str) |
|
|
|
if hasattr(e, "text"): |
|
|
|
out_str += e.text |
|
|
|
out_str += f"{content_foot}\n" |
|
|
@ -104,3 +179,4 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str: |
|
|
|
|
|
|
|
return out_str |
|
|
|
|
|
|
|
|
|
|
|