use viewpoint_js::js;
pub fn aria_snapshot_js() -> &'static str {
js! {
(function(element) {
const iframeRefs = [];
let iframeCounter = 0;
function getAriaSnapshot(el) {
if (!el || el.nodeType !== Node.ELEMENT_NODE) {
return null;
}
const tagName = el.tagName.toUpperCase();
if (tagName === "IFRAME" || tagName === "FRAME") {
const frameRef = "frame-" + (iframeCounter++);
iframeRefs.push(frameRef);
const name = el.getAttribute("aria-label") ||
el.getAttribute("title") ||
el.getAttribute("name") ||
null;
return {
role: "iframe",
name: name,
isFrame: true,
frameUrl: el.src || null,
frameName: el.getAttribute("name") || null,
frameRef: frameRef
};
}
const role = el.getAttribute("role") || getImplicitRole(el);
if (!role) {
const children = [];
for (const child of el.children) {
const childSnapshot = getAriaSnapshot(child);
if (childSnapshot) {
children.push(childSnapshot);
}
}
if (children.length === 1) {
return children[0];
}
if (children.length > 0) {
return { role: "group", children: children };
}
return null;
}
const snapshot = { role: role };
const name = getAccessibleName(el);
if (name) {
snapshot.name = name;
}
const desc = el.getAttribute("aria-describedby");
if (desc) {
const descEl = document.getElementById(desc);
if (descEl) {
snapshot.description = descEl.textContent.trim();
}
}
if (el.getAttribute("aria-disabled") === "true" || el.disabled) {
snapshot.disabled = true;
}
const checked = el.getAttribute("aria-checked");
if (checked === "true") {
snapshot.checked = "true";
} else if (checked === "mixed") {
snapshot.checked = "mixed";
} else if (checked === "false") {
snapshot.checked = "false";
} else if (el.type === "checkbox" || el.type === "radio") {
snapshot.checked = el.checked ? "true" : "false";
}
if (el.getAttribute("aria-expanded") === "true") {
snapshot.expanded = true;
}
if (el.getAttribute("aria-selected") === "true") {
snapshot.selected = true;
}
if (el.getAttribute("aria-pressed") === "true") {
snapshot.pressed = true;
}
const level = el.getAttribute("aria-level") ||
(role === "heading" && el.tagName.match(/H([1-6])/) ? el.tagName[1] : null);
if (level) {
snapshot.level = parseInt(level, 10);
}
const valueNow = el.getAttribute("aria-valuenow");
if (valueNow) snapshot.valueNow = parseFloat(valueNow);
const valueMin = el.getAttribute("aria-valuemin");
if (valueMin) snapshot.valueMin = parseFloat(valueMin);
const valueMax = el.getAttribute("aria-valuemax");
if (valueMax) snapshot.valueMax = parseFloat(valueMax);
const valueText = el.getAttribute("aria-valuetext");
if (valueText) snapshot.valueText = valueText;
const children = [];
for (const child of el.children) {
const childSnapshot = getAriaSnapshot(child);
if (childSnapshot) {
children.push(childSnapshot);
}
}
if (children.length > 0) {
snapshot.children = children;
}
return snapshot;
}
function getImplicitRole(el) {
const tag = el.tagName.toLowerCase();
const roleMap = {
"a": el.hasAttribute("href") ? "link" : null,
"article": "article",
"aside": "complementary",
"button": "button",
"dialog": "dialog",
"footer": "contentinfo",
"form": "form",
"h1": "heading", "h2": "heading", "h3": "heading",
"h4": "heading", "h5": "heading", "h6": "heading",
"header": "banner",
"img": "img",
"input": getInputRole(el),
"li": "listitem",
"main": "main",
"nav": "navigation",
"ol": "list",
"option": "option",
"progress": "progressbar",
"section": "region",
"select": "combobox",
"table": "table",
"tbody": "rowgroup",
"td": "cell",
"textarea": "textbox",
"th": "columnheader",
"tr": "row",
"ul": "list"
};
return roleMap[tag] || null;
}
function getInputRole(el) {
const type = el.type || "text";
const typeRoles = {
"button": "button",
"checkbox": "checkbox",
"email": "textbox",
"number": "spinbutton",
"radio": "radio",
"range": "slider",
"search": "searchbox",
"submit": "button",
"tel": "textbox",
"text": "textbox",
"url": "textbox"
};
return typeRoles[type] || "textbox";
}
function getAccessibleName(el) {
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel) return ariaLabel;
const labelledBy = el.getAttribute("aria-labelledby");
if (labelledBy) {
const labels = labelledBy.split(" ").map(function(id) {
const labelEl = document.getElementById(id);
return labelEl ? labelEl.textContent.trim() : "";
}).filter(Boolean);
if (labels.length) return labels.join(" ");
}
if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
if (el.id) {
const label = document.querySelector("label[for=\"" + el.id + "\"]");
if (label) return label.textContent.trim();
}
const parent = el.closest("label");
if (parent) {
const clone = parent.cloneNode(true);
const inner = clone.querySelector("input,textarea,select");
if (inner) inner.remove();
const text = clone.textContent.trim();
if (text) return text;
}
}
if (el.tagName === "IMG") {
return el.getAttribute("alt") || "";
}
if (el.tagName === "BUTTON" || el.tagName === "A") {
return el.textContent.trim();
}
const title = el.getAttribute("title");
if (title) return title;
return null;
}
const result = getAriaSnapshot(element);
if (result && iframeRefs.length > 0) {
result.iframeRefs = iframeRefs;
}
return result;
})
}
}
pub fn aria_snapshot_with_refs_js() -> &'static str {
js! {
(function(element) {
const elements = [];
const iframeRefs = [];
let iframeCounter = 0;
function getAriaSnapshot(el) {
if (!el || el.nodeType !== Node.ELEMENT_NODE) {
return null;
}
const elementIndex = elements.length;
elements.push(el);
const tagName = el.tagName.toUpperCase();
if (tagName === "IFRAME" || tagName === "FRAME") {
const frameRef = "frame-" + (iframeCounter++);
iframeRefs.push(frameRef);
const name = el.getAttribute("aria-label") ||
el.getAttribute("title") ||
el.getAttribute("name") ||
null;
return {
role: "iframe",
name: name,
isFrame: true,
frameUrl: el.src || null,
frameName: el.getAttribute("name") || null,
frameRef: frameRef,
elementIndex: elementIndex
};
}
const role = el.getAttribute("role") || getImplicitRole(el);
if (!role) {
const children = [];
for (const child of el.children) {
const childSnapshot = getAriaSnapshot(child);
if (childSnapshot) {
children.push(childSnapshot);
}
}
if (children.length === 1) {
return children[0];
}
if (children.length > 0) {
return { role: "group", children: children, elementIndex: elementIndex };
}
return null;
}
const snapshot = { role: role, elementIndex: elementIndex };
const name = getAccessibleName(el);
if (name) {
snapshot.name = name;
}
const desc = el.getAttribute("aria-describedby");
if (desc) {
const descEl = document.getElementById(desc);
if (descEl) {
snapshot.description = descEl.textContent.trim();
}
}
if (el.getAttribute("aria-disabled") === "true" || el.disabled) {
snapshot.disabled = true;
}
const checked = el.getAttribute("aria-checked");
if (checked === "true") {
snapshot.checked = "true";
} else if (checked === "mixed") {
snapshot.checked = "mixed";
} else if (checked === "false") {
snapshot.checked = "false";
} else if (el.type === "checkbox" || el.type === "radio") {
snapshot.checked = el.checked ? "true" : "false";
}
if (el.getAttribute("aria-expanded") === "true") {
snapshot.expanded = true;
}
if (el.getAttribute("aria-selected") === "true") {
snapshot.selected = true;
}
if (el.getAttribute("aria-pressed") === "true") {
snapshot.pressed = true;
}
const level = el.getAttribute("aria-level") ||
(role === "heading" && el.tagName.match(/H([1-6])/) ? el.tagName[1] : null);
if (level) {
snapshot.level = parseInt(level, 10);
}
const valueNow = el.getAttribute("aria-valuenow");
if (valueNow) snapshot.valueNow = parseFloat(valueNow);
const valueMin = el.getAttribute("aria-valuemin");
if (valueMin) snapshot.valueMin = parseFloat(valueMin);
const valueMax = el.getAttribute("aria-valuemax");
if (valueMax) snapshot.valueMax = parseFloat(valueMax);
const valueText = el.getAttribute("aria-valuetext");
if (valueText) snapshot.valueText = valueText;
const children = [];
for (const child of el.children) {
const childSnapshot = getAriaSnapshot(child);
if (childSnapshot) {
children.push(childSnapshot);
}
}
if (children.length > 0) {
snapshot.children = children;
}
return snapshot;
}
function getImplicitRole(el) {
const tag = el.tagName.toLowerCase();
const roleMap = {
"a": el.hasAttribute("href") ? "link" : null,
"article": "article",
"aside": "complementary",
"button": "button",
"dialog": "dialog",
"footer": "contentinfo",
"form": "form",
"h1": "heading", "h2": "heading", "h3": "heading",
"h4": "heading", "h5": "heading", "h6": "heading",
"header": "banner",
"img": "img",
"input": getInputRole(el),
"li": "listitem",
"main": "main",
"nav": "navigation",
"ol": "list",
"option": "option",
"progress": "progressbar",
"section": "region",
"select": "combobox",
"table": "table",
"tbody": "rowgroup",
"td": "cell",
"textarea": "textbox",
"th": "columnheader",
"tr": "row",
"ul": "list"
};
return roleMap[tag] || null;
}
function getInputRole(el) {
const type = el.type || "text";
const typeRoles = {
"button": "button",
"checkbox": "checkbox",
"email": "textbox",
"number": "spinbutton",
"radio": "radio",
"range": "slider",
"search": "searchbox",
"submit": "button",
"tel": "textbox",
"text": "textbox",
"url": "textbox"
};
return typeRoles[type] || "textbox";
}
function getAccessibleName(el) {
const ariaLabel = el.getAttribute("aria-label");
if (ariaLabel) return ariaLabel;
const labelledBy = el.getAttribute("aria-labelledby");
if (labelledBy) {
const labels = labelledBy.split(" ").map(function(id) {
const labelEl = document.getElementById(id);
return labelEl ? labelEl.textContent.trim() : "";
}).filter(Boolean);
if (labels.length) return labels.join(" ");
}
if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT") {
if (el.id) {
const label = document.querySelector("label[for=\"" + el.id + "\"]");
if (label) return label.textContent.trim();
}
const parent = el.closest("label");
if (parent) {
const clone = parent.cloneNode(true);
const inner = clone.querySelector("input,textarea,select");
if (inner) inner.remove();
const text = clone.textContent.trim();
if (text) return text;
}
}
if (el.tagName === "IMG") {
return el.getAttribute("alt") || "";
}
if (el.tagName === "BUTTON" || el.tagName === "A") {
return el.textContent.trim();
}
const title = el.getAttribute("title");
if (title) return title;
return null;
}
const snapshot = getAriaSnapshot(element);
if (snapshot && iframeRefs.length > 0) {
snapshot.iframeRefs = iframeRefs;
}
return { snapshot: snapshot, elements: elements };
})
}
}