I'm having an issue with my contentscript. I cannot get Jquery to function no matter what! Perhaps you can help me figure out what it is?
I am trying to "catch" a value I write in a field and pass it on for processing after I click a button. I am recieving the "$ is not defined" error which probably means it cannot load JQuery.
Here is my manifest, my html and my code:
{
"name": "Test 2017",
"manifest_version": 2,
"version": "0.1",
"description": "TestApp Jquery",
"browser_action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"background": {
"scripts": ["jquery-3.2.1.min.js",
"background.js"
]
},
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"content_scripts":
[
{
"matches": [ "http://*/*", "https://*/*"],
"js":["jquery-3.2.1.min.js",
"contentscript.js"]
}
]
}
Popup.html:
<html>
<head>
<script src="jquery-3.2.1.min.js"></script>
<script src="popup.js"></script>
<style type="text/css" media="screen">
body { min-width:250px; text-align: center; }
#click-me { font-size: 20px; }
</style>
</head>
<body>
<div>Input: <input id="input">
<input id="click-me" type="button" value="Go!"/>
</body>
Popup.js
function clickHandler(e) {
chrome.extension.sendMessage({directive: "popup-click"}, function(response)
{
this.close(); // close the popup when the background finishes processing
request
});
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('click-me').addEventListener('click', clickHandler);
})
background.js
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "popup-click":
// execute the content script
chrome.tabs.executeScript(null, { // defaults to the current tab
file: "contentscript.js", // script to inject into page and run in sandbox
allFrames: true // This injects script into iframes in the page and doesn't work before 4.0.266.0.
});
sendResponse({}); // sending back empty response to sender
break;
default:
// helps debug when request directive doesn't match
alert("Unmatched request of '" + request + "' from script to
background.js from " + sender);
}
}
);
Contentscript.js where I try to run Jquery:
var abc = $("#input").val();
console.log(abc);
And then I get the error.
Any help here? Why can't my extension load JQuery? I have the scripts loaded in the right order and all.
Thanks in advance!
There is no need to use a content script for what you are trying to achieve. Content scripts are used to control the DOM of the website that is loaded in your browser. The button you are trying to manipulate is in your popup window and is controlled by popup.js, not contentscript.js. Simply move the jquery code to popup.js and it should work as expected.
Content Scripts are JavaScript files that run in the context of web pages. By using the standard Document Object Model (DOM), they can read details of the web pages the browser visits, or make changes to them.
Popup.html (nothing changed here, jquery script tag is present):
<html>
<head>
<script src="jquery-3.2.1.min.js"></script>
<script src="popup.js"></script>
<style type="text/css" media="screen">
body { min-width:250px; text-align: center; }
#click-me { font-size: 20px; }
</style>
</head>
<body>
<div>Input: <input id="input">
<input id="click-me" type="button" value="Go!"/>
</body>
Popup.js:
function clickHandler(e) {
chrome.extension.sendMessage({directive: "popup-click"}, function(response)
{
this.close(); // close the popup when the background finishes processing
request
});
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('click-me').addEventListener('click', clickHandler);
})
var abc = $("#input").val();
console.log(abc);
Related
I created an extension, where I placed a script into a page markup and performs some actions according to the following article:
var s = document.createElement('script');
s.src = chrome.runtime.getURL('code.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
I also displayed a checkbox in "default_popup" which should indicate whether to execute a part of methods in script from "code.js" (web_accessible_resources) or not.
However, I have no idea how to interact between the script from "content_scripts" (which has access to "default_popup") and the script from "web_accessible_resources".
Could you suggest something?
I understand that I can completely replace the "web_accessible_resources" script, but this does not seem to be the best practice.
Thank you.
This is a sample of communication between popup and tab.
manifest.json
{
"name": "content_scripts + popup",
"version": "1.0",
"manifest_version": 3,
"content_scripts": [
{
"js": [
"matches.js"
],
"matches": [
"<all_urls>"
]
}
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html"
}
}
popup.js
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
console.log("Send");
chrome.tabs.sendMessage(tabs[0].id, "message", (response) => {
console.log("Recv response = " + response.title);
document.getElementById("title").innerText = response.title;
});
});
matches.js
console.log("matches.js");
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("Recv. Send response = " + document.title);
sendResponse({ title: document.title });
return true;
});
popup.html
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
* {
font-size: x-large;
}
</style>
</head>
<body style="min-width:300px">
<div id="title"></div><br>
<script src="popup.js"></script>
</body>
</html>
I'm not sure exactly what you're asking but I'm assuming you have 3 things: (1) a pop up, (2) a content script, and (3) a script injected into the page, running in page context. Firstly, to send messages to the popup, you can run chrome.runtime.sendMessage() and have a listener in your popup's script.js file with chrome.runtime.onMessage(). To get the data from the page script is different, it cannot communicate with your browser extension directly. So, from your page context script, you can create an element with a unique ID and store some data in an attribute. Use a modification of a MutationObserver to run a waitForElm() function (see this thread - How to wait until an element exists?). In your content script, you'll wait for the element to be created, collect data from the attribute you set, and then run chrome.runtime.sendMessage() as mentioned earlier to get that data to your pop up.
That's it. Lemme explaim myself.
I coded a chrome extension that when clicking on a button, it will open a new resized tab (a paypal login) , but I can't manage to click the "log in button" of paypal because trying to
document.getElementById('btnLogin').click();
isn't working, neither adding that:
var paypal = window.open("https://www.paypal.com/es/signin", "PayPal", "width=400,height=400,location=yes,menubar=yes,status=yes,titilebar=yes,resizable=yes");
paypal.onload = function() {
paypal.document.getElementById('btnLogin').click();
}
Check out all of my code:
manifest.json
{
"manifest_version": 2,
"name": "Zapatillao",
"description": "Yatusabe te cojo sapatilla",
"version": "2.0.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"browser_action": {
"default_popup": "popup.html",
"default_icon": "icon128.jpg"
},
"permissions": [
"tabs",
"http://*/*",
"https://*/*",
"chrome://*/*"
]
}
content.js
document.getElementById('paypal_prelog').addEventListener('click', function() {
chrome.tabs.executeScript({
file: "paypal_prelog.js"
});
});
popup.html
<html>
<head>
<style>
html, body {
height: 200px;
width: 200px;
}
</style>
</head>
<body>
<h1>Discord: Loan#2334</h1>
<button id='paypal_prelog'>PayPal Prelogin</button>
<script src='content.js'></script>
</body>
</html>
paypal_prelog.js
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var paypal = window.open("https://www.paypal.com/es/signin", "PayPal", "width=400,height=400,location=yes,menubar=yes,status=yes,titilebar=yes,resizable=yes");
paypal.onload = function() {
paypal.document.getElementById('btnLogin').click();
}
function closeWin() {
paypal.close();
}
I have tried thousand of things, hope you can help me.
The solution for a ManifestV2 extension, which you are writing, in short, is to open a new paypal sign-in window using chrome.windows.create and then use chrome.tabs.executeScript to inject a content script code that clicks btnLogin . Your current code does it all wrong though.
Remove content_scripts, tabs, and chrome://*/* from manifest.json.
Remove content.js from your extension and popup.html
Remove paypal_prelog.js
Create popup.js
document.getElementById('paypal_prelog').onclick = () => {
chrome.windows.create({
url: 'https://www.paypal.com/es/signin',
width: 400,
height: 400,
}, w => {
chrome.tabs.executeScript(w.tabs[0].id, {
code: `(${() => {
document.getElementById('btnLogin').click();
}})()`,
});
});
};
load popup.js in popup.html:
<script src="popup.js"></script>
</body>
I am currently writing a simple chrome extension that saves the current webpage to local storage when you click the extension icon in the header.
I have successfully saved the url into local storage using background.js as per the Chrome Documentation here: https://developer.chrome.com/extensions/activeTab.
My issue is that when I click the chrome extension icon the first time my event fires but my popup.js errors out with
Uncaught TypeError: Cannot read property 'getSelected' of undefined
background.js
chrome.browserAction.onClicked.addListener(function(tab) {
console.log('Turning ' + tab.url + ' red!');
var tabNew = tab.url
chrome.storage.sync.set({ ["key" + 1]: tabNew}, function(){
// A data saved callback omg so fancy
});
chrome.storage.sync.get(/* String or Array */["key" + 1], function(items){
// items = [ { "yourBody": "myBody" } ]
console.log(items)
});
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="red"'
});
chrome.browserAction.setPopup({popup: 'popup.html'});
});
popup.js
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentLink').innerHTML = tab.url;
});
document.addEventListener('DOMContentLoaded', function() {
var link = document.getElementById('download');
// onClick's logic below:
link.addEventListener('click', function() {
chrome.storage.sync.get(null, function(items) { // null implies all items
// Convert object to a string.
var result = JSON.stringify(items);
// Save as file
chrome.downloads.download({
url: 'data:application/json;base64,' + btoa(result),
filename: 'filename_of_exported_file.json'
});
});
});
});
popup.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<link href='style.css' rel='stylesheet' type='text/css'>
<title>Discoveroo</title>
<!-- <script type="text/javascript" src="https://www.google.com/jsapi"></script> -->
<base target="_blank">
</head>
<body>
<p id="currentLink">Loading ...</p>
<hr />
<ul id="savedLinks"></ul>
<script type="text/javascript" src="popup.js"></script>
<button id="download">Download All</button>
</body>
</html>
manifest.json
{
"name": "APPNAME",
"version": "0.1",
"manifest_version": 2,
"description": "APP DESC",
"permissions": ["activeTab", "storage", "downloads", "<all_urls>"],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"matches": ["http://*/*", "https://*/*"],
"js": ["popup.js"]
}],
"browser_action": {
"default_title": "Add this page to my list"
},
"icons": {
"128": "icon.png"
}
}
Don't use popup.js as a content script. You don't need the content script. See the architecture overview. The content scripts have limited access to chrome API and run in the web page, not in the browserAction popup which is a totally separate full extension page with its own chrome-extension:// URL and own devtools console etc, not related to the web page.
browserAction.onClicked doesn't work simultaneously with a popup html so you should pick one. In this case since you need to display the popup page, declare it in manifest.json, remove browserAction.onClicked, put its inner code into your popup.js
As a consequence, there'll be no need for the background script
There's probably no need for <all_urls> permission since you already have activeTab which gives you full access to the active tab after the extension icon is clicked.
chrome.tabs.getSelected is deprecated and will be removed eventually so use chrome.tabs.query({active: true, currentWindow: true}, tabs => { ... })
No need to read chrome.storage since you already get the active URL in your popup.js.
Regarding "omg so fancy", callbacks are not an arbitrary weirdness, but a consequence of the basic fact: the API is asynchronous so the callback is invoked at a later point in time, it's like a one-time "onload" event listener. There are many tutorials about asynchronous JavaScript.
Use the safe textContent property instead of the potentially unsafe innerHTML for displaying a plain text string such as the URL.
manifest.json
remove "background"
remove "content_scripts"
add "default_popup"
"browser_action": {
"default_title": "Add this page to my list",
"default_popup": "popup.html"
},
background.js
Delete it.
popup.js
The only things from the old background script you might need, are executeScript and sync.set calls.
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="red"'
});
chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
document.getElementById('currentLink').textContent = tab.url;
chrome.storage.sync.set({key1: tab.url});
});
You can also load the Mozilla WebExtension polyfill (using <script> tag in your popup.html right before popup.js) and switch to async/await syntax instead of callbacks:
(async () => {
const [tab] = await browser.tabs.query({active: true, currentWindow: true});
document.getElementById('currentLink').textContent = tab.url;
await chrome.storage.sync.set({key1: tab.url});
})();
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/*"
],
I have read the documentation and this should be basic but I can't seem to get those alerts to appear. What's wrong?
popup.html
<html>
<head>
<script>
function finder() {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendMessage(tab.id, {type: "feature"}, function(response) {
console.log(response.farewell);
});
});
}
</script>
<style>
p {
border: 1px solid black;
width:200px;
font-size:10px;
}
</style>
</head>
<body>
<p><a id="jira">Click to populate FE description</a></p>
<script>
var jira = document.getElementById('jira');
jira.addEventListener('click', finder, false);
</script>
</body>
</html>
Content Script:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
alert('sreceived');
if (request.type == "feature") {
alert('score!');
}
});
Inline JavaScript will not be executed. This restriction bans both inline blocks and inline event handlers (e.g. <button onclick="...">).
By above lines it is clear that your popup.html violates restrictions, which can be solved as follows:
Remove all <script> tags in popup.html and move the original code to popup.js.
<html>
<head>
<script src="popup.js"></script> <!-- Added this line -->
<style>
p {
border: 1px solid black;
width:200px;
font-size:10px;
}
</style>
</head>
<body>
<p><a id="jira">Click to populate FE description</a></p>
</body>
</html>
I did not literally copy-paste the code in popup.js. These are the changes I made:
chrome.tabs.getSelected() is deprecated in favour of chrome.tabs.query(), so I updated chrome.tabs.getSelected(null, function(tab) {});
Commented out console.log(response.farewell); because there is no response handler from content script.
Final popup.js
function finder() {
chrome.tabs.query({
"status": "complete",
"currentWindow": true,
"active": true
}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
type: "feature"
}, function (response) {
//console.log(response.farewell);
});
});
}
document.addEventListener('DOMContentLoaded',= function() {
document.getElementById('jira').onclick = finder;
});
Cautions for manifest.json
Ensured permissions are available as "permissions":["tabs","<all_urls>"],
Permissions for content script also
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
Final manifest.json
{
"name":"Basic Message Passing",
"description":"This demonstrates Basic Message Passing",
"browser_action":{
"default_popup":"popup.html",
"default_icon":"screen.png"
},
"manifest_version":2,
"version":"2",
"permissions":["tabs","<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
Your content script was fine, so I did not change it.
Demonstration
Output:
Let me know if you need more information..