I found several approaches, but they seem outdated or simply won't work for some reasons for me. Maybe tunnelvision:
First things first:
I have the correct permissions in my manifest.json, I think:
"permissions": [
"tabs",
"activeTab"
]
I have 2 simple scripts, background.js and content.js (which are recognized correctly, the error can't be here).
In my background.js I tried several approaches:
chrome.browserAction.onClicked.addListener(buttonClicked);
var sharedUrl;
function buttonClicked(tab) {
chrome.tabs.getCurrent(function(tab) {
// please read further, this was my last resort, I tried other stuff as well
sharedUrl = console.log(window.location.href);
});
let msg = {
txt: "Hello",
url: sharedUrl
}
chrome.tabs.sendMessage(tab.id, msg);
}
I tried it with getCurrent() and then tab.url, but that didn't work (neither with tab[0].url
I tried it also with getSelected() as well as with something like this:
chrome.tabs.query({active: true, currentWindow: true}, function(arrayOfTabs) {
var activeTab = arrayOfTabs[0];
});
and my content.js is simply this here:
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendResponse) {
console.log(message.txt);
console.log(message.url);
}
It displays "Hello", but not the URL I'm looking for.
Edit:
It might of importance, that I want to retrieve the url after a button-click in my extension.
Thanks for the feedback and help.
Ok, based on the documentation you are not able to grab the tab object while you are not in the tab context. The tab context includes only content scripts. So you can't access to tab because you are calling it from your backend page. You can only do it, if your extension has generated the tab.
Gets the tab that this script call is being made from. May be
undefined if called from a non-tab context (for example: a background
page or popup view).
So, the only possible way is to change your extension data flow.
Related
I am currently making a chrome extension using the following Chrome tutorial:
https://developer.chrome.com/docs/extensions/mv3/getstarted/
I ran into some issues with my own code initially so now I'm just using their code as a basis for my own thing.
In popup.js, the tutorial has a function that changes the background color on click.
function setPageBackgroundColor() {
chrome.storage.sync.get("color", ({ color }) => {
document.body.style.backgroundColor = color;
});
I replaced the line in the code instead to what I wanted it to do.
document.getElementById(xyz).miscfunction(arg1, arg2);
The getting started extension works as intended (obviously). When I run my line of code in the console in Chrome, it works exactly as intended. However, when I run the line using the extension, it gives me the following error:
Uncaught TypeError: document.getElementById(...).miscfunction is not a function
I have tested and found out that getElementById is indeed getting the element I want because when I try to run this on a tab that does not have said element, it gives me an error saying that the element is null. It does not do so for the tab that actually does have the element.
What is preventing my extension from being able to access the miscfunction? When I was last trying to debug this months ago, I recall having some issues with injection and the content security policy but I do not remember what I did to get to that point. Any help would be appreciated.
EDIT:
I have since updated the popup to call a script js file instead of calling a function, and then put the function in a separate file.
To access the document element of the page you are viewing, you need to paste the required code in the content script.
You first need to add content script and it's scope in manifest.json
"content_scripts" : [{
"matches" : ["https://<website-you-are-working-on>"]
"js" : ["script.js"] //file containing the code you need to execute
}]
The pop up script now needs to send message to content script to do what you want to do.
popup.js
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
const activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {
"action" : "change-background"
"payload": {
//required info
}
})});
Now listen for the message in the content script and do the required task.
script.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if(message.action == "change-background"){
//your code here
}
})
I am currently trying to make a chrome extension that lists all of the open tabs in its popup window. With more functionality to be added later, such as closing a specific tab through the popup, opening up a new tab with a specific URL etc.
manifest.json
{
"manifest_version": 2,
"name": "List your tabs!",
"version": "1.0.0",
"description": "This extension only lists all of your tabs, for now.",
"background": {
"persistent": true,
"scripts": [
"js/background.js"
]
},
"permissions": [
"contextMenus",
"activeTab",
"tabs"
],
"browser_action": {
"default_popup": "popup.html"
}
}
background.js
const tabStorage = {};
(function() {
getTabs();
chrome.tabs.onRemoved.addListener((tab) => {
getTabs();
});
chrome.tabs.onUpdated.addListener((tab) => {
getTabs();
});
}());
function getTabs() {
console.clear();
chrome.windows.getAll({populate:true},function(windows){
windows.forEach(function(window){
window.tabs.forEach(function(tab){
//collect all of the urls here, I will just log them instead
tabStorage.tabUrl = tab.url;
console.log(tabStorage.tabUrl);
});
});
});
chrome.runtime.sendMessage({
msg: "current_tabs",
data: {
subject: "Tabs",
content: tabStorage
}
});
}
popup.js
(function() {
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.msg === "current_tabs") {
// To do something
console.log(request.data.subject)
console.log(request.data.content)
}
}
);
}());
From my understanding, since you're supposed to have listeners in background.js for any changes to your tabs. Then when those occur, you can send a message to popup.js
As you can see, for now I'm simply trying to log my tabs in the console to make sure it works, before appending it to a div or something in my popup.html. This does not work, however, because in my popup.html I'm getting the following error in the console:
popup.js:3 Uncaught TypeError: Cannot read property 'sendMessage' of undefined
so I'm... kind of understanding that I can't use onMessage in popup.js due to certain restrictions, but I also have no clue, then, on how to achieve what I'm trying to do.
Any help would be appreciated.
The Google's documentation about the background script is a bit vague. The important thing for your use case is that the popup runs only when it's shown, it doesn't run when hidden, so you don't need background.js at all, just put everything in popup.js which will run every time your popup is shown, here's your popup.html:
<script src="popup.js"></script>
The error message implies you were opening the html file directly from disk as a file:// page, but it should be opened by clicking the extension icon or via its own URL chrome-extension://id/popup.html where id is your extension's id. This happens automatically when you click the extension icon - the popup is a separate page with that URL, with its own DOM, document, window, and so on.
The popup has its own devtools, see this answer that shows how to invoke it (in Chrome it's by right-clicking inside the popup, then clicking "inspect").
Extension API is asynchronous so the callbacks run at a later point in the future, after the outer code has already completed, which is why you can't use tabStorage outside the callback like you do currently. More info: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference.
There should be no need to enumerate all the tabs in onRemoved and onUpdated because it may be really slow when there's a hundred of tabs open. Instead you can modify your tabStorage using the parameters provided to the listeners of these events, see the documentation for details. That requires tabStorage to hold the id of each tab so it would make sense to simply keep the entire response from the API as is. Here's a simplified example:
let allTabs = [];
chrome.tabs.query({}, tabs => {
allTabs = tabs;
displayTabs();
});
function displayTabs() {
document.body.appendChild(document.createElement('ul'))
.append(...allTabs.map(createTabElement));
}
function createTabElement(tab) {
const el = document.createElement('li');
el.textContent = tab.id + ': ' + tab.url;
return el;
}
I'm new to Chrome extensions. I know there's lots of similar questions and info out there, but none of it seems to address this problem.
I need my content script to execute on every page that matches *://*.youtube.com/watch?v=*.
I've tried using the above value and *://*.youtube.com/* as the match property, but neither works supposedly due to the way YouTube handles requests. I've also tried using the onhashchange event, but of course YouTube doesn't use anchors in their URLs. I've read about webRequest, but I don't need the function to be called when somebody is scrolling through the comments and the page loads more comments.
All I need is a way to call my content script when the URL changes. How exactly can I accomplish this?
Additionally, I cannot load the content script at document_start because the extension scrapes the HTML and parses it.
I had the same issue and this is what I did. I added a background script to listen to all changes
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url) {
chrome.tabs.sendMessage(tabId, {
message: 'hello',
url: changeInfo.url
});
}
});
Then in my content script, I listen to it and reload the URL
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'hello') {
const { url } = request;
chrome.location.replace(url);
}
});
I'm trying to automate the task of taking customers data from an ebay page and inserting it into a form in another page. I used Imacros but i don't quite like it.
Are chrome extensions good for this kind of work?
And if yes, where the dom logic should go, on the background page or in the content script?
Can anyone provide me a simple example of code?
NOTE: since January 2021, use Manifest V3 with chrome.scripting.executeScript() and the scripting permission and move <all_urls> to host_permissions instead of using the deprecated chrome.tabs.executeScript() with the tabs permission.
Task
What you need here is a Chrome extension with the ability to read DOM content of the customer page inside a tab with a content script, and then store the information and send it to another tab.
Basically, you'll need to:
Inject a content script in the customer page
Retrieve the data and send it to the background
Elaborate the data and send it to another content script, that will:
Insert the data in the form on another page
Implementation:
So, first of all, your manifest.json will need the permission to access the tabs and the URLs you need, plus the declaration for your background script, something like this:
{
"manifest_version": 2,
"name": "Extension name",
"description": "Your description...",
"version": "1",
"permissions": [
"<all_urls>",
"tabs"
],
"background": { "scripts": ["background.js"] }
}
Now, following the steps:
Add a listener to chrome.tabs.onUpdated to find the customer page and inject the first content script, plus find the tab with the form and inject the second script, all from background.js:
chrome.tabs.onUpdated.addListener(function(tabID, info, tab) {
if (~tab.url.indexOf("someWord")) {
chrome.tabs.executeScript(tabID, {file: "get_data.js"});
// first script to get data
}
if (~tab.url.indexOf("someOtherWord")) {
chrome.tabs.executeScript(tabID, {file: "use_data.js"});
// second script to use the data in the form
}
});
Ok, now the above code will inject your get_data.js script in the page if its URL contains "someWord" and use_data.js if its URL contains "someOtherWord" (you must obviously replace "someWord" and "someOtherWord" with the right words to identify the correct page URLs).
Now, in your get_data.js you'll need to retrieve data and send it to the background.js script, using chrome.runtime.sendMessage, something like this:
var myData = document.getElementById("some-id").textContent;
// just an example
chrome.runtime.sendMessage({messgae: "here is the data", data: myData});
Now you've sent the data, so inside background.js you'll need a listener to catch and elaborate it:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message = "here is the data") {
// elaborate it
chrome.tabs.query({url: "*://some/page/to/match/*"}, function(tabs) {
chrome.tabs.sendMessage(tab[0].id, {message: "here is the data", data: request.data});
});
}
});
Ok, you are almost finished, now you'll need to listen to that message in the second content script, which is use_data.js, and use it in the form:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message == "here is the data") {
// use the data to do something in the page:
var myData = request.data;
// for example:
document.getElementById("input-id").textContent = data;
}
});
And you are done!
Documentation
This wast just an example, and I strongly recommend you to check out the documentation to fully understand the functions and methods to use, here are some useful links:
chrome.tabs
.query
.onUpdated
.sendMessage
.executeScript
chrome.runtime
.onMessage
.sendMessage
Chrome extension message passing
I try to write a Google Chrome extension that simply opens a new tab when I click left-right in a short interval. The JavaScript is no problem but I implemented this as a "content_scripts" script.
In some other threads I read that I can't access the chrome.* APIs from content_scripts (except the chrome.extension API).
Even if it's not necessary to access the chrome.tabs API to open a new window (window.open should do the job) it seems I need it though for opening a new tab with the new tab page which obviously isn't possible via window.open.
So I can't really figure out what is the best way to do that. I could use a background page which I could call from the content_script but I think there should be a much more simple way to do that, I just don't get it.
Anyone have an idea?
I think your content script will have to send a message to your background page to invoke chrome.tabs.create - content scripts cannot use the chrome api, nor can they directly communicate with the background page.
Here's a reference about message passing inside Chrome extensions for further detail, but here's the example code ( modified from the example in said reference )
// in background
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
switch ( request.action) {
case 'newTab' : {
//note: passing an empty object opens a new blank tab,
//but an object must be passed
chrome.tabs.create({/*options*/});
// run callback / send response
} break;
}
return true; //required if you want your callback to run, IIRC
});
// in content script:
chrome.extension.sendMessage({action: "newTab"}, function(response) {
//optional callback code here.
});
simple and easy
document.body.onclick = function openNewWindow( ) {
window.location.href = 'javascript:void window.open( "chrome://newtab" )';
}
manifest:
,"permissions":[
"http://*/*"
,"https://*/*"
]
,"manifest_version": 2
,"content_scripts":[{
"matches":[
"http://*/*"
,"https://*/*"
]
,"js":[
"js/openWindow.js"
]
}]
alright i miss understanding the question... modified