Chrome Extension - Dynamic Right-Click Menu

2020-05-13 20:50发布

问题:

I am trying to create an option in the right-click menu that is dynamic based on the user's action. If the user selects some text, then right-clicks, the option will say "Display It". If the user right-clicks without selecting some text, the option will say "Select Some Text First" and be grayed out. I am wondering how do I achieve this?

I currently have it so that the option will appear only when the user has selected some text. I am unsure how to modify it to meet my second requirements.

chrome.contextMenus.create ({
    title:"Display It!", contexts:["selection"], onclick:function(info,tab) {
        chrome.tabs.sendRequest(
            tab.id,
            {callFunction: "displaySidebar", info: info}, 
            function(response) {console.log(response);}
        );
    }           
});

回答1:

You cant grey an item out...Chrome has gone to a bit of effort to only make context menu items appear when its relevant which is why i guess theres no grey out option. Your way goes against what Chrome have tried to implement and I think you really should rethink the way you go about this.
Saying that, you can use the chrome.contextMenus.update to change a menu item.
The following code is about as good as your going to get it your way (seriously, rethink this idea)....

function selectedTrueOnClick(info, tab) {
    chrome.tabs.sendRequest(
    tab.id, {
        callFunction: "displaySidebar",
        info: info
    }, function(response) {
        console.log(response);
    });
}

function selectedFalseOnClick(info, tab) {
    //
}

var contextMenuID = chrome.contextMenus.create({
    title: "Select some text",
    contexts: ["all"],
    onclick: selectedFalseOnClick
});

function contextMenuUpdate(selected) {
    if (selected) chrome.contextMenus.update(contextMenuID, {
        title: 'You selected "%s"',
        contexts: ["all"],
        onclick: selectedTrueOnClick
    });
    else chrome.contextMenus.update(contextMenuID, {
        title: "Select some text",
        contexts: ["all"],
        onclick: selectedTrueOnClick
    });
}

contextMenuUpdate(false);


回答2:

I was looking to accomplish the same thing as the original post, and was able to get it working using some message passing. Regardless of whether it's bad practice or not, I used the enabled(true/false) contextMenu property to leave my context menu option present, but grayed out.

I created a context menu. The important property is the id. The rest is mostly arbitrary because it will be changed dynamically.

In content.js

//This event listener will determine if the context menu should be updated 
//based on if the right-button was clicked and if there is a selection or not
document.addEventListener("mousedown", function(event){
    if (event.button !== 2) {
        return false;
    }
    var selected = window.getSelection().toString();
        if(event.button == 2 && selected != '') {
                //get selected text and send request to bkgd page to create menu
            chrome.extension.sendMessage({
                   'message': 'updateContextMenu', 
                   'selection': true});
        } else {
        chrome.extension.sendMessage({
                   'message': 'updateContextMenu',
                   'selection': false});
        }
}, true);

In background.js:

//add a message listener that will modify the context menu however you see fit
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.message == 'updateContextMenu') {
        if (request.selection) {
            chrome.contextMenus.update('contextMenuId',{
                'title': 'New Title', 
                'enabled': true, 
                "contexts": ["all"],
                'onclick': someFunction
            });
        } else {
            chrome.contextMenus.update('contextMenuId',{
                'title': 'Select some text first', 
                'enabled': false, 
                "contexts": ["all"]
            });
        }
    } else {
        sendResponse({});
    }
});

//The original context menu.  The important property is the id.  The rest is mostly 
//arbitrary because it will be changed dynamically by the listener above.
    chrome.contextMenus.create({
        'id': 'contextMenuId', 
        'enabled': false, 
        'title': 'Some Title', 
        "contexts": ["all"]
        });