markdown_it_lazyload/
lib.rs1use markdown_it::{
11 parser::core::CoreRule,
12 plugins::cmark::{self, inline::image::Image},
13 MarkdownIt, Node, NodeValue,
14};
15
16struct LazyLoadImageRule;
17
18impl CoreRule for LazyLoadImageRule {
19 fn run(root: &mut Node, _: &MarkdownIt) {
20 root.walk_mut(|node: &mut Node, _| {
21 if node.is::<Image>() {
22 if let Some(img) = node.cast::<cmark::inline::image::Image>() {
23 node.replace(LazyLoadImage {
24 cmark_image: Image {
25 url: img.url.clone(),
26 title: img.title.clone(),
27 },
28 loading: "lazy".to_string(),
29 })
30 }
31 }
32 });
33 }
34}
35
36#[derive(Debug)]
37pub struct LazyLoadImage {
38 pub cmark_image: Image,
39 pub loading: String,
40}
41
42impl NodeValue for LazyLoadImage {
43 fn render(&self, node: &markdown_it::Node, fmt: &mut dyn markdown_it::Renderer) {
45 let mut attrs = node.attrs.clone();
46
47 attrs.push(("src", self.cmark_image.url.clone()));
48 attrs.push(("alt", node.collect_text()));
49
50 if let Some(title) = &self.cmark_image.title {
51 attrs.push(("title", title.clone()));
52 }
53
54 if !self.cmark_image.url.trim().is_empty() {
55 attrs.push(("loading", self.loading.clone()));
56 }
57
58 fmt.self_close("img", &attrs);
59 }
60}
61
62pub fn add(md: &mut MarkdownIt) {
64 md.add_rule::<LazyLoadImageRule>().after_all();
65}