chrome.storage between popup and browser action window - javascript

I'm writing a chrome extension and I want to manage all of the data/variables with chrome storage. From what I understand, I should be able to use chrome.storage across my extension.
I want to set something in browser_action script and then access it in the window created by the background script. The HTML and JS files all have corresponding names.
This is what I have tried with no luck:
//manifest.json
{
"manifest_version": 2,
"name": "extension",
"description": "my extension",
"version": "0.1",
"permissions": [
"tabs",
"storage"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": {
"38": "images/icon38.png"
},
"default_popup": "settings.html"
}
}
//background.js
chrome.windows.create({'url': chrome.extension.getURL("newPage.html"),'type': "detached_panel",'focused': true}, function(){
//created newPage.html which has newPage.js
});
//setting.js
document.addEventListener('DOMContentLoaded', function(){
chrome.storage.local.set({'enabled': 'TRUE'});
});
//newPage.js
chrome.storage.local.get('enabled', function(result){
document.getElementById("myId").innerHTML += "<br>script loaded... and status: " + result.enabled;
});
When I do this, newPage.html displays "script loaded... and status: undefined".
Even with it being asyncronous, the storage value should be populated on running the script a second time, right?
I may just be using this incorrectly. If that's the case, what's the correct way to set something with chrome storage to access in my new window?
Any help would be appreciated!

I think that your newPage.html is asking for the value of 'enabled' before it's been set by the event handler in settings.html, which only executes after you've actually opened the browser popup. So this is why it's undefined. Open the popup and you should see that it's defined.

Related

chrome extension: when does a persistent background script stop running?

If my chrome extension has a persistent background script, I could use it to store data in the script that I would eventually want to store in chrome.storage.local. When / what event triggers the background script to stop running (so that I can add a callback to store the data in chrome.storage.local before the local data goes out of scope)?
Background scripts can either be registered persistent (always running while the extension is enabled and has not crashed) or non-persistent (not always but temporarily runs when runtime.getBackgroundPage or any runtime event callback registerd in the background script is invoked)
They are registered in the manifest under the "background" field, and "persistent" should be specified as false for non-persistent background scripts/pages.
}
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
There is a runtime event callback for when the non-persistent background script is unloaded (because they unload on their own after a few seconds of inactivity), it does not get invoked when an extension with persistent background script is disabled (or crashed of-course).
chrome.runtime.onSuspend.addListener(function() {
console.log("Unloading.");
});
You can verify that with this simple extension:
manifest.json
{
"name": "onSuspend",
"description": "onsuspent",
"version": "1.0",
"manifest_version": 2,
"permissions": [
"storage"
],
"background": {
"scripts": ["background.js"],
"persistent": true
}
}
background.js
chrome.runtime.onSuspend.addListener(function() {
console.log("Unloading.");
chrome.storage.local.set({"Saved": "yes"}, function() {});
});
chrome.storage.local.get("Saved", function(data) {
console.log("shouldn't be an empty object": data);
});
The only way I found that you can register a callback to run before the persistent background script is disabled is by loading a background page instead and using the window's unload event, code use for testing:
{
"name": "callback before stopping persistent background script",
"description": "callback before stopping persistent background script",
"version": "1.0",
"manifest_version": 2,
"permissions": [
"storage"
],
"background": {
"page": "background.html",
"persistent": true
}
}
background.js
window.addEventListener('unload', function(event) {
localStorage.setItem("Saved", "yes");
});
console.log("Saved:", localStorage.getItem('Saved'));
background.html
<html><body></body><script src="background.js"></script></html>
To test it try disabling and re-enabling or reloading the extension twice.

Can't access content of page when attempting to add Dom to chrome-extension:// URL

