I have this rather simple extention and content script:
manifest.json:
{
"name": "My.First.App.Uses.Native.Api",
"version": "1.0",
"manifest_version": 2,
"description": "My app uses my first Native Api",
"icons": {
"128": "icon-128__2.png"
},
"permissions": [
"nativeMessaging", "activeTab"
],
"browser_action": {"default_popup": "ext-page.htm"},
"content_scripts": [
{
"matches": ["file:///*"],
"js": ["content-script.js"]
}
]
}
ext-script.js:
// Listen for messages that come from the client script.
chrome.runtime.onMessage.addListener(
function( request, sender, sendResponse ) {
if( request.greeting ) {
//connectToNative();
sendResponse( { farewell: request.greeting + ' -> received' } );
}
} );
content-script.js:
var btn = document.getElementById( 'mybutton' );
if( btn ) {
btn.addEventListener( 'click', function() {
var msg = document.getElementById( 'mytext' ).value;
if( msg ) {
chrome.runtime.sendMessage( { greeting: msg }, function( response ) {
console.log( response.farewell );
} );
//port.postMessage({joke: "Knock knock"});
}
else {
alert( "content script could not send message" );
}
} );
}
ext-page.htm:
<!DOCTYPE html>
<html>
<head>
<script src='./ext-script.js'></script>
</head>
<body>
This is a test Extention.
</body>
</html>
A sample page which the content script is injected in :
<html>
<head>
<title>Connecting to a Chrome Extention using Content Script</title>
</head>
<body>
<p>
<!--<input id="btn" type="button" value="open document" />-->
<input id="mytext" type="text" />
<input id="mybutton" name="mybutton" type="button" value="open document" />
</p>
</body>
</html>
My problem:
If I select the extention and "inspect popup" it (meaning start the debug mode), and click mybutton button on my sample page, then I receive a message back from the extension and I can see it in my page's console. What I want is to get that message simply right after clicking that button in my sample page-- of course without debugging the extension. If I do not "inspect popup" the extension, then I receive this error message:
Error in event handler for (unknown): TypeError: Cannot read property 'farewell' of undefined
Thanks!
I think because you're executing your alert inside main.js which is inside your popup, the popup needs to be open. Try inserting your alert inside background.js. Because background.js gets inserted into your sample page as a content_script, the alert should show up right in your sample page.
Instead of in background.js
if( msg ) {
chrome.extension.sendRequest( msg );
}
Do
var msg = document.getElementById( 'mytext' ).value;
if( msg ) {
alert( msg );
}
The docs suggest to have a manifest like this:
{
"manifest_version": 2,
"name": "Test",
"version": "0.1",
"background": {
"scripts": ["background.js"],
//this script is the main one which your extension communicates with
"persistent": false
},
"browser_action": {
"default_title": "BET",
"default_popup": "popup.html"
//this html file is the one that will be shown when clicked on your extension icon
},
"content_scripts": [{
//this file will get injected into the tabs
"matches": ["file:///*"],
"js": ["content.js"]
}],
"permissions": [
"tabs",
"<all_urls>"
]
}
So inside your content.js your should have
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
And inside background.js you receive the message
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request.greeting);
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
Doing it this way, you will be able to log what you sent from your injected script to your extension...just open the background console from the extensions page.
Hope this will help if you change the structure around a little. Let me know if it helps
Related
i am completely new to chrome extension development.
I am trying to change the DOM (append data to active webpage) when clicked on a button in the extension popup. How is this possible.
the manifest file
{
"manifest_version": 2,
"name": "test 2",
"description": "test ext 2",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js": ["jquery.min.js", "main.js"]
}
],
"permissions": [
"activeTab"
]
}
suppose if the popup.html file is
<!doctype html>
<html>
<head>
<title>test extension 2</title>
<script src="popup.js"></script>
</head>
<body>
<a id="button">button</a>
</body>
</html>
and when i click on #button, i want to execute some jquery code in main.js file which will append some data to the active webpage.
Thank you.
Use Programmatic injection. You could register event listener in popup.js and call chrome.tabs.executeScript to inject some js code/file to current active tab. This requires host permissions.
popup.js
document.getElementById('button').addEventListener('click', function() {
chrome.tabs.query({ active: true, currentWindow: true}, function(activeTabs) {
// WAY 1
chrome.tabs.executeScript(activeTabs[0].id, { code: 'YOUR CODE HERE' });
});
});
Use Message Passing. You could call chrome.tabs.sendMessage in popup.js and listen to that via chrome.runtime.onMessage in content.js.
popup.js
// WAY 2 (Replace WAY1 with following line)
chrome.tabs.sendMessage(activeTabs[0].id, { action: 'executeCode' });
content.js
chrome.runtime.onMessage.addListener(function(request) {
if(request.action === 'executeCode') {
// YOUR CODE HERE
}
});
Use Storage. You could call chrome.storage.local.set in popup.js and listen to storage change in content.js via chrome.storage.onChanged.
popup.js
// WAY 3 (Replace WAY1 with following line)
chrome.storage.local.set({ action: 'executeCode' });
content.js
chrome.storage.onChanged.addListener(function(changes) {
var action = changes['action'];
if(action.newValue === 'executeCode') {
// YOUR CODE HERE
}
});
EDIT -- added background script
I need to get a message from the popup script in my chrome extension to the content script. It should send the message when a button inside the popup is clicked.
After reading more, it seems like you can't communicate directly between the popup script and the content script.
I think I need to go:
popup.js > background.js > script.js
I've tried doing this, but I can't seem to get it to work. There are a couple different ways to implement message passing, but not much documentation for this use case.
here's the code (it doesn't seem to pass a message at all right now):
popup.js
/* when something is saved in local storage... */
chrome.storage.sync.set({'myFilter': filter}, function(){
/* send message to background script */
chrome.runtime.sendMessage({greeting: "hello from popup"}, function(response) {
console.log(response.farewell);
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "new filter saved"}, function(response) {
console.log(response.farewell);
});
});
});
background.js
/*listen for message from popup, send message to content script */
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a background script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello from popup") {
alert("message passed to background script");
console.log("message passed to background script");
/* send message to content script */
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "popup sent message"}, function(response) {
console.log(response.farewell);
});
});
return true;
sendResponse({farewell: "goodbye"});
}
return false;
});
script.js
/* get notice from background script*/
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "popup sent message") {
alert("message passed to content script");
console.log("message passed to content script");
location.reload();
walkWithFilter();
return true;
sendResponse({farewell: "goodbye"});
}
return false;
});
manifest.json
{
"manifest_version": 2,
"name": "filter",
"description": "This extension allows twitter users to filter content in their feed",
"version": "1.0",
"content_scripts":
[
{
"matches": ["*://*/*"],
"js": ["bower_components/jquery/dist/jquery.min.js", "script.js"],
"run_at": "document_end"
}
],
"permissions": [
"tabs",
"storage",
"contextMenus",
"background",
"https://twitter.com/",
"http://twitter.com/"
],
"icons": {
"16": "fa-moon.png"
},
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "filter",
"default_icon": "fa-moon.png",
"default_popup": "popup.html"
}
}
right now this is doing nothing -- no alert message pops up and nothing is printed to the console when I pressed the button with the click event.
This is how it should run:
1) User enters input into popup window 'save-button' and clicks save
2) onclick of the save-button, input is saved in localstorage (this part works)
3) onclick of the save-button, message is sent from popup.js to script.js telling
it that new input has been saved to localstorage
4) Script.js receives message and prints to the regular console "message passed"
The reason I'm doing this is that I need to make the content script do some logic when it receives notice that new input has been saved in local storage. Does this seem reasonable?
You can actually go directly from
popup.js > script.js since the background page's messaging api is accessible to the popup too.
manifest.json
{
"manifest_version": 2,
"name": "filter",
"description": "This extension allows twitter users to filter content in their feed",
"version": "1.0",
"content_scripts":
[
{
"matches": ["<all_urls>"],
"js": ["script.js"],
"run_at": "document_end"
}
],
"permissions": [
"tabs",
"storage",
"contextMenus",
"background",
"https://twitter.com/",
"http://twitter.com/"
],
"icons": {
},
"background": {
"scripts": []
},
"browser_action": {
"default_title": "filter",
"default_popup": "popup.html"
}
}
popup.html
<button id="save-button">save-button</button>
<script src="/popup.js" type='text/javascript'></script>
popup.js
document.getElementById("save-button").onclick = function(){
console.log("clicked button");
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
if(tabs.length == 0){
console.log("could not send mesage to current tab");
}else{
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello, how are you content script?"}, function(response) {
console.log("received message from content script: "+response.farewell);
});
}
});
}
script.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
console.log("received message from popup: "+request.greeting);
sendResponse({farewell: "I'm good, thank you popup!"});
});
A very important permission for message passing i.e. tabs which is used to interact with the browser's tab system, is missing in your permission list.
Replace permissions array in manifest.json with
"permissions": [
"tabs",
"storage",
"contextMenus",
"background",
"https://twitter.com/",
"http://twitter.com/"
],
I'm trying to create a Chrome extension that displays the current page's DOM in a popup.
As a warmup, I tried putting a string in getBackgroundPage().dummy, and this is visible to the popup.js script. But, when I try saving the DOM in getBackgroundPage().domContent, popup.js just sees this as undefined.
Any idea what might be going wrong here?
I looked at this related post, but I couldn't quite figure out how to use the lessons from that post for my code.
Code:
background.js
chrome.extension.getBackgroundPage().dummy = "yo dummy";
function doStuffWithDOM(domContent) {
//console.log("I received the following DOM content:\n" + domContent);
alert("I received the following DOM content:\n" + domContent);
//theDomContent = domContent;
chrome.extension.getBackgroundPage().domContent = domContent;
}
chrome.tabs.onUpdated.addListener(function (tab) {
//communicate with content.js, get the DOM back...
chrome.tabs.sendMessage(tab.id, { text: "report_back" }, doStuffWithDOM); //FIXME (doesnt seem to get into doStuffWithDOM)
});
content.js
/* Listen for messages */
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
/* If the received message has the expected format... */
if (msg.text && (msg.text == "report_back")) {
/* Call the specified callback, passing
the web-pages DOM content as argument */
//alert("hi from content script"); //DOESN'T WORK ... do we ever get in here?
sendResponse(document.all[0].outerHTML);
}
});
popup.js
document.write(chrome.extension.getBackgroundPage().dummy); //WORKS.
document.write(chrome.extension.getBackgroundPage().domContent); //FIXME (shows "undefined")
popup.html
<!doctype html>
<html>
<head>
<title>My popup that should display the DOM</title>
<script src="popup.js"></script>
</head>
</html>
manifest.json
{
"manifest_version": 2,
"name": "Get HTML example w/ popup",
"version": "0.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"]
}],
"browser_action": {
"default_title": "Get HTML example",
"default_popup": "popup.html"
},
"permissions": ["tabs"]
}
You got the syntax of chrome.tabs.onUpdated wrong.
In background.js
chrome.tabs.onUpdated.addListener(function(id,changeInfo,tab){
if(changeInfo.status=='complete'){ //To send message after the webpage has loaded
chrome.tabs.sendMessage(tab.id, { text: "report_back" },function(response){
doStuffWithDOM(response);
});
}
})
I am doing a project and I need to display on a chrome extension popup all the images of the current selected tab website, I tried many things but the popup always shows as a small popup with nothing on it.
Here is the code:
Dom.js:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.action == "getDOM")
sendResponse({dom: document.body.getElementsByTagName("img")});
else
sendResponse({}); // Send nothing..
});
Manifest.json:
{
"manifest_version": 2,
"name": "PrintIt",
"version": "1.0",
"description": "Partilha conteudo com redes sociais",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs"
],
"content_scripts": [{
"matches": [
"http://www.google.com/*"
],
"js": [
"dom.js"
]
}]
}
Popup.html:
<html>
<head>
<script>
chrome.tabs.getSelected(null, function(tab) {
// Send a request to the content script.
chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, function(response) {
document.write(response.dom);
});
});
</script>
</head>
<body>
</body>
</html>
I did console.log(response.dom) and i got the folowing errors in estension console:
Port error: Could not establish connection. Receiving end does not exist. miscellaneous_bindings:236
chromeHidden.Port.dispatchOnDisconnect miscellaneous_bindings:236
Error in event handler for 'undefined': Cannot read property 'dom' of
undefined TypeError: Cannot read property 'dom' of undefined
at chrome-extension://cfboppmcojfddlkbpohfnnnkogpeflgk/popup.js:4:23
at miscellaneous_bindings:281:11
at chrome.Event.dispatchToListener (event_bindings:390:21)
at chrome.Event.dispatch_ (event_bindings:376:27)
at chrome.Event.dispatch (event_bindings:396:17)
at Object.chromeHidden.Port.dispatchOnDisconnect (miscellaneous_bindings:239:27) event_bindings:380
I run into the same problem some time ago. It's simply prohibited to place script code inside the popup.html so it's not working. Place your code completely inside of dom.js and everything should be fine.
I am making a chrome extension that will open all links on a page in new tabs.
Here are my code files:
manifest.json
{
"name": "A browser action which changes its icon when clicked.",
"version": "1.1",
"permissions": [
"tabs", "<all_urls>"
],
"browser_action": {
"default_title": "links", // optional; shown in tooltip
"default_popup": "popup.html" // optional
},
"content_scripts": [
{
"matches": [ "<all_urls>" ],
"js": ["background.js"]
}
],
"manifest_version": 2
}
popup.html
<!doctype html>
<html>
<head>
<title>My Awesome Popup!</title>
<script>
function getPageandSelectedTextIndex()
{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function (response)
{
console.log(response.farewell);
});
});
}
chrome.browserAction.onClicked.addListener(function(tab) {
getPageandSelectedTextIndex();
});
</script>
</head>
<body>
<button onclick="getPageandSelectedTextIndex()">
</button>
</body>
</html>
background.js
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
updateIcon();
});
function updateIcon() {
var allLinks = document.links;
for (var i=0; i<allLinks.length; i++) {
alllinks[i].style.backgroundColor='#ffff00';
}
}
Initially I wanted to highlight all the links on the page or mark them in some way; but I get the error "Refused to execute inline script because of Content-Security-Policy".
When I press the button inside the popup, I get this error: Refused to execute inline event handler because of Content-Security-Policy.
Please help me fix these errors, so I can open all links in new tabs using my chrome extension.
One of the consequences of "manifest_version": 2 is that Content Security Policy is enabled by default. And Chrome developers chose to be strict about it and always disallow inline JavaScript code - only code placed in an external JavaScript file is allowed to execute (to prevent Cross-Site Scripting vulnerabilities in extensions). So instead of defining getPageandSelectedTextIndex() function in popup.html you should put it into a popup.js file and include it in popup.html:
<script type="text/javascript" src="popup.js"></script>
And <button onclick="getPageandSelectedTextIndex()"> has to be changed as well, onclick attribute is also an inline script. You should assign an ID attribute instead: <button id="button">. Then in popup.js you can attach an event handler to that button:
window.addEventListener("load", function()
{
document.getElementById("button")
.addEventListener("click", getPageandSelectedTextIndex, false);
}, false);