Search code examples
javascriptgoogle-chrome-extensioncontextmenucontent-script

Unable to send message from context menu to content script


I want to send a message to the content script, when the user selects a context menu item. The content script will then, based on the message, format the webpage as required.

I was unable to do so and I have been able to locate the problem to the code responsible for sending the message (in the context menu script) or the one responsible for receiving message (in the content script).

Below, I try to present a simplified version of the code that tries to duplicate the problem:

manifest.json

{
    "manifest_version": 2,
    "name": "MCVE for SO",
    "version": "1",

    "description": "Demonstrate message passing from context menu to content script",

    "author": "Nityesh Agarwal",

    "permissions": [
        "tabs",
        "activeTab",
        "contextMenus"
    ],  

    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["markr.js"]
        }
    ],  

    "background": {
        "scripts": ["backgroundContextMenus.js"]
    }   
}

backgroundContextMenus.js:

chrome.runtime.onInstalled.addListener(function(){
    chrome.contextMenus.create({"title": "Testing",
                                "contexts": ["selection"],
                                "id": "testing"});
});
chrome.contextMenus.onClicked.addListener(function(info, tab){
    console.log("testing..");
    console.log("Before sending the bold message");
    chrome.tabs.sendMessage(tab.id, {changeParameter: "bold"});
    console.log("After sending the bold message");
});

markr.js:

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse){
        console.log("Text toggled bold");
    }); 

Upon selecting the context menu item, the console shows these messages:

backgroundContextMenus.js:8 testing..
backgroundContextMenus.js:9 Before sending the bold message
backgroundContextMenus.js:11 After sending the bold message

So, as you may notice, there is no log saying something like

Text toggled bold

This means that the code inside the markr.js file isn't getting executed. Therefore, I suspect that there must be something wrong with the code responsible for sending message: chrome.tabs.sendMessage(tabs[0].id, {changeParameter: "bold"});)

Here's another code snippet which I tried to duplicate but it gave the same problem - https://stackoverflow.com/a/14473739/7082018


I am unable to figure out what exactly is wrong with it. It would be of great help if someone could help tell me how I might be able to successfully pass messages between the context menu and the content page.


Solution

  • Taking a cue from this answer I modified my backgroundContextMenus.js as follows:

    function ensureSendMessage(tabId, message, callback){ 
      chrome.tabs.sendMessage(tabId, {ping: true}, function(response){ 
        if(response && response.pong) { // Content script ready
          chrome.tabs.sendMessage(tabId, message, callback);
        } else { // No listener on the other end
          console.log("Injecting script programmatically");
          chrome.tabs.executeScript(tabId, {file: "markr.js"}, function(){
            if(chrome.runtime.lastError) {
              console.error(chrome.runtime.lastError);
              throw Error("Unable to inject script into tab " + tabId);
            }
            // OK, now it's injected and ready
            console.log("Sending msg now");
            chrome.tabs.sendMessage(tabId, message, callback);
          });
        }
      });
    }
    
    chrome.runtime.onInstalled.addListener(function(){
        chrome.contextMenus.create({"title": "Testing",
                                    "contexts": ["selection"],
                                    "id": "testing"});
    });
    
    chrome.contextMenus.onClicked.addListener(function(info, tab){
        ensureSendMessage(tab.id, {greeting: "hello"});
    });
    

    Then I modified the markr.js as follows:

    chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
        if(request.ping){ 
            sendResponse({pong: true}); 
            return; 
        }   
        console.log("Text toggled bold");
    }); 
    

    Now the console logs are exactly what one may expect:

    Console log:

    markr.js:11 Text toggled bold

    Remember that this log is present console log of the webpage's devtools and not the background script's inspect views.