My chrome extension spawns a temp .html page. I want to manipulate the DOM of the sample.html page that was created, but can't. I can manipulate the DOM for any other page without issue. The problem seems to be with the fact my temp .html page resides within chrome-extension://
Error Message:
Unchecked runtime.lastError while running tabs.executeScript: Cannot access contents of url "chrome-extension://123/sample.html?id=100". Extension manifest must request permission to access this host.
Note: for simplicity sake I provided sample code that exhibits the same Error. Once loaded I can use the key combo to inject a div and some text into any webpage (Mac-> Cmd+Shift+P or PC Ctrl+Shift+P)
I've tried adding all possible permissions and even web_accessible_resources to the manifest.json. (I don't believe this to be the issue). I've tried different ways to inject the code into the sample.html by calling out the specific tabId, activeTab or even setting the tabId to null within the background file. I've read through stackoverflow, googled and looked around but came up short.
manifest.json
{
"manifest_version": 2,
"name": "sample1",
"description": "sample1",
"version": "0.0.1",
"browser_action":
{
"default_title": "sample"
},
"commands":
{
"saveImageCommand":
{
"suggested_key":
{
"default": "Ctrl+Shift+Z",
"mac": "Command+Shift+Z"
},
"description": "Toggle Save Image"
},
"playback":
{
"suggested_key":
{
"default": "Ctrl+Shift+P",
"mac": "Command+Shift+P"
},
"description": "load player Image"
}
},
"permissions": [
"tabs",
"activeTab",
"storage",
"<all_urls>",
"*://*/*"
],
"background":
{
"persistent": false,
"scripts": ["background.js"]
}
,
"web_accessible_resources": [
"chrome-extension://*/sample.html?id=*"
]
}
background.js
chrome.commands.onCommand.addListener(function(command) {
if (command === 'saveImageCommand') {
capturecurrent();
}
if (command === 'playback') {
chrome.tabs.executeScript(null, {
code: 'var divNode = document.createElement("div");divNode.setAttribute("id", "video1Div");var instructions = document.createTextNode("testing");divNode.appendChild(instructions);document.body.appendChild(divNode)'
});
}
});
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.captureVisibleTab(function(screenshotUrl) {
var viewTabUrl = chrome.extension.getURL('sample.html')
chrome.tabs.create({ url: viewTabUrl });
});
});
sample.html
<html>
<head></head>
<body>
<div id="firstDiv">firstDiv</div>
</body>
</html>
Expected Results:
For me to interact directly with the DOM on the temp sample.html page.
Note:
I don't want to build out buttons for DOM manipulation directly within the sample.html page. That defeats the purpose of this exercise. Esp since I want to use shortcut key combos to call this DOM manipulation (Mac-> Cmd+Shift+P or PC Ctrl+Shift+P)
Actual Results:
I am able to interact with the DOM on any normal website using the shortcut key combo but not the sample.html that URL starts with chrome-extension://

Why does it seem that my Google Extension begins execution only when I'm observing background script console

I would like my Google Extension to start execution as soon as Google Chrome window is opened. I have the following code in my background.js :
if (window.Notification) {
setInterval( function() { callAutomate(); }, 60000 );
}
function callAutomate() {
// Code to automate hello-hello.com
}
The manifest file is as follows -
{
"name" : "Hello.co Extension",
"version" : "1.1",
"description" : "Say Hello",
"background" :
{
"scripts": ["background.js"],
"persistent": false
},
"page_action" :
{
"default_icon" : "hello-19.png",
"default_title": "Hello World",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["https://www.hellohello.com/*"],
"js": [
"content.js",
"webDB.js"
]
}
],
"permissions": [
"tabs",
"storage",
"unlimitedStorage",
"webNavigation",
"notifications",
"https://www.hellohello.com/"
],
"options_page": "options.html",
"icons" : {
"48" : "hello-48.png",
"128" : "hello-128.png"
},
"manifest_version": 2,
"web_accessible_resources": [
"hello-48.png"
]
}
Here is my problem the callAutomate(); function seems to called only while I'm observing the console logs for background.js. However the expected behavior of the extension is to call the callAutomate(); function every one minute from the time Google Chrome window is opened.
Any help with explanatory code would be highly appreciated.
As explained in the Chrome extension documentation, there are 2 types of background pages:
persistent background page : always "opened"
event background page : "open and closed" as needed
You are using the second one, as specified with the "persistent": false in your manifest.json file,
so the background code will not execute itself when you normally load your page.
And I am pretty sure that when you are using the developer tool ("observing the console") on your background page, the page is "opened" and does not close while the console remains open.
By removing the "persistent": false your code will be executed.
But as suggested in the documentation, you should use event pages as much as possible so have a look at the lifetime documentation to see the different ways you can communicate with your background page and thus execute your desired code.
That is because of "persistent": false in the manifest.
This describes an Event page, that is, a page Chrome can unload at will if it is idle for more than a couple of seconds, only keeping track of registered event handlers.
Notes for Event pages explicitly mention:
If your extension uses window.setTimeout() or window.setInterval(), switch to using the alarms API instead. DOM-based timers won't be honored if the event page shuts down.
And if you open a Dev Tools window for the background page, it will NOT be unloaded, leading to your code executing properly.
You can switch to using chrome.alarms API, but before you do, carefully read the Event page documentation. You need to understand all the limitations: for instance, since the page is unloaded, all local state in variables is lost. If you need to persist state, you'll need to employ storage APIs.
If that is too complicated for your purposes, remove "persistent": false to revert to a normal Background page.

