i am new to Javascript and am trying to implement a google chrome extension. I read the instructions (https://developer.chrome.com/extensions/getstarted), but still I have some troubles with my code.
I have got a popup menu with buttons and I want to get back the DOM content of the current page when a button is clicked.
Therefore i created a contentscript.js and a popup.js. The popup.js asks the contentscript to get the DOM (still needs to be implemented how I do that) and send back the DOM.
I receive the error:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
This is my code:
popup.js
var ads = ["increase", "reduce", "blabla"];
function markAds(text) {
document.getElementById("markAd").innerHTML=ads[0];
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
alert(response.farewell);
});
});
}
document.addEventListener('DOMContentLoaded', function() {
var markAd = document.getElementById('markAd');
// onClick's logic below:
markAd.addEventListener('click', function() {
markAds();
});
});
mainfest.js
{
"name": "Test",
"description": "Test Description",
"version": "0.7",
"permissions": ["contextMenus","activeTab"],
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["contentscript.js"]
}],
"browser_action": {
"default_popup": "popup.html"
},
"manifest_version": 2
}
contentscript.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
Related
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);
}
);
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.
I've been trying for hours to get popup.js to talk with the rest of my chrome extension using chrome api's sendMessage and onMessage. For testing purposes, all I want right now is to log something onto my currently active tab when a button is pressed on popup.js. This seems like it should be simple, but I just can't figure out what the problem is. Would really appreciate any help and explanation!
popup.html
<!DOCTYPE html>
<body>
<p>testing</p>
<input type="submit" id="clickme" value="button">
</body>
popup.js
function popup(){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
}
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("clickme").addEventListener("click",popup)
});
content.js (I expect this to log 'started' onto console of my active tab)
// content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "clicked_browser_action" ) {
console.log('started')
}
}
);
Just in case it applies, this is the manifest.json
{
"manifest_version":2,
"name": "extension",
"version": "0.1",
"content_scripts":[
{
"matches": [
"<all_urls>"
],
"js":["jquery-3.1.1.min.js","content.js"]
}],
"browser_action":{
"default_icon":"icon.png",
"default_popup":"popup.html"
},
"background":{
"scripts":["background.js"]
}
}
I am writing a Google Chrome extension to automate some common tasks. The functionality I want is as follows:
Create a new tab and navigate to my webmail
enter username and password
click "submit" button
Wait until the webmail page appears, and choose the "roundcube" client.
I have completed steps 1,2,and 3 and they work. I am having a lot of trouble trying to listen for the url change after my credentials are submitted so that the function that selects roundcube client can run
I know I can run a script when client selection page appears by adding to my manifest but I want to use "chrome.tabs.executeScript" instead so that roundcube is chosen only if I run the script from the chrome extension and not if I go to client selection page manually.
Here is my manifest.json:
{
"manifest_version": 2,
"name" : "Chrome Autobot",
"description": "This extension will run various automation scripts for google chrome",
"version" : "1.0",
"browser_action" : {
"default_icon" : "icon.png",
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"webNavigation",
"tabs",
"http://*/*",
"https://*/*"
]
}
Here is my chrome script:
jQuery(function($) {
"Use Strict";
var openWebmail = function() {
chrome.tabs.create({
url: 'http://mywebmaillogin.com:2095/'
}, function() {
chrome.tabs.executeScript(null, {file: "scripts/openEmail.js"});
});
chrome.tabs.onUpdated.addListener(function(){
chrome.tabs.executeScript(null, {file: "scripts/openEmail.js"});
alert('i work');
});
};
var init = $('.script-init');
init.on('click', function() {
openWebmail();
});
});
and here is the content script to be executed as a callback of tab creation (when the email login page is fetched and the DOM has loaded), and also when the email credentials are submitted and the client selection page's DOM has loaded (which is not working right now)
var openEmail = function() {
var loc = window.location.href;
if(loc === 'http://mywebmaillogin.com:2095/') {
var submit = document.getElementById('login_submit');
user.value = 'myusername';
pass.value = 'mypassword';
if(user.value === 'myusername' && pass.value === 'mypassword') {
submit.click();
}
else {
openEmail();
}
}
if(loc.indexOf('http://mywebmaillogin:2095/') > -1 && loc.indexOf('login=1') > -1) {
alert('I work');
}
}()
any help would be appreciated... thanks!
As mentioned by #NycCompSci, you cannot call the chrome api from content scripts. I was able to pass api data to content scripts with message passing though, so thought I'd share that here. First call onUpdated in background.js:
Manifest
{
"name": "My test extension",
"version": "1",
"manifest_version": 2,
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
],
"permissions": [
"tabs"
]
}
background.js
chrome.tabs.onUpdated.addListener(function
(tabId, changeInfo, tab) {
// read changeInfo data and do something with it (like read the url)
if (changeInfo.url) {
// do something here
}
}
);
Then you can expand that script to send data (including the new url and other chrome.tabs.onUpdated info) from background.js to your content script like this:
background.js
chrome.tabs.onUpdated.addListener(
function(tabId, changeInfo, tab) {
// read changeInfo data and do something with it
// like send the new url to contentscripts.js
if (changeInfo.url) {
chrome.tabs.sendMessage( tabId, {
message: 'hello!',
url: changeInfo.url
})
}
}
);
Now you just need to listen for that data in your content script:
contentscript.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
// listen for messages sent from background.js
if (request.message === 'hello!') {
console.log(request.url) // new url is now in content scripts!
}
});
use chrome.tabs.onUpdated
Maifest.json
{
"name": "My test extension",
"version": "1",
"manifest_version": 2,
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
],
"permissions": [
"tabs"
]
}
contentscript.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
alert('updated from contentscript');
});
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
alert('updated from background');
});
Based on / Thanks to #ztrat4dkyle's answer, what works for me:
manifest.json
{
...
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"tabs"
]
}
background.js
chrome.runtime.onInstalled.addListener(function() {
// ...
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
// changeInfo object: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated#changeInfo
// status is more reliable (in my case)
// use "alert(JSON.stringify(changeInfo))" to check what's available and works in your case
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tabId, {
message: 'TabUpdated'
});
}
})
});
content.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.message === 'TabUpdated') {
console.log(document.location.href);
}
})
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