diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs index 011412f..cc56eda 100644 --- a/htmlua-parser/src/render.rs +++ b/htmlua-parser/src/render.rs @@ -5,9 +5,10 @@ use std::{ rc::Rc, }; -use anyhow::{Result, anyhow}; +use anyhow::{anyhow, Result}; use kuchikiki::{NodeRef, traits::TendrilSink}; -use mlua::Lua; +use markup5ever::{LocalName, Namespace, QualName}; +use mlua::{Lua, Table}; use pulldown_cmark::{Options, Parser, html}; use syntect::{ easy::HighlightLines, @@ -180,6 +181,29 @@ pub fn process_syntax_highlighting(document: NodeRef) -> Result { Ok(document) } +pub fn generate_footnotes(document: NodeRef) -> Result { + let Ok(footnote_container) = document.select_first("footnotecontainer") else { return Ok(document) }; + + let ctx_name = QualName::new(None, Namespace::from("http://www.w3.org/1999/xhtml"), LocalName::from("div")); + for (i, footnote) in document.select("footnote").map_err(|()| anyhow!("Failed to get footnote"))?.enumerate() { + let i = i + 1; + let fn_text = footnote.text_contents(); + let sup_tag = kuchikiki::parse_fragment(ctx_name.clone(), Vec::new()).one( + format!("{i}") + ).select_first("a").map_err(|()| anyhow!("parse err"))?; + footnote.as_node().insert_after(sup_tag.as_node().clone()); + let text_tag = kuchikiki::parse_fragment(ctx_name.clone(), Vec::new()).one( + format!("

{i}: {fn_text}

") + ).select_first("p").map_err(|()| anyhow!("parse err"))?; + footnote_container.as_node().insert_before(text_tag.as_node().clone()); + } + while let Ok(i) = document.select_first("footnote") { + i.as_node().detach(); + } + footnote_container.as_node().detach(); + Ok(document) +} + #[cfg(test)] mod tests { use httptest::{Expectation, ServerPool, matchers::*, responders::*}; @@ -372,6 +396,46 @@ mod tests { assert!(d.select_first("includeelement").is_err()); } + #[test] + fn footnotes() { + let page = r" + + + + Basic HTML Page + + +
+

asdf

+

asdfum actually

+

asdf

+

asdfno

+
+
+ +
+ + "; + let document = kuchikiki::parse_html().one(page); + let d = generate_footnotes(document).unwrap(); + let sup1 = d.select_first("#ft-sup-1").unwrap(); + assert_eq!(sup1.attributes.borrow().get("title").unwrap(), "um actually"); + assert_eq!(sup1.text_contents(), "1"); + + let sup2 = d.select_first("#ft-sup-2").unwrap(); + assert_eq!(sup2.attributes.borrow().get("title").unwrap(), "no"); + assert_eq!(sup2.text_contents(), "2"); + + let ft_text_1 = d.select_first("#ft-text-1").unwrap(); + assert!(ft_text_1.text_contents().contains("um actually")); + + let ft_text_2 = d.select_first("#ft-text-2").unwrap(); + assert!(ft_text_2.text_contents().contains("no")); + + assert!(d.select_first("footnote").is_err()); + assert!(d.select_first("footnotecontainer").is_err()); + } + #[test] fn basic_markdown() { let page = r"