1

I am writing a chrome extension v3, where the content script (content.js) listens for the form submission event and gets the search input from the form. It then sends a message to the background script (background.js) to perform the search, and displays the search results in the search results container. The codes are as followed

manifest.json

{
  "manifest_version": 3,
  "name": "Get Free Copy",
  "description": "Searches for free copies of research papers on various websites",
  "version": "1.0",
  "permissions": ["declarativeNetRequest","tabs","webRequest", "webNavigation"],
  "host_permissions": ["https://*/*"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Get Free Copy",
    "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": ["https://*/*"],
      "js": ["content.js"]
    }
  ]
}

content.js

// Listen for the form submission event
document.getElementById("search-form").addEventListener("submit", function(event) {
  event.preventDefault();

  // Get the search input
  var searchInput = document.getElementById("search-input").value;

  // Send a message to the background script to perform the search
  chrome.runtime.sendMessage({ type: "search", title: searchInput }, function(response) {
    // Clear the search results container
    document.getElementById("search-results").innerHTML = "";

    // Display the search results
    response.results.forEach(function(result) {
      var resultElement = document.createElement("a");
      resultElement.href = result.url;
      resultElement.textContent = result.title;
      document.getElementById("search-results").appendChild(resultElement);
    });
  });
});

background.js

// Handle the message event
self.addEventListener("message", (event) => {
  var request = event.data;
  if (request.type === "search") {
    // Perform the searches and send the results back to the content script
    var title = request.title;
    var title2 = title.replace(/ /g, "+"); // Replace spaces with +
    var results = [];
    var queries = [
      {
        url: `https://www.ncbi.nlm.nih.gov/pmc/?term=${title}`,
        title: "NCBI PMC"
      },
      {
        url: `https://www.biorxiv.org/search/${title}`,
        title: "bioRxiv"
      },
      {
        url: `https://www.medrxiv.org/search/${title}`,
        title: "medRxiv"
      },
      {
        url: `https://www.google.com/search?q=${title2}+filetype:pdf`,
        title: "PDF Search"
      }
    ];
    queries.forEach(function (query) {
      fetch(query.url)
        .then(function (response) {
          return response.text();
        })
        .then(function (html) {
          // Extract the relevant information from the HTML using cheerio or regular expressions
          var $ = cheerio.load(html);
          // ...
          results.push({
            title: query.title,
            url: query.url
            /* Extract other relevant information */
          });
        });
    });

    // Send the results back to the content script
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.sendMessage(tabs[0].id, { results: results });
    });
  }
});

popup.html

<!DOCTYPE html>
<html>
<head>
  <title>Get Free Copy</title>
</head>
<body>
  <!-- Create a form for the search input -->
  <form id="search-form">
    <input type="text" id="search-input" placeholder="Enter the title of the research paper">
    <button type="submit">Search</button>
  </form>

  <!-- Create a container for the search results -->
  <div id="search-results"></div>

  <!-- Include the content script in the popup -->
  <script src="content.js"></script>
</body>
</html>

However, i kept getting the error Error handling response: TypeError: Cannot read properties of undefined (reading 'results') suggesting that the results expected by content.js were not received from background.js

When I inspect the console, I did not receive any errors/nor messages if i put a console.log in background.js

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
Kuan
  • 21
  • 4

1 Answers1

1

If you want to use popup-to-background messaging:

  1. Remove self.addEventListener and use chrome.runtime.onMessage correctly.
  2. Remove content_scripts from manifest.json and rename content.js to popup.js everywhere because it's not a content script. Content scripts are extension scripts that run in the web page, whereas the popup is not a web page, it's an extension page with a chrome-extension:// URL.
  3. Use sendResponse and return true (more info) to send the data back to the popup because chrome.tabs.sendMessage won't work with the popup - it doesn't run inside a tab, it's a separate window.
  4. Since the popup may be closed before the response is sent back you can also save the results to chrome.storage and display it when the popup opens next time.

P.S. For this task you don't need the background script: you can do everything inside popup.js, no need for messaging or libraries like cheerio (you can use the built-in DOMParser).

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • Thanks @wOxxOm, I edited according to your suggestions: manifest.json ```{ "manifest_version": 3, "name": "Get Free Copy", "description": "Searches for free copies of research papers on various websites", "version": "1.0", "permissions": ["declarativeNetRequest","tabs","webRequest", "webNavigation"], "host_permissions": ["https://*/*"], "action": { "default_title": "Get Free Copy", "default_popup": "popup.html" } }``` – Kuan Dec 29 '22 at 10:39
  • popup.js ```// Handle the message event chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if (request.type === "search") {``` and then ```// Send the results back to the popup sendResponse({ results: results }); return true; } });``` – Kuan Dec 29 '22 at 10:41
  • popup.html remains the same but updated content to popup.js No errors, but i still don't get any results back to the popup... – Kuan Dec 29 '22 at 10:42
  • Look at the article for [messaging](https://developer.chrome.com/extensions/messaging) again. I think you can start by implementing everything in the popup without messaging and the background script. – wOxxOm Dec 29 '22 at 11:20
  • Using ```// Wait for the DOM to be ready document.addEventListener("DOMContentLoaded", function() { // Select the search form and the search results container var form = document.getElementById("search-form"); var container = document.getElementById("search-results");``` now and handle everything using popup.js – Kuan Dec 30 '22 at 01:40