I am trying to make a function execute when clicking the extension's icon in the toolbar(on the right corner). I added chrome.browserAction.onClicked.addListener in background.js file but it is not working. please help me.
Ultimately, My goal is to set a different icon by HTML element in http://localhost:3000 that I use in the iframe tag.
(check there is a specific element in localhost:3000 -> set icon)
The reference that I follow:
https://developer.chrome.com/extensions/samples#search:a%20browser%20action%20which%20changes%20its%20icon%20when%20clicked
my code is below.
manifest.json
{
"name": "test",
"version": "1.0",
"description": "test",
"manifest_version": 2,
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"permissions": [
"storage"
],
"browser_action": {
"default_title": "test",
"default_popup": "popup.html"
}
}
background.js
chrome.browserAction.onClicked.addListener(() => {
console.log('test for browser action');
});
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<iframe src="http://localhost:3000" width="400" height="600"></iframe>
<script src="./background.js" charset="UTF-8"></script>
</body>
</html>
Specifying default_popup in manifest.json disables chrome.browserAction.onClicked event.
Solution: simply put the code in popup.js and load it as any other script in popup.html.
popup.html
<script src=popup.js></script>
</body>
</html>
popup.js
console.log('This will run every time the popup is opened');
To inspect the popup and its console, right-click inside the popup, then click "inspect".
Note that you don't need the background script for this. The background script runs in a hidden background page so it should never be used anywhere else. Remove it from popup.html.
P.S. You're using the wrong reference extension. Search for popup.html using the built-in browser search via Ctrl-F (not the search input on the page).
Related
I am making an autofill chrome extension. Namely, once pressing a button, an input form in the content web page will be populated by the text from the popup.html. I am getting this "cannot read properties of null" error starting from where I added an event listener to my button. [Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')][1]
Here is my html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Autofill</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p id="testText">Text to put</p>
<button id="fillForm">Fill!</button>
<script src="app.js" ></script>
</body>
</html>
Here is my app.js
console.log('background running!!!')
let testtext = document.getElementById('testText')
let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);
function buttonClick(){
params = {
active: true,
currentWindow: true
}
chrome.tabs.query(params, gotTabs);
function gotTabs(tabs){
let text = testtext.innerHTML
let content = {
username: text
}
chrome.tabs.sendMessage(tabs[0].id, content);
}
}
Here is my content.js
console.log("Receiving message...")
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendReponse){
document.getElementById('email').value = content.username
}
Lastly, my manifest.json
{
"name": "Resume Autofiller",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 2,
"browser_action":{
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [ "content.js" ]
}
],
"background": {
"scripts": ["app.js"]
}
}
I have read online that I should put my script tag at the bottom of the body tag, but I still get this error. I feel like I am overseeing something obvious, therefore any help is greatly appreciated. Thanks!!
Attached is the error I am getting.
[1]: https://i.stack.imgur.com/GyNXO.png
As said, removing background from manifest will fix this, but there appears to be a conceptual mix-up in the code sample, which is why I would like to explain why this solution works.
The script called app.js seems to be intended to be the popup script, but being used as a background script in the example. Popup is different from background. It will help to understand the difference between these two extension parts and their use cases. For continuity, the following explanation will refer to MV3 version and terms.
Background: "A background service worker is loaded when it is needed, and unloaded when it goes idle [...] Structure background scripts around events the extension depends on. Defining functionally relevant events allows background scripts to lie dormant until those events are fired and prevents the extension from missing important triggers." (Manage events with service workers) Additional note: background is literally in the background; there is no visible user interface. User would not be interacting with buttons in the background (though it is possible to send events to background for further handling through message passing). Consider background as a singleton.
Popup: This is one of the possible places to provide a UI for the extension user. The popup is activated by user clicking the extension icon, and destroyed when the popup loses focus (also when tab is closed), and reloaded again when user clicks the icon the next time. "Like the background script, this file must be declared in the manifest in order for Chrome to present it in the extension's popup. To do this, add an action object to the manifest and set popup.html as the action's default_popup." (Introduce a user interface). In the popup you can add buttons and other elements for user to click. Popup is specific to each tab. Opening multiple browser windows and clicking the icon, multiple popups can be open at the same time.
In short: the error is coming from looking for button element in the background, when there are no such buttons; removing the manifest key will prevent this.
Minimal working example
manifest.json: background key removed
{
"name": "Resume Autofiller",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 2,
"browser_action":{
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [ "content.js" ]
}
]
}
index.html: no change
(style.css will raise not found error, but not a concern regarding this question)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Autofill</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p id="testText">Text to put</p>
<button id="fillForm">Fill!</button>
<script src="app.js" ></script>
</body>
</html>
app.js: changed log text, no significant change
console.log('popup running!!!')
let testtext = document.getElementById('testText')
let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);
function buttonClick(){
params = {
active: true,
currentWindow: true
}
chrome.tabs.query(params, gotTabs);
function gotTabs(tabs){
let text = testtext.innerHTML
let content = {
username: text
}
chrome.tabs.sendMessage(tabs[0].id, content);
}
}
content.js: change log outputs a bit, commented out assignment
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendResponse){
console.log("Receiving message...")
console.log('message', JSON.stringify(message));
// next line has undefined references, commenting out
// document.getElementById('email').value = content.username
}
I am trying to make a function execute when clicking the extension's icon in the toolbar(on the right corner). I added chrome.browserAction.onClicked.addListener in background.js file but it is not working. please help me.
Ultimately, My goal is to set a different icon by HTML element in http://localhost:3000 that I use in the iframe tag.
(check there is a specific element in localhost:3000 -> set icon)
The reference that I follow:
https://developer.chrome.com/extensions/samples#search:a%20browser%20action%20which%20changes%20its%20icon%20when%20clicked
my code is below.
manifest.json
{
"name": "test",
"version": "1.0",
"description": "test",
"manifest_version": 2,
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"permissions": [
"storage"
],
"browser_action": {
"default_title": "test",
"default_popup": "popup.html"
}
}
background.js
chrome.browserAction.onClicked.addListener(() => {
console.log('test for browser action');
});
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<iframe src="http://localhost:3000" width="400" height="600"></iframe>
<script src="./background.js" charset="UTF-8"></script>
</body>
</html>
Specifying default_popup in manifest.json disables chrome.browserAction.onClicked event.
Solution: simply put the code in popup.js and load it as any other script in popup.html.
popup.html
<script src=popup.js></script>
</body>
</html>
popup.js
console.log('This will run every time the popup is opened');
To inspect the popup and its console, right-click inside the popup, then click "inspect".
Note that you don't need the background script for this. The background script runs in a hidden background page so it should never be used anywhere else. Remove it from popup.html.
P.S. You're using the wrong reference extension. Search for popup.html using the built-in browser search via Ctrl-F (not the search input on the page).
I'm working on a simple chrome extension to see how they're done, and I've followed tutorials but still can't get it working properly.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Extension</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans" type="text/css">
</head>
<body>
<div class="popup">
<div class="step-1-test-extension flex-container active">
<div class="step-number">
<p>1</p>
</div>
<div class="step-explanation">
<p>Go to Link Test.</p>
</div>
Visit Facebook
</div>
</div>
<script src="test.js"></script>
</body>
</html>
test.js:
window.onload = () => {
let testButton = document.getElementById('test-button');
testButton.innerText = 'test';
testButton.addEventListener('click', console.log('test click'));
console.log('Chrome extension go');
}
Manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"description": "Quick Test Extension",
"version": "1.0.0",
"icons": {"128": "icon_128.png"},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["activeTab"],
"content_scripts": [{
"js": ["test.js"],
"matches": ["https://www.facebook.com/*"]
}]
}
Nothing in the test.js is working properly. It's not console.logging anything and no action is taken when I click the button, so the addEventListener isn't working either. I've reloaded the extension, it's properly set to dev mode and it's appearing on my browser bar with the popup working, but none of the content script is working?
Any help is greatly appreciated, thanks in advance!
As far as I understood, you have one script (test.js) that's being referenced both as a Content Script and as a script in the Popup
The script in the popup.html will only run in the context of the popup
The content script, however, will only run in the actual page
You can communicate between them using messages, which I believe is what you need.
This line looks kinda plain and funny... can you do that these days?
testButton.addEventListener('click', console.log('test click'));
Shouldn't it be more like...
testButton.addEventListener('click',function(e){
console.log('test click');
},true); // <-- should it bubble?
Also, should you be using an expensive event listener when you could just...
testButton.onclick=function(e){console.log('test click');};
Eh?
I am trying to make a google chrome extension that allows the user to press a button in the chrome extension menu and that causes a button on a selected webpage to be clicked.The problem I have currently is the syntax and code in my injector.js. It says unexpected token ; and unexpected token [. I would appreciate any help.
Here is my manifest.json:
{
"manifest_version":2,
"name": "Button Click",
"description": "Be able to press buttons",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"storage"
]
}
Here is my html
<!DOCTYPE html>
<html>
<head>
<title>Fill</title>
</script><script src="popup.js"></script>
</head>
<body>
<h2 id="htwo">Button presser</h2>
<button id="press">Press Button</button>
</body>
</html>
and my javascript:
window.onload=function(){
if(document.getElementById("press")){
document.getElementById("press").addEventListener('click',function(){
document.getElementById("htwo").innerHTML="yay";
chrome.tabs.executeScript({
file:"injector.js"
});
});
}
}
injector.js:
function pressButton(){
var buttons=document.getElementsByClassName("button"),
button[0].click();
}
pressButton();
By the way, the button I am trying to click is an input button in which I inspect element, I get:
"(input type="submit" name="commit" value="add to cart" class="button")"
for some reason wont display
This button can be found here:
http://www.supremenewyork.com/shop/accessories/p840x2jsc/yks6zay73
Note: I know there were other people asking questions about the same topic, but the method that they used didn't work for me.
Thanks for helping me out!
Now it works. Install it and check it out.
To see how the extension works, you should be on this site (StackOverflow) and provide all these files and icon.png
manifest.json
{
"manifest_version": 2,
"name": "Button Click",
"description": "Be able to press buttons",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["tabs", "<all_urls>"]
}
popup.html
<!doctype html>
<html>
<head><title>Fill</title></head>
<body>
<h2 id="htwo">Button presser</h2>
<button id="press">Go to activity tab</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
function injectTheScript() {
// Gets all tabs that have the specified properties, or all tabs if no properties are specified (in our case we choose current active tab)
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
// Injects JavaScript code into a page
chrome.tabs.executeScript(tabs[0].id, {file: "utilities.js"});
});
}
// adding listener to your button in popup window
document.getElementById('press').addEventListener('click', injectTheScript);
utilities.js
/**
* Gets the desired element on the client page and clicks on it
*/
function goToActivityTab() {
var activityTab = document.getElementsByClassName("my-profile")[0];
activityTab.click();
}
goToActivityTab();
For more information use these links
chrome.tabs
Content Scripts
Tutorial for beginners from Google
I'm developing a chrome extension which involves getting selected text of the current tab. Here is the html file that I use:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script>
chrome.tabs.executeScript( {
code: "window.getSelection().toString();"
}, function(selection) {
document.getElementById("output").value = selection[0];
});
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>
It doesn't work, why? As followed is the error message from Chrome App & Extension Developer Tool, some of these error messages are cut with ellipses, sorry I haven't figured out how to view the full error messages here, view details only gives me the stack track, not the full error message.
As #Xan suggested, the method mentioned before (you can find it here) is overcomplicated. To get it to work, there are only two things to do:
Change value to innerHTML in document.getElementById("output").value
Add an activeTab permission in manifest.json file
Here is the complete source code, three files in total.
manifest.json
{
"manifest_version": 2,
"name": "sample",
"description": "A sample extension to get the selected text",
"version": "1.0",
"icons": {
"16": "img/icon16.png",
"48": "img/icon48.png",
"128": "img/icon128.png"
},
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="popup.js"></script>
<title></title>
</head>
<body>
<div id="output"></div>
</body>
</html>
popup.js
chrome.tabs.executeScript( {
code: "window.getSelection().toString();"
}, function(selection) {
document.getElementById("output").innerHTML = selection[0];
});
Your original approach was correct (and probably taken from this question).
It had 2 problems:
Inline scripts (<script>...</script>) are not allowed; it's fixed by putting code in a separate file, say, popup.js.
You need permission to access a page for content script injection; in your particular case, there's a specific permission, "activeTab", that does it in a transparent and painless way with no security warnings. When your extension is invoked (by clicking on the button), you are given access to the current tab.
With those fixed, your "direct" approach works.
By the way, to debug such problems in future, you need to inspect the popup page.
As for your own answer, you are over-complicating things a lot.
You don't need an Event page is this particular case; your popup can call executeScript and listen to messages. There are cases when you do need it, specifically when you can't guarantee that popup is open when content script sends messages; but here you can guarantee it.
Supposing you need the event page, consider not using getBackgroundPage to call a method in it - it tightly couples code; you can instead send a message. sendResponse can be used to pass the results back, even asynchronously.
Finally, your schema is confusing with respect to content.js. Only one copy of it executes, in a special context that is attached to the target page (and not in the extension context).