Building Project Files
هذا الالتزام موجود في:
176
venv/lib/python3.12/site-packages/mistune/directives/image.py
Normal file
176
venv/lib/python3.12/site-packages/mistune/directives/image.py
Normal file
@@ -0,0 +1,176 @@
|
||||
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"
|
المرجع في مشكلة جديدة
حظر مستخدم