Toggle content script function from browserAction.onClicked

Hello,

I’m writing an extension that uses a content script that gets executed in a given tab with the user preses the browserAction icon button.

The desired behavour I’m looking for is as follows:

  • First press - Executes content script and triggers a function (showing a div for example)
  • Second press - Sends a message to content script and triggers a function (hides the div for example)
  • Third press shows the div… and so on.

At the moment, every press of the button executes a new script.

I have an idea of how to achieve my desied outcome but it seems a bit overkill and I’m wondering if anone has faced a similar challenge and if there’s a more elegant way.

My current idea:

  • Query for all tabs and keep track of open and closed tabs with event listeners
  • Wite tab id’s to an object to keep track of them i.e
    {tabID1: {status: false}, tabID2: {status: true}}
  • When the user presses the button, check if tabID1.status is false, if so execute script and send initial toggle message
  • 2nd press - Again, check tab.id.status and if the extension is running (div is visible), send a message to hide the div.

Is this best way or am I overthinking it?

Thanks,
Nick

Actually you can define new property on the window object and then check it’s value.

So your content script code could look something like this:

(() => {
  // when running first time, `_myDivNode` is not defined
  if (window._myDivNode) return removeSelf();
  // create your div
  const divNode = document.createElement('div');
  document.body.appendChild(divNode);
  // and save it to the window
  window._myDivNode = divNode;
  
  function removeSelf() {
    window._myDivNode.remove();   // removing your previous div
    window._myDivNode = null;     // and resetting value
  }
})();

I’m doing this in my Save my Password extension (you can unzip it and check the source).

That was so simple, thank you!
I didn’t reslise you could write to the window object.

Quick question, I’m fairly new to JS and I’ve not seen this type of function before:
(() => {})();

I get the middle bit is an arrow function but what does wrapping it in ( ) and ending with (); do?

Yes it’s a arrow function, and if you wrap it with braces, you can immediately invoke it. It’s called IIFE:

EDIT:
The reason I use it here is that you get an error if you use const in your code and run your content script again - it would complain that you are trying to re-define a const.

In which case you could just use a free-standing block instead:

For this simple case yes, but if you use IIFE you can easily make it async and then use await inside (which is not possible in the top level block). Also you can break execution with return :slight_smile: .