Skip to content

Commit

Permalink
Support multiple on_end_tag callbacks on Element.
Browse files Browse the repository at this point in the history
  • Loading branch information
orium committed Apr 24, 2023
1 parent 05c4390 commit 6f4f170
Showing 1 changed file with 66 additions and 10 deletions.
76 changes: 66 additions & 10 deletions src/rewritable_units/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub struct Element<'r, 't> {
start_tag: &'r mut StartTag<'t>,
end_tag_mutations: Option<Mutations>,
modified_end_tag_name: Option<Bytes<'static>>,
end_tag_handler: Option<EndTagHandler<'static>>,
end_tag_handlers: Vec<EndTagHandler<'static>>,
can_have_content: bool,
should_remove_content: bool,
encoding: &'static Encoding,
Expand All @@ -60,7 +60,7 @@ impl<'r, 't> Element<'r, 't> {
start_tag,
end_tag_mutations: None,
modified_end_tag_name: None,
end_tag_handler: None,
end_tag_handlers: Vec::new(),
can_have_content,
should_remove_content: false,
encoding,
Expand Down Expand Up @@ -489,7 +489,8 @@ impl<'r, 't> Element<'r, 't> {

/// Sets a handler to run when the end tag is reached.
///
/// Subsequent calls to the method on the same element replace the previous handler.
/// Subsequent calls to the method on the same element replace the previous handler. If you
/// want to run multiple handlers use [`Element::add_on_end_tag`].
///
/// # Example
///
Expand Down Expand Up @@ -536,9 +537,64 @@ impl<'r, 't> Element<'r, 't> {
pub fn on_end_tag(
&mut self,
handler: impl FnOnce(&mut EndTag) -> HandlerResult + 'static,
) -> Result<(), EndTagError> {
self.end_tag_handlers.clear();
self.add_on_end_tag(handler)
}

/// Adds a handler to run when the end tag is reached.
///
/// Contrary to [`Element::on_end_tag`] this method does not replace previous handlers: all
/// handlers will run in the order by which they were registered.
///
/// # Example
///
/// ```
/// use lol_html::html_content::ContentType;
/// use lol_html::{element, rewrite_str, text, RewriteStrSettings};
/// let buffer = std::rc::Rc::new(std::cell::RefCell::new(String::new()));
/// let html = rewrite_str(
/// "<span>Short</span><span><b>13</b> characters</span>",
/// RewriteStrSettings {
/// element_content_handlers: vec![
/// element!("span", |el| {
/// // Truncate string for each new span.
/// buffer.borrow_mut().clear();
/// let buffer = buffer.clone();
/// el.add_on_end_tag(move |end| {
/// let s = buffer.borrow();
/// if s.len() == 13 {
/// // add text before the end tag
/// end.before("!", ContentType::Text);
/// } else {
/// // replace the end tag with an uppercase version
/// end.remove();
/// let name = end.name().to_uppercase();
/// end.after(&format!("</{}>", name), ContentType::Html);
/// }
/// Ok(())
/// })?;
/// Ok(())
/// }),
/// text!("span", |t| {
/// // Save the text contents for the end tag handler.
/// buffer.borrow_mut().push_str(t.as_str());
/// Ok(())
/// }),
/// ],
/// ..RewriteStrSettings::default()
/// },
/// )
/// .unwrap();
///
/// assert_eq!(html, "<span>Short</SPAN><span><b>13</b> characters!</span>");
/// ```
pub fn add_on_end_tag(
&mut self,
handler: impl FnOnce(&mut EndTag) -> HandlerResult + 'static,
) -> Result<(), EndTagError> {
if self.can_have_content {
self.end_tag_handler = Some(Box::new(handler));
self.end_tag_handlers.push(Box::new(handler));
Ok(())
} else {
Err(EndTagError::NoEndTag)
Expand All @@ -548,11 +604,11 @@ impl<'r, 't> Element<'r, 't> {
pub(crate) fn into_end_tag_handler(self) -> Option<EndTagHandler<'static>> {
let end_tag_mutations = self.end_tag_mutations;
let modified_end_tag_name = self.modified_end_tag_name;
let end_tag_handler = self.end_tag_handler;
let end_tag_handlers = self.end_tag_handlers;

if end_tag_mutations.is_some()
|| modified_end_tag_name.is_some()
|| end_tag_handler.is_some()
|| !end_tag_handlers.is_empty()
{
Some(Box::new(move |end_tag: &mut EndTag| {
if let Some(name) = modified_end_tag_name {
Expand All @@ -563,11 +619,11 @@ impl<'r, 't> Element<'r, 't> {
end_tag.mutations = mutations;
}

if let Some(handler) = end_tag_handler {
handler(end_tag)
} else {
Ok(())
for handler in end_tag_handlers.into_iter() {
handler(end_tag)?;
}

Ok(())
}))
} else {
None
Expand Down

0 comments on commit 6f4f170

Please sign in to comment.