Not a duplicate of Executing Chrome extension onclick instead of page load because I need to execute script on a button press in popup.html, not when the user presses the icon.
This is my first chrome extension and I've got my content.js working the way it should on page load, but I only want to execute it after the user pushes a button in popup.html. I know you can specify run_at in manifest.json, but this doesn't work because I want it to only run when the user clicks a button (not the icon), and I'm using pageAction so I need the icon to be grayed out on urls which don't contain the letter 'g', hence the specification in my background.js. I think I must be missing something regarding the communication between background.js and content.js, but I'm feeling very lost so if anyone can explain what I'm missing that would be great.
Here is my manifest.json:
{
"manifest_version": 2,
"name": "my extension",
"description": "it doesnt work",
"version": "0.1",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"declarativeContent"
],
"page_action": {
"default_popup": "popup.html"
},
"icons" : { "16": "16.png",
"48": "48.png",
"128": "128.png" },
"content_scripts": [
{
"js": ["content.js"],
"matches": ["<all_urls>"],
"run_at": "document_end"
}
]
}
Background.js:
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'g' },
})
],
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "content.js"});
}); ]
}
]);
});
});
Content.js:
document.addEventListener("DOMSubtreeModified", function(event){
if(document.getElementsByClassName(".class")) {
var x = document.querySelectorAll(".class");
var i;
for (i = 0; i < x.length; i++) {
x[i].style.visibility = "hidden";
} }
});
popup.html:
<html>
<head>
<script type="text/javascript" src="content.js"></script>
</head>
<body>
<p>Turn off <span>class, "class"</span></p>
<button type="button">Turn off</button>
</body>
</html>
This will run if you are on the selected tab. You may need to change how you select that tab though. Basically this will will send a request to the tab and the tab listens for these requests. If you get the proper greeting, you can do your function.
popup.html
<html>
<head>
<script type="text/javascript" src="content.js"></script>
</head>
<body>
<p>Turn off <span>class, "class"</span></p>
<button type="button" id="button">Turn off</button>
</body>
</html>
background.js
$('#button').on('click',function()
{
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.executeScript(tab.id, {file: "content_script.js"});
});
});
content.js
if(document.getElementsByClassName(".class")) {
var x = document.querySelectorAll(".class");
var i;
for (i = 0; i < x.length; i++) {
x[i].style.visibility = "hidden";
}
}
Also, as #Makyen had suggested, remove content scripts from your manifest so it isn't always being injected into every tab. I edited my answer as well per this suggestion.
Related
Unlike other similar posts where they had code issues (SO1, SO2), I am no longer getting a
Uncaught TypeError: Cannot read property 'addEventListener' of null
as I am using document.onload() so their solution didn't help
My code:
popup.html
<button class="submit" id='checkButton'>
Submit
</button>
<script type="text/javascript" src="./content.js"></script>
<script type="text/javascript" src="/background.js"></script>
Background.js
function submit(){
alert('loaded')
}
document.onload = function(){
document.getElementById("checkButton").addEventListener("click", submit);
console.log('loaded')
}
manifest.json
{
"manifest_version": 2,
"name": "To be named",
"description": "This extension helps...",
"version": "0.1.0",
"browser_action":{
"default_popup":"popup.html"
},
"permissions": [
"storage",
"identity",
"identity.email",
"http://127.0.0.1:5000/test",
"http://127.0.0.1:5000/get/info",
"http://127.0.0.1:5000/test",
"http://0.0.0.0:5000/test",
"http://127.0.0.1:5000/Time"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [{
"matches": ["https://www.blank.org/"],
"js": ["content.js"],
"css": ["styles.css"]
}]
}
Yet, when I click on submit from extension. I don't get any 'loaded' (same applies if I move func to content.js) nor do I get any error in my chrome://extemsion as mentioned.
I'm no expert, but I think the problem is your trying to edit the popup.html DOM from a background script. That won't work. Instead try this:
background.js:
//Your other javascript...
var views = chrome.extension.getViews({
type: "popup"
});
for (var i = 0; i < views.length; i++) {
views[i].document.getElementById('checkButton').addEventListener("click", submit);
console.log("loaded");
}
I'm assuming this as if you were using the background.js as a background script. I don't see why you're including background.js in the bottom of popup.html, though. Here's what I suggest:
popup.html:
<button class="submit" id='checkButton'>
Submit
</button>
<script type="text/javascript" src="./popup.js"></script>
popup.js:
function submit(){
alert('loaded')
}
document.onload = function() {
document.getElementById("checkButton").addEventListener("click", submit);
console.log('loaded')
}
Hope this works! :)
I'm working on Chrome extensions. I try to learn messaging between content and background. I develop simple project for this. But I have issue.
Basic idea is
User click button on extension popup
A function (bot.js) find image from content of tab then extension (background.js) will download it.
The issue is port.onMessage.addListener() in background.js fired twice.
When background.js sends message to contentscript.js there are two same messages in console or when I try to download in background.js (the code line "Do Something") it download the file twice.
How can I solve this problem?
popup.html
<!doctype html>
<html>
<head>
<title>Test Plugin</title>
<script src="background.js"></script>
<script src="popup.js"></script>
</head>
<body>
<h1>Test Plugin</h1>
<button id="btnStart">Button</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('btnStart');
checkPageButton.addEventListener('click', function() {
GetImages("Some URL");
}, false);
}, false);
var tab_title = '';
function GetImages(pageURL){
// Tab match for pageURL and return index
chrome.tabs.query({}, function(tabs) {
var tab=null;
for(var i=0;i<tabs.length;i++){
if(tabs[i].url==undefined || tabs[i].url=="" || tabs[i]==null){}
else{
if(tabs[i].url.includes(pageURL)){
tab=tabs[i];
break;
}
}
}
if(tab!=null){
chrome.tabs.executeScript(tab.id, {
file: "bot.js"
}, function(results){
console.log(results);
});
}
});
}
bot.js
var thumbImagesCount = document.querySelectorAll('.classifiedDetailThumbList .thmbImg').length;
var megaImageURL=document.querySelectorAll('.mega-photo-img img')[0].src;
console.log(megaImageURL + " from bot.js");
port.postMessage({key:"download", text: megaImageURL});
background.js
chrome.runtime.onConnect.addListener(function (port) {
console.assert(port.name == "content-script");
port.onMessage.addListener(function(message) {
console.log(message);
if(message.key=="download"){
// Do Something
// Event fires twice
port.postMessage({key:"download", text: "OK"});
}
})
});
contentscript.js
console.log("content script loaded!");
var port = chrome.runtime.connect({name: "content-script"});
port.onMessage.addListener(function(message){
console.log(message);
});
manifest.json
{
"manifest_version": 2,
"name": "Test Extension",
"description": "This extension will download images from gallery",
"version": "1.0",
"icons": {
"16": "bot16.png",
"48": "bot48.png",
"128": "bot128.png" },
"browser_action": {
"default_icon": "bot48.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"downloads",
"http://*/",
"https://*/"
],
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
]
}
The background script declared in manifest.json already has its own page, a hidden background page where it runs, so you should not load it in the popup as it makes no sense in case there are listeners for API events, the background page is already listening for them. In this case the copy also creates the second listener while the popup is open.
Solution: don't load background.js in popup.
See also Accessing console and devtools of extension's background.js.
Hello there,
I want to remove thumbnail images that appear on YouTube. I am using the following code for this.
while (true) {
$("ytd-thumbnail").remove()
}
When I paste this code into console, all thumbnail images are removed. I want it to work on the backplane by adding an extension. The code for the plug-in I'm preparing is below.
manifest.json;
{
"manifest_version": 2,
"name": "test",
"description": "test extension",
"version": "1.0",
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
popup.html
<!doctype html>
<html>
<head>
<title>TEST</title>
<script src="popup.js"></script>
</head>
<body>
<h1>TEST</h1>
<button id="checkPage">Check !</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function() {
chrome.tabs.getSelected(null, function(tab) {
d = document;
while (true) {
$("ytd-thumbnail").remove()
}
});
}, false);
}, false);
When I press the checkPage button nothing happens. But this code works when I add a console. What is the problem? Thanks in advance.
There are several issues with the extension :
You are trying to use $ i.e. jquery which is not available in your
popup.js
You are trying to access "ytd-thumbnail" dom elements which belong
to youtube page and not your popup.html. So, even if you replace $
with document.querySelector , you won't find those elements.
I created a working version that looks something like this. I have not included popup.html which is same as yours.
manifest.json
{
"manifest_version": 2,
"name": "Hello Extensions",
"description" : "Base Level Extension",
"version": "1.0",
"browser_action": {
"default_icon": "hello_extensions.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["background.js"],
"all_frames" : true
}
],
"permissions": [
"activeTab",
"tabs"
]
}
2.popup.js
document.addEventListener('DOMContentLoaded', function()
{
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function()
{
chrome.tabs.query({"active":true}, function (tabs){
chrome.tabs.sendMessage(tabs[0].id, "removeThumbnails", function (response) {
});
});
});
});
When the button is clicked, retrieve the active tab and send it a "removeThumbnails" message.
3.background.js
chrome.runtime.onMessage.addListener(function(message, callback) {
if (message == "removeThumbnails")
{
var elements = document.querySelectorAll("ytd-thumbnail");
elements.forEach(a => a.parentNode.removeChild(a));
}
});
background.js is content script and runs in youtube page. It can now access all the dom elements in youtube page. When we receive a "removeThumbnails" message , get all ytd-thumbnail elements and remove them from page.
I'm currently coding my first chrome extension which runs youtube.com/tv in a background process so you can always accesses it with a phone or table, this is working fine but if you want to view the video not just hear the audio I have to open the page which the background process is on, and this is where the problems start, because opening the new page creates a second process which conflicts with the first instant crashing them both, so i need to know if there is a way to open the background instance into a view able tab.
Code Below:
manifest.json
{
"manifest_version": 2,
"name": "Youtube TV",
"version": "1.0",
"description": "A simple extension which runs 'www.youtube.com/tv' in the background of your browser do you can connect to it with your phone whenever your computer is turned on.",
"background": {
"persistent": true,
"page": "background.html",
"script": "background.js"
},
"browser_action": {
"default_icon": "icon.png"
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/",
"webRequest",
"webRequestBlocking",
"<all_urls>",
"tabs"
]
}
background.html
<html>
<head>
<style type="text/css">
</style>
</head>
<body style="margin:0px">
<script src="background.js"></script>
<iframe style="margin:0px; border:0px" src="http://youtube.com/tv" width="100%" height="100%" >
</iframe>
</body>
</html>
background.js
chrome.webRequest.onHeadersReceived.addListener(
function (details) {
for (var i = 0; i < details.responseHeaders.length; ++i) {
if (details.responseHeaders[i].name.toLowerCase() == 'x-frame-options') {
details.responseHeaders.splice(i, 1);
return {
responseHeaders: details.responseHeaders
};
}
}
}, {
urls: ["<all_urls>"]
}, ["blocking", "responseHeaders"]);
chrome.browserAction.onClicked.addListener(
function (activeTab) {
var newURL = "http://youtube.com/tv";
chrome.tabs.create({ url: newURL });
});
chrome.tabs.create({url: chrome.extension.getURL('background.html')});
EDIT
Sorry i didnt properly understand the question. See the answer to this question here
The real background page is hidden, and cannot be shown
I am trying to append a div to page of current active tab. However I am getting this error:
Error during tabs.executeScript: Cannot access contents of url ....
Extension manifest must request permission to access this host.
My Code: (show_loader.js)
var dv = document.createElement('div');
dv.id = 'myid';
dv.innerHTML = 'test';
document.body.appendChild(dv);
However when I put this code:
document.body.style.backgroundColor = 'green';
It works as expected and background color of current tab is changed with no other change except for the code in show_loader.js file which is run from popup.js like this:
chrome.tabs.executeScript(null, {file: "show_loader.js"});
My Manifest file also does have:
"permissions":
[
"tabs",
"notifications",
"http://*/",
"https://*/"
],
So I wonder why it gives above error when I try to do anything else other than setting background color. Even simple alert or console.log alone on that page gives same above mentioned error.
How to fix that ?
Update: Complete Relevant Code
Manifest:
{
... name and description ...
"icons":
{
"16" : "img/icon.png",
"48" : "img/48.png",
"128" : "img/128.png"
},
"permissions":
[
"tabs",
"notifications",
"http://*/*",
"https://*/*"
],
"browser_action":
{
"default_icon": "img/icon.png",
"default_title": "Page title",
"default_popup": "popup.html"
}
}
popup.js
// send data to server for saving
$('#btn').click(function(){
chrome.tabs.executeScript(null, {file: "show_loader.js"});
$loader.show();
var data = $(this).closest('form').serialize();
$.ajax({.....});
});
window.onload = function(){
var $loader = $('#loader');
$loader.show();
chrome.tabs.getSelected(null, function(tab) {
//console.log(tab);
$('#url').val(tab.url);
$('#title').val(tab.title);
$loader.hide();
});
};
popup.html
<html>
<head>
<link rel="stylesheet" href="css/style.css" type="text/css" />
</head>
<body>
<form action="" method="post" name="frm" id="frm">
<table border="0" cellpadding="3" cellspecing="0" width="370">
......
</table>
</form>
<script src='js/jquery.js'></script>
<script src='popup.js?v=014423432423'></script>
</body>
</html>
show_loader.js
console.log($); // doesn't work
// document.body.style.backgroundColor = 'green'; // WORKS
Code which worked
manifest.json
{
"name": "Manifest Permissions",
"description": "http://stackoverflow.com/questions/14361061/extension-manifest-must-request-permission-to-access-this-host",
"version": "1",
"manifest_version": 2,
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"notifications",
"http://*/",
"https://*/"
]
}
popup.html
<html>
<head>
<script src="back.js"></script>
</head>
<body>
<button id="tmp-clipboard">Click Me</button>
</body>
</html>
back.js
document.addEventListener("DOMContentLoaded", function () {
document.getElementById('tmp-clipboard').onclick = function () {
chrome.tabs.executeScript(null, {
file: "script.js"
});
}
});
script.js
var dv = document.createElement('div');
dv.id = 'myid';
dv.innerHTML = 'test';
document.body.appendChild(dv);
Try Eliminating deprecated chrome.tabs.getSelected from your code and use chrome.tabs.query instead.
Sample Usage
chrome.tabs.query({
"currentWindow": true,
"status": true,
"active": true //Add any parameters you want
}, function (tabs) {//It returns an array
for (tab in tabs) {
//Do your stuff here
}
});
Edit 1
If you intention is to capture active browsing tab in current window where he clicked browser action use this code
chrome.tabs.query({
"currentWindow": true,//Filters tabs in current window
"status": "complete", //The Page is completely loaded
"active": true // The tab or web page is browsed at this state,
"windowType": "normal" // Filters normal web pages, eliminates g-talk notifications etc
}, function (tabs) {//It returns an array
for (tab in tabs) {
$('#url').val(tabs[tab].url);
$('#title').val(tabs[tab].title);
$loader.hide();
}
});
The manifest v3 uses a different permission schema. This is what worked for me:
"host_permissions": [
"https://music.youtube.com/*"
],