I have an extension, with a background script:
"background": {
"scripts": ["scripts/background.js"]
},
and a content script:
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["scripts/content_script.js"]
}
],
a popup window (popup.html), and a popup script (popup.js). popup.js is not registrated into manifest,and it deals with popup.html look, and listen for user actions made in popup.html, such as clicking a button.
I want to make an extension, what emails the current tab's page, and for this, I need to get the page DOM with the content_script, pass data (DOM) to the background script. After this, when the user triggers an event in popup.html, popup.js catches this event, and I want popup.js to be able to get the passed data(DOM) from background.js. How could I make this? So, my question is, how could I communicate between background.js and popup.js?
I found an answer to my own question:
Thanks Elvis, I think I solved the problem; I only need to get the DOM of site in content script, but my question's solution was this:
content_script.js
// SEND DOM structure to the background page
chrome.extension.sendRequest({dom: "page DOM here"});
background.html
<html>
<head>
<script>
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.dom != "")
var theDOM = request.dom;
console.log(request.dom); // page DOM here -> works
chrome.extension.sendRequest({theDOM: theDOM}); // theDOM : "page DOM here"
});
</script>
</head>
<body>
</body>
</html>
popup.js
var dom;
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.theDOM != ""){
console.log("popup request: "+request.theDOM);
dom = request.theDOM;
}
});
// HANDLE TAB_1 REQUESTS (EMAIL PAGE)
// ---------------------------------
$("#send").click(function(){
console.log(dom); // page DOM here
}
Thanks for the help ;)
You can do Message Passing. From the documentation:
Use this in your content script:
chrome.extension.sendRequest({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
It sends {greeting: "hello"} to the background. Notice the callback specified
The background page can listen to these requests using:
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
The arguments to the sendResponse function will be passed to the callback
Related
How am I going to write something when user clicks extension icon and loads the window?
I've already tried
window.onload = function() {
console.log("das");
}
and ]
$(document).ready(function(){
console.log('document is ready');
});
but still there isn't any log?
Maybe it's not the best idea but you can use chrome.tabs.sendMessage and chrome.runtime.onMessage.addListener to communicate between contentscript.js and popup.js
contentscript.js is running directly in page scope so you can easily detect when page is ready. After that you can send a message chrome.tabs.sendMessage(tabs.id, {action: 'pageReady'});. In popup.js you are listening to:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action === 'pageReady') {
// Do what you want to do on page ready
}
});
It should works good for you. You can also send response to the caller:
contentscript.js send information to the popup.js that page is ready.
popup.js do what you want to do (show table).
popup.js send information to the contentscript.js that table is added.
EDIT
I'm not sure about my solution because I found information that:
The popup, while being an extension page, is not a background page. It
is only accessible when it is open
I don't know if it is possible to listen on events in popup. You need to check it.
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've developed a Chrome extension that injects a button into the toolbar of a rich-text editor of a specific web page, code available here. This basic extension is based on the concept of the "content script" and works well because the toolbar is present as soon as the page has loaded.
Now, however, I'm confronted by another page where I cannot simply inject my button as soon as the page loads because the user needs to interact with the page first (make a selection or press a button) before the toolbar appears.
So I'm looking for a way to track any changes in the active tab (I have a URL pattern for the page). I don't want or need a browser action (i.e. the little button on the right-hand side of the omnibox), so I was hoping to get away with a background.js event page where I can declare an event listener for certain user-originated events but somehow it's not working.
To explain: I've got my manifest.json, great:
{
"name": "basic tab test",
"description": "blah di blah",
"version": "1.0",
"permissions": [
"activeTab"
],
"background": {
"scripts": ["background.js"], // background script shown below
"persistent": false
},
"content_scripts": [
{
"matches": [
"file://*" // for testing only, of course
],
"js": [
"contentscript.js" // <-- content script shown below
]
}
],
"manifest_version": 2
}
The background.js script looks like this at the moment:
console.log("in background.js");
chrome.tabs.getCurrent(function(tab) {
tab.onActivated.addListener(function(){
console.log("GOT HERE onActivated (inside tab)");
});
});
chrome.tabs.getCurrent(function(tab) {
tab.onZoomChange.addListener(function(){
console.log("GOT HERE onZoomChange (inside tab)");
});
});
// this is actually part of the message passing test
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 == "hello")
sendResponse({farewell: "goodbye"});
});
Of course, these are just tests, but none of the above events actually ever fire. Becoming slightly desperate, I then thought 'well, let's use the message passing method' to send messages from the contentscript.js to the background.js whenever the user presses a button. The contentscript.js looks like this:
document.addEventListener("DOMContentLoaded", function(event) {
console.log("just a canary - got here...");
var btn = document.getElementById("button");
if (btn) {
console.log("there is a button!");
} else {
console.log("there is NO button!");
}
btn.addEventListener("click", function () {
console.log("clicked the button!!!!");
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
})
});
Also, we never arrive inside this event handler (but why oh why?! this is standard jquery-less code for when the DOM is completely loaded). So, this is when I thought I might ask the assembled experts for advice.
TL;DR: I want to track events on the activeTab and if a given DOM element makes its appearance manipulate it (by injecting an element).
By default, "run_at" property for Content Script is "document_idle", which means you scripts will be injected after window.onload event fires, and obviously later than DOMContentLoaded event. So in fact your code in content script is not executed at all.
To make your code work, either:
Remove the outer DOMContentLoaded event listener
Or add "run_at": "document_start" part in your manifest.json
You could take a look at run_at part fore more details.
Suppose I want to run a content script when I click a button in the popup page in a google chrome extension?
I have tried the following:
//popup.js
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('button').addEventListener('click', clicked);
main();
});
function clicked(){
chrome.tabs.getCurrent(
function(tab){
console.log(tab);
chrome.tabs.sendMessage(tab.id, "doSomething");
}
);
}
And in the content script:
chrome.extension.onMessage.addListener(
function(message, sender, sendResponse){
console.log("hello world");
}
);
The problem is that the tab in the callback from chrome.tabs.getCurrent( ) is undefined.
Have you given permissions for tabs in manifest.json as shown here.
"permissions": [
"tabs"
],
Moreover tab.id which the following code returns is of popup view (NOT A CONTENT SCRIPT TAB.ID)
chrome.tabs.getCurrent(
function(tab){
console.log(tab);
chrome.tabs.sendMessage(tab.id, "doSomething");
}
);
If you want to send message to tab you are browsing use following code's tab.id, it gives correct results
chrome.tabs.query({"status":"complete","windowId":chrome.windows.WINDOW_ID_CURRENT,"active":true}, function(tabs){
console.log(JSON.stringify(tabs[0]));
console.log(tabs[0].id);
});
Let me know if you need more information
The answer provided by #Sudarshan is valid and works fine, but I just found another solution to my problem. Just thought i put it here:
function clicked() {
chrome.tabs.executeScript(null,
{code:"console.log('hello world');"});
}
It will inject and execute the script.
Google Chrome Extensions Message Passing Problem :
In this Chrome Extension
My Popup Page:
chrome.browserAction.onClicked.addListener(getMessage);
getMessage();
function getMessage()
{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});//getting response from content script
});
}
My Script Page :
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
else
sendResponse({});
});
I am not getting any response from the content script.
Edits:
As per #serg , i have moved the code to the background page. But still, it is not working
You can't have chrome.browserAction.onClicked listener if you have popup page attached to the browser action button, it won't fire.
Remove popup, leave only button
Move everything into background page.
Replace tab.id with null.
Remove createFile(); call at the beginning as it won't do anything in this case (content script isn't ready to listen yet).
Don't use alerts for debugging extension, use console.log().