chrome extension to open in new tab instead of popup - javascript

I am trying to get some data from current tab to my extension. It's working fine if I change it to popup style but I am looking for the same functionality to open it in a new tab on extension click. Can anybody guide on this how I can achieve this? Thanks in advance
manifest.json.js
{
"manifest_version": 2,
"name": "Hello World",
"description": "A simple page-scraping extension for Chrome",
"version": "1.0",
"author": "#thomasforth",
"background": {
"scripts": ["popup.js"],
"persistent": true
},
"permissions": [
"tabs",
"http://*/",
"*://*/",
"activeTab"
],
"browser_action": {
"default_icon": "logo.png"
}
}
payload.js
// send the page title as a chrome message
chrome.runtime.sendMessage(document.title);
console.log(document.title)
popup.js
// Inject the payload.js script into the current tab after the popout has loaded
window.addEventListener('load', function (evt) {
chrome.extension.getBackgroundPage().chrome.tabs.executeScript(null, {
file: 'payload.js'
});;
});
// Listen to messages from the payload.js script and write to popout.html
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.create({ url: "popup.html", selected: false })
chrome.runtime.onMessage.addListener(function (message) {
document.getElementById('pagetitle').innerHTML = message;
})
})
This the is error which I am getting

Use the id of the tab where onClicked was triggered and pass it to popup script using its URL:
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.create({
url: `popup.html?tabId=` + tab.id,
selected: false,
});
});
// popup.js
const tabId = +new URLSearchParams(location.search).get('tabId');
chrome.tabs.executeScript(tabId, {
file: 'payload.js'
});

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.

Chrome extension message passing from background script to content script error: receiving end doesn't exist

I'm working on a chrome extension currently, and I keep getting this error:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist
I'm trying to pass a message from my background script to my content script. The background script fetches the url of the current tab, and I'm trying to pass that URL to my content script. I've found a few different solutions to this error, but none of them are working for me. From what I understand, it has something to do with the content script not being loaded when the background script tries to send the message, though I've tried some workarounds for that and nothing has worked for me. This is my code:
Background script:
//use a query to get the current URL of the tab
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function(tabs){
var currentTab = tabs[0];
var currentUrl = currentTab.url;
//send a message from background script to content script
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
const port = chrome.tabs.connect(tabs[0].id);
port.postMessage({url: currentUrl});
port.onMessage.addListener(function(response){
console.log(response);
});
});
}
);
Content Script:
chrome.runtime.onConnect.addListener(function(port){
port.onMessage.addListener(function(msg){
if(msg.url.includes("amazon")){
console.log("You are on amazon.com");
}
port.postMessage("This is my response!");
});
});
Here is my manifest as well:
{
"manifest_version": 2,
"name": "First Browser Extension",
"version": "1.0.0",
"description": "Add a better description later.",
"page_action": {
"default_icon": "icon.png",
"default_title": "BrowserExtension",
"default_popup": "index.html"
},
"background":{
"scripts": ["background.js"],
"persistent": false
},
"content_scripts":[
{
"matches": ["https://www.amazon.com/*"],
"js": ["content.js"]
}
],
"permissions": [
"tabs",
"activeTab",
"https://*/*"
],
"icons": {"48": "icon.png"}
}
I can't figure out what's going wrong. Any insight would be greatly appreciated!
Edit: updated code
Background
chrome.tabs.query({
active: true,
currentWindow: true //changed lastFocusedWindow to currentWindow
}, function(tabs){
var currentTab = tabs[0];
var currentUrl = currentTab.url;
console.log(currentUrl);
//----------NEW CODE---------------------------
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery === "getURL") {
sendResponse({url: currentUrl});
return true; // Will respond asynchronously.
}
});
}
);
Content
chrome.runtime.sendMessage(
{contentScriptQuery: "getURL"},
function(urlFromBackground){
console.log(urlFromBackground.url);
}
);

Going bonkers over this small code, chrome.runtime.onMessage gives undefined, always. What can I do?

I know there are similar questions and I've tried almost everything in them. I'm trying to build a chrome extension and it needs to pass a message from content.js to background.js.
The code:
background.js
var xstext;
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
xstext=request.stext;
});
var wtf = "https://www.google.com/search?q="+xstext;
chrome.commands.onCommand.addListener(function(command) {
if(command=="ntab"){
chrome.tabs.create({ url: wtf});
}
});
content.js
var text = window.getSelection();
var stext=text.toString();
chrome.runtime.sendMessage({stext: stext});
manifest.json
"manifest_version": 2,
"name": "vind",
"version": "1.0",
"description": "Search stuff easily!",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [
{
"all_frames": true,
"run_at": "document_start",
"matches": [
"<all_urls>"
],
"js": ["content.js"]
}
],
"browser_action": {
"default_icon": {
"16": "images/icon16.png",
"32": "images/icon32.png"
},
"default_popup": "popup.html"
},
"commands": {
"ntab": {
"suggested_key": {
"default": "Alt+G",
"windows": "Alt+G",
"mac": "Alt+G",
"chromeos": "Alt+G",
"linux": "Alt+G"
},
"description": "New tab for the query"
}
}
}
I want to pass the selected text from content.js to background.js, I have tried adding return: true; in the listener to no avail. I'm getting 'undefined' added to the main string, so nothing seems to get passed. what should I do?
This approach won't work because 1) your content script is saving the text at the moment it runs which happens just one time at page load and 2) since the background script is not persistent it'll unload after receiving a message and xstext will disappear.
Do the reverse: ask the content script when the hotkey is pressed.
background.js, entire contents:
chrome.commands.onCommand.addListener(command => {
if (command === 'ntab') {
chrome.tabs.query({active: true, lastFocusedWindow: true}, ([tab]) => {
if (!tab) return;
chrome.tabs.sendMessage(tab.id, 'getText', text => {
chrome.tabs.create({
url: 'https://www.google.com/search?q=' + encodeURIComponent(text),
});
});
});
}
});
content.js, entire contents:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg === 'getText' && document.hasFocus()
&& (!document.activeElement || !/^I?FRAME$/.test(document.activeElement.tagName))) {
sendResponse(getSelection().toString());
}
});
P.S. An advanced solution would be to run the content script on demand (using chrome.tabs.executeScript in background.js onCommand listener) so you can remove content_scripts section from manifest.json and use activeTab permission instead.

