I wrote an extension for Chrome. I want when I click on button from my extension, the value 'abc' will be set into active input on active page.
Here are my codes:
1) manifest.json
{
"name": "Test",
"short_name": "Test",
"manifest_version": 2,
"version":"2.0.0.0",
"browser_action": {
"default_popup": "index.html",
"default_title": "Load EmojiSelector"
},
"background":{
"scripts":["background.js"],
"persistent": false
},
"content_scripts":[
{
"matches":["http://*/*", "https://*/*"],
"js":["content.js"]
}
]
,
"permissions": [
"activeTab"
]
}
2) index.html
<!DOCTYPE html>
<html>
<head>
<title>Test SendMessage</title>
<script src='content.js'></script>
</head>
<body>
<input id='btsend' type='button' value='Send abc to input'>
</body>
</html>
3) background.js
chrome.runtime.onMessage.addListener(function(response, sender, sendResponse){
var act = chrome.tabs.getSelected(null, function(tab){
//How to set the value of response to active input in page????
});
});
4) content.js
onload=function(e){
var btsend = document.getElementById('btsend');
btsend.onclick = function(){
chrome.runtime.sendMessage('abc');
}
}
How can I set value for active input in active page by using DOM.
Make sure to read about the extension architecture: your popup script should be different from the content script. Actually, you don't need an unconditionally injected content script at all, use chrome.tabs.executeScript like shown in the official sample extension Page Redder.
Note: It's not possible to insert text on the default new tab page because Chrome redirects keyboard input to its built-in omnibox (address bar) which accepts only trusted (real) key presses, not the ones sent from JavaScript.
The correct popup script should attach a click listener to the element
You don't need a background page script at all for this task
manifest.json:
{
"name": "Test",
"manifest_version": 2,
"version":"2.0.0.0",
"browser_action": {
"default_popup": "popup.html",
"default_title": "Load EmojiSelector"
},
"permissions": [
"activeTab"
]
}
popup.html:
<input id='btsend' type='button' value='Send abc to input'>
<script src='popup.js'></script>
popup.js:
document.getElementById('btsend').onclick = () => {
chrome.tabs.executeScript({file: 'content.js'});
};
content.js:
document.execCommand('insertText', false, 'abc');
Related
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 have been trying to create an extension that fills a form with data from a popup, I'm a bit confused regarding the use of "background" and "content" files, I don't think I need one. Here is my code:
Manifest:
{
"name": "Browser action for Form",
"description": "Fill a form with data from the popup",
"version": "1.0",
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"browser_action": {
"default_title": "Form Test",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["https://the-site-with-a-form.com/*"],
"js": ["jquery-3.1.1.min.js", "content.js"]
}
],
"manifest_version": 2
}
popup.html
<!doctype html>
<html>
<head>
<title>Form</title>
<script src="popup.js"></script>
</head>
<body>
<form>
<textarea id="txtArea"></textarea>
<input type="button" id="btn1" value="Run">
</form>
</body>
</html>
popup.js
function click(){
var text = document.getElementById("txtArea")
chrome.tabs.sendMessage(
tabs[0].id,
{from: 'popup', subject: 'DOMInfo',data1: text});
}
content.js
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
//Fill the form with the data of the popup
document.getElementById("The textbox from the form").value = msg.data1;
}
});
what is wrong in the code?
Thanks!
Please learn to debug extension popups. If you did, you would see an informative error message.
With that in mind, tabs in your popup code doesn't come from anywhere - so your code there stops with an error. Clearly, that part is ripped out of context (of a tabs.query call, most likely). Note that if your intent is to message the currently active tab, you can just skip the first argument of sendMessage entirely.
You defintiely do need a content script, since it's the only part of an extension that can interact with a webpage's form. Recommended reading: How do all types of Chrome extension scripts work?
Here is the popup.js with the fixed "tabs" argument
function click(e) {
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
var activeTab = tabs[0];
var text = document.getElementById("txtArea").value;
chrome.tabs.sendMessage(activeTab.id, {from: 'popup', subject: 'DOMInfo',data1: text});
});
window.close();
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('submitBtn').addEventListener('click', click);
});
I am creating a chrome extension that I want to be able to enable/disable. I have successfully made a popup that does just that. The trouble is, if I reload the extension (or if the user downloads it initially) my content scripts default to being off. I could just inject the content script in the manifest.json but that results in the content script being injected for any new tab--which I do not want. The behavior should be that if you download/reload the extension, it is on by default, but then you can enable it/disable it and that applies to every new tab. I have tried to put an initialization in background.js but that does not get called at startup apparently.
manifest.json
{
"manifest_version": 2,
"name": "Rotten Tomatoes Search",
"description": "This extension searches rotten tomatoes with highlighted text",
"version": "1.0",
"browser_action": {
"default_icon": "./icons/icon_on.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"<all_urls>",
"background"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"js": ["jquery-1.12.3.min.js"],
"matches": ["<all_urls>"]
}]
}
background.js
var isExtensionOn = true;
chrome.tabs.executeScript({code: "console.log('backgournd hit...')"});
turnItOn();
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.cmd == "setOnOffState") {
isExtensionOn = request.data.value;
}
if (request.cmd == "getOnOffState") {
sendResponse(isExtensionOn);
}
});
function turnItOn() {
chrome.browserAction.setIcon({path: "./icons/icon_on.png"});
chrome.tabs.executeScript({file:"openTooltipMenu.js"});
//$('#toggle').text('disable');
}
popup.js
document.addEventListener('DOMContentLoaded', function() {
// show different text depending on on/off state (for icon, handled by having default icon)
chrome.extension.sendMessage({ cmd: "getOnOffState" }, function(currentState){
if (currentState) $('#toggle').text('disable');
else $('#toggle').text('enable');
});
// allow user to toggle state of extension
var toggle = document.getElementById('toggle')
toggle.addEventListener('click', function() {
//chrome.tabs.executeScript({code: "console.log('toggled...')"});
chrome.extension.sendMessage({ cmd: "getOnOffState" }, function(currentState){
var newState = !currentState;
// toggle to the new state in background
chrome.extension.sendMessage({ cmd: "setOnOffState", data: { value: newState } }, function(){
// after toggling, do stuff based on new state
if (newState) turnOn();
else turnOff();
});
});
})
});
function turnOn() {
chrome.browserAction.setIcon({path: "./icons/icon_on.png"});
chrome.tabs.executeScript({file:"openTooltipMenu.js"});
$('#toggle').text('disable');
}
function turnOff() {
chrome.browserAction.setIcon({path: "./icons/icon_off.png"});
chrome.tabs.executeScript({code: "$('body').off();"});
$('#toggle').text('enable');
}
popup.html
<some code>
<script src="./jquery-1.12.3.min.js"></script>
<script src="./popup.js"></script><style type="text/css"></style>
</head>
<body>
<div class="popupMenu" style="list-style-type:none">
<div class="header">Rotten Tomatoes Search</div>
<hr>
<div class="menuEntry" id="toggle"></div>
</div>
</body>
</html>
I have figured out the issue. My architectural approach was wrong. One should inject the content_script globally but check with the script whether or not something should be done. To be clearer, in the script get the status from the background page and do something based on that. Previously, I was only injecting the script once the popup was loaded or once initially when the background was initialized. Additionally, one must loop through all tabs in all windows to update the state in all tabs (if that's what one wants).
Hello, I am writing a simple chrome extension which will be used to:
1. open new webpage
2. fill timesheet form based on pasted string array
3. submit timesheet (just clicking "ok" button in the form)
4. open new webpage
For this to work my extension needs to contain:
1. popup.html Browser Action popup, with input textfield for string array, and submit button.
2. timesheet.js - javascript file to add logic to popup.html
3. background.js - background page to take care of filling form, after clicking submit button
4. content_script.js - to access newly opened webpage DOM, to fill the form.
For now, I made a simplified version, which is supposed to:
1. open www.google.com in new tab
2. wait few seconds (optionally, wait or page to finish loading)
3. change background color
Everything seems to be woring fine, except for content_script.js listener doesn't react to message send by background.js
Here is the code:
manifest.json:
{
"manifest_version": 2,
"name": "Timesheet Filler",
"description": "Description.",
"version": "1.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["http://www.google.com/*"],
"js": ["content_script.js"]
}],
"browser_action": {
"default_title": "Timesheet Filler",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"activeTab",
"http://www.google.com/*"
]
}
popup.html:
<!DOCTYPE html>
<html>
<body>
<button id="btn" >Click Me!</button>
<script src="timesheet.js"></script>
</body>
</html>
timesheet.js:
document.addEventListener('DOMContentLoaded', function(){
init();
});
function init(){
var btn = document.getElementById('btn');
btn.onclick = function() { onBtnClick(); }
}
function onBtnClick(){
chrome.runtime.sendMessage({action:"btnClick"}, btnClickCallback);
}
function btnClickCallback(any){
alert(any);
}
background.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.action == "btnClick"){
chrome.tabs.create({url: "http://www.google.com", active:true});
setTimeout(function(){ delayed(); }, 3000);
}
});
function delayed(){
chrome.tabs.query({active:true}, queryCallback);
}
function queryCallback(arr){
var tabId = arr[0].id;
console.log("message shown 3 second after clicking button") // THIS IS WORKING
chrome.tabs.sendMessage(tabId, {action:"doSomething"}); // CONTENT SCRIPT DOESNT REACT TO THIS
}
function contentScriptCallback(any){
alert(any);
}
content_script.js:
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if( message.action == "doSomething"){
document.body.style.backgroundColor='#000000';
alert("do something");
}
});
Download all files in one ZIP here
How to make content_script.js react to to message and change webpage bg color?
SOLUTION: (thanks to #wOxxOm)
Content script wasn't called since matches in content_scripts section as well as permisions of manifest.json was defined wrong.
Easiest fix was to change URL range to: <all_urls>
(for precise urls matches see this link)
Fixed manifest.json:
{
"manifest_version": 2,
"name": "Timesheet Filler",
"description": "Description.",
"version": "1.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content_script.js"]
}],
"browser_action": {
"default_title": "Timesheet Filler",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"activeTab",
"<all_urls>"
]
}
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/*"
],