use std::collections::BTreeMap;
#[cfg(feature = "visitor")]
use crate::converter::utility::content::collect_tag_attributes;
use crate::converter::utility::content::is_block_level_element;
use crate::visitor::{NodeContext, NodeType, VisitResult};
pub fn handle_visitor_element_start(
visitor_handle: &crate::visitor::VisitorHandle,
tag_name: &str,
node_handle: &tl::NodeHandle,
tag: &tl::HTMLTag,
parser: &tl::Parser<'_>,
output: &mut String,
_ctx: &crate::converter::Context,
depth: usize,
dom_ctx: &crate::converter::DomContext,
) -> VisitAction {
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
let node_id = node_handle.get_inner();
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
let node_ctx = NodeContext {
node_type: NodeType::Element,
tag_name: tag_name.to_string(),
attributes,
depth,
index_in_parent,
parent_tag,
is_inline: !is_block_level_element(tag_name),
};
let visitor_start_result = {
let mut visitor = visitor_handle.borrow_mut();
visitor.visit_element_start(&node_ctx)
};
match visitor_start_result {
crate::visitor::VisitResult::Continue => VisitAction::Continue,
crate::visitor::VisitResult::Skip => VisitAction::Skip,
crate::visitor::VisitResult::Custom(custom_output) => {
output.push_str(&custom_output);
if !matches!(tag_name, "table") {
let element_content = &custom_output;
let mut visitor = visitor_handle.borrow_mut();
let _ = visitor.visit_element_end(&node_ctx, element_content);
}
VisitAction::Custom
}
crate::visitor::VisitResult::Error(_msg) => VisitAction::Error,
_ => VisitAction::Continue,
}
}
pub fn handle_visitor_element_end(
visitor_handle: &crate::visitor::VisitorHandle,
tag_name: &str,
node_handle: &tl::NodeHandle,
tag: &tl::HTMLTag,
parser: &tl::Parser<'_>,
output: &mut String,
element_output_start: usize,
ctx: &crate::converter::Context,
depth: usize,
dom_ctx: &crate::converter::DomContext,
) {
if matches!(tag_name, "table") {
return;
}
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
let node_id = node_handle.get_inner();
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
let node_ctx = NodeContext {
node_type: NodeType::Element,
tag_name: tag_name.to_string(),
attributes,
depth,
index_in_parent,
parent_tag,
is_inline: !is_block_level_element(tag_name),
};
let safe_start = element_output_start.min(output.len());
let safe_start = crate::converter::utility::content::floor_char_boundary(output, safe_start);
let element_content = &output[safe_start..];
let mut visitor = visitor_handle.borrow_mut();
match visitor.visit_element_end(&node_ctx, element_content) {
VisitResult::Continue => {}
VisitResult::Custom(custom) => {
output.truncate(safe_start);
output.push_str(&custom);
}
VisitResult::Skip => {
output.truncate(safe_start);
}
VisitResult::Error(err) => {
if ctx.visitor_error.borrow().is_none() {
*ctx.visitor_error.borrow_mut() = Some(err);
}
}
VisitResult::PreserveHtml => {}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisitAction {
Continue,
Skip,
Custom,
Error,
}