Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome extension event listener fires multiple of times

Introduction

I've got a problem with my extension for Chrome. It supposed to show a small overlay popup window (created in jQuery) with search results from Google based on your text selection. Basically you should be able to highlight a text on any page, right click on it (context menu), click on "Search for 'selected keyword'" and a small window pops up in the same tab as an overlay with all search results from Google.

The problem

It works as described, HOWEVER only for the first time. When I'll highlight another keyword and search for it, extension still REMEMBERS previous keywords and throws 2 windows at the same time. And if I would search for another keyword that would give me 3 windows with 2 previous searches and a new one...

I've tried to remove listener in background script after it executes, but didn't work. It looks like the old listeners are there and they are replying for a request from content script. Can I somehow remove them?

I've tried to put:

chrome.extension.onConnect.removeListener(listener);

at the end of getClickHandler() function but doesn't work.

I was also thinking that maybe this piece of code in background script is doing that, but not sure

return function(info, tab) {

Please, do you have any suggestions?

Many thanks in advance!

PS. This pop-up window cannot be closed at the moment and am aware of that. But you can always refresh the page to get a clean window. The problem is that the second time I will get 2 pop ups opened in the same time... and so on as described above.

Manifest file:

{
  "name": "Easy search Accelerator",
  "version": "1.0",
  "manifest_version": 2,
  "description": "Easily search for anything...",
  "icons": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  },
  "background": {
    "scripts": ["sample.js"]
  },
  "permissions": [
    "contextMenus",
    "tabs",
    "http://*/*",
    "https://*/*"
  ],
  "manifest_version": 2
}

Background page / script (sample.js):

chrome.contextMenus.create({
    "title": 'Search for "%s"',
    "contexts":['selection'],
    "onclick": getClickHandler()
});
function getClickHandler() {
    return function(info, tab) {

    var url = "https://www.google.co.uk/search?q=" + info.selectionText;

    chrome.extension.onConnect.addListener(function listener(port) {
    console.assert(port.name == "searchQuery");
    port.onMessage.addListener(function(msg) {
        if (msg.keywordRequest == "Yes")
        port.postMessage({keyword: url});
    });
});

    chrome.tabs.executeScript(null, { file: "jquery-1.7.2.min.js" }, function() {
    chrome.tabs.executeScript(null, { file: "frame.js" });

    });
  };
};

Content script (frame.js)

var port = chrome.extension.connect({name: "searchQuery"});
port.postMessage({keywordRequest: "Yes"});
port.onMessage.addListener(function listen(msg) {

  var test = msg.keyword;
  $("body").append("<div style=\"position: fixed;top: 20px;right: 20px;z-index: 9999;\"><iframe style=\"border:1px solid #868686;-webkit-box-shadow: 2px 2px 20px 1px rgba(0, 0, 0, 0.5);\" src=\""+ test +"\" width=328 HEIGHT=240></iframe></div>");
});
like image 905
lokigfx Avatar asked Jun 25 '12 10:06

lokigfx


1 Answers

Ports should be used for long-lived "connections".

chrome.extension.sendRequest (content script) and chrome.extension.onRequest (background) should be used in your case (sendMessage/onMessage instead of *Request in Chrome 20+).

These methods can be used as follows:

  • On extension initialisation: Bind a onRequest event in the background
  • Content script: Fire sendRequest(request_obj, response_func)
  • Background: Received the previous object. Do something, and invoke response_func.

PS. Are you really including jQuery, just for appending a string? If yes, I strongly recommend to drop jQuery and use vanilla JavaScript:

var div = document.createElement('div');
div.style.cssText = "position: fixed;top: 20px;right: 20px;z-index: 9999;";
div.innerHTML = "<iframe style=\"border:1px solid #868686;-webkit-box-shadow: 2px 2px 20px 1px rgba(0, 0, 0, 0.5);\" src=\""+ test +"\" width=328 HEIGHT=240></iframe>";
document.body.appendChild(div);
like image 132
Rob W Avatar answered Oct 15 '22 09:10

Rob W