1
votes

I'm working on Chrome extensions. I try to learn messaging between content and background. I develop simple project for this. But I have issue.

Basic idea is

  • User click button on extension popup
  • A function (bot.js) find image from content of tab then extension (background.js) will download it.

The issue ise port.onMessage.addListener() in background.js fired twice.

When background.js send message to contentscript.js there are two same messages in console or when I try to download in background.js (the code line "Do Something") it download the file twice.

How can I solve this problem?

popup.html

<!doctype html>
<html>
  <head>
    <title>Test Plugin</title> 
    <script src="background.js"></script>
    <script src="popup.js"></script>
  </head>
  <body>
    <h1>Test Plugin</h1>
    <button id="btnStart">Button</button>
  </body>
</html>

popup.js

document.addEventListener('DOMContentLoaded', function() {
    var checkPageButton = document.getElementById('btnStart');
    checkPageButton.addEventListener('click', function() {  
      GetImages("Some URL");
    }, false);
  }, false);


  var tab_title = '';
  function GetImages(pageURL){
    // Tab match for pageURL and return index
    chrome.tabs.query({}, function(tabs) {
      var tab=null;      
      for(var i=0;i<tabs.length;i++){
        if(tabs[i].url==undefined || tabs[i].url=="" || tabs[i]==null){}
        else{
          if(tabs[i].url.includes(pageURL)){
            tab=tabs[i];
            break;
          }
        } 
      }
      
      if(tab!=null){
          chrome.tabs.executeScript(tab.id, {
            file: "bot.js"
          }, function(results){
            console.log(results);
          });
      }
    });
  }

bot.js

var thumbImagesCount = document.querySelectorAll('.classifiedDetailThumbList .thmbImg').length;
var megaImageURL=document.querySelectorAll('.mega-photo-img img')[0].src;
console.log(megaImageURL + " from bot.js");
port.postMessage({key:"download", text: megaImageURL});

background.js

chrome.runtime.onConnect.addListener(function (port) {
    console.assert(port.name == "content-script");
    port.onMessage.addListener(function(message) {
        
        console.log(message);
        if(message.key=="download"){
            // Do Something
            // Event fires twice
            port.postMessage({key:"download", text: "OK"});
        }
    })
});

contentscript.js

console.log("content script loaded!");
var port = chrome.runtime.connect({name: "content-script"});
port.onMessage.addListener(function(message){
    console.log(message);
});

manifest.json

{
    "manifest_version": 2,
  
    "name": "Test Extension",
    "description": "This extension will download images from gallery",
    "version": "1.0",
    "icons": { 
        "16": "bot16.png",
        "48": "bot48.png",
       "128": "bot128.png" },
    "browser_action": {
        "default_icon": "bot48.png",
        "default_popup": "popup.html"
    },
    "permissions": [
        "activeTab",
        "downloads",
        "http://*/",
        "https://*/"
    ],
    "background": {
        "persistent": false,
        "scripts": ["background.js"]
    },
    "content_scripts": [
        {
            "matches": ["http://*/*", "https://*/*"],
            "js": ["contentscript.js"]
        }
    ]
  }
1
The background script declared in manifest.json already has its own page, a hidden background page where it runs, so you should not load it in the popup as it makes no sense. In this case it also creates the second listener. See also Accessing console and devtools of extension's background.js - wOxxOm
Thank you for your answer. It solve my problem. - BK52
@wOxxOm Looks like we have a classic example of why not to post answers or partial answers in comments - the OP's problem is solved, but the Question still shows as Unanswered and no one can vote on, improve, or accept your solution. :( - IMSoP
@IMSoP, Thing is, extensions have so many moving parts that sometimes it's wasteful to post an answer without confirmation the guess was right. - wOxxOm
@wOxxOm Yeah, the platform's not great for that kind of thing, but the ideal is to keep comments to questions that clarify, and post guesses as answers, which can always be deleted if clarifications make them obsolete. - IMSoP

1 Answers

1
votes

The background script declared in manifest.json already has its own page, a hidden background page where it runs, so you should not load it in the popup as it makes no sense in case there are listeners for API events, the background page is already listening for them. In this case the copy also creates the second listener while the popup is open.

Solution: don't load background.js in popup.

See also Accessing console and devtools of extension's background.js.