test(home): replace clutter outliner with click-to-inspect

User reported the previous diagnostic was too cluttered to read,
and the white bar showed no outline anyway — meaning the flat
``querySelectorAll('body *')`` walker missed it (likely inside an
iframe's contentDocument, which the script didn't recurse into).

New approach: a single red button "CLAUDE: click here, then click
the white bar" in the top-right. Clicking the button arms an
inspect handler. The next click anywhere on the page reports the
full element stack at that point via ``elementsFromPoint`` AND
recursively descends into any same-origin iframe at the click
location, so iframe contents are no longer invisible.

A black report panel lists every element in the stack with its
tag/id/testid/class, position, z-index, background color, and
bounding rect — TOP element highlighted in red. User clicks the
white bar exactly once and we know what it is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 22:23:35 +00:00
parent 8232ab1ca7
commit f106275643

View File

@@ -310,33 +310,22 @@ def _home_page() -> None:
""" """
<script> <script>
(function () { (function () {
// Cast a wide net: outline EVERY element whose visible rect lives // CLICK-TO-INSPECT: a single button enters inspect mode. The next
// in the bottom 200px of the viewport, regardless of position type. // click anywhere on the page reports the full element stack at
// Different border styles for different position values so the user // that point — including elements inside same-origin iframes
// can tell at a glance what kind of element each box is. // (which earlier diagnostics couldn't reach with a flat walker).
// Also dump a readable list onto the page (top-right panel) so the // No clutter outside the button + the report panel; nothing
// user can read the labels without needing devtools. // re-runs on scroll.
function styleFor(pos, idx) { function init() {
var palette = ['#e6194b', '#3cb44b', '#4363d8', '#f58231', '#911eb4',
'#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080'];
var color = palette[idx % palette.length];
var width = '3px';
var style = 'solid';
if (pos === 'sticky') style = 'dashed';
else if (pos === 'absolute') style = 'dotted';
else if (pos === 'static' || pos === 'relative') {
style = 'solid';
width = '1px';
}
return { color: color, css: width + ' ' + style + ' ' + color };
}
function inspect() {
var doc = window.parent.document; var doc = window.parent.document;
if (!doc) return;
var winp = window.parent; var winp = window.parent;
var vh = winp.innerHeight; if (!doc || !doc.body) { setTimeout(init, 300); return; }
var vw = winp.innerWidth; // Clear any earlier diagnostic chrome.
// Clear previous outlines + labels. ['claude-diag-panel', 'claude-inspect-btn', 'claude-inspect-report']
.forEach(function (id) {
var prev = doc.getElementById(id);
if (prev) prev.remove();
});
doc.querySelectorAll('[data-claude-label]').forEach(function (n) { doc.querySelectorAll('[data-claude-label]').forEach(function (n) {
n.remove(); n.remove();
}); });
@@ -345,92 +334,115 @@ def _home_page() -> None:
el.style.outlineOffset = ''; el.style.outlineOffset = '';
el.removeAttribute('data-claude-outlined'); el.removeAttribute('data-claude-outlined');
}); });
var panel = doc.getElementById('claude-diag-panel');
if (panel) panel.remove(); var btn = doc.createElement('button');
panel = doc.createElement('div'); btn.id = 'claude-inspect-btn';
panel.id = 'claude-diag-panel'; btn.type = 'button';
panel.style.cssText = btn.textContent = 'CLAUDE: click here, then click the white bar';
'position:fixed;top:8px;right:8px;width:420px;max-height:60vh;' btn.style.cssText =
+ 'overflow:auto;background:rgba(0,0,0,0.88);color:#fff;' 'position:fixed;top:8px;right:8px;z-index:2147483647;'
+ 'font:11px/1.35 ui-monospace,monospace;padding:8px 10px;' + 'background:#b00020;color:#fff;font:13px/1.2 system-ui,sans-serif;'
+ 'border-radius:6px;z-index:2147483647;' + 'font-weight:700;padding:8px 14px;border:none;border-radius:6px;'
+ 'box-shadow:0 4px 16px rgba(0,0,0,0.4);'; + 'cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,0.35);';
panel.innerHTML = doc.body.appendChild(btn);
'<div style="font-weight:700;margin-bottom:4px;">'
+ 'CLAUDE DIAG — elements in bottom ' + 200 + 'px of viewport ' function describe(el) {
+ '(vh=' + vh + ')</div>' if (!el || !el.tagName) return '?';
+ '<div style="font-size:10px;opacity:.7;margin-bottom:6px;">' var testid = el.getAttribute && el.getAttribute('data-testid');
+ 'Border styles: solid=fixed, dashed=sticky, dotted=absolute, ' var cls = (el.className && typeof el.className === 'string')
+ 'thin=static/relative</div>'; ? el.className.split(/\\s+/).slice(0, 3).join('.') : '';
var rows = []; var cs = (el.ownerDocument.defaultView || winp)
var idx = 0; .getComputedStyle(el);
var seen = new Set();
doc.querySelectorAll('body *').forEach(function (el) {
if (seen.has(el)) return;
var rect = el.getBoundingClientRect(); var rect = el.getBoundingClientRect();
// Must intersect the bottom 200px of the viewport. return el.tagName.toLowerCase()
if (rect.bottom < vh - 200 || rect.top > vh) return;
if (rect.width < 2 || rect.height < 2) return;
if (rect.width > vw + 50 || rect.height > vh + 50) return;
var cs = winp.getComputedStyle(el);
// Skip transparent backgrounds — we want to find OPAQUE
// overlays. But keep fixed/sticky regardless, since those can
// still cause overlay even without bg color (children paint).
var hasOpaqueBg =
cs.backgroundColor !== 'rgba(0, 0, 0, 0)'
&& cs.backgroundColor !== 'transparent';
var positioned = cs.position === 'fixed'
|| cs.position === 'sticky' || cs.position === 'absolute';
if (!hasOpaqueBg && !positioned) return;
seen.add(el);
var st = styleFor(cs.position, idx);
idx += 1;
el.style.outline = st.css;
el.style.outlineOffset = '-3px';
el.setAttribute('data-claude-outlined', '1');
var testid = el.getAttribute('data-testid');
var name = el.tagName.toLowerCase()
+ (el.id ? '#' + el.id : '') + (el.id ? '#' + el.id : '')
+ (testid ? '[' + testid + ']' : '') + (testid ? '[testid=' + testid + ']' : '')
+ (el.className && typeof el.className === 'string' + (cls ? '.' + cls : '')
? '.' + el.className.split(/\\s+/).slice(0, 2).join('.') : ''); + ' { pos=' + cs.position
var summary = + ', z=' + cs.zIndex
'pos=' + cs.position + ', bg=' + cs.backgroundColor
+ ' z=' + cs.zIndex + ', rect=(' + Math.round(rect.left) + ','
+ ' top=' + Math.round(rect.top) + Math.round(rect.top) + ' '
+ ' h=' + Math.round(rect.height) + 'px' + Math.round(rect.width) + 'x'
+ ' bg=' + cs.backgroundColor; + Math.round(rect.height) + ') }';
rows.push( }
'<div style="margin:2px 0;padding:3px 5px;'
+ 'border-left:4px solid ' + st.color + ';background:#111;">' function showReport(stack, x, y, frameLabel) {
+ '<div style="color:' + st.color + ';font-weight:700;">' var prev = doc.getElementById('claude-inspect-report');
+ name + '</div>' if (prev) prev.remove();
+ '<div style="opacity:.85;">' + summary + '</div></div>' var panel = doc.createElement('div');
); panel.id = 'claude-inspect-report';
// Floating label on the element itself. panel.style.cssText =
var lbl = doc.createElement('div'); 'position:fixed;top:8px;left:8px;right:8px;max-height:60vh;'
lbl.setAttribute('data-claude-label', '1'); + 'overflow:auto;background:rgba(0,0,0,0.92);color:#fff;'
lbl.textContent = name; + 'font:12px/1.4 ui-monospace,monospace;padding:10px 12px;'
lbl.style.cssText = + 'border-radius:6px;z-index:2147483647;'
'position:fixed;left:' + Math.max(0, rect.left) + 'px;' + 'box-shadow:0 4px 18px rgba(0,0,0,0.5);';
+ 'top:' + Math.max(0, rect.top - 16) + 'px;' var html =
+ 'background:' + st.color + ';color:#fff;' '<div style="font-weight:700;color:#ffb;margin-bottom:6px;">'
+ 'font:10px/1.2 ui-monospace,monospace;' + 'CLICKED AT (' + x + ',' + y + ') — ' + frameLabel + '</div>';
+ 'padding:1px 4px;border-radius:3px;' stack.forEach(function (el, i) {
+ 'z-index:2147483646;pointer-events:none;' html += '<div style="margin:3px 0;padding:3px 6px;'
+ 'white-space:nowrap;max-width:60vw;overflow:hidden;' + 'background:' + (i === 0 ? '#3a0010' : '#111')
+ 'text-overflow:ellipsis;'; + ';border-left:3px solid '
doc.body.appendChild(lbl); + (i === 0 ? '#ff4060' : '#555') + ';">'
+ (i === 0 ? '<b>TOP: </b>' : ('[' + i + '] '))
+ describe(el) + '</div>';
});
html += '<button onclick="this.parentElement.remove()" '
+ 'style="margin-top:8px;background:#444;color:#fff;'
+ 'border:none;padding:4px 10px;border-radius:4px;'
+ 'cursor:pointer;">close</button>';
panel.innerHTML = html;
doc.body.appendChild(panel);
}
function pickFromPoint(targetDoc, x, y, label, depth) {
depth = depth || 0;
var stack = (targetDoc.elementsFromPoint
? targetDoc.elementsFromPoint(x, y) : []);
// Recurse into any same-origin iframe at the click point.
for (var i = 0; i < stack.length; i++) {
var el = stack[i];
if (el && el.tagName === 'IFRAME' && depth < 3) {
try {
var inner = el.contentDocument;
if (inner) {
var r = el.getBoundingClientRect();
var innerStack = pickFromPoint(inner,
x - r.left, y - r.top,
label + ' > IFRAME(' + (el.src || 'srcdoc') + ')',
depth + 1);
if (innerStack && innerStack.length) {
return innerStack.concat(stack);
}
}
} catch (e) { /* cross-origin */ }
}
}
// Tag the frame label onto the returned stack via showReport.
showReport(stack, x, y, label);
return stack;
}
btn.addEventListener('click', function (e) {
e.stopPropagation();
btn.textContent = 'click the white bar now…';
btn.style.background = '#0a8';
function onPick(ev) {
ev.preventDefault();
ev.stopPropagation();
doc.removeEventListener('click', onPick, true);
btn.textContent = 'CLAUDE: click here, then click the white bar';
btn.style.background = '#b00020';
pickFromPoint(doc, ev.clientX, ev.clientY, 'parent doc', 0);
}
setTimeout(function () {
doc.addEventListener('click', onPick, true);
}, 50);
}); });
panel.innerHTML += rows.join('') || '<i>(nothing found)</i>';
doc.body.appendChild(panel);
} }
setTimeout(inspect, 400); init();
setTimeout(inspect, 1500);
setTimeout(inspect, 3500);
window.parent.addEventListener('scroll', function () {
setTimeout(inspect, 80);
}, true);
})(); })();
</script> </script>
""", """,