I'm working on a pretty simple browser extension, but can't get the message passing to work:
I can send messages, but the response is never delivered!
My code:
Its mostly just a copy from the browserActions tutorial, contentscripts tutorial (manifest) and message-passing api definition.
manifest.json:
{
"manifest_version":2,
"name": "FUN SCRIPT",
"version": "1",
"description": "THIS IS SOME FUN SCRIPT",
"browser_action": {
"name": "Fun",
"icons": ["icon.png"],
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [ {
"js": [ "jquery.js", "background.js" ],
"matches": [ "http://*/*", "https://*/*"]
}],
}
background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
popup.js
document.addEventListener('DOMContentLoaded', function () {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
});
popup.html
<!doctype html>
<html>
<head>
<title>Getting Started Extension's Popup</title>
<style>
body {
min-width: 357px;
overflow-x: hidden;
}
img {
margin: 5px;
border: 2px solid black;
vertical-align: middle;
width: 75px;
height: 75px;
}
</style>
<script src="popup.js"></script>
</head>
<body>
</body>
</html>
Since the message from your popup to the content script is sent whenever the popup is loaded, be sure to reload the page to ensure the content script is loaded. Otherwise, you could end up with the following error:
Could not establish connection. Receiving end does not exist.
That said, I tried what you provided, and it worked as is. Since your output is in popup.js, the response is in the console output of the popup. You can view it by right-clicking on your browser action icon, and selecting 'Inspect popup'.
Related
I'm working on a little sideproject in form of a chrome extension which displays the local stream via the getUserMedia API.
First I had issues requesting the gum (getUserMedia) since I tried to access it via the popup.js and the background.js. After some testing I got it working within the content.js, but now the issue was acutally displaying the stream in the popup.html. Further investigation suggested using the inbuild sendMessage from chrome (since the content script has no access to the popup).
So my workflow is now a onClick listener on my popup, on user click sending a notification to my content script, requesting the gum there and executing a callback function from the received message which sets the stream on my video element. The issue now my send stream is altered by transferring it via the sendMessage function, which results in an error setting the stream on my video element, since the stream is no longer a MediaStream object.
My approach is a trial and error approach since I'm neither a webdeveloper nor do I have any experience with chrome-extensions. Any suggestions or help on how I can achive this are highly appreciated
-- popup.js
let startStream = document.getElementById('gum');
function setStream(stream) {
if(stream != null){
video = document.getElementById('localStream');
if("srcObject" in video) {
console.log("videoelement supports scrObject.")
}
console.log('stream: ', stream)
video.srcObject = stream;
} else {
console.log("popup: passed stream is not definded")
}
}
startStream.onclick = function(element) {
console.log("popup start stream clicked");
chrome.tabs.query({
active: true,
currentWindow: true
}, tabs => {
chrome.tabs.sendMessage(
tabs[0].id,
{from: 'popup', action: 'startStream'},
setStream);
});
};
-- popup.html
<!DOCTYPE html>
<html>
<head>
<style>
button {
height: 30px;
width: 30px;
outline: none;
}
</style>
</head>
<body>
<video controls id=localStream></video>
<button id="gum">Start</button>
<script src="popup.js"></script>
</body>
</html>
-- content.js
console.log('content script init')
chrome.runtime.onMessage.addListener((msg, sender, response) => {
console.log(sender.tab ?
"message from a content script:" + sender.tab.url :
"message from the extension");
if (msg.from == "popup" && msg.action == "startStream"){
console.log('content script start stream action')
navigator.mediaDevices.getUserMedia({video:true, audio:true})
.then((stream) => {
console.log('content gum successfull: ', toString(stream));
console.log('stream: ', stream);
response(stream);
})
.catch((err) => {
console.log('content gum error: ' + error);
response(null);
});
return true;
}
});
-- manifest.json
{
"version": "1.0",
"name": "Some test",
"description": "Build an Extension!",
"manifest_version": 2,
"permissions": ["declarativeContent", "storage", "activeTab", "tabs"],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_idle",
"all_frames": false
}],
"browser_action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon-off-16.png",
"32": "images/icon-off-32.png",
"48": "images/icon-off-48.png",
"64": "images/icon-off-64.png",
"128": "images/icon-off-128.png"
},
"default_title": "World Domination"
},
"icons": {
"16": "images/icon-off-16.png",
"32": "images/icon-off-32.png",
"48": "images/icon-off-48.png",
"64": "images/icon-off-64.png",
"128": "images/icon-off-128.png"
}
}
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);
I need to build a chrome extension that manipulates dom
I am following some tutorial and now
I have this manifest.json:
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/"
]
}
This is my popup.html:
<!doctype html>
<!--
This page is shown when the extension button is clicked, because the
"browser_action" field in manifest.json contains the "default_popup" key with
value "popup.html".
-->
<html>
<head>
<title>Getting Started Extension's Popup</title>
<style>
body {
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
font-size: 100%;
}
#status {
/* avoid an excessively wide status text */
white-space: pre;
text-overflow: ellipsis;
overflow: hidden;
max-width: 400px;
}
</style>
<!--
- JavaScript and HTML must be in separate files: see our Content Security
- Policy documentation[1] for details and explanation.
-
- [1]: https://developer.chrome.com/extensions/contentSecurityPolicy
-->
<script src="popup.js"></script>
<script type="text/javascript">console.log('attempt #0 to console log something');</script>
</head>
<body>
<div id="status"></div>
<img id="image-result" hidden>
</body>
</html>
And this is my popup.js:
document.addEventListener('DOMContentLoaded', function() {
console.log('attempt #3');
});
chrome.tabs.onUpdated.addListener(
function ( tabId, changeInfo, tab )
{
if ( changeInfo.status === "complete" )
{
chrome.tabs.executeScript({ code: "console.log('attempt #4');" }, function() {
console.log("console.log(attempt #5)");
});
}
});
As you can see I tried various ways to console log something after page loaded but none of them work
what do I do?
So I think that the simple solution is just to create a content script and there to wait until the page is load :
manifest.json
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"content_scripts": [
{
//Set your address you want the extension will work in mataches!!!
"matches": ["http://mail.google.com/*", "https://mail.google.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"permissions": ["activeTab", "https://ajax.googleapis.com/"],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
content.js
window.onload=function(){
console.log("page load!");
}
You could also use with message passing between background.js and your content page and to check that tab is loaded but for your case I think it's enough.
This is how I do:
manifest.json
...
"background": {
"scripts": [
"assets/js/background.js"
],
"persistent": false
},
....
background.js
function openOrFocusOptionsPage() {
var optionsUrl = chrome.extension.getURL('popup.html');
chrome.tabs.query({}, function(extensionTabs) {
var found = false;
for(var i=0; i < extensionTabs.length; i++) {
if(optionsUrl == extensionTabs[i].url) {
found = true;
chrome.tabs.update(extensionTabs[i].id, {"selected": true});
}
}
if(found == false) {
chrome.tabs.create({url: "popup.html"});
}
});
}
chrome.extension.onConnect.addListener(function(port) {
var tab = port.sender.tab;
port.onMessage.addListener(function(info) {
var max_length = 1024;
if(info.selection.length > max_length)
info.selection = info.selection.substring(0, max_length);
openOrFocusOptionsPage();
});
});
chrome.browserAction.onClicked.addListener(function(tab) {
openOrFocusOptionsPage();
});
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..
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