| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- 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 = '<img src="' + escape_text(src) + '"'
- style = ""
- if alt:
- img += ' alt="' + escape_text(alt) + '"'
- if width:
- if width.isdigit():
- img += ' width="' + width + '"'
- else:
- style += "width:" + width + ";"
- if height:
- if height.isdigit():
- img += ' height="' + height + '"'
- else:
- style += "height:" + height + ";"
- if style:
- img += ' style="' + escape_text(style) + '"'
- 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 = '<a class="' + _cls + '" href="' + href + '">'
- return outer + img + "</a>\n"
- else:
- return '<div class="' + _cls + '">' + img + "</div>\n"
- class Figure(DirectivePlugin):
- NAME = "figure"
- def parse_directive_content(
- self, block: "BlockParser", m: Match[str], state: "BlockState"
- ) -> Optional[List[Dict[str, Any]]]:
- content = self.parse_content(m)
- if not content:
- return None
- tokens = list(self.parse_tokens(block, content, state))
- caption = tokens[0]
- if caption["type"] == "paragraph":
- caption["type"] = "figcaption"
- children = [caption]
- if len(tokens) > 1:
- children.append({"type": "legend", "children": tokens[1:]})
- return children
- return None
- def parse(self, block: "BlockParser", m: Match[str], state: "BlockState") -> Dict[str, Any]:
- options = dict(self.parse_options(m))
- image_attrs = _parse_attrs(options)
- image_attrs["src"] = self.parse_title(m)
- align = image_attrs.pop("align", None)
- fig_attrs = {}
- if align:
- fig_attrs["align"] = align
- for k in ["figwidth", "figclass"]:
- if k in options:
- fig_attrs[k] = options[k]
- children = [{"type": "block_image", "attrs": image_attrs}]
- content = self.parse_directive_content(block, m, state)
- if content:
- children.extend(content)
- return {
- "type": "figure",
- "attrs": fig_attrs,
- "children": children,
- }
- 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("figure", render_figure)
- md.renderer.register("block_image", render_block_image)
- md.renderer.register("figcaption", render_figcaption)
- md.renderer.register("legend", render_legend)
- def render_figure(
- self: Any,
- text: str,
- align: Optional[str] = None,
- figwidth: Optional[str] = None,
- figclass: Optional[str] = None,
- ) -> str:
- _cls = "figure"
- if align:
- _cls += " align-" + align
- if figclass:
- _cls += " " + figclass
- html = '<figure class="' + _cls + '"'
- if figwidth:
- html += ' style="width:' + figwidth + '"'
- return html + ">\n" + text + "</figure>\n"
- def render_figcaption(self: Any, text: str) -> str:
- return "<figcaption>" + text + "</figcaption>\n"
- def render_legend(self: Any, text: str) -> str:
- return '<div class="legend">\n' + text + "</div>\n"
|