I'm tring to get current tab id in content script. But it fails all the time. I'm not sure, what i'm doing false.
Here are some solutions from another topics, but these are not working in my extension:
CODE 1 - content.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
alert("sent from tab.id=", sender.tab.id);
});
CODE 2 - content.js
chrome.extension.sendRequest({
action: "WhatYouWant"
});
chrome.extension.onRequest.addListener(function (request, sender, sendResponse) {
if (request.action) {
alert('The response is : ' + request.action);
}
});
background.js
chrome.extension.onRequest.addListener(function (request, sender, sendResponse) {
if (request.action) {
// Make what you want
chrome.tabs.getSelected(null, function (tabs) {
chrome.tabs.sendRequest(tabs.id, {
action: "response"
});
});
}
});
manifest.json
...
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"all_frames": true,
"js": ["content.js"],
"matches": ["<all_urls>"],
"run_at": "document_end"
}],
"web_accessible_resources": [
"content.js"
],
...
Note: This is not duplicate topic, the solutions in other questions don't work for me.
The chrome.tabs API is not accessible inside a content script:
Use simply (javascript) :
location.href
to get the URL of the current Web page.
chrome.tabs.query() function returns tabs Array.
refer to this document:
https://developer.chrome.com/extensions/tabs#method-query
when i tried tabs.query() function, the callback function returns all current tabS array.
chrome.tabs.query( {}, function(cbResult){
console.log(cbResult);});
with google's document and above call back returns, you can find the proper tab is using first query() argument.
if the first argument is Null, then query function returns all tabs array.
you can narrow the candidate tabs using the first argument.
Screenshot
Related
This question already has answers here:
What is the difference between a function call and function reference?
(6 answers)
Closed 1 year ago.
So I'm trying to make an extension that allows you to write custom JS to be injected on any page for a given domain. My popup loads the saved JS code, and when clicking save, the JS is evaluated, and that works just fine. I can't figure out how to get the code to evaluate on page load, though.
Here is what I have so far.
//Content.js
//Globals
var entries = {"test": "test"}; //Entries dictionary "domain": "js code"
var url = window.location.href; //Full URL of the tab
var parts = url.split("/"); //URL split by '/' character
var domain = parts[2] + ''; //Just the domain (global)
loadChanges();
chrome.runtime.onMessage.addListener(listener);
window.onload=eval(entries[domain]); //doesn't work
function listener (request, sender, sendResponse) {
console.log("Manipulating data for: " + domain);
if (request == "LOAD"){
if(entries.hasOwnProperty(domain)){
console.log("PE - Loaded Value: " + entries[domain].toString());
sendResponse(entries[domain]);
} else {
console.log("Nothing to load");
sendResponse('');
}
} else {
entries[domain] = request;
console.log(entries[domain]);
saveChanges();
eval(request); //This one DOES work
}
}
//Load saved code (on startup)
function loadChanges() {
chrome.storage.local.get(['PE'], function (data){
console.log(data.PE);
if (data.PE == null){
return;
}
entries=data.PE;
});
if(entries.hasOwnProperty(domain)){
eval(entries[domain]); //doesn't work
}
}
//Save changes to code (on button press)
function saveChanges() {
chrome.storage.local.set({PE: entries}, function(data){
console.log("Saved Value: " + entries[domain])
});
}
Note the "doesn't work" comments in there.
manifest.json
{
"name": "PersistEdit",
"version": "0.1.1",
"manifest_version": 2,
"content_scripts":[
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end",
"persistent": false
}
],
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"browser_action": {
"default_popup": "popup.html",
"default_title": "PersistEdit"
},
"permissions": [
"storage"
]
}
document.addEventListener('DOMContentLoaded', onload, false);
function onload(){
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
chrome.tabs.sendMessage(tabs[0].id, "LOAD");
});
}
Didn't include my popup.html or popup.js because those parts of it work as intended, but I can include them if necessary. I'm not sure what I'm missing here, any guidance would be appreciated.
window.onload is supposed to be a function.
Here window.onload=eval(entries[domain]); you are just assigning the result of eval to onload(which happens immediately during the assignment). It's possible that entries isn't properly populated at that time.
Try the following code
window.onload=function () {
eval(entries[domain]);
}
I wrote this script to send a message from a background script to a script in a new tab but for some reason, the script in the tab isn't receiving the message. Is this a problem with my script or my browser (Firefox 62.0.3)
my "manifest":
{
"manifest_version":2,
"name": "test",
"version": "1.0",
"description": "this is a test extension",
"background":{
"scripts": ["OnButtonClick.js"]
},
"permissions": [
"tabs"
],
"content_scripts": [{
"matches": ["www.youtube.com"],
"js": ["input.js"]
}],
"browser_action": {
"default_icon": "button.png",
"default_title": "test button"
}
}
my "OnButtonClick.js":
function action(){
browser.tabs.create({
url: "www.youtube.com"
});
browser.tabs.sendMessage(1,{"message":"hi"})
}
browser.browserAction.onClicked.addListener(action);
and my "input.js":
function handleMessage(msg){
console.log(msg);
}
browser.runtime.onMessage.addListener(handleMessage)
browser.tabs.create() is a asynchronous therefore, browser.tabs.sendMessage() runs even before a tab is created.
You have to wait for it to run first.
Here are some suggestions:
// first create the tab
const newTab = browser.tabs.create({
url: 'https://example.org'
});
newTAb.then(onCreated, onError);
// after tab is created
function onCreated(tab) {
browser.tabs.sendMessage(tab.id,{message: 'hi'});
}
// in case of error
function onError(error) {
console.log(`Error: ${error}`);
}
// above can also be written as this
browser.tabs.create({
url: 'https://example.org'
}).then(
tab => browser.tabs.sendMessage(tab.id,{message: 'hi'}),
error => console.log(error)
);
// another alternative for above
browser.tabs.create({url: 'https://example.org'})
.then(tab => browser.tabs.sendMessage(tab.id,{message: 'hi'}))
.catch(error => console.log(error));
// Using chrome and callback function
chrome.tabs.create({url: 'https://example.org'}, tab =>
browser.tabs.sendMessage(tab.id,{message: 'hi'})
);
// same as above, all with chrome
chrome.tabs.create({url: 'https://example.org'}, tab =>
chrome.tabs.sendMessage(tab.id,{message: 'hi'})
);
You can also use async/await but that may make it more complicated in this case.
Update on comment:
content_scripts by default run at "document_idle" (corresponds to complete. The document and all its resources have finished loading.)
"content_scripts": [{
"matches": ["www.youtube.com"],
"js": ["input.js"]
}],
Therefore, the input.js is injected once everything is loaded. However, the sendMessage() runs as soon as tab is created and thus there is no listener to listen to its message.
In your simple example, that can be fixed by "run_at": "document_start"
"content_scripts": [{
"matches": ["www.youtube.com"],
"js": ["input.js"],
"run_at": "document_start"
}],
However, if input.js needs to access DOM after receiving message, then you need to add a DOMContentLoaded or load listener and run it after the document is loaded.
why do you want to use "sendMessage"?
you can use this code
browser.tabs.executeScript(tabID, { code: "func()" /* your function in content script*/,frameId:0 /* for send to all frame or put id for use a special frame id*/});
or this code as file
browser.tabs.executeScript(tabID, { file: "/filename.js",frameId:0});
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 have an chrome extension, with 2 content script injected by manifest and one background script.
{
"manifest_version": 2,
"name": "Test",
"permissions": [
"tabs", "<all_urls>", "activeTab", "storage"
],
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": [
"content/autofill/lib_generic.js",
"content/autofill/lib.js"],
"run_at": "document_end"
}
],
"web_accessible_resources": [
"content/specific_scripts/*"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
lib_generic.js contains one function named apply_forms(...) (its description is not important). The function is called from lib.js file. But this procedure doesn't work with several pages, so for each such page a I have a special script - also with only one function named apply_forms(...).
I have a function, which takes current domain as input and returns name of desired specific script or false if generic should be used.
There is too many files and it's logic is more complicated, so I can't just list all (url, script) pairs in "content_scripts" directive (I also don't want to inject all specific files as content script).
I've tried something like this in background (note that it's only for demonstration):
var url = ""; //url of current tab
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete") {
var filename = getSpecificFilename(url);
chrome.tabs.executeScript(tabId, {file: filename}, function() {
//script injected
});
}
});
NOTE: getSpecificFilename(...) will always return a name
But I get Unchecked runtime.lastError while running tabs.executeScript: Cannot access a chrome:// URL on the 5th line.
Can anyone help me with this? Is it the good way to "override` function definition dynamically, or should I go different way (which one, then).
Thanks.
This means, probably, that you're getting an onUpdated event on an extension/internals page (popup? options page? detached dev tools?).
One option is to filter by URL:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete") {
if(!tab.url.match(/^http/)) { return; } // Wrong scheme
var filename = getSpecificFilename(url);
chrome.tabs.executeScript(tabId, {file: filename}, function() {
//script injected
});
}
});
Another (and probably better) option is to make your content script request this injection:
// content script
chrome.runtime.sendMessage({injectSpecific : true}, function(response) {
// Script injected, we can proceed
if(response.done) { apply_forms(/*...*/); }
else { /* error handling */ }
});
// background script
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.injectSpecific){
var filename = getSpecificFilename(sender.url);
chrome.tabs.executeScript(sender.tab.id, {file: filename}, function() {
sendResponse({ done: true });
});
return true; // Required for async sendResponse()
}
});
This way you know that a content script is injected and initiated this.
Let me explain my issue. I'm currently developing an Google Chrome Extension which inject a toolbar as an iframe in every web page.
The problem is that i need in some case to hide the toolbar, re-display it and things like that. Basicelly i was thinking to put my listener on my background-page, but it's useless because this page can't manipulate graphicely the object. So my plan was to put this listener on a content_script (who can manipulate graphiquely the objet). But the second problem is that a content-script in opposite to a background-page is not executed all the time but only once.
So i'm asking myself if it's possible to make a content-script sounds like a background-page, by putting a loop on it or something like that...
Thanks in advance.
I've tried this :
manifest.json
{
"background_page" : "background.html",
"browser_action" :
{
"default_icon" : "images/extension.png"
//"popup" : "activateToolbar.html"
},
"content_scripts":
[ {
"all_frames": true,
"css": ["css/yourtoolbar.css"],
"js": ["js/jquery.js", "js/yourtoolbar.js", "js/listener.js"],
"matches": ["http://*/*"],
"run_at": "document_end"
} ],
"permissions" : ["tabs", "unlimitedStorage", "http://*/*", "notifications"],
"name" : "YourToolbar",
"version" : "1.1",
"description" : "Make your own Toolbar"
}
toolbar.html
<!-- Close Button -->
<input type="image" src="images/close.png" name="close" width="18" height="18">
Tool.js
function hideToolbar()
{
chrome.extension.sendRequest({action : "hideToolbar"});
window.webkitNotifications.createHTMLNotification('instantMessage.html', 'Ask Show Menu').show();
}
listener.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
if(request.action)
{
$('body').remove();
console.log('Received Start');
alert(request.action);
console.log('Received End');
}
else
{
console.log('nothing');
alert('Not For Me [listener.js]');
}
});
background.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse)
{
if(request.newTab)
{
// Create a new Tab
chrome.tabs.create({url: request.newTab});
}
else if(request.newWindow)
{
// Create a new Window
chrome.windows.create({url: request.newWindow});
}
else if(request.action)
{
chrome.tabs.getAllInWindow(null, function(tabs) {
$.each(tabs, function() {
chrome.tabs.sendRequest(this.id, {"action":"hideToolbar"} );
});
});
}
});
But the problem is that the addListener didn't block the execution and he just didn't catch anything...
To send a request from a background page to a content script you need to use chrome.tabs.sendRequest (not chrome.extension.sendRequest) and provide tab id.
In a content script you don't need to periodically create chrome.extension.onRequest.addListener, just create it once and it will be there permanently.
EDIT
To send a request from a content script you need to run chrome.extension.sendRequest there and add chrome.extension.onRequest.addListener to a background page.