John Boe
John Boe

Reputation: 3611

Why cannot the addon page receive message?

I am trying to send a message from addon (webextension) to a html page which is in the addon. The webextension API is using the chrome interface which is compatible with Chrome browser. I am using Firefox 48 beta.

This is the background script (the "initiate-page" message is important):

chrome.runtime.onMessage.addListener(  
  function(package, sender
    ){
    switch (package.message){
      case "open":
        if (package.subject == "tab")
          {
          win = myNamespace.tabs[package.module];
          result = win ? false : true; 

          if (result)
            chrome.tabs.create(
              {"url": package.url },
              function(tab) {        
                if (chrome.extension.lastError )
                  console.log(chrome.extension.lastError);
                else
                  myNamespace.tabs[package.module] = tab.id;
                chrome.tabs.onRemoved.addListener(
                    function( tabId, removeInfo )                    
                    {
                    for (var k in myNamespace.tabs )
                      {
                      if (tabId === myNamespace.tabs[k])
                        {
                        myNamespace.tabs[k] = null;
                        break;
                        } 
                      }  
                    }
                  );
              }
            );
          }
      break;
      case "initiate-page":
        if (package.subject == "html-add-listeners")
          {
          switch(package.module){
            case "easy_options":
            case "advanced_options":
            case "images_options":            
            chrome.tabs.sendMessage(
              package.sender.id,
              { message:"initiate-page-response", 
                subject:"accept-namespace", 
                recepient: {id: package.sender.id },
                module: package.module,
                namespace: myNamespace,
                info: "response to tab exists message"   
              }
             )
            break;
            }
          }
      break;
    }
  }
)

So, when the addon receives a message from the module "easy_options", it means that easy_options.html needs some data to load to its document. Therefore I send a message with namespace which contains the data.

Now the addons page easy_options.js (again, the second part is important where chrome.runtime.onMessage listener is added):

chrome.tabs.query(
{ active: true,  currentWindow: true}, 
  function(tabs) {
    browser.runtime.sendMessage(
      { message:"initiate-page", 
        subject: "html-add-listeners",
        module: "easy_options",
        sender:{id:tabs[0].id}   
      }
      )
  }
);

chrome.runtime.onMessage.addListener(  
  function(package, sender
    ){
    switch (package.message){
      case "initiate-page-response":    
        if (package.subject == "accept-namespace")
          {
          switch(package.module){
            case "easy_options":
              document.addEventListener('DOMContentLoaded', myNamespace.easy.restore);
              document.getElementById("easy_form_save").addEventListener("submit", myNamespace.easy.save);
              document.getElementById("easy_form_restore").addEventListener("submit", myNamespace.easy.restore);
              document.getElementById("easy_form_remove_item").addEventListener("submit", myNamespace.easy.remove_profiles);
              document.getElementById("easy_form_remove_profiles").addEventListener("submit", myNamespace.easy.remove_profiles);
              document.getElementById("list").addEventListener("change", myNamespace.easy.restoreDefault);
            break;
            }
          }
      break;
    }
  }
)

What happens is: 1. I send message (A) to background listener and it accepts the message 2. background listener sends message (B) 3. addons options script receives the first message (A) in the runtime.OnMessage listener (I do not want to process this message)

What should happen 1. I send message (A) to background listener and it accepts the message 2. background listener sends message (B) 3. addons options script receives the first message (A) in the runtime.OnMessage listener (I do not want to process this message) 4. addons options script should receive the second message (B) in the runtime.OnMessage listener and I should process it

Question: Why does the fourth step not happen? Why is the message (B alias "initiate-page-response") not received?

Maybe Chrome addon programmers can help too, I think the things should work similarly.

Upvotes: 1

Views: 69

Answers (2)

John Boe
John Boe

Reputation: 3611

Thanks to Xan's explanation, I have found this works like charm

background script:

chrome.runtime.onMessage.addListener(  
  function(package, sender, sendResponse
    ){
    switch (package.message){
      case "open":
        if (package.subject == "tab")
          {
          win = myNamespace.tabs[package.module];
          result = win ? false : true; 

          if (result)
            chrome.tabs.create(
              {"url": package.url },
              function(tab) {        
                if (chrome.extension.lastError )
                  console.log(chrome.extension.lastError);
                else
                  myNamespace.tabs[package.module] = tab.id;
                chrome.tabs.onRemoved.addListener(
                    function( tabId, removeInfo )                    
                    {
                    for (var k in myNamespace.tabs )
                      {
                      if (tabId === myNamespace.tabs[k])
                        {
                        myNamespace.tabs[k] = null;
                        break;
                        } 
                      }  
                    }
                  );
              }
            );
          }
      break;
      case "initiate-page":    
        if (package.subject == "html-add-listeners")
          {
          switch(package.module){
            case "easy_options":
            case "advanced_options":
            case "images_options":            
            sendResponse(
              { message:"initiate-page-response", 
                subject:"accept-namespace", 
                recepient: {id: package.sender.id },
                module: package.module,
                namespace: myNamespace,
                info: "response to initiate-page message"   
              }
             )
            break;
            }
          }
      break;
    }
  }
)

Addon's option page script:

chrome.tabs.query(
{ active: true,  currentWindow: true}, 
  function(tabs) {
    browser.runtime.sendMessage(
      { message:"initiate-page", 
        subject: "html-add-listeners",
        module: "easy_options",
        sender:{id:tabs[0].id}   
      },
      function response(message){
        console.log("RESPONSE:");
        console.log(message);
      return true;
      }
      )
  }
);

Upvotes: 1

Xan
Xan

Reputation: 77482

Since it's an extension page, and not a content script, chrome.tabs.sendMessage is not going to reach it.

You need to broadcast your message with chrome.runtime.sendMessage to reach chrome-extension:// pages such as an options page.

If you don't like the broadcast nature of runtime.sendMessage, you should use sendResponse callback argument to pass a response back to sender (probably preferable), or establish a long-lived port with runtime.connect.

Upvotes: 3

Related Questions