Product details
Critical product description
diff --git a/moli-html2md/src/machine.rs b/moli-html2md/src/machine.rs
index d6afabd4c..e79dd48c3 100644
--- a/moli-html2md/src/machine.rs
+++ b/moli-html2md/src/machine.rs
@@ -234,7 +234,20 @@ impl<'a, D: Dom + ?Sized> Machine<'a, D> {
.attribute(node, "src")
.filter(|src| !src.is_empty())
{
- self.writer().image(alt, src, title);
+ // Lazy-image placeholders carry no visible image. Keep
+ // accessible alternate text without emitting a data URI.
+ if is_empty_svg_placeholder(src) {
+ if !alt.is_empty()
+ && !self
+ .dom
+ .attribute(node, "aria-hidden")
+ .is_some_and(|value| value.trim().eq_ignore_ascii_case("true"))
+ {
+ self.writer().text(alt);
+ }
+ } else {
+ self.writer().image(alt, src, title);
+ }
}
return;
}
@@ -428,6 +441,13 @@ impl<'a, D: Dom + ?Sized> Machine<'a, D> {
}
}
+fn is_empty_svg_placeholder(src: &str) -> bool {
+ let lower = src.to_ascii_lowercase();
+ lower.starts_with("data:image/svg+xml,%3csvg")
+ && lower.ends_with("%3c/svg%3e")
+ && lower.matches("%3c").count() == 2
+}
+
fn class_language(class: Option<&str>) -> Option<&str> {
class?
.split_ascii_whitespace()
diff --git a/moli-html2md/tests/regressions.rs b/moli-html2md/tests/regressions.rs
index 1eae5b299..1959ed734 100644
--- a/moli-html2md/tests/regressions.rs
+++ b/moli-html2md/tests/regressions.rs
@@ -225,6 +225,21 @@ fn images_without_sources_do_not_emit_placeholder_markdown() {
}
}
+#[test]
+fn empty_svg_lazy_image_placeholders_do_not_emit_data_uris() {
+ let placeholder = "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20720%20960'%3E%3C/svg%3E";
+ let html = format!("beforeafter");
+ assert_eq!(markdown(&html, false), "beforeRecipe photoafter");
+
+ let html =
+ format!("beforeafter");
+ assert_eq!(markdown(&html, false), "beforeafter");
+
+ let real_svg = "data:image/svg+xml,%3Csvg%3E%3Cpath%20d='M0%200'/%3E%3C/svg%3E";
+ let html = format!("
");
+ assert!(markdown(&html, false).contains(real_svg));
+}
+
#[test]
fn list_paragraphs_and_code_blocks_require_blank_lines_between_items() {
for (html, expected) in [
diff --git a/moli-renderer-v8/src/runtime/page_dump.rs b/moli-renderer-v8/src/runtime/page_dump.rs
index 5cf4cf192..ee2f639de 100644
--- a/moli-renderer-v8/src/runtime/page_dump.rs
+++ b/moli-renderer-v8/src/runtime/page_dump.rs
@@ -157,8 +157,6 @@ fn apply_strip_options(dom: &mut NativeDom, strip: RendererPageDumpStripOptions)
| "dialog"
| "menu"
| "menuitem"
- | "details"
- | "summary"
));
if should_remove {
remove.push(node_id);
diff --git a/moli/src/fetch_dump/tests.rs b/moli/src/fetch_dump/tests.rs
index 78f03f86f..84e3229a2 100644
--- a/moli/src/fetch_dump/tests.rs
+++ b/moli/src/fetch_dump/tests.rs
@@ -129,6 +129,33 @@ async fn render_page_dump_default_html_uses_renderer_live_serialize() -> Result<
Ok(())
}
+#[tokio::test]
+async fn strip_ui_keeps_content_inside_details() -> Result<()> {
+ let (_browser, mut page, http_server) = load_page(
+ "
Critical product description