在内容脚本得到响应之前,禁止启动上下文菜单

Prevent context menu from launching until content script gets a response back

本文关键字:禁止 启动 菜单 上下文 响应 脚本      更新时间:2023-09-26

(我将内容脚本称为cs.js,background.js称为ba.jsTR

场景:

点击oncontextmenu,我需要确定页面的url及其阻止状态,并将其发送到ba.js。代码(cs.js:

var triggered = false;
window.oncontextmenu = function(event){
    if(triggered) return;
    chrome.runtime.sendMessage({
        url: window.location.href,
        blocked: isBlocked
    }, function(response){  // after work has been done
        triggered = true;           
        triggerEvent(window, "contextmenu", event); // line A
        triggered = false; // line C
    });
    return false; // line B
};

问题是,当我得到响应时,上下文菜单已经显示给用户,而没有我想要的消息(因为我没有得到响应,这意味着ba.js还没有完成chrome.contextMenus.update调用)。因此,作为一个解决方案,我有:

  1. 返回false以防止其显示(B行)
  2. 使用trigger布尔值来确保在a行I triggerEvent(全局)时不会再次发送消息
  3. 然后重置C线上的trigger布尔值

然而,这种方法并不奏效。因此,我需要一种方法:

在上下文菜单操作中,从相关的cs.js向ba.js发送一条消息,根据仅对cs.js可用的某些参数更新上下文菜单,然后,仅在收到消息后,向用户显示上下文菜单

注意:我已经尝试过使用chrome.tabs.onUpdated和其他朋友(这样我就可以检测到用户所在的当前页面,从而自己获得必要的参数),但是,我也无法使用它们来实现这一点。

ba.jsonMessage:

chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse){   
    if(typeof msg.url !== undefined){
        url = msg.url; // global
        isBlocked = msg.blocked; // global
        action = isBlocked ? "Unblock" : "Block"; // global
        chrome.contextMenus.update("blockSite", { // update action
            title: action + " this site"
        });
        sendResponse("done");  // send confirmation
    }
});

triggerEvent代码:

function triggerEvent(node, eventName, obj){
    var ev = new CustomEvent(eventName, obj || {});
    node.dispatchEvent(ev);
}

更新

所以,我使用了onActivated,这次它运行得很好,除了一个大问题:

如果我打开一个新的选项卡,然后单击网站互动程序/键入网站地址,网站就会打开。然后,onActivated侦听器不会启动(这当然是显而易见的)我不能使用onUpdated,因为每当iframe更新时,即使在当前不活动的页面中,它也会触发。

我能做些什么来纠正这个错误?

您无法在Chrome中实际触发内置上下文菜单。因为这是Chrome用来授予某些临时权限(如activeTab)的用户手势之一。

使用tabs.onActivatedtabs.onUpdated事件侦听器跟踪活动选项卡中的更改,并相应地更新上下文菜单。

  • 持久背景页(默认模式):

    var activeTabId;
    chrome.tabs.onActivated.addListener(function(info) { updateContextMenu(info.tabId) });
    chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
        if (tabId == activeTabId) {
            updateContextMenu(tabId);
        }
    });
    function updateContextMenu(tabId) {
        activeTabId = tabId;
        chrome.tabs.get(tabId, function(tab) {
            var isBlocked = checkBlockedState(tab.url);
            chrome.contextMenus.update("blockSite", {
                title: (isBlocked ? "Unblock" : "Block") + " this site"
            });
        });
    }
    
  • 事件页面("persistent" : false):

    chrome.tabs.onActivated.addListener(function(info) { updateContextMenu() });
    chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            if (tabs[0].id == tabId) {
                updateContextMenu();
            }
        });
    });
    function updateContextMenu() {
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            var isBlocked = checkBlockedState(tabs[0].url);
            chrome.contextMenus.update("blockSite", {
                title: (isBlocked ? "Unblock" : "Block") + " this site"
            });
        });
    }