node_html_parser/dom/element/
content.rs

1use super::main::HTMLElement;
2use crate::dom::node::{CowStr, Node, NodeOrStr};
3use crate::dom::text::TextNode;
4
5impl HTMLElement {
6	// ---------------- Mutation APIs (部分 JS parity) ----------------
7	/// 解析片段为节点列表(不包裹额外 root),使用默认 Options
8	/// insertAdjacentHTML(position, html)
9	/// 支持: beforebegin | afterbegin | beforeend | afterend
10	/// beforebegin/afterend 会插入到父节点 children 中(若无父则忽略)
11	pub fn insert_adjacent_html(&mut self, position: &str, html: &str) -> Result<(), String> {
12		let pos = position.to_lowercase();
13		match pos.as_str() {
14			"afterbegin" => self.insert_children_at(0, html),
15			"beforeend" => {
16				let len = self.children.len();
17				self.insert_children_at(len, html);
18			}
19			"beforebegin" => self.insert_as_sibling(html, false),
20			"afterend" => self.insert_as_sibling(html, true),
21			_ => {
22				return Err(format!(
23					"The value provided ('{}') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'",
24					position
25				));
26			}
27		}
28		Ok(())
29	}
30
31	/// replaceWith(html_fragment) 用片段替换自身
32	pub fn replace_with(&mut self, html_fragment: &str) {
33		self.replace_with_items(&[NodeOrStr::Str(CowStr(html_fragment))]);
34	}
35	pub fn replace_with_items(&mut self, items: &[NodeOrStr]) {
36		let parent_ptr = match self.parent {
37			Some(p) => p,
38			None => return,
39		};
40		unsafe {
41			let parent = &mut *parent_ptr;
42			let idx = match self.index_in_parent() {
43				Some(i) => i,
44				None => return,
45			};
46			let mut nodes = collect_items(items);
47			for n in nodes.iter_mut() {
48				if let Node::Element(e) = n {
49					e.parent = Some(parent_ptr);
50				}
51			}
52			// 删除原节点
53			parent.children.remove(idx);
54			for (i, n) in nodes.into_iter().enumerate() {
55				parent.children.insert(idx + i, n);
56			}
57		}
58	}
59
60	pub fn text(&self) -> String {
61		html_escape::decode_html_entities(&self.raw_text()).to_string()
62	}
63	/// 对应 JS innerText: 返回未解码聚合文本 (即 rawText)
64	pub fn inner_text(&self) -> String {
65		self.raw_text()
66	}
67	/// 对应 JS textContent getter: 返回解码后的文本
68	pub fn text_content(&self) -> String {
69		self.text()
70	}
71	/// 对应 JS textContent setter: 先对传入进行实体编码,再替换子节点为单一文本节点
72	pub fn set_text_content(&mut self, val: &str) {
73		// JS HTMLElement.textContent 在实现中: this.childNodes = [ new TextNode(val, this) ] 并不对 val 做实体编码
74		self.children.clear();
75		self.children
76			.push(Node::Text(TextNode::new(val.to_string())));
77	}
78	pub fn set_content_str(&mut self, content: &str, comment_override: Option<bool>) {
79		let allow_comment = comment_override.unwrap_or(self.parse_comment);
80		let (mut nodes, parsed_inner) = parse_fragment_with_opts(
81			content,
82			self.parse_comment,
83			self.parse_lowercase,
84			comment_override,
85		);
86		if !allow_comment {
87			// 过滤掉注释节点
88			nodes.retain(|n| !matches!(n, Node::Comment(_)));
89		}
90		// JS: 若解析后 childNodes 为空,则回退为 TextNode(r.innerHTML) 而不是原始 content
91		let fallback = if nodes.is_empty() {
92			parsed_inner.as_str()
93		} else {
94			content
95		};
96		self.replace_children_with(nodes, fallback);
97	}
98
99	fn replace_children_with(&mut self, mut nodes: Vec<Node>, raw_fallback: &str) {
100		if nodes.is_empty() {
101			use crate::dom::text::TextNode;
102			nodes.push(Node::Text(TextNode::new(raw_fallback.to_string())));
103		}
104		let self_ptr: *mut HTMLElement = self as *mut HTMLElement;
105		for n in nodes.iter_mut() {
106			if let Node::Element(e) = n {
107				e.parent = Some(self_ptr);
108			}
109		}
110		self.children.clear();
111		self.children.extend(nodes);
112	}
113
114	/// JS 兼容别名:set_content(字符串) -> set_content_str,无注释覆盖。
115	pub fn set_content(&mut self, content: &str) {
116		self.set_content_str(content, None);
117	}
118	pub fn set_content_nodes(&mut self, mut nodes: Vec<Node>) {
119		let self_ptr: *mut HTMLElement = self as *mut HTMLElement;
120		for n in nodes.iter_mut() {
121			if let Node::Element(e) = n {
122				e.parent = Some(self_ptr);
123			}
124		}
125		self.children.clear();
126		self.children.extend(nodes);
127	}
128}
129
130fn parse_fragment_with_opts(
131	html: &str,
132	base_comment: bool,
133	lower: bool,
134	override_comment: Option<bool>,
135) -> (Vec<Node>, String) {
136	use crate::parser::{parse_with_options, Options};
137	let mut opts = Options::default();
138	// JS set_content 行为:若传入 override 则使用其值;否则继承 base_comment。
139	opts.comment = override_comment.unwrap_or(base_comment);
140	opts.lower_case_tag_name = lower;
141	let mut root = parse_with_options(html, &opts);
142	let fallback_inner = root.inner_html();
143	(root.children.drain(..).collect(), fallback_inner)
144}
145pub(super) fn parse_fragment(html: &str) -> Vec<Node> {
146	use crate::parser::{parse_with_options, Options};
147	let mut opts = Options::default();
148	if html.contains("<!--") {
149		opts.comment = true;
150	}
151	let mut root = parse_with_options(html, &opts);
152	root.children.drain(..).collect()
153}
154
155pub(super) fn collect_items(items: &[NodeOrStr]) -> Vec<Node> {
156	let mut out = Vec::new();
157	for it in items {
158		match it {
159			NodeOrStr::Str(s) => {
160				let mut frag = parse_fragment(&s.0);
161				out.extend(frag.drain(..));
162			}
163			NodeOrStr::Existing(n) => out.push(n.clone()), // 暂用 clone 语义
164		}
165	}
166	out
167}