140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
|
"""Details."""
|
||
|
import xml.etree.ElementTree as etree
|
||
|
from .block import Block, type_boolean, type_html_identifier
|
||
|
from ..blocks import BlocksExtension
|
||
|
import re
|
||
|
|
||
|
RE_SEP = re.compile(r'[_-]+')
|
||
|
RE_VALID_NAME = re.compile(r'[\w-]+')
|
||
|
|
||
|
|
||
|
class Details(Block):
|
||
|
"""
|
||
|
Details.
|
||
|
|
||
|
Arguments (1 optional):
|
||
|
- A summary.
|
||
|
|
||
|
Options:
|
||
|
- `open` (boolean): force the details block to be in an open state opposed to collapsed.
|
||
|
- `type` (string): Attach a single special class for styling purposes. If more are needed,
|
||
|
use the built-in `attributes` options to apply as many classes as desired.
|
||
|
|
||
|
Content:
|
||
|
Detail body.
|
||
|
"""
|
||
|
|
||
|
NAME = 'details'
|
||
|
|
||
|
ARGUMENT = None
|
||
|
OPTIONS = {
|
||
|
'open': [False, type_boolean],
|
||
|
'type': ['', type_html_identifier]
|
||
|
}
|
||
|
|
||
|
DEF_TITLE = None
|
||
|
DEF_CLASS = None
|
||
|
|
||
|
def on_validate(self, parent):
|
||
|
"""Handle on validate event."""
|
||
|
|
||
|
if self.NAME != 'details':
|
||
|
self.options['type'] = {'name': self.NAME}
|
||
|
if self.DEF_TITLE:
|
||
|
self.options['type']['title'] = self.DEF_TITLE
|
||
|
if self.DEF_TITLE:
|
||
|
self.options['type']['class'] = self.DEF_CLASS
|
||
|
return True
|
||
|
|
||
|
def on_create(self, parent):
|
||
|
"""Create the element."""
|
||
|
|
||
|
# Is it open?
|
||
|
attributes = {}
|
||
|
if self.options['open']:
|
||
|
attributes['open'] = 'open'
|
||
|
|
||
|
# Set classes
|
||
|
obj = self.options['type']
|
||
|
dtype = def_title = class_name = ''
|
||
|
if isinstance(obj, dict):
|
||
|
dtype = obj['name']
|
||
|
class_name = obj.get('class', dtype)
|
||
|
def_title = obj.get('title', RE_SEP.sub(' ', class_name).title())
|
||
|
elif isinstance(obj, str):
|
||
|
dtype = obj
|
||
|
class_name = dtype
|
||
|
def_title = RE_SEP.sub(' ', class_name).title()
|
||
|
if dtype:
|
||
|
attributes['class'] = class_name
|
||
|
|
||
|
# Create Detail element
|
||
|
el = etree.SubElement(parent, 'details', attributes)
|
||
|
|
||
|
# Create the summary
|
||
|
summary = None
|
||
|
if self.argument is None:
|
||
|
if dtype:
|
||
|
summary = def_title
|
||
|
elif self.argument:
|
||
|
summary = self.argument
|
||
|
|
||
|
# Create the summary
|
||
|
if summary is not None:
|
||
|
s = etree.SubElement(el, 'summary')
|
||
|
s.text = summary
|
||
|
|
||
|
return el
|
||
|
|
||
|
|
||
|
class DetailsExtension(BlocksExtension):
|
||
|
"""Admonition Blocks Extension."""
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
"""Initialize."""
|
||
|
|
||
|
self.config = {
|
||
|
"types": [
|
||
|
[],
|
||
|
"Generate Admonition block extensions for the given types."
|
||
|
]
|
||
|
}
|
||
|
|
||
|
super().__init__(*args, **kwargs)
|
||
|
|
||
|
def extendMarkdownBlocks(self, md, block_mgr):
|
||
|
"""Extend Markdown blocks."""
|
||
|
|
||
|
block_mgr.register(Details, self.getConfigs())
|
||
|
|
||
|
# Generate an details subclass based on the given names.
|
||
|
for obj in self.getConfig('types', []):
|
||
|
if isinstance(obj, dict):
|
||
|
name = obj['name']
|
||
|
class_name = obj.get('class', name)
|
||
|
title = obj.get('title', RE_SEP.sub(' ', class_name).title())
|
||
|
else:
|
||
|
name = obj
|
||
|
class_name = name
|
||
|
title = RE_SEP.sub(' ', class_name).title()
|
||
|
subclass = RE_SEP.sub('', name).title()
|
||
|
block_mgr.register(
|
||
|
type(
|
||
|
subclass,
|
||
|
(Details,),
|
||
|
{
|
||
|
'OPTIONS': {'open': [False, type_boolean]},
|
||
|
'NAME': name,
|
||
|
'DEF_TITLE': title,
|
||
|
'DEF_CLASS': class_name
|
||
|
}
|
||
|
),
|
||
|
{}
|
||
|
)
|
||
|
|
||
|
|
||
|
def makeExtension(*args, **kwargs):
|
||
|
"""Return extension."""
|
||
|
|
||
|
return DetailsExtension(*args, **kwargs)
|