在框架层次结构中识别真正的活动元素

Identify true activeElement in a frame hierarchy

我正在寻找一种方法来获取任何页面的重点输入,目的是更新它的值。

我有一个接收值并检查 activeElement 是否为 <input>.

的内容脚本

挑战在于主文档的 activeElement 是 iframe。我可以在清单中设置 all_frames: true,这将找到任何活动的 <input>,但我只想设置活动 iframe 的 activeElement 的值。

目前我正在通过让子内容脚本 blur() 除了当前的所有 activeElements(将处理程序附加到 focusin)来解决这个问题,但是一个不修改的解决方案恕我直言,文档状态会更好。

是否可以只向主文档发送消息,如果这个的 activeElement 是一个 iframe,获取那个 frameId(然后重试)?

我不控制网页。

注入一个新的内容脚本来检查框架的完整层次结构,包括 cross-domain 个框架。

主要内容脚本 询问 background/event 页面是否需要:

if (document.activeElement.matches('input') && window == parent) {
    console.log('Input', document.activeElement);
    document.activeElement.value += ' gotcha!';
} else {
    chrome.runtime.sendMessage({action: 'modifyInput'});
}

background/event page脚本在所有帧中执行附加内容脚本:

chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse)) {
    if (msg.action == 'modifyInput') {
        chrome.tabs.executeScript(sender.tab && sender.tab.id, {
            file: 'modify-input.js',
            allFrames: true,
            matchAboutBlank: true,
            runAt: 'document_end',
        });
    }
});

modify-input.js,IIFE 用于确保垃圾收集删除注入的东西。

;(function() {
if (isInputActive()) {
    if (window == parent) {
        foundTheInput();
    } else {
        askParent();
    }
} else if (isFrameActive()) {
    window.addEventListener('message', function onMessage(e) {
        if (!e.data || e.data.id != chrome.runtime.id)
            return;
        switch (e.data.action) {
        // request from a child frame
        case 'checkme':
            if (window == parent) {
                confirmChild(e.source);
                window.removeEventListener('message', onMessage);
            } else {
                askParent();
            }
            break;
        // response from a parent
        case 'confirmed':
            window.removeEventListener('message', onMessage);
            if (isInputActive()) {
                foundTheInput();
            } else if (isFrameActive()) {
                confirmChild(e.source);
            }
            break;
        }
    });
}

function isInputActive() {
    return document.activeElement.matches('input');
}

function isFrameActive() {
    return document.activeElement.matches('frame, iframe');
}

function askParent() {
    parent.postMessage({id: chrome.runtime.id, action: 'checkme'}, '*');
}

function confirmChild(childWindow) {
    console.log('Frame', document.activeElement);
    childWindow.postMessage({id: chrome.runtime.id, action: 'confirmed': true}, '*');
}

function foundTheInput() {
    console.log('Input', document.activeElement);
    document.activeElement.value += ' gotcha!';
}
})();

我没有对此进行测试,但之前确实使用过并看到过类似的代码。