Chrome extension - injecting script and running it on inactive tab

I have Chrome extension that injects a script into a page on load. If it is a certain page, it opens a set of links on that page in new tabs and when those tabs are loaded the injected script submits a form on the tab. The issue is that the injection is not happening on tabs that are not current. It works only on the current tab.
A simplified version of my code:
manifest.json
{
"name": "name",
"version": "0.0.1",
"manifest_version": 2,
"description": "Doing stuff",
"background": {
"scripts": [
"background.js"
],
"persistent": true
},
"browser_action": {
"default_title": "Bot"
},
"permissions": [
"https://*.url.com/*",
"*://*/*",
"tabs"
]
}
background.js :
chrome.tabs.onUpdated.addListener( function (tabId, changeInfo, tab) {
if(changeInfo.status == 'complete') {
try {
chrome.tabs.executeScript(tab.ib, {
file: 'inject.js'
});
} catch(err) {
console.log(" extension cannot run on the chrome:// page ")
}
}
})
inject.js :
(function() {
function page1() {
links = document.querySelectorAll("a.link_class");
for(var link in links) {
link.setAttribute("target", "_blank");
link.click();
}
}
function page2() {
// this does not run in tabs that are inactive
// in order to make it run, i have to click in the inactive tab and reload it manually
document.querySelector("input[name='field_to_update']").text = "setting the field value";
button = document.querySelector("input[name='button']");
button.click();
}
if(document.querySelector("div.page1") != null) {
page1();
} else {
page2();
}
})();

Accessing Current Tab DOM Object from a Chrome Extension

I have been searching around on how to accomplish this. I have found some articles most notably
Accessing Current Tab DOM Object from "popup.html"?
However I am very new to JavaScript and making chrome extensions and I have hit a dead end.
My guess is that the response isn't being received which explains why document.write("Hellp")
isn't working. Any help to fix this up would be appreciated.
I have three main files
manifest.json
{
"name": "My First Extension",
"version": "1.0",
"description": "The first extension that I made.",
"browser_action":
{
"default_icon": "icon.png",
"popup": "popup.html"
},
"permissions":
[
"tabs"
],
"content_scripts":
[{
"matches": ["<all_urls>"],
"js": ["dom.js"]
}]
}
popup.html
<html>
<body>
</body>
<script>
chrome.tabs.getSelected(null, function(tab)
{
// Send a request to the content script.
chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, function(response)
{
document.write("Hello");
document.write(response.title)
});
});
</script>
</html>
dom.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse)
{
if (request.action == "getDOM")
sendResponse({dom: document.getElementsByTagName("body")[0]});
else
sendResponse({}); // Send nothing..
});
I see this is an older question, but it's unanswered and I ran into the same issue. Maybe it's a security feature, but you don't seem to be able to return a DOM object. You can, however, return text. So for dom.js:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.action == "getDOM")
sendResponse({dom: document.body.innerHTML});
else
sendResponse({}); // Send nothing..
});
I'm workin on an extension that transfers the html of the element as a text and then rebuilding the element back using innerHTML.
Hope that clarifies how to get the DOM elements from the current page**
This is the way I've got the DOM:
Manifest.json
{
"manifest_version": 2,
"version" : "2.0",
"name": "Prettify search",
"description": "This extension shows a search result from the current page",
"icons":{
"128": "./img/icon128.png",
"48": "./img/icon48.png",
"16": "./img/icon16.png"
},
"page_action": {
"default_icon": "./img/icon16.png",
"default_popup": "popup.html",
"default_title": "Prettify Results!"
},
// If the context is the Mach url = sends a message to eventPage.js: active icon
"content_scripts": [
{
"matches": ["http://www.whatever.cat/*"],
"js": ["./js/content.js", "./js/jquery-3.1.1.min.js"]
}
],
"permissions": [
"tabs",
"http://www.whatever.cat/*",
"http://loripsum.net/*" //If you need to call and API here it goes
],
"background":{
"scripts": ["./js/eventPage.js"],
"persistent": false
}
}
Popup.js
$(function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {action: "getPage"}, function(response) {
var importedCode = response.searchResults;
var fakeHtml = document.createElement( 'html' );
fakeHtml.innerHTML = importedCode; // recieved String becomes html
});
});
Eventpage.js
>Able/disable the extension button
chrome.runtime.onMessage.addListener(function(req, sender, resp) {
if(req.todo === 'showPageAction'){
chrome.tabs.query({active:true, currentWindow:true}, function(tabs) {
chrome.pageAction.show(tabs[0].id);
});
}
});
content.js
Content_Scripts can not use the Chrome API to enable or disable the >extension icon. We pass a message to Event_Page, js, he can indeed
use the Api
chrome.runtime.sendMessage({ todo: "showPageAction"});
window.onload = function() {
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.action == "getPage"){
sendResponse({searchResults: document.body.innerHTML});
}
});
};
popup.html
Just link popup.js

Categories