Merge pull request #507 from mnaza/fix/insert-adjacent-html-495

fix(js): case-insensitive insertAdjacentHTML that keeps table/select fragments
This commit is contained in:
SGavrl authored and GitHub committed 2026-08-03 15:33:34 +00:00
commit 42f7fad709
5 files changed
+110 -12

No files matched your search

+10 -1
View File
@@ -391,7 +391,16 @@ fn op_dom_inner(state: &OpState, cmd: String, arg1: String, arg2: String) -> Str
dom.detach(child);
}
if !arg2.is_empty() {
let fragment = obscura_dom::parse_fragment(&arg2);
let context_name = dom
.with_node(target, |node| match &node.data {
NodeData::Element { name, .. } => Some(name.clone()),
_ => None,
})
.flatten();
let fragment = match context_name {
Some(name) => obscura_dom::parse_fragment_with_context(&arg2, name),
None => obscura_dom::parse_fragment(&arg2),
};
let import_root = fragment.find_body_or_root();
dom.import_children_from(target, &fragment, import_root);
}
+55
View File
@@ -1549,6 +1549,61 @@ mod tests {
assert_eq!(out, serde_json::json!("1|OPTION|choice"));
}
#[test]
fn insert_adjacent_html_parses_table_fragments() {
let mut rt = setup_runtime(
r#"<html><body><table id="t"><tbody id="tb"></tbody></table></body></html>"#,
);
let out = rt
.evaluate("(function(){var tb=document.getElementById('tb'); tb.insertAdjacentHTML('beforeend','<tr><td>1</td><td>2</td></tr>'); var tr=tb.firstElementChild; return tr ? (tr.tagName+':'+tr.children.length) : 'NULL';})()")
.unwrap();
assert_eq!(out, serde_json::json!("TR:2"));
}
#[test]
fn insert_adjacent_html_position_is_case_insensitive() {
let mut rt = setup_runtime(r#"<html><body><div id="host"><span>base</span></div></body></html>"#);
let out = rt
.evaluate("(function(){var h=document.getElementById('host'); h.insertAdjacentHTML('BeforeEnd','<b>x</b>'); return h.lastElementChild ? h.lastElementChild.tagName : 'NULL';})()")
.unwrap();
assert_eq!(out, serde_json::json!("B"));
}
#[test]
fn insert_adjacent_html_rejects_invalid_position() {
let mut rt = setup_runtime(r#"<html><body><div id="host"></div></body></html>"#);
let out = rt
.evaluate("(function(){var h=document.getElementById('host'); try { h.insertAdjacentHTML('nope','<b>x</b>'); return 'no-throw'; } catch(e){ return e.name; }})()")
.unwrap();
assert_eq!(out, serde_json::json!("SyntaxError"));
}
#[test]
fn insert_adjacent_html_keeps_leading_comments_in_table_contexts() {
let mut rt = setup_runtime(
r#"<html><body><table><tbody id="tb"><tr id="row"></tr></tbody></table></body></html>"#,
);
let out = rt
.evaluate(
"(function(){var tb=document.getElementById('tb');tb.insertAdjacentHTML('beforeend','<!--m--><tr><td>v</td></tr>');var row=document.getElementById('row');row.insertAdjacentHTML('beforeend','<!--n--><td>x</td>');return Array.from(tb.childNodes).map(function(n){return n.nodeName}).join('|')+';'+Array.from(row.childNodes).map(function(n){return n.nodeName}).join('|');})()",
)
.unwrap();
assert_eq!(out, serde_json::json!("TR|#comment|TR;#comment|TD"));
}
#[test]
fn insert_adjacent_html_uses_the_insertion_element_as_context() {
let mut rt = setup_runtime(
r#"<html><body><div id="d"></div><table id="table"><tbody id="tb"></tbody></table></body></html>"#,
);
let out = rt
.evaluate(
"(function(){var d=document.getElementById('d');d.insertAdjacentHTML('beforeend','<tr><td>v</td></tr>');var table=document.getElementById('table');table.insertAdjacentHTML('beforeend','<tr><td>x</td></tr>');var tb=document.getElementById('tb');tb.insertAdjacentHTML('beforeend','<tr><td>y</td></tr>tail');return d.firstChild.nodeName+':'+d.textContent+';'+table.lastElementChild.tagName+';'+Array.from(tb.childNodes).map(function(n){return n.nodeName+(n.data?':'+n.data:'')}).join('|');})()",
)
.unwrap();
assert_eq!(out, serde_json::json!("#text:v;TBODY;TR|#text:tail"));
}
#[test]
fn test_document_title() {
let mut rt = setup_runtime("<html><head><title>Test</title></head><body></body></html>");