import re
from typing import TYPE_CHECKING, Any, Dict, List, Match, Optional
from ..util import escape as escape_text
from ..util import escape_url
from ._base import BaseDirective, DirectivePlugin
if TYPE_CHECKING:
from ..block_parser import BlockParser
from ..core import BlockState
from ..markdown import Markdown
from ..renderers.html import HTMLRenderer
__all__ = ["Image", "Figure"]
_num_re = re.compile(r"^\d+(?:\.\d*)?")
_allowed_aligns = ["top", "middle", "bottom", "left", "center", "right"]
def _parse_attrs(options: Dict[str, Any]) -> Dict[str, Any]:
attrs = {}
if "alt" in options:
attrs["alt"] = options["alt"]
# validate align
align = options.get("align")
if align and align in _allowed_aligns:
attrs["align"] = align
height = options.get("height")
width = options.get("width")
if height and _num_re.match(height):
attrs["height"] = height
if width and _num_re.match(width):
attrs["width"] = width
if "target" in options:
attrs["target"] = escape_url(options["target"])
return attrs
class Image(DirectivePlugin):
NAME = "image"
def parse(self, block: "BlockParser", m: Match[str], state: "BlockState") -> Dict[str, Any]:
options = dict(self.parse_options(m))
attrs = _parse_attrs(options)
attrs["src"] = self.parse_title(m)
return {"type": "block_image", "attrs": attrs}
def __call__(self, directive: "BaseDirective", md: "Markdown") -> None:
directive.register(self.NAME, self.parse)
assert md.renderer is not None
if md.renderer.NAME == "html":
md.renderer.register("block_image", render_block_image)
def render_block_image(
self: "HTMLRenderer",
src: str,
alt: Optional[str] = None,
width: Optional[str] = None,
height: Optional[str] = None,
**attrs: Any,
) -> str:
img = '"
_cls = "block-image"
align = attrs.get("align")
if align:
_cls += " align-" + align
target = attrs.get("target")
if target:
href = self.safe_url(target)
outer = ''
return outer + img + "\n"
else:
return '