120 lines
3.2 KiB
Python
120 lines
3.2 KiB
Python
|
# 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 <https://www.gnu.org/licenses/>.
|
||
|
|
||
|
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
|