user3597313 user3597313 - 20 days ago 6
Javascript Question

How to turn on/off chrome extension using local storage in background page?

I've been reading a lot of other answers on here for similar questions but I'm still having trouble. I want the user to be able to turn off my chrome extension at any point by clicking on the icon. The extension that I wrote will execute once at each page load, so when the icon is clicked, it should disable the code from occurring on next page load. When the icon is clicked, it either turns grey to show that it's off, or back to color. This part of the code works, but it is also supposed to be updating a localStorage variable to off/on. Then when the user starts a new page and the content script runs again, the content script checks the localStorage variable and, ideally, will only execute if the variable is set to "on." But instead, it executes every time, even when the icon is grey. I checked the localStorage in the console and the variable says "on" every time. What am I doing wrong?

P.S. I did also check to see whether the content script was always setting the storage variable to "on" (because it checks to see if there is no variable saved yet), but that wasn't the case.

Manifest.json

{
"manifest_version": 2,
"name": "My Extension",
"version": "0.1",

"icons":
{
"128": "128.png",
"48": "48.png",
"16": "16.png"
},

"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.1.1.min.js", "content.js"]
}
],

"browser_action": {
"default_icon": "16.png"
},

"background": {
"scripts": ["background.js"],
"persistent": true
},

"permissions": ["tabs", "storage"],

"web_accessible_resources": [
"spritesheet.png"
]

}


Background Page

chrome.browserAction.onClicked.addListener(function(tab) {

//if on, turn off
if (localStorage.onoff == "on") {

chrome.browserAction.setIcon({path:{"16": "16grey.png", "48": "48grey.png","128": "128grey.png"}});
localStorage.onoff = "off";

//if off, turn on
} else {

chrome.browserAction.setIcon({path:{"16": "16.png", "48": "48.png","128": "128.png"}});
localStorage.onoff = "on";
}


});


Content script

if (!localStorage.onoff) {
localStorage.onoff = "on";
}


if (localStorage.onoff == "on") {
//execute the extension
}

Answer

Use chrome.storage.local

You can not use localStorage to move data between your background script and your content script. In your content script, it will access the localStorage of the page/domain for the page in which you have injected the script. This is as it should be. Your content script should be for affecting the page into which it is injected. Thus, the functionality that is not part of the Chrome APIs should work more, or less, as it would if written in a page script.

To set a data value in your background script prior to your content script loading which your content script can read, you should use chrome.storage.local.

You can set it with chrome.storage.local.set():

chrome.storage.local.set({
    onOff: 'on'
}, function(){
    console.log('Data saved');
});

You can read it with chrome.storage.local.get():

chrome.storage.local.get({
    onOff: 'off'
}, function(data) {
    if(data.onOff === 'on') {
        //Do your code
    }
});

Other issues

Loading jQuery:
You are loading jQuery on every page. Particularly given that you are injecting your scripts on every page, you should seriously consider not using jQuery. jQuery is 85KiB of minimized code. That is a fairly heavy burden to add to every single page the user loads.

One of jQuery's primary benefits, cross browser compatibility, is not needed given that you are writing an extension which, very specifically, can only function in one browser (or a very small number of browsers). Thus, this primary benefit has no value to your code.

Everything that you are doing with jQuery in your code can be written in vanilla JavaScript. This will normally cost you very little additional code, particularly when compared to the 85KiB of minimized jQuery code. Thus, while you might be saving a bit of coding, it is at the cost of forcing your users to have 85KiB of jQuery code loaded and evaluated on every single page they view.

I don't know what you are using jQuery for in your code. It could be that it is actually needed for something. On the other hand, it is much more likely that loading it is just a convenience for you (Some people use it just because it makes their code look cleaner). If you are using just some basic jQuery, you may find the queryAll() function written in this other answer of mine to give you some of the functionality that is often looked for.

Injecting your content script in <all_urls>:
You should seriously consider if injecting into every single page the user visits is needed. It quite possibly is. You have given no indication what your code is doing. Thus, there is no way for us to tell. If all URLs are not actually affected by your extension, please look into limiting the URLs into which your code is injected.

In addition, you are turning on and of your content script functionality using a browserAction button. As such, you should consider using tabs.executeScript() to only inject your content script(s) when your extension is turned on.