Files
fn_registry/functions/browser/cdp_pick_element_js.js
egutierrez a03675113a chore: auto-commit (286 archivos)
- .claude/agents/fn-orquestador/SKILL.md
- .claude/commands/fn_claude.md
- .claude/rules/INDEX.md
- .claude/rules/cpp_apps.md
- .claude/rules/ids_naming.md
- CHANGELOG.md
- apps/dag_engine/README.md
- apps/dag_engine/api.go
- apps/dag_engine/dags_migrated/example.yaml
- apps/dag_engine/dags_migrated/example_lineage_tracking.yaml
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:33:22 +02:00

121 lines
4.6 KiB
JavaScript

// cdp_pick_element_js - JS injected via CDP Runtime.evaluate.
// Activates click-to-pick mode: hover highlights, click captures element selectors
// and prints via console.log so caller (navegator_dashboard) reads via
// Runtime.consoleAPICalled event.
//
// Inject as expression: see cdp_pick_element_js.md for the wrapping payload.
// Idempotent: re-injecting cleans up previous overlays before reattaching.
(function () {
if (window.__fn_pick_active) {
window.__fn_pick_cleanup && window.__fn_pick_cleanup();
}
window.__fn_pick_active = true;
const overlay = document.createElement('div');
overlay.id = '__fn_pick_overlay';
Object.assign(overlay.style, {
position: 'fixed', pointerEvents: 'none', zIndex: '2147483647',
border: '2px solid #f44', background: 'rgba(255,80,80,0.10)',
boxSizing: 'border-box', transition: 'all 30ms linear',
left: '0px', top: '0px', width: '0px', height: '0px',
});
document.body.appendChild(overlay);
function cssPath(el) {
if (!(el instanceof Element)) return '';
const path = [];
while (el && el.nodeType === Node.ELEMENT_NODE && el !== document.body) {
let seg = el.tagName.toLowerCase();
if (el.id) { seg += '#' + CSS.escape(el.id); path.unshift(seg); break; }
// Prefer class-based path when class is short and not utility-noise.
if (el.className && typeof el.className === 'string') {
const cls = el.className.trim().split(/\s+/).filter(c => c && c.length < 24 && !/^(active|hover|focus|selected|open|disabled|[0-9])/.test(c));
if (cls.length) seg += '.' + cls.map(CSS.escape).join('.');
}
// Disambiguate by nth-of-type when siblings share tag.
if (el.parentNode) {
const siblings = [...el.parentNode.children].filter(c => c.tagName === el.tagName);
if (siblings.length > 1) {
const idx = siblings.indexOf(el) + 1;
seg += `:nth-of-type(${idx})`;
}
}
path.unshift(seg);
el = el.parentNode;
if (path.length > 6) break;
}
return path.join(' > ');
}
function xpath(el) {
if (!el) return '';
if (el.id) return `//*[@id="${el.id}"]`;
const parts = [];
while (el && el.nodeType === Node.ELEMENT_NODE) {
let ix = 0;
for (const sib of el.parentNode ? el.parentNode.childNodes : []) {
if (sib === el) { parts.unshift(`${el.tagName.toLowerCase()}[${ix + 1}]`); break; }
if (sib.nodeType === 1 && sib.tagName === el.tagName) ix++;
}
el = el.parentNode;
if (el === document.body) { parts.unshift('body'); break; }
}
return '/html/body/' + parts.join('/');
}
function describe(el) {
if (!el) return null;
const r = el.getBoundingClientRect();
const attrs = {};
for (const a of el.attributes || []) attrs[a.name] = a.value;
return {
selector: cssPath(el),
xpath: xpath(el),
tag: el.tagName.toLowerCase(),
text: (el.innerText || el.textContent || '').trim().slice(0, 200),
attrs,
rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) },
};
}
function onMove(e) {
const el = e.target;
if (!el || el === overlay) return;
const r = el.getBoundingClientRect();
overlay.style.left = r.left + 'px';
overlay.style.top = r.top + 'px';
overlay.style.width = r.width + 'px';
overlay.style.height = r.height + 'px';
}
function onClick(e) {
e.preventDefault();
e.stopPropagation();
const info = describe(e.target);
console.log('__fn_picked__', JSON.stringify(info));
cleanup();
}
function onKey(e) {
if (e.key === 'Escape') {
console.log('__fn_picked__', JSON.stringify({ cancelled: true }));
cleanup();
}
}
function cleanup() {
window.__fn_pick_active = false;
document.removeEventListener('mousemove', onMove, true);
document.removeEventListener('click', onClick, true);
document.removeEventListener('keydown', onKey, true);
overlay.remove();
}
window.__fn_pick_cleanup = cleanup;
document.addEventListener('mousemove', onMove, true);
document.addEventListener('click', onClick, true);
document.addEventListener('keydown', onKey, true);
return 'pick mode active';
})();