I'm developing a chrome extension. It will make it possible to press a button, and it will capture a screenshot of your screen, then you will be able to save it to your computer.
However after attempting to load my extension at chrome://extensions/
I'm getting either of 2 messages:
"Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
"Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem:". Either the 'unsafe-inline' keyword, a hash ('sha256-0xoq3Fm+45tEb3FQIwY9RYnpdCuDu/FcIzz/s1HPTAM='), or a nonce ('nonce-...') is required to enable inline execution."
I've been at this for a long time now and can't seem to find the problem. I have inserted the codes below, can anyone help me fix this?
Might be even the smallest oversight from my part, but would be super grateful for any help.
See code below:
manifest.json
{
"manifest_version": 2,
"name": "MySnap",
"description": "Take a screenshot of a selected portion of the screen",
"version": "1.0",
"permissions": [
"tabs",
"activeTab"
],
"browser_action": {
"default_icon": "icon.png",
"default_title": "MySnap",
"default_popup": "popup.html"
},
"content_security_policy": "script-src 'self' 'sha256-Ws4H0eytNaM/o8NllzTlOPZFeyohSxu1N5dQ7JOcjMI='"
}
popup.html
<!DOCTYPE html>
<html>
<head>
<title>MySnap</title>
</head>
<body>
<h1>MySnap</h1>
<button id="screenshot-button">Take Screenshot</button>
<div id="screenshot-container"></div>
<script src="screenshot.js"></script>
<script>
document.getElementById("screenshot-button").addEventListener("click", function() {
chrome.runtime.sendMessage({message: "take_screenshot"}, function(response) {
// Do something with the response
});
});
</script>
<script>
function takeScreenshot() {
chrome.runtime.sendMessage({message: "take_screenshot"}, function(response) {
if (response && response.screenshotUrl) {
// Create a link element and set its href to the screenshot URL
var link = document.createElement("a");
link.href = response.screenshotUrl;
// Set the download attribute of the link element
link.download = "screenshot.png";
// Append the link element to the DOM
document.body.appendChild(link);
// Click the link to initiate the download
link.click();
// Remove the link element from the DOM
document.body.removeChild(link);
}
});
}
</script>
</body>
</html>
screenshot.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "take_screenshot") {
chrome.tabs.captureVisibleTab(null, {}, function(screenshotUrl) {
sendResponse({screenshotUrl: screenshotUrl});
});
}
return true;
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "take_screenshot") {
chrome.tabs.captureVisibleTab(null, {}, function(screenshotUrl) {
sendResponse({screenshotUrl: screenshotUrl});
});
}
});
You can make the screenshot in the popup script, no need for messaging.
remove content_security_policy from manifest.json
remove all <script> elements from popup.html except <script src="screenshot.js">
remove background.js
// popup.html:
<!DOCTYPE html>
<h1>MySnap</h1>
<button id="screenshot-button">Take Screenshot</button>
<div id="screenshot-container"></div>
<script src="screenshot.js"></script>
// screenshot.js:
document.getElementById('screenshot-button').onclick = () => {
chrome.tabs.captureVisibleTab(url => {
const el = document.createElement('a');
el.href = url;
el.download = 'screenshot.png';
document.body.appendChild(el);
el.click();
el.remove();
});
};
Related
After recent update of chrome browser to Version 57.0.2987.133 (64-bit)
my extension stopped working.Following is the explanation of the working on extension:
Popup.js
document.addEventListener('DOMContentLoaded', function() {
chrome.tabs.getSelected(null, function(tab) {
d = document;
var f = d.createElement('form');
f.action = 'https://example.com/login';
f.method = 'post';
var i = d.createElement('input');
i.type = 'hidden';
i.name = 'url';
i.value = tab.url;
console.log(tab.url);
f.appendChild(i);
d.body.appendChild(f);
f.submit();
});
});
popup.html
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery-2.1.1.js"></script>
<script src="popup.js"></script>
<style type="text/css">
.image {
display: block;
margin-left: auto;
margin-right: auto
}
</style>
</head>
<body style="width: 350px;height:340px;">
<h3>Connecting to server please wait ...</h3>
<br/>
<br/>
<br/>
<img src="/loader.gif" alt="Please Wait" class="image" align="middle">
</body>
</html>
manifest.json
{
"update_url": "https://clients2.google.com/service/update2/crx",
"manifest_version": 2,
"name": "test name",
"description": "test description",
"version": "0.1.2",
"browser_action": {
"default_icon": "128.png",
"default_popup": "popup.html"
},
"icons": {
"16": "128.png",
"32": "128.png",
"64": "128.png",
"128": "128.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"web_accessible_resources": [ "128.png" ],
"permissions": [
"tabs"
]
}
Before the chrome update, extension was working fine.
- I am submitting a form with post method.
- I am sending a key 'url' which I am checking on server site if the request is from extension and thus loading login form for extension. - Once the extension login loads into the popup, user logs in and is redirected to appropriate page within the popup.
This is the flow of extension. But after the update, Loading continues on popup. The form submit request is being cancelled by the browser. On googling about the problem, I found using ajax post method for submitting the form instead of direct form submit. This method was able to fetch the login form from but that without any css and js of the webpage as the urls were relative in the page and chrome extension id was prepended as the base url with all the links. So, I changed those urls to absolute but the submit functionality was not working again as it was again a form. Again I changed the form submit into ajax post submit request on server side. But the javascript written over the webpage is not working in chrome extension.
So question is how to make the extension work which was working earlier?
chrome.tabs.getSelected() is deprecated since Chrome 33. try using chrome.tabs.query({ active: true }) like this:
document.addEventListener('DOMContentLoaded', function() {
chrome.tabs.query({ active: true }, function(tabs) {
var tab = tabs[ 0 ];
d = document;
var f = d.createElement('form');
f.action = 'https://example.com/login';
f.method = 'post';
var i = d.createElement('input');
i.type = 'hidden';
i.name = 'url';
i.value = tab.url;
console.log(tab.url);
f.appendChild(i);
d.body.appendChild(f);
f.submit();
});
});
I've been encountering an issue where the DOMContentLoaded event appears to fire before the DOM is fully rendered. This has been an issue since my Chrome updated to 57.0.2987.133.
Perhaps you could use the window load event instead.
window.addEventListener('load', function() {
I want to have several html files in my extension so I can open each of them according to some conditions or events. Say I want a.html to be opened when the user chooses an option on the context menu.
I tried the following:
manifest.json:
{
"name": "My extension",
"version": "1.1",
"background": { "page": ["background.html"] },
"incognito": "split",
"permissions": ["tabs", "<all_urls>", "contextMenus"],
"icons": { "16": "images/16.png" },
"manifest_version": 2
}
background.html:
<!DOCTYPE html>
<html>
<head>
<script src="background.js"></script>
<script src='someWindow.js'></script>
</head>
<body>
</body>
</html>
background.js:
var winID;
chrome.contextMenus.onClicked.addListener(function proccess_interested(info, tab){
chrome.tabs.create({active: false}, function(newTab) {
// After the tab has been created, open a window to inject the tab into it.
chrome.windows.create(
{
tabId: newTab.id,
type: "popup",
url: chrome.extension.getURL('a.html'),
focused: true
},function(window){
winID = newWindow.id;
});
});
})
chrome.extension.onMessage.addListener(function(Msg, sender, sendResponse) {
if(Msg.close_comment_win){
chrome.windows.remove(winID, function(){});
}
});
someWindow.js:
function hide_win()
{
chrome.extension.sendMessage({close_win: close}, function(response) {});
}
a.html:
<!DOCTYPE html>
<html>
<head>
<script src='someWindow.js'></script>
head //with tags, can't show it here
body
<input type='button' value=' Cancel ' onclick="hide_win()"></input>
</body>
</html>
The window is opened when context menu is clicked, but when hitting cancel, it's not closed. console.log says: Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:". I guess the reason is that a.html is not part of the extension, even though someWindow.js which triggers sendMessage is part of the extension.
Including a.html in the extension through manifest isn't an option as no more than one background html page can be included.
Of course I get the same when putting chrome.windows.remove(winID, function(){}); directly in hide_win() without using sendMessage.
Any ideas how to get this job done?
Just as the error says, it is against v2's content security policy to have any inline code in extension html pages. Simply move that handler to your js file and it should work fine.
I'm trying to write a trivial Chrome pageAction extension to change all anchors on a page from one domain to another... but I can't quite seem to get it to work, and I'm having trouble debugging it.
Am I misunderstanding how this kind of extension needs to be built? Or am I just misusing the API?
manifest.json:
{
"name": "theirs2ours",
"version": "1.0",
"description": "Changes all 'their' URLs to 'our' URLs.",
"background_page": "background.html",
"permissions": [
"tabs"
],
"page_action": {
"default_icon": "cookie.png",
"default_title": "theirs2ours"
},
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["content.js"]
}
]
}
background.html:
<html>
<head>
<script type='text/javascript'>
chrome.tabs.onSelectionChanged.addListener(function(tabId) {
chrome.pageAction.show(tabId);
});
chrome.tabs.getSelected(null, function(tab) {
chrome.pageAction.show(tab.id);
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.sendRequest(tab.id, {}, null);
});
</script>
</head>
<body>
</body>
</html>
content.js:
var transform = function() {
var theirs = 'http://www.yourdomain.com';
var ours = 'http://sf.ourdomain.com';
var anchors = document.getElementsByTagName('a');
for (var a in anchors) {
var link = anchors[a];
var href = link.href;
if (href.indexOf('/') == 0) link.href = ours + href;
else if (href.indexOf(theirs) == 0) link.href = href.replace(theirs, ours);
}
};
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
transform();
});
I think this is not the way to do the extension you want.
First of all, I assume you want to replace the anchors when you click the page action button.
The manifest you have injects content.js on every page, no matter if you click or not the page action button.
I suggest you remove the content_scripts field from your manifest, and inject content.js manually, with
chrome.tabs.executeScript(tabId, {file:'content.js'})
You should do this in the page action's click listener.
By the way, in that listener you are sending a request to the content script, but it hasn't a listener to listen to such request message. In this extension you won't need to use senRequest.
You're not requesting permission to run content scripts on these pages. The matches for content scripts determines what pages they are executed in but you still need to request permission to inject scripts in to these pages.
"permissions": [
"tabs",
"http://*/*"
]
this is my manifest.json file
{
"name": "My First Extension",
"version": "1.0",
"description": "The first extension that I made.",
"background_page": "background.html",
"page_action":
{
"default_icon": "icon.png"
},
"permissions" : [
"tabs"
]
}
This is the background.html
<html>
<head>
<script>
// Called when the url of a tab changes.
function checkForValidUrl(tabId, changeInfo, tab) {
// If the letter 'page' is found in the tab's URL...
if (tab.url.indexOf('google') > -1) {
// ... show the page action.
chrome.pageAction.show(tabId);
}
};
// Listen for any changes to the URL of any tab.
chrome.tabs.onUpdated.addListener(checkForValidUrl);
chrome.pageAction.onClicked.addListener(function(tab)
{
tab.url = 'www.bing.com';
console.log('I am clicked');
}
);
</script>
</head>
</html>
when i click on the page action icon , i want to redirect the page to Bing.com, but this click event is not working for me.
Thanks
If you want to redirect a tab you need to use:
chrome.tabs.update(tab.id, {url: "http://www.bing.com"});
You also need to check for status of the page as checkForValidUrl will be executed twice for every page:
function checkForValidUrl(tabId, changeInfo, tab) {
if(changeInfo.status === "loading") {
//...
}
});
Have u tried using javascripts window.location function instead? e.g:
window.location="http://www.bing.com";
If that doesn't work then it's probably a problem with your event listener I would have thought.
I'm new to the Chrome extensions development, and i have the following questions:
My extension should work in background, with no UI, and show an alert dialog every time the user visits a specific web page. So it should work always, in backround, when the browser is executed.
I was trying with the following code without results:
manifest.json
{
"name": "My First Extension",
"version": "1.0",
"description": "The first extension that I made.",
"background_page": "background.html",
"permissions": [
"history"
]
}
background.html
<html>
<head>
<script>
chrome.history.onVisited.addListener(function(HistoryItem result) {
if (result.url == "http://my.url.com") {
alert("My message");
}
});
</script>
</head>
</html>
What's wrong with this code?
Thanks
Take HistoryItem out of the function and you are fine:
<html>
<head>
<script>
chrome.history.onVisited.addListener(function(result) {
if (result.url == "http://my.url.com/") {
alert("My message");
}
});
</script>
</head>
</html>
Also note that I added the slash at the end of "http://my.url.com/" since that is what will be returned in result.url.
Test this:
<script>
chrome.history.onVisited.addListener(function(e) { console.log(e)})
</script>
it's clearly