Search code examples
google-chrome-extension

How to cause a chrome extension to close only by clicking on the icon or a button


I am developing a chrome extension, in which I have used iframe, which I want to keep open even if we do some activity on the active web page itself or open a new tab or a new window. The extension should get closed only on clicking on the extension icon again or by clicking a close button, present on the extension itself. I am hinting on something like join pouch extension.

Other questions pertaining to this topic only caters to opening a window through extension which remains open or keeping the extension popup open just for debugging purposes, by inspecting the popup.

I know there is a way to do this, since I have seen some extensions as such, but am unable to find.


Solution

  • You can embed that iframe into the DOM structure of every single page you open. Unfortunately, Google doesn't provide any solution besides a default popup that disappears when the first click outside of it happens. The flipside is, you'll need to run one instance of your content script per page, which might mean there will be hundreds of them running (at least for me as I'm a compulsive new-tab-opener).

    This is one of the ways, how you can approach this.

    Step 1. As I've already said, the default action on icon click is opening a popup. You can disable that behaviour by including the following entry in your manifest.json:

    "browser_action": {},
    

    Step 2. The next thing would be creating a content script that runs on every page. In your manifest, it would look like this:

    "content_scripts": [
      {
        "run_at": "document_end",
        "matches": ["*://*/*"],
        "js": ["path/to/your/content/script.js"]
      }
    ],
    

    Step 3. Your content script should embed that iframe you mentioned into the currently open page (when the DOM fully loaded).

    window.addEventListener('load', function load(event) {
      var iframe = document.createElement('iframe');
      /* some settings, these are mine */
      iframe.style.width = "250px";
      iframe.style.background = "#eee";
      iframe.style.height = "100%";
      iframe.style.position = "fixed";
      iframe.style.top = "0px";
      iframe.style.right = "0px";
      iframe.style.zIndex = "1000000000000000";
      iframe.frameBorder = "none";
      /* end of settings */
      iframe.src = 
      chrome.runtime.getURL("path/to/contents/of/your/iframe.html");
      document.body.appendChild(iframe);
    });
    

    Step 4. You must make sure, people can access iframe.html. Add this line to your manifest file:

    "web_accessible_resources": ["path/to/contents/of/your/iframe.html"], 
    

    (or just add that file to the list if it was already there.

    Step 5. Create a function in your content script that knows how to hide your iframe. Something like that:

    function toggle_iframe() {
      if (iframe.style.width == "0px"){
        iframe.style.width="250px";
      } else {
        iframe.style.width="0px";
      }
    }
    

    Now, the only thing left is to know when to call it.

    Step 6. Unfortunately, background script is the only place that can get information about extension icon being clicked. Add this snippet to your background script:

    chrome.browserAction.onClicked.addListener(function(){
      chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
        chrome.tabs.sendMessage(tabs[0].id, { action: "must_toggle_iframe" });
      })
    });
    

    It sends a message, when the icon has been clicked.

    Step 7. The last part is to allow your content script to receive that message. Your content script needs a listener.

    chrome.runtime.onMessage.addListener(function(msg, sender) {
      if (msg.action == "must_toggle_iframe"){
        toggle_iframe();
      }
    }
    

    Of course, the solution is not ideal, but you could refine it. For example by remembering in the chrome.storage.local/chrome.storage.sync whether the iframe has been hidden.