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);
});
}
})
Related
I want to extract the HTML of a webpage so that I can analyze it and send a notification to my chrome extension. Sort of like how an adblocker does it when analyzing a web page for ads and then tell the extension how many possible ads there are.
I am trying to use the document object in content-scripts to get the HTML, however, I always seem to get the HTML of my popup file instead. Can anybody help?
content-script.js
chrome.tabs.onActivated.addListener(function(activeInfo) {
chrome.tabs.get(activeInfo.tabId, function(tab) {
console.log("[content.js] onActivated");
chrome.tabs.sendMessage(
activeInfo.tabId,
{
content: document.all[0].innerText,
type: "from_content_script",
url: tab.url
},
{},
function(response) {
console.log("[content.js]" + window.document.all[0].innerText);
}
);
});
});
chrome.tabs.onUpdated.addListener((tabId, change, tab) => {
if (tab.active && change.url) {
console.log("[content.js] onUpdated");
chrome.tabs.sendMessage(
tabId,
{
content: document.all[0].innerText,
type: "from_content_script",
url: change.url
},
{},
function(response) {
console.log("[content.js]" + window.document.all[0].innerText);
}
);
}
});
background.js
let messageObj = {};
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Arbitrary string allowing the background to distinguish
// message types. You might also be able to determine this
// from the `sender`.
if (message.type === "from_content_script") {
messageObj = message;
} else if (message.type === "from_popup") {
sendResponse(messageObj);
}
});
manifest.json
{
"short_name": "Extension",
"version": "1.0.0",
"manifest_version": 3,
"name": "My Extension",
"description": "My Extension Description",
"permissions": ["identity", "activeTab", "tabs"],
"icons": {
"16": "logo-16.png",
"48": "logo-48.png",
"128": "logo-128.png"
},
"action": {
"default_icon": "ogo_alt-16.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["./static/js/content-script.js"],
"run_at": "document_end"
}
],
"background": {
"service_worker": "./static/js/background.js"
}
}
Your current content script is nonfunctional because content scripts cannot access chrome.tabs API. If it kinda worked for you, the only explanation is that you loaded it in the popup, which is wrong because the popup is not a web page, it's a separate page with a chrome-extension:// URL.
For your current goal, there's no need for the background script at all because you can simply send a message from the popup to the content script directly to get the data. Since you're showing the info on demand there's also no need to run the content scripts all the time in all the sites i.e. you can remove content_scripts from manifest.json and inject the code on demand from the popup.
TL;DR. Remove content_scripts and background from manifest.json, remove background.js and content-script.js files.
manifest.json:
"permissions": ["activeTab", "scripting"],
popup.html:
<body>
your UI
<script src=popup.js></script>
</body>
popup.js:
(async () => {
const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
let result;
try {
[{result}] = await chrome.scripting.executeScript({
target: {tabId: tab.id},
func: () => document.documentElement.innerText,
});
} catch (e) {
document.body.textContent = 'Cannot access page';
return;
}
// process the result
document.body.textContent = result;
})();
If you want to to analyze the page automatically and display some number on the icon then you will need the background script and possibly content_scripts in manifest.json, but that's a different task.
I am trying to create a Chrome extension that retrieves some content from the DOM of the current tab, then opens a new tab, and performs an operation on this new tab using the previously retrieved content.
I am attempting to use callbacks to perform this sequence, but I can't figure out a proper way to do it. Now I am able to execute the first script, and get the content from the current tab DOM: what I still can't do is passing this content to the second script, utilities2.js, to be executed on the new tab.
Here's my current code:
popup.html
<!doctype html>
<html>
<head><title>Extension</title></head>
<body>
<button id="clickactivity">Click here</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
function injectTheScript() {
var tempStorage;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content_script.js"}, function(results){
tempStorage = results[0];
});
chrome.tabs.create({"url":"http://www.google.com","selected":true}, function(tab) {
});
});
}
document.getElementById('clickactivity').addEventListener('click', injectTheScript);
contentScript.js
function execContentScript() {
var code = document.getElementById('textarea').value;
return code;
}
execContentScript();
manifest.json
{
"manifest_version": 2,
"name": "My extension",
"description": "My extension",
"version": "1.0",
"permissions": ["tabs", "<all_urls>","activeTab"],
"browser_action": {
"default_popup": "popup.html"
}
}
You can store the content in the local storage of Chrome extension and after navigating to next tab, you can get the content from local storage of Chrome.
The following code may help you in this case:
chrome.storage.local.set({key: value}, function() {
console.log('Value is set to ' + value);
});
chrome.storage.local.get(['key'], function(result) {
console.log('Value currently is ' + result.key);
});
If you want to learn more about the local storage of Chrome, please read from here.
Edit:
I think you don't have idea of background scripts in the Chrome extension. Background scripts which have highest privileges to run the Chrome commands.
The complete workflow will be as follows:
popup.js is included as script
When you click button, injectTheScript function will be called from popup.js
Then it will get the element id from page and then send the request to background.js
Then background.js will save the value to Chrome storage
Then background.js will create new tab
After successful creation of tab, it will execute callback function and get the value from storage of Chrome
The following is the complete code of working extension:
manifest.json
{
"manifest_version": 2,
"name": "My extension",
"description": "My extension",
"version": "1.0",
"permissions": ["tabs", "<all_urls>","activeTab","storage"],
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
popup.html
<!doctype html>
<html>
<head><
title>Extension</title>
</head>
<body>
<button id="clickactivity">Click here</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
function injectTheScript() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var code="abc";
//var code = document.getElementById('textarea').value;
chrome.runtime.sendMessage({type: "navigate",value:code}, function(response) {
console.log('code saved to local storage');
});
});
}
document.getElementById('clickactivity').addEventListener('click', injectTheScript);
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.type == "navigate"){
chrome.storage.sync.set({key: request.value}, function() {
console.log('Background got request for saving the code '+request.value+' to local storage');
chrome.tabs.create({"url":"http://www.google.com","selected":true}, function( tab) {
console.log('navigated to new tab');
chrome.storage.sync.get(['key'], function(result) {
console.log('new tab key is '+result.key);
});
});
});
}
});
You don't need utilities2.js and content_script.js.
I've tested the code and it's working according to your requirements.
You can not see the console output if anything is consoled in background page. To see the output on console (for anything in background), open the link chrome://extensions
and click the button Background Page as following
A new window will appear as following
I am writing my First Chrome Plugin and I just want to get some text present on the current webpage and show it as a alert when i click the Extension. Lets say I am using any any webpage on www.google.com after some Search query, Google shows something like "About 1,21,00,00,000 results (0.39 seconds) " . I want to show this Text as an alert when i execute my plugin. This is what i am doing.
here is the manifest.json that i am using
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["*://*.google.com/*"],
"js": ["content.js"]
}],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
Here is my popup.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("checkPage").addEventListener("click", handler);
});`
function handler() {
var a = document.getElementById("resultStats");
alert(a.innerText); // or alert(a.innerHTML);
}
Here is my content.js
// Listen for messages
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
// If the received message has the expected format...
if (msg.text === 'report_back') {
// Call the specified callback, passing
// the web-page's DOM content as argument
sendResponse(document.all[0].outerHTML);
}
});
Here is my background.js
var urlRegex = /^https?:\/\/(?:[^./?#]+\.)?google\.com/;
// A function to use as callback
function doStuffWithDom(domContent) {
console.log('I received the following DOM content:\n' + domContent);
}
// When the browser-action button is clicked...
chrome.browserAction.onClicked.addListener(function (tab) {
// ...check the URL of the active tab against our pattern and...
if (urlRegex.test(tab.url)) {
// ...if it matches, send a message specifying a callback too
chrome.tabs.sendMessage(tab.id, {text: 'report_back'}, doStuffWithDom);
}
});
1) run content scrip after document ready ** check "run_at"
"content_scripts": [{
"run_at": "document_idle",
"matches"["*://*.google.com/*"],
"js": ["content.js"]
}],
2) on click of extension make another js to run( popup js). The popup js has access to the ( open page document)
// A function to use as callback
function doStuffWithDom() {
//console.log('I received the following DOM content:\n' + domContent);
//get tabID when browser action clicked # tabId = tab.id
chrome.tabs.executeScript(tabId, {file: "js/popup.js"});
}
3) In popup JS simple you can set alert
var a = document.getElementById("resultStats");
alert(a.innerText); // or alert(a.innerHTML);
Just remove "default_popup" part in manifest.json, as you have listened to chrome.browserAction.onClicked event in background page. They can't live at the same time.
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
}
});
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.