use crate::SelectorKind;
pub(crate) fn property_expr(property: &str) -> &'static str {
match property {
"value" => "(e.value===undefined?null:String(e.value))",
"href" => "(e.href?String(e.href):null)",
"name" => "(e.getAttribute('name'))",
"id" => "(e.id||null)",
"checked" => "(e.checked===undefined?null:(e.checked?'true':'false'))",
"tag" => "(e.tagName||null)",
_ => "(e.textContent==null?'':String(e.textContent))",
}
}
pub(crate) fn locate_script(kind: SelectorKind, value: &str, property: Option<&str>) -> String {
let embedded = serde_json::to_string(value).unwrap_or_default();
let prop_field = match property {
Some(p) => format!(",property:{}", property_expr(p)),
None => String::new(),
};
match kind {
SelectorKind::Css => format!(
"(function(){{var els=document.querySelectorAll({embedded});\
if(els.length===0)return JSON.stringify({{matches:0}});\
if(els.length>1)return JSON.stringify({{matches:els.length}});\
var e=els[0];\
return JSON.stringify({{matches:1,text:e.textContent==null?'':String(e.textContent),\
tag:e.tagName,id:e.id||null,name:e.getAttribute('name')||null{prop_field}}});}})()"
),
SelectorKind::Xpath => format!(
"(function(){{var it=document.evaluate({embedded},document,null,\
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);\
if(it.snapshotLength===0)return JSON.stringify({{matches:0}});\
if(it.snapshotLength>1)return JSON.stringify({{matches:it.snapshotLength}});\
var e=it.snapshotItem(0);\
return JSON.stringify({{matches:1,text:e.textContent==null?'':String(e.textContent),\
tag:e.tagName||null{prop_field}}});}})()"
),
}
}
pub(crate) fn locate_all_script(kind: SelectorKind, value: &str, property: Option<&str>) -> String {
let embedded = serde_json::to_string(value).unwrap_or_default();
let prop_field = match property {
Some(p) => format!(",property:{}", property_expr(p)),
None => String::new(),
};
match kind {
SelectorKind::Css => format!(
"(function(){{var els=document.querySelectorAll({embedded});\
var out=[];for(var i=0;i<els.length;i++){{var e=els[i];\
out.push({{text:e.textContent==null?'':String(e.textContent),\
tag:e.tagName,id:e.id||null,name:e.getAttribute('name')||null{prop_field}}});}}\
return JSON.stringify({{matches:els.length,elements:out}});}})()"
),
SelectorKind::Xpath => format!(
"(function(){{var it=document.evaluate({embedded},document,null,\
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);\
var out=[];for(var i=0;i<it.snapshotLength;i++){{var e=it.snapshotItem(i);\
out.push({{text:e.textContent==null?'':String(e.textContent),\
tag:e.tagName||null,name:e.getAttribute('name')||null{prop_field}}});}}\
return JSON.stringify({{matches:it.snapshotLength,elements:out}});}})()"
),
}
}
pub(crate) fn locate_deep_script(
kind: SelectorKind,
value: &str,
property: Option<&str>,
) -> String {
let embedded = serde_json::to_string(value).unwrap_or_default();
let prop_field = match property {
Some(p) => format!(",property:{}", property_expr(p)),
None => String::new(),
};
let query = match kind {
SelectorKind::Css => format!(
"try{{var els=root.querySelectorAll({embedded});\
for(var i=0;i<els.length&&out.length<5000;i++)out.push(els[i]);}}catch(e){{}}"
),
SelectorKind::Xpath => format!(
"try{{var it=document.evaluate({embedded},root,null,\
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);\
for(var i=0;i<it.snapshotLength&&out.length<5000;i++)out.push(it.snapshotItem(i));}}catch(e){{}}"
),
};
format!(
"(function(){{\
var out=[];var visited=0;var capped=false;\
function collect(root){{{query}\
try{{var all=root.querySelectorAll('*');\
for(var j=0;j<all.length;j++){{\
if(visited>50000){{capped=true;return;}}\
visited++;\
var sr=all[j].shadowRoot;\
if(sr)collect(sr);}}}}catch(e){{}}\
}}\
collect(document);\
var payload=[];\
for(var k=0;k<out.length;k++){{var e=out[k];\
payload.push({{text:e.textContent==null?'':String(e.textContent),\
tag:e.tagName,id:e.id||null,name:e.getAttribute('name')||null{prop_field}}});}}\
return JSON.stringify({{matches:out.length,elements:payload,\
traversal_capped:capped}});}})()"
)
}
pub(crate) fn popup_scan_script(selector: &str) -> String {
let embedded = serde_json::to_string(selector).unwrap_or_default();
format!(
"(function(){{\
try{{\
var els=document.querySelectorAll({embedded});\
var total=0;var samples=[];\
for(var i=0;i<els.length;i++){{var e=els[i];\
if(e.getClientRects().length===0)continue;\
total++;\
if(samples.length<5){{\
var t=e.textContent==null?'':String(e.textContent);\
samples.push({{tag:e.tagName,id:e.id||null,\
text:t.replace(/\\s+/g,' ').trim().slice(0,200)}});}}}}\
return JSON.stringify({{total:total,samples:samples}});\
}}catch(err){{return JSON.stringify({{error:String(err)}});}}\
}})()"
)
}