I am writing an extension and I encountered a problem: I can not send data from the extension menu to content.js. In the extension menu I have a couple of intuitions, after filling in and clicking on the button, I write down their values and I want to send them to content.js where this data will be used for implementation inhtml But for some reason, the data is not sent.
document.getElementById('btn').onclick = function() {
var first = document.getElementById('first').value;
var second = document.getElementById('second').value;
//send in content
chrome.extension.sendMessage('hello');
}
<head>
<script type="text/javascript" src="content.js"></script>
<script type="text/javascript" src="background.js"></script>
</head>
<input type="text" id="first">
<input type="text" id="second">
<input type="button" id="btn" value="send">
Here is the manifest.json (maybe there's something wrong)
{
"manifest_version": 2,
"version": "1.3",
"description": "name",
"browser_action":{
"default_popup": "content/popup.html"
},
"background": {
"persistent": false,
"scripts": ["content/background.js"]
},
"content_scripts": [
{
"matches": [ "https://google.com/*" ],
"js": ["content/content.js"],
"css": ["content/qq.css"],
"run_at": "document_end"
}
]
}
content.js: get data from background
chrome.extension.onMessage.addListener(function(request){
if(request=='hello'){
console.log('1. Принято: ', request);
}
});
As I can see everything, background.js is the file that is responsible forjs in the extension menu. content.js is the file that is responsible for making changes to the DOM on the sites.
Your files' structure is unclear: what is the content of popup.html? why do you load both content.js and background.js in the same page?
Here is an example that does what I think you try to accomplish.
It works like this:
The popup screen will display the inputs for the user to fill.
When the button is pressed, the value of the inputs is sent to the background script which, in turn, sends them to the content script. The content script then uses those values in the way you want: for instance, to fill an input in the host webpage.
manifest.json
{
"manifest_version": 2,
"version": "1.3",
"description": "name",
"browser_action":{
"default_popup": "content/popup.html"
},
"background": {
"persistent": true,
"scripts": ["content/background.js"]
},
"content_scripts": [
{
"matches": [ "https://google.com/*" ],
"js": ["content/content.js"],
"css": ["content/qq.css"],
"run_at": "document_end"
}
]
}
background.js
var contentTabId;
chrome.runtime.onMessage.addListener(function(msg,sender) {
if (msg.from == "content") { //get content scripts tab id
contentTabId = sender.tab.id;
}
if (msg.from == "popup" && contentTabId) { //got message from popup
chrome.tabs.sendMessage(contentTabId, { //send it to content script
from: "background",
first: msg.first,
second: msg.second
});
}
});
content.js
chrome.runtime.sendMessage({from:"content"}); //first, tell the background page that this is the tab that wants to receive the messages.
chrome.runtime.onMessage.addListener(function(msg) {
if (msg.from == "background") {
var first = msg.first;
var second = msg.second;
//here you use the values as you wish, for example:
//document.getElementById("anInput").value = first;
}
});
popup.html
<html>
<body>
<input type="text" id="first">
<input type="text" id="second">
<button id="send">Send</button>
<script src="popup.js"></script>
</body>
</html>
popup.js (this file must be located in the same directory as popup.html)
document.getElementById("send").onclick = function() {
chrome.runtime.sendMessage({ //send a message to the background script
from: "popup",
first: document.getElementById("first").value,
second: document.getElementById("second").value
});
}
I hope that helps.
I think you are looking for the runtime property of the chrome / browser object.
This would make your send message command chrome.runtime.sendMessage without the use of the extension property.
Likewise the on message event would be chrome.runtime.onMessage.
I'm pulling this info from the following documentation: https://developer.chrome.com/apps/messaging
content.js should not be included into popup.html. content.js is run whenever a site matches the pattern in your manifest.json. Right now, whenever someone visits google.com with your extension installed, the content.js script is run in the background of google.com.
background.js also shouldn't be loaded into the popup. It's a script that's always run in the background of the browser, it's not something that should get loaded by anything. It's where you add stuff like code to change the omnibox behavior.
You should create a new popup.js script that gets included by popup.html, and it should only handle things like onload and onclick events for the actual popup window.
The various files you mention, content.js, background.js and the file you should create popup.js all have different jobs and should not communicate between each other. There's neither a need nor a possibility for it. If you want to e.g. get the value of what's inside some other site put it in content.js, which is run on each site that matches your pattern, and do all the handling in there.
background.js = code that sets up your extension inside the browser, stuff like changing the omnibox behavior.
content.js = code that runs on each website that matches a certain pattern.
popup.js = code that runs when the user opens the popup window of your extension.
So don't have them communicate, they aren't supposed to, they fill entirely different functions.
There's no reason why you should need to communicate between them either, please explain a scenario where you'd need this and I'll explain why you don't need it. :)
To communicate with content.js, you need to use chrome.tabs.sendMessage instead of chrome.extension.sendMessage, because to communicate with the content.js you need to provide the tabId, which is passed as an argument in the former listed API.
Related
Following up on a previous post, I am now trying to create a version of a Chrome extension that does not specify content_scripts: or matches: in the manifest.json file; instead the content script is to be injected programmatically by a en event triggered from the options page which prompts the user to grant optional permissions for executing the content script. The rationale is to be able to have the extension working on pages from hosts with different top-level domain names (see previous post for details). I have read the documentation on this and tried to connect the dots, but I'm not quite getting there.
Below is a demo version of what I have created so far. I manage to get the optional permissions request processed and the user prompt for granting that request shown (the alert "granted!" is displayed). However, when I try to have the message listener in background.js execute the script content.js (by removing the /* commented-out code */ there), I get the error message
Unchecked runtime.lastError: Cannot access contents of url
"chrome-extension://[blah]/options.html". Extension manifest must
request permission to access this host.
Any guidance as to what I have missed here would be most welcome.
I also have a second question: since I am using jQuery in the content.js script, do I have to execute the jQuery.js file as well in response to the granted permission, and if so, should that be done by adding another separate chrome.tabs.executeScript() command?
manifest.json:
{
"manifest_version": 2,
"name": "My Extension",
"version": "1",
"description": "Demo extension",
"options_page":"options.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"optional_permissions":["tabs","https://*/*"],
"permissions": ["activeTab","storage"]
}
options.html:
<html>
<head>
<style>
button#permreq{font-size:2em;}
</style>
</head>
<body>
<button id="permreq">Click this button to enable My Extension</button>
<script src="jQuery.js"></script>
<script src="options.js"></script>
</body>
</html>
options.js:
jQuery(function($){
$(document).ready(function(){
$("button#permreq").click(function(){
chrome.permissions.request({
permissions: ['tabs'],
origins: ["https://*/*"]
}, function(granted) {
if (granted) {
chrome.runtime.sendMessage("granted");
} else {
alert("denied");
}
});
});
});
});
background.js:
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "granted"){
/*chrome.tabs.executeScript({
file: "content.js"
});*/
alert("granted!");//no errors as long as above code is commented out
} else{
alert("denied");
}
});
I need a script to execute before any other scripts on page, and so using Chrome extension to inject it in to every page. The script did injected before the head element but somehow it only run first when I use Control + F5, otherwise if I only use F5 or browse the page it will run last, even though it still in the same position when I check by developer tool.
My manifest.json
{
"manifest_version": 2,
"name": "My test 15",
"version": "1.0.0",
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["loadscript.js"],
"run_at": "document_start"
}
],
"web_accessible_resources": ["test.js"]
}
My loadscript.js
var s = document.createElement('script');
s.src = chrome.runtime.getURL('test.js');
(document.head || document.documentElement).appendChild(s);
Script in test.js
window.alert("hello from test.js");
Script in the page
window.alert("hello from page");
When I browse to the page on localhost, everything look to be load correctly as
<html>
<script src="chrome-extension://idjbemfgdjiggddofddpkcoccihmnefa/test.js"></script>
<head></head>
<body>
<script>window.alert("hello from page");</script>
</body>
The thing is script in test.js only run first if I press control + f5. If I browse to the page even in the first time or using f5 only, then the script in test.js will run last. Can anyone has a solution for this? thank you.
Directories
----MyExtension
|----popup.html
|----popup.js
|----content.js
|----background.js
|----manifest.json
mainfest.json
{
"manifest_version": 2,
...........
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"browser_action": {
"default_title": "Practice",
"default_popup": "popup.html"
},
"permissions": [
"<all_urls>",
"tabs",
"storage",
"activeTab"
],
"background": {
"scripts": ["background.js"]
}
}
....
popup.html
<html>
<head>
....
<script src="popup.js"></script>
</head>
<body>
<input id="status" type="chckbox">
</body>
</html>
popup.js
$(document).ready(function(){
$on = $("#status");
//sends the settings to background to save it
$on.on("click",function(){
$obj = {"on":$on.prop("checked")}
browser.runtime.sendMessage($obj);
console.log("sending....");
})
})
What im trying to do is simply send a message to background script if the check box in popup.html is checked.
The problem is I cannot access the browser namespace in popup.js because its not content script or background script. And i cannot access the check box from the content scrip as it not linked to popup.html (if its linked i get reference error browser is not defined. I've tried countless google searches and spent hours reading web extension docs still cannot find an answer how to go around it any help appreciated.
I have good news for you - you can access the browser namespace in your browser action poupus, otherwise they would be pretty useless :)
Which means that something else is broken.
First, if you didn't do it yet, open 'browser toolbox' with Ctrl+Shift+Alt+I to see that you probably have a bit different kind of error there.
Then include this in your background.js :
function handleMessage(request, sender, sendResponse) {
console.log("Message from somewhere: ", request);
}
browser.runtime.onMessage.addListener(handleMessage);
To actually read the message.
See:
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction
JavaScript running in the popup gets access to all the same WebExtension APIs as your background scripts, but its global context is the popup, not the current page displayed in the browser. To affect web pages you need to communicate with them via messages.
Edit, unrelated:
$on = $("#status");
You do realize that by doing so you refer to/create a global variable '$on', right? Did you mean:
var $on = $("#status");
?
i want to display the array data i have in the background when the get data button is clicked but nothing is done when i click the button am very new for chrome ext. thanks.
manifest.json:
{
"name":"modz",
"manifest_version":2,
"version":"1.0",
"description":"this ext. will help you record all the urls you have visited",
"background": {
"scripts": ["background.js"]
},
"browser_action":
{
"default_icon":"icon.png",
"default_popup":"popup.html"
},
"permissions":[
"tabs"
]
}
background.js:
var data=[];
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
var url = tab.url;
if (url!=="undefined" && changeInfo.status=="complete")
{
data.push (tab.url);
alert(data.length);
}
}
);
chrome.runtime.onMessage.addListener(function(message,sender,sendrespose){
//send the array data back
});
popup.js:
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('btn').addEventListener('click',function(){
chrome.runtime.sendMessage("getdata");
});
});
popup.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="C:\Users\modz\Desktop\modz_extention\popup.js"></script>
<style type="text/css">
body{
width:440px;
}
</style>
</head>
<body>
<input id="btn" type="button" value="get data" />
<div id="data"></div>
</body>
</html>
The official reference for messaging is here. In your case, you’d want background.js to have
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
sendResponse({"dataArray":data});
});
popup.js would have
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('btn').addEventListener('click',function(){
chrome.runtime.sendMessage({},function(response){
document.getElementById("data").textContent = response.dataArray.toString();
});
});
});
This would also work in a content script. But if the content script were running at the default document_end, it wouldn’t need the DOMContentLoaded event, since document_end happens afterward.
This is actually sending an empty message (the empty object {}). If there were different messages you wanted to send, you’d want to change that. This is also why message isn’t used in background.js.
Since you’re not really sending a message, another approach is to use getBackgroundPage. background.js wouldn’t need the listener, and popup.js would have:
chrome.runtime.getBackgroundPage(function(backgroundWindow){
document.getElementById("data").textContent = backgroundWindow.data.toString();
});
Two more things:
popup.html can’t use the absolute path to popup.js. Put both in the extension directory, and use a relative path: src="popup.js".
Google recommends that you transition background pages to event pages. The biggest difference is that you can’t have the global variable data in event pages (you can, but it gets reset when the event page reloads). If you have trouble getting that working, I’d recommend getting your extension working as a background page, and then posting another question.
I'm new in javascript and chrome extensions (this is first application).
Extension get a QRcode of the open page's URL.
For QRcode generation I use this lib: https://github.com/jeromeetienne/jquery-qrcode
I read some quides and many answers on SO, but extension doesn't work.
All *.js libraries are in the root catalog with manifest.json
manifest.json
{
"manifest_version": 2,
"name": "QRify",
"description": "This extension shows a QR code of the open page",
"version": "1.0",
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"js": [
"jquery.min.js",
"jquery.qrcode.js",
"jquery.qrcode.min.js",
"qrcode.js"
]
}
],
"browser_action":{
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<title>basic example</title>
</head>
<body>
<script src="popup.js"></script>
</body>
</html>
popup.js
var pathname = window.location.pathname;
jQuery('#URLqrcodeCanvas').qrcode({
text : pathname
});
Most likely I forgot something...
There are few things which are wrong in your code. Let's take them step by step
Inclusion of both jquery.qrcode.js and jquery.qrcode.min.js : In production code, we try to use minified jquery because downloading of minified js files is faster.
No element with selector used in popup.js : You are trying to access URLqrcodeCanvas in your popup.js while no such element is present in popup.html. May be you should add this
You have not included jquery and qrcode in your popup.html : You need to understand the context of content script, popup scripts and background scripts. Read this
SO Answer: Difference between popup script, background and content script
Wrong use of window.location.pathname : May be you wanted to access the path of current active tab instead of popup. Once you understand the difference between popup and content script then you will be easily figure out this point. Read this
SO Answer: How to get url of active tab ?
Thanks to #Abraham for adding points 3 and 4 in this answer. Hope it helps!!