background
I simply want to create a chrome extension where I click on the extension icon, it loads a popup that loads a javascript file.
I was able to do an html only popup simply by adding these two files:
manifest.json
{
..
"browser_action": {
"default_popup": "popup.html",
..
}
}
popup.html
<html>
..
hello world
</html>
problem
I want to actually load a chrome events page so that the popup page calls the events page and interacts with it.
what i have tried
I added this to manifest.json
"background": {
"scripts": ["eventsPage.js"],
"persistent": false
}
and added a simple eventsPage.js file:
chrome.runtime.onInstalled.addListener(onInit);
chrome.runtime.onStartup.addListener(onStartup);
function onInit() {
console.log("on init");
}
function onStartup() {
console.log("on startup");
}
if (chrome.runtime && chrome.runtime.onStartup) {
chrome.runtime.onStartup.addListener(function() {
console.log('on startup stuff');
});
}
when I launch the extension and click on inspect to see chrome dev tools.. nothing shows up on the console:
I've also tried adding the src of eventsPage.js to popup.html:
</head>
..
<script src="eventsPage.js"></script>
<body>
..
but that changes nothing, I can't even find the eventsPage.js source in chrome dev tools.
How do I do this?
Many ways:
Add a script for example popup.js in popup.html and call chrome.runtime.getBackgroundPage(function callback) to interact with event page.
popup.html
...
<script src="popup.js"></script>
...
popup.js
chrome.runtime.getBackgroundPage(backgroundPage => backgroundPage.testMethod());
eventsPage.js
const testMethod = () => console.log('test');
Use Message Passing(there are many examples in this link) to communicate with event page.
Since you want to transfer data between popup page and event page, there are many other workarounds, for example, we could use global storage such as chrome.storage to save/load/react to changes.
Related
This is my issue:
I update the localStorage in popup.js in a new tab. I access the same localStorage(same key) in the background.js.
Now this is returning null in every tab apart from the chrome://extensions tab(when I load the extensions.)
I thought localStorage was persistant across all tabs.
Code:
popup.js:
$(document).ready(function (){
alert(localStorage.getItem('filters'));
var oldFilters = localStorage.getItem('filters');
//All the filters show up on the popup.html page.
document.getElementById('td1').innerHTML = oldFilters;
var dat = oldFilters + "," + newArray[j]
localStorage.setItem('filters',String(dat));
}
background.js:
$(window).ready(function() {
// Handler for .ready() called.
var filters = localStorage.getItem('filters');
alert("background + "+ filters);
//This shows all the filters in the chrome:extensions page but always pops up "background + null" in every new tab load.
//changeImage(filters);
});
Background and Browser Action(In your case) Pages live in isolated worlds, their local storage details are not accessible to each other, if you want this sort of access to happen use chrome.storage for your storage needs.
It has few advantages
Your extension's content scripts can directly access user data without the need for a background page.
A user's extension settings can be persisted even when using split incognito behavior.
User data can be stored as objects (the localStorage API stores data in strings).
Methods used
chrome.storage.local.get
chrome.storage.local.set
(use sync instead of local if the data needs to be synchronized with Google Sync)
Demonstration
manifest.json
Ensure all permissions are available for accessing storage API.
{
"name":"Local Storage Demo",
"description":"This is a small use case for using local storage",
"version":"1",
"manifest_version":2,
"background":{
"scripts":["background.js"]
},
"browser_action":{
"default_popup":"popup.html",
"default_icon":"logo.png"
},
"permissions":["storage"]
}
popup.html
A trivial popup html page which refers popup.js to surpass CSP.
<!doctype html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
</body>
</html>
background.js
This scripts sets content to chrome storage
//Set some content from background page
chrome.storage.local.set({"identifier":"Some awesome Content"},function (){
console.log("Storage Succesful");
});
//get all contents of chrome storage
chrome.storage.local.get(null,function (obj){
console.log(JSON.stringify(obj));
});
popup.js
This script retrieves and sets content from\to chrome storage
document.addEventListener("DOMContentLoaded",function (){
//Fetch all contents
chrome.storage.local.get(null,function (obj){
console.log(JSON.stringify(obj));
});
//Set some content from browser action
chrome.storage.local.set({"anotherIdentifier":"Another awesome Content"},function (){
console.log("Storage Succesful");
});
});
If you look at outputs of these js pages, communication of storage (Background -> popup and popup -> background) is achieved.
I've made a chrome extension that downloads some stuff from a certain site. Basically, it goes around through all links I'm interested in, stores them in an array and then downloads it one by one. The thing is, the storing is done in a separate file called download.js. Then, I proceed to send a message to popup.js using chrome.extension.sendRequest. I pick it up in popup.js with chrome.extension.onRequest.addListener. It works perfectly when I don't switch my tab, but I'd like it to work while I'm browsing some other stuff in the meantime. I can see the code reaching the point to send the request to popup.js through a console log, but I can't see what's going on in popup.js because when I switch my tab the popup console immediately closes.
download.js:
// logic behind link gathering and storing that works
...
gatherLinks().then(function() {
// logs is defined, don't worry
chrome.extension.sendRequest(logs);
)};
popup.js:
document.addEventListener('DOMContentLoaded', function() {
var downloadButton = document.getElementById('download');
downloadButton.addEventListener('click', downloadStuff);
});
function downloadStuff() {
chrome.tabs.executeScript({
file: 'jquery-3.1.1.min.js'
});
chrome.tabs.executeScript({
file: 'download.js'
});
chrome.extension.onRequest.addListener(function(message_logs) {
message_logs.forEach(function(log) {
chrome.downloads.download({
url: log.link,
filename: log.filename
});
}
}
manifest.json:
{
...
"permissions": [
"tabs",
"activeTab",
"downloads"
],
"background": {
"scripts": ["download.js"]
}
}
When you switch away, the popup window closes.
It does not hide the popup, the popup is properly closed, as you would close a tab. Therefore, its code is no longer executing and there's nothing to listen for your messages.
This is a job for background (or better, event) pages. They exist, invisibly, independent of what you're doing with the browser. Therefore, such a page should be the one to receive commands when the popup may not exist.
Also,
BIG SCARY WARNING!
If your content script and your background script are the same, there is a 99% probability you're doing something wrong. Do not try to reuse code in both, unless it's some auxilliary library - main logic should never be the same in those very different contexts.
I'm trying to make my first Chrome Extension without any prior JS knowledge, and I have some trouble doing it.
What does the extension do?
It's a page action extension for generating a string and copying it to the clipboard. The string includes certain element attributes from the DOM.
Scope
It's only applicable on two pages (the domains below are examples):
https://xxx.abc.com/CFM/Messages/CFMEWFA/*
https://xxx.abc.com/CFM/Messages/FraudPrevention/*
Elements of the extension
The extension has a popup.html with three clickable options to be chosen at the user's discretion:
No response
Invalid
Valid
The string is formatted based on the user's choice from the popup, and whether the tab URL contains "CFMEWFA" or "FraudPrevention".
popup.html
<!doctype html>
<html>
<body>
<script src="popup.js"></script>
<ul id="MENU">
<li id="MENUnoResponse">No reponse
</li>
<li id="MENUinValid">Invalid
</li>
<li id="MENUvalid">Valid
</li>
</ul>
</body>
</html>
popup.js is supposed to listen for clicks in popup.html, employ a multi item clickhandler, then message background.js at the event of a click. The message should include an argument corresponding to the li id in popup.html.
popup.js
var theParentMenu = document.querySelector("#MENU");
theParentMenu.addEventListener("click", userHasClicked, false);
function userHasClicked(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
chrome.runtime.sendMessage({
directive: e.target.id
}, function(response) {
this.close();
});
};
e.stopPropagation();
}
background.js is governing where the extension icon is shown. It also listens for messages from popup.js (containing an argument determined by the user's choice from popup.html) before executing content.js, a script which runs in the tab.url fetching attributes from the DOM and generating the string. I have yet to start building content.js because of unresolved issues earlier in other files.
background.js
//Displays the page action extension only on specific pages
function checkForValidUrl(tabId, changeInfo, tab) {
if (tab.url.indexOf("https://xxx.abc.com/CFM/Messages/FraudPrevention/") == 0)
{
chrome.pageAction.show(tabId);
}
else if (tab.url.indexOf("https://xxx.abc.com/CFM/Messages/CFMEWFA/") == 0)
{
chrome.pageAction.show(tabId);
}
};
chrome.tabs.onUpdated.addListener(checkForValidUrl)
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "MENUnoReponse":
// execute the content script
chrome.tabs.executeScript(null, { // defaults to the current tab
//file: "contentscript.js", // script to inject into page and run in sandbox
//allFrames: true // This injects script into iframes in the page.
});
sendResponse({}); // sending back empty response to sender
case "MENUinValid":
// execute the content script
chrome.tabs.executeScript(null, { // defaults to the current tab
//file: "contentscript.js", // script to inject into page and run in sandbox
//allFrames: true // This injects script into iframes in the page.
});
sendResponse({}); // sending back empty response to sender
case "MENUvalid":
// execute the content script
chrome.tabs.executeScript(null, { // defaults to the current tab
//file: "contentscript.js", // script to inject into page and run in sandbox
//allFrames: true // This injects script into iframes in the page.
});
sendResponse({}); // sending back empty response to sender
break;
default:
// helps debug when request directive doesn't match
alert("Unmatched request of '" + request + "' from script to background.js from " + sender);
}
}
);
manifest.json
{
"manifest_version": 2,
"name": "EW logger",
"description": "This extension creates logs for early warning and fraud prevention cases",
"version": "1.0",
"page_action": {
"default_title": "EW",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs",
"clipboardWrite",
"https://xxx.abc.com/*"
]
}
What works:
The extension icon appears like it should.
My problems:
The options in popup.html are not working. Popup.js doesn't do anything when I click.
Do you have any suggestion to how I can "listen" for clicks in popup.html properly, and then send a message containing an argument to background.js?
Your script is running before the body is loaded, so the element is not found. You can fix this by moving the script tag to the bottom of the body. Alternatively, use <script src="popup.js" defer></script> to delay execution until the dom is loaded.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
Also, you should use console.log(message) and the Chrome Devtools console to debug and check for errors.
https://developer.mozilla.org/en-US/docs/Web/API/Console/log
https://developers.google.com/web/tools/chrome-devtools/
I have a chrome extension and its popup.html has a link to a oauth/openid login page. To be exact to a page like this
I need this login page to be opened in a popup browser window with only an address bar. There should not be any other tool/menu bars. I tried window.open chrome.windows.create and window.showModalDialog methods.
All of them create a popup tab the way I wanted but none shows the address bar no matter what. When the popup.html is directly browsed via the browser, it shows the address bar, when the link is clicked. But not when the popup is loaded through the extension.
Since this page shows an oauth/openid login page, it is absolutely imperative that the user sees the address of the current page shown in the popup. No one would supply their facebook/google credentials to a page that does not have the address bar.
Any help is really appriciated.
I had a look around and it seems this is a known bug....
http://code.google.com/p/chromium/issues/detail?id=108875&q=popup%20bar&colspec=ID%20Pri%20Mstone%20ReleaseBlock%20OS%20Area%20Feature%20Status%20Owner%20Summary
You should star that for future updates and I think you should probably comment on your situation aswell.
The only way you could get the popup you want from your extensions code is to open a tab, get it to open the popup and then close the tab.....far from ideal.
But incase thats good enough for you here's some sample code....
manifest.json
{
"name": "Popup with adresse bar",
"version": "1.0",
"permissions": [
"tabs", "<all_urls>"
],
"browser_action": {
"default_title": "Popup with adresse bar.",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"manifest_version" : 2
}
popup.html
<!doctype html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
<a id='clicky' href='#'>clicky</a>
</body>
</html>
popup.js
clicky = function() {
chrome.tabs.create({
url: 'open.html#' + 'http://www.google.com',
active: false
});
}
onload = function() {
document.querySelector('#clicky').onclick = clicky;
}
window.onload = onload;
open.html
<script src='open.js'></script>
open.js
window.close();
window.open(window.location.hash.substr(1), '…', '…');
Ok I am going to give this question a try. I understand what you are talking about with the address bar being hidden. For instance, my rem-i-con extension. If the user hasn't registered it will open a new tab, that will then ask them to create a account or login. But the address bar is blank.
However, in my popup.html file, I have a few links that do open a new tab with the address shown in the window. I understand you want a model type window but I am not sure that can be done. Here is something you can try.
Have a regular link asdd
When clicked you can have listener that watches the tab that has just been opened. This you could do easily by scanning the active tabs.
Then once the tab is closed, you could then have your popup.html file reload. You will need to use a background.html file for this.
If this works, then you could just automate the tag click.
Okay, I'm building an extension like so:
has a browseraction which invokes a popup.html that has an input field, a submit button, and a link that invokes a javascript action
a background.html page that receives the input value data via popup.html and then uses them to inject custom CSS into the page
I'm using localStorage to store the input data for future use. Here's what I need help with:
run javascript in the background.html (which injects the CSS) when a button is clicked in the popup.html
passing along the data from the input field in the popup.html to background.html
I scoured google source code but could not really find anything. I'm not looking to inject the CSS to every page (I know how to do that) or when the browser action icon is clicked (I know how to do that as well). I need to get that CSS injected only when a user inputs data into the popup.html and clicks on a link or button.
UPDATED:
I'm still not able to do what I need to do with this. Here's my code:
<script type="text/javascript">
var bgrSize = localStorage.getItem('gridSize');
function insert(){
chrome.tabs.executeScript(null, {code:'body{ backgroundImage: -webkit-linear-gradient(#eee 0.05em, transparent 0.05em); backgroundPosition: 100% 0 %; backgroundSize: 100% '+ bgrSize +';}'});
}
</script>
That's on my background.html page. Here's what fires from the popup.html page:
function showGrid(){
chrome.extension.getBackgroundPage().insert();
}
The "showGrid" function fires when a button is clicked. The gridSize data is already stored in localStorage (I have a section of the popup.html that updates to show the localStorage information).
What am I doing wrong? I just can't figure it out. Btw, the manifest.json includes my background.html
In popup use chrome.extension.getBackgroundPage and then execute proper function in background page. Inject data with insertCSS or executeScript
Pass data thru function parameter or localStorage if you want use it later.
Resuming:
// popup.html
<script>
window.onload = function(){
document.getElementById('my-form').addEventListener('submit', function(){
console.log('popup');
chrome.extension.getBackgroundPage().insert({
param: 'example',
input: document.getElementById('my-input').value
});
});
}
</script>
<form id="my-form">
<input type="text" id="my-input"/>
<input type="submit" />
</form>
// background.html
function insert(data){
console.log('inserting', data.input);
chrome.tabs.insertCSS(null, {
code: 'a { font-size: ' + data.input + 'px;}'
}, function(){
console.log('inserted');
});
}
// manifest.js
...
"permissions": ["tabs", "*://*/*"]
This example works - I have checked it manually ;)