Pass data between chrome extension and webpage - javascript

I'm trying to create tiny chrome extension.
This one has one input that contains login that user can typea dn a button. Once clicked, script is injected to current page and I'm trying to pass data (the login entered in extension html) but it looks it isn't running and I don't know how to test it more in order to find the reason why it isn't running.
At this point, the alert("inject is running"); is runing but not the alert("csEvent fired"); when I press the button and ther eis no error message in the extension manager.
Here is the code:
Manifest
{
"name" :"Quick Pass",
"version" :"1.0",
"manifest_version": 2,
"description" :"Password for quick access",
"browser_action" :
{
"default_icon" : "icone.png",
"default_popup": "popup.html"
},
"web_accessible_resources": ["inject.js"],
"permissions": [
"https://*/*",
"http://*/*",
"tabs",
"activeTab"
]
}
buttonScript.js
document.getElementById("myButton").addEventListener("click", myFunction);
// When user clicks on the submit button of the extension, load the script on current tab
function myFunction() {
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.executeScript({
file: 'inject.js'
});
});
// data you want to sent
let data = {
login: document.getElementById("loginPopup").value,
pwd: "Password"
};
// send data through a DOM event
document.dispatchEvent(new CustomEvent('csEvent', {detail: data}));
}
inject.js
// Injected from Chrome "APPI Pass" extension
(function() {
alert("inject is running");
document.addEventListener('csEvent', function (event) {
alert("csEvent fired");
console.log(event.detail.login+event.detail.pwd);
document.getElementById("Email").value = event.detail.login;
document.getElementById("Password").value = event.detail.pwd
document.getElementByTagName("form").submit();
});
})();
And the popup.html:
<DOCTYPE html>
<head>
</head>
<body>
<h2>Appi Magic</h2>
<h3>Enter Login:</h3>
<input type="text" id="loginPopup">
<button id="myButton">Let go</button>
<script src="buttonScript.js"></script>
</body>
</html>
Thanks

Related

Chrome extension message listener fires twice

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.

Set value active input in active page from chrome extension

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');

Fill forms with a data from popup.html

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);
});

Inject content script on extension reload programmatically (chrome extension)

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).

Extension manifest must request permission to access this host

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/*"
],

Categories