How can I run this script when the tab reloads (chrome extension)?

So i'd like to run a script when the tab reloads in a specified URL. It almost works, but actually id doesn't :)
This is my manifest file:
{
"manifest_version": 2,
"name": "Sample Extension",
"description": "Sample Chrome Extension",
"version": "1.0",
"content_scripts":
[
{
"matches": ["http://translate.google.hu/*"],
"js": ["run.js"]
}
],
"permissions":
[
"activeTab",
"tabs"
],
"browser_action":
{
"default_title": "Sample",
"default_icon": "icon.png"
}
}
and this is run.js:
chrome.tabs.onUpdated.addListener(
function ( tabId, changeInfo, tab )
{
if ( changeInfo.status === "complete" )
{
chrome.tabs.executeScript( null, {file: "program.js"} );
}
}
);
The programs.js just alerts some text (yet). When I put an alert to the first line of the run.js, it alerts, but when I put it in the if, it doesn't. I can't find the problem. Did I type something wrong?
Assuming that http://translate.google.hu/* pages are the ones you wish to inject code into on reload, you would have to go about it in a slightly different way. Currently you are always injecting code into those pages (without the permission to do so, no less) and then trying to use the chrome.tabs api inside that content script, which you can't do. Instead, we will put the listener in a background page and inject the code only on a page refresh, like you want. First the manifest:
{
"manifest_version": 2,
"name": "Sample Extension",
"description": "Sample Chrome Extension",
"version": "1.0",
"background": {
"scripts": ["background.js"]
},
"permissions":[
"http://translate.google.hu/*", "tabs"
]
}
background.js
chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
if (tab.url.indexOf("http://translate.google.hu/") > -1 &&
changeInfo.url === undefined){
chrome.tabs.executeScript(tabId, {file: "program.js"} );
}
});
This will listen for the onUpdated event, checks if it is one of the url's that we want to inject into, and then it checks if the page was reloaded. That last step is accomplished by checking if changeInfo.url exists. If it does, then that means that the url was changed and thus not a refresh. Conversely, if it doesn't exist, then the page must have only been refreshed.
2021
If you want to detect reload from background.js in manifest 3 (maybe also 2), chrome.tabs.onUpdated approach didn't work for me :/ It was invoked too many times.
That what worked for me in the end!
// --- On Reloading or Entering example.com ---
chrome.webNavigation.onCommitted.addListener((details) => {
if (["reload", "link", "typed", "generated"].includes(details.transitionType) &&
details.url === "http://example.com/") {
codeAfterReload();
// If you want to run only when the reload finished (at least the DOM was loaded)
chrome.webNavigation.onCompleted.addListener(function onComplete() {
codeAfterReloadAndFinishSomeLoading();
chrome.webNavigation.onCompleted.removeListener(onComplete);
});
}
});
For more transition types: https://developer.chrome.com/docs/extensions/reference/history/#transition_types
good luck :)
content_scripts are run at every page (re)load, so it's best to just use those to detect it.
This way you also don't risk running any code in the background before your content_script is ready to receive any message.

Chrome extension not accessing target page DOM

After reviewing the suggested responses, I was not able to resolve the following issue:
My javascript is not accessing the page DOM, but it is running.
Manifest.json
{
"name": "Clicky",
"version": "1.0",
"background": { "scripts": ["jquery.js", "clickclickboom.js"] },
"permissions": [
"tabs", "http://*/*"
],
"browser_action": {
"name": "Find all links",
"icons": ["icon.jpg"]
},
"manifest_version": 2
}
clickclickboom.js
alert("script runs");
function clicky() {
alert ("clicky got called");
jQuery(".testClass").find("a");
}
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(
null, {code: clicky()});
});
Both alerts pop up but when I debug, I see the extension accessing the background.html DOM but not the targeted pages' DOM.
Any help would be greatly appreciated, thank you in advance!
In your chrome.tabs.executeScript(), the code property must be a string containing the code.
What's happening currently with your code is: clicky() is executed, which returns undefined, which basically is making your executeScript a no-operation call...
One thing you can do is use clicky.toString() though I don't personally recommend it! In this case, the alert ("clicky got called") may work (if you are lucky). The next line will not work because jQuery is not defined in the content script. Your inclusion of jquery is limited to background page.
From your code, it seems you are not really familiar with chrome extension's architecture, so I suggest you start with http://code.google.com/chrome/extensions/getstarted.html

Categories