summaryrefslogtreecommitdiff
path: root/src/mistune/directives/image.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/mistune/directives/image.py')
-rw-r--r--src/mistune/directives/image.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/mistune/directives/image.py b/src/mistune/directives/image.py
new file mode 100644
index 0000000..5d9d40a
--- /dev/null
+++ b/src/mistune/directives/image.py
@@ -0,0 +1,152 @@
+import re
+from ._base import DirectivePlugin
+from ..util import escape as escape_text, escape_url
+
+__all__ = ['Image', 'Figure']
+
+_num_re = re.compile(r'^\d+(?:\.\d*)?')
+_allowed_aligns = ["top", "middle", "bottom", "left", "center", "right"]
+
+
+def _parse_attrs(options):
+ 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, m, state):
+ 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, md):
+ directive.register(self.NAME, self.parse)
+ if md.renderer.NAME == 'html':
+ md.renderer.register('block_image', render_block_image)
+
+
+def render_block_image(self, src: str, alt=None, width=None, height=None, **attrs):
+ img = '<img src="' + 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 = escape_text(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, m, state):
+ content = self.parse_content(m)
+ if not content:
+ return
+
+ tokens = 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
+
+ def parse(self, block, m, state):
+ 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, md):
+ directive.register(self.NAME, self.parse)
+
+ 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, text, align=None, figwidth=None, figclass=None):
+ _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, text):
+ return '<figcaption>' + text + '</figcaption>\n'
+
+
+def render_legend(self, text):
+ return '<div class="legend">\n' + text + '</div>\n'