html2md_bulletty/
images.rs

1use super::TagHandler;
2use super::StructuredPrinter;
3
4use crate::common::get_tag_attr;
5use crate::dummy::IdentityHandler;
6
7use markup5ever_rcdom::Handle;
8
9use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
10
11const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
12
13/// Handler for `<img>` tag. Depending on circumstances can produce both
14/// inline HTML-formatted image and Markdown native one
15#[derive(Default)]
16pub struct ImgHandler {
17    block_mode: bool
18}
19
20impl TagHandler for ImgHandler {
21
22    fn handle(&mut self, tag: &Handle, printer: &mut StructuredPrinter) {
23        // hack: detect if the image has associated style and has display in block mode
24        let style_tag = get_tag_attr(tag, "src");
25        if let Some(style) = style_tag {
26            if style.contains("display: block") {
27                self.block_mode = true
28            }
29        }
30
31        if self.block_mode {
32            // make image on new paragraph
33            printer.insert_newline();
34            printer.insert_newline();
35        }
36
37        // try to extract attrs
38        let src = get_tag_attr(tag, "src");
39        let alt = get_tag_attr(tag, "alt");
40        let title = get_tag_attr(tag, "title");
41        let height = get_tag_attr(tag, "height");
42        let width = get_tag_attr(tag, "width");
43        let align = get_tag_attr(tag, "align");
44
45        if height.is_some() || width.is_some() || align.is_some() {
46            // need to handle it as inline html to preserve attributes we support
47            let mut identity = IdentityHandler::default();
48            identity.handle(tag, printer);
49        } else {
50            // need to escape URL if it contains spaces
51            // don't have any geometry-controlling attrs, post markdown natively
52            let mut img_url = src.unwrap_or_default();
53            if img_url.contains(' ') {
54                img_url = utf8_percent_encode(&img_url, FRAGMENT).to_string();
55            }
56
57            printer.append_str(
58                &format!("![{}]({}{})", 
59                    alt.unwrap_or_default(), 
60                    &img_url,
61                    title.map(|value| format!(" \"{}\"", value)).unwrap_or_default()));
62        }
63    }
64
65    fn after_handle(&mut self, printer: &mut StructuredPrinter) {
66        if self.block_mode {
67            printer.insert_newline();
68            printer.insert_newline();
69        }
70    }
71}