diff --git a/.gitignore b/.gitignore index e91bb0b..8af953e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /index.pickle __pycache__ -/wikinote/markup_custom.py +/wikinote/markup_custom2.py diff --git a/wikinote/markup.py b/wikinote/markup.py index 7f77b8f..cdbca9a 100644 --- a/wikinote/markup.py +++ b/wikinote/markup.py @@ -411,9 +411,13 @@ class FootnoteInlineProcessor(markdown.extensions.footnotes.FootnoteInlineProces return None, None, None # Custom directives and roles +from . import markup_custom +directives.update(markup_custom.directives) +roles.update(markup_custom.roles) + try: - from . import markup_custom - directives.update(markup_custom.directives) - roles.update(markup_custom.roles) + from . import markup_custom2 + directives.update(markup_custom2.directives) + roles.update(markup_custom2.roles) except ImportError: pass diff --git a/wikinote/markup_custom.py b/wikinote/markup_custom.py new file mode 100644 index 0000000..ba39e38 --- /dev/null +++ b/wikinote/markup_custom.py @@ -0,0 +1,119 @@ +# WikiNote3 +# Copyright © 2020 Lee Yingtong Li (RunasSudo) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import flask + +import os.path +import re +import xml.etree.ElementTree as ET + +directives = {} +roles = {} + +class DirectiveElement(ET.Element): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.directive = None + +class Directive: + def __init__(self, md, arg=None, content=None): + self.md = md + self.arg = arg + self.content = content + +class RoleElement(ET.Element): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.role = None + +class Role: + def __init__(self, parser, content=None): + self.parser = parser + self.md = parser.md + self.content = content + +def capitalise(n): + if n.startswith('('): + return '(' + capitalise(n[1:]) + return n[0].upper() + n[1:] + +class DirectiveTag(Directive): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.md.meta['tags'] = self.md.meta.get('tags', []) + self.arg.split(', ') + + def render(self): + return DirectiveElement('div') + +directives['tag'] = DirectiveTag + +class DirectiveInclude(Directive): + def render(self): + el = DirectiveElement('div') + with open(flask.safe_join('./data', self.arg), 'r') as f: + self.md.parser.parseChunk(el, f.read()) + return el + +directives['include'] = DirectiveInclude + +def make_role_ref(is_upper): + class RoleRef(Role): + def render(self): + if ';' in self.content: + label, path = self.content.split(';') + else: + path = self.content + label = path.split('/')[-1] + if is_upper: + label = label[0].upper() + label[1:] + else: + label = label[0].lower() + label[1:] + + # Tooltip wrapper + el = RoleElement('span') + el.set('class', 'tooltip xref') + el.set('data-xref', path) + + # Link + a = ET.SubElement(el, 'a') + if os.path.exists(flask.safe_join('./data/pages', path + '.md')): + a.set('class', 'ref') + else: + a.set('class', 'ref redlink') + self.md.meta['redlinks'] = self.md.meta.get('redlinks', []) + [path] + a.set('href', flask.url_for('page_view', path=path)) + a.text = label + + # Tooltip content container + div = ET.SubElement(el, 'span') + div.set('class', 'tooltip-content') + div.text = 'Loading…' + + return el + return RoleRef + +roles['ref'] = make_role_ref(False) +roles['Ref'] = make_role_ref(True) + +class RoleImage(Role): + def render(self): + el = RoleElement('a') + el.set('href', flask.url_for('image_about', name=self.content)) + img = ET.SubElement(el, 'img') + img.set('src', flask.url_for('image_view', name=self.content)) + return el + +roles['image'] = RoleImage