Injecting Javascript into Newly Created Tab in Chrome Extension - javascript

I am attempting to make a chrome extension that creates a new tab with a local 'blanksite.html' and injects some javascript code turning it green. Here's what I have so far.
background.js
chrome.browserAction.onClicked.addListener(function(activeTab){
chrome.tabs.create({'url': chrome.extension.getURL("blanksite.html") }, function(tab) {
chrome.tabs.executeScript(tab.id, {
code: 'document.body.style.backgroundColor="green"'
});
});
});
manifest.json
{
"manifest_version": 2,
"name": "Open Green Google Tab",
"description": "This extension opens a Green Google tab.",
"version": "1.0",
"background":{
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": "icon.png"
},
"permissions": [
"tabs",
"activeTab"
]
}
This opens "blanksite.html" (literally an empty html file) in a new tab, but does not turn the tab green.
I've read the other answers at Chrome extension: create tab then inject content script into it, so I know why this doesn't work (not able to directly inject code into chrome://extension pages); but I wasn't able to make the solutions posted on the other answers work for me. Is there a clear, full piece of small code that can make what I want to do work?
I'm afraid I do not understand messaging very well, so for any solution that has that as a piece, a more comprehensive explanation would be greatly appreciated.

Not sure why starting message passing from background page to blanksite.html won't succeed (maybe it's too late to listen to message in blanksite.html when it's created?).
However, starting message passing from blanksite.html and executing corresponding action in the response work well, see following sample code:
blanksite.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="blanksite.js"></script>
</body>
</html>
blanksite.js
chrome.runtime.sendMessage({src: "newtab"}, function(response) {
if(response.action === 'changeColor') {
document.body.style.backgroundColor = 'green';
}
});
background.js
chrome.browserAction.onClicked.addListener(function(activeTab) {
chrome.tabs.create({url: chrome.runtime.getURL('newtab.html')});
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request.src === 'blanksite') {
sendResponse({action: 'changeColor'});
}
});

Related

Chrome extension programmatic script injection error

Following up on a previous post, I am now trying to create a version of a Chrome extension that does not specify content_scripts: or matches: in the manifest.json file; instead the content script is to be injected programmatically by a en event triggered from the options page which prompts the user to grant optional permissions for executing the content script. The rationale is to be able to have the extension working on pages from hosts with different top-level domain names (see previous post for details). I have read the documentation on this and tried to connect the dots, but I'm not quite getting there.
Below is a demo version of what I have created so far. I manage to get the optional permissions request processed and the user prompt for granting that request shown (the alert "granted!" is displayed). However, when I try to have the message listener in background.js execute the script content.js (by removing the /* commented-out code */ there), I get the error message
Unchecked runtime.lastError: Cannot access contents of url
"chrome-extension://[blah]/options.html". Extension manifest must
request permission to access this host.
Any guidance as to what I have missed here would be most welcome.
I also have a second question: since I am using jQuery in the content.js script, do I have to execute the jQuery.js file as well in response to the granted permission, and if so, should that be done by adding another separate chrome.tabs.executeScript() command?
manifest.json:
{
"manifest_version": 2,
"name": "My Extension",
"version": "1",
"description": "Demo extension",
"options_page":"options.html",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"optional_permissions":["tabs","https://*/*"],
"permissions": ["activeTab","storage"]
}
options.html:
<html>
<head>
<style>
button#permreq{font-size:2em;}
</style>
</head>
<body>
<button id="permreq">Click this button to enable My Extension</button>
<script src="jQuery.js"></script>
<script src="options.js"></script>
</body>
</html>
options.js:
jQuery(function($){
$(document).ready(function(){
$("button#permreq").click(function(){
chrome.permissions.request({
permissions: ['tabs'],
origins: ["https://*/*"]
}, function(granted) {
if (granted) {
chrome.runtime.sendMessage("granted");
} else {
alert("denied");
}
});
});
});
});
background.js:
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "granted"){
/*chrome.tabs.executeScript({
file: "content.js"
});*/
alert("granted!");//no errors as long as above code is commented out
} else{
alert("denied");
}
});

I got a error "browser is not defined" in the console when I try create Bookmark in chrome

I am trying create a bookmarks (on this case in chrome)
API/bookmarks/create
my code is :
function onCreated(node) {
console.log(node);
}
var createBookmark = browser.bookmarks.create({
title: "bookmarks.create() on MDN",
url: "https://developer.mozilla.org/Add-ons/WebExtensions/API/bookmarks/create"
});
createBookmark.then(onCreated);
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<p>text example</p>
</body>
</html>
I got this error when I run the code in chrome:
Uncaught ReferenceError: browser is not defined
I run other code this :
function onFulfilled(bookmarkItems) {
if (bookmarkItems.length) {
console.log("active tab is bookmarked");
} else {
console.log("active tab is not bookmarked");
}
}
function onRejected(error) {
console.log(`An error: ${error}`);
}
function checkActiveTab(tab) {
var searching = browser.bookmarks.search({url: tab.url});
searching.then(onFulfilled, onRejected);
}
browser.browserAction.onClicked.addListener(checkActiveTab);
from :here I got the same error.
Update question :
my manifest.json in this moment:
{
"name": "add site random",
"version": "1.0",
"description": "this is my first extension in production",
"manifest_version": 2
}
any idea because I have this error I am trying create a folder and add a site in my bookmarks from the code?
From your recent edit and by looking at your manifest.json it looks like you are missing few permissions field,
Hence update your manifest.json like this, (then package a new extension afresh)
{
"name": "add site random",
"version": "1.0",
"description": "this is my first extension in production",
"manifest_version": 2,
"background": {
"scripts": ["YOUR_BACKGROUND_SCRIPT_NAME.js"]
},
"permissions": [
"notifications",
"activeTab"
]
}
Hope this helps!
Aside from missing script calls within the manifest file, which after checking the commented gist link appears to have been resolved (good catch #DavidR!), however, both versions of the question's code are still missing a reference to the manifest file from within the html's <head> block, eg. something like <link rel="manifest" href="/manifest.webmanifest"> as suggested by Mozilla might just allow ya past the current issues.
For completeness sake the following is what I perpose you do to that index.html file...
<!DOCTYPE html>
<html>
<head>
<link rel="manifest" href="/manifest.webmanifest">
<title>test</title>
</head>
<body>
</body>
</html>
... and I'll also suggest renaming the manifest file to have the webmanifest extension because of reasons related to the specification.

I wanted to build a chrome extension that will update some page but without any popup

I wanted to build a chrome extension that will update some page (from other source/page) without any popup (the question is silly as I know as I am new in extension dev)
For example, I had my manifest.json:
{......
"browser_action": {
"default_icon": "icon.png",
"default_title": "My chrome extension title"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/"
]
......
}
background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.create({ url: "pageloader.html" });
});
pageloader.html:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function () {
$("#status").append("hello chrome extension");
})
</script>
<title>Page loader</title>
</head>
<body>
<div id="status">
</div>
<p>hello</p>
</body>
</html>
When I open 'pageloader.html', javascript is just running fine and showing the output in the browser like:
hello chrome extension
hello
But when I run install the extension and clicking on the 'extension' it is opening 'pageloader.html' in the new tab but showing only
hello
I mean, the javascript part is not running. I will appreciate, if someone would show me my mistake.
CSP does not allow inline javascript and loading resources like jquery from external servers. In order to make it work.
Download jquery and save it in local directory under extension folder.
Move the inline javascript in external file and then include this file after jquery.
If you want to relax the default policy : https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing

Chrome Apps, FileSystem API: chooseEntry method isn't working

Edit: Found the error, but can't solve it, see below.
manifest.json
{
...
"offline_enabled": true,
"app": {
"background": {
"persistent": true,
"scripts": [
"/js/background.js"
]
}
},
"permissions": [
"notifications",
"storage",
{"fileSystem": ["directory"]}
]
}
background.js
chrome.app.runtime.onLaunched.addListener(function() {
window.open('/index.html');
});
index.html
<!DOCTYPE html>
<html>
<head>
<title>Achshar Player</title>
<script src="/js/index.js"></script>
</head>
<body>
<input id="input" type="button">
</body>
</html>
index.js
window.addEventListener('load', function() {
document.getElementById('input').addEventListener('click', function() {
chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {
console.log(readOnlyEntry);
});
});
});
The method is called and so is the callback, but the file choosing dialogue never comes and the readOnlyEntry is undefined when the callback is executed. No errors on the dev tools, I am on 35.0.1916.153 m.
I have tried different variations of manifest declarations for fileSystem but since the function is not undefined in the script execution, the manifest is unlikely to be the issue.
When I use the official example extension of fileSystem API the app works, so the chrome setup isn't the problem either. The problem seem to be my code, but I am lost here.
Edit: I added each file's content
Edit 2: Found the error, now how to solve it?
I tried it in canary and realize the errors are shown via chrome.runtime.lastError and not the normal console. And this is the error I get.
Invalid calling page. This function can't be called from a background page.
But this is not in background.js, this is in index.js which is called from index.html.
I just tried this in Chrome, and there doesn't seem to be anything wrong with the code that you've posted. I suspect that there is a problem with the way that you are loading the javascript, or possibly the context that it is running in (foreground page vs. background page)
For instance, if your JavaScript code snippet is actually in main.js, then that will run in the background page, and its window and document elements won't be the ones from your main page.
My test app looks very similar to yours, except that I have left out the main.js file from the manifest, and I have constructed a small index.html file, which loads a foreground.js script instead. This is the complete app:
manifest.json
{
"manifest_version": 2,
"name": "Stack overflow question test app",
"version": "1",
"offline_enabled": true,
"app": {
"background": {
"persistent": true,
"scripts": [
"/js/background.js"
]
}
},
"permissions": [
"notifications",
"storage",
{"fileSystem": ["directory"]}
]
}
js/background.js
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create("index.html");
});
index.html
<!DOCTYPE html>
<html>
<head>
<title>TEST</title>
<script src="js/foreground.js"></script>
</head>
<body>
<input id="input" />
</body>
</html>
js/foreground.js
window.addEventListener('load', function() {
document.getElementById('input').addEventListener('click', function() {
chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {
console.log(readOnlyEntry);
});
});
});
When I run this, I can click on the input element, and I see a file picker. Choosing an entry returns a FileEntry object, which is logged to the console (of the foreground page, not the background page. Right-click in the app window and select "Inspect Element", rather than "Inspect Background Page", to see the foreground console.):
FileEntry {filesystem: DOMFileSystem, fullPath: "/TestFile.rtf", name: "TestFile.rtf", isDirectory: false, isFile: true…} foreground.js:4
Note:
From your original code, it appeared that you were using a framework like jQuery to search for DOM elements within your page. Chrome Apps work just fine with jQuery, but you have to be aware of when you are using a raw DOM Node object, and when you have a wrapped jQuery object.
Specifically, the line
$('input').addEventListener('click', function() {
would have caused you problems.
Replacing it with
document.querySelector('input').addEventListener('click'), function() {
would correctly find the element on the page, and attached the click handler to it.

Scripts defined in content scripts but not accessible in popup (Chrome extension)

I'm new in javascript and chrome extensions (this is first application).
Extension get a QRcode of the open page's URL.
For QRcode generation I use this lib: https://github.com/jeromeetienne/jquery-qrcode
I read some quides and many answers on SO, but extension doesn't work.
All *.js libraries are in the root catalog with manifest.json
manifest.json
{
"manifest_version": 2,
"name": "QRify",
"description": "This extension shows a QR code of the open page",
"version": "1.0",
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"js": [
"jquery.min.js",
"jquery.qrcode.js",
"jquery.qrcode.min.js",
"qrcode.js"
]
}
],
"browser_action":{
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<title>basic example</title>
</head>
<body>
<script src="popup.js"></script>
</body>
</html>
popup.js
var pathname = window.location.pathname;
jQuery('#URLqrcodeCanvas').qrcode({
text : pathname
});
Most likely I forgot something...
There are few things which are wrong in your code. Let's take them step by step
Inclusion of both jquery.qrcode.js and jquery.qrcode.min.js : In production code, we try to use minified jquery because downloading of minified js files is faster.
No element with selector used in popup.js : You are trying to access URLqrcodeCanvas in your popup.js while no such element is present in popup.html. May be you should add this
You have not included jquery and qrcode in your popup.html : You need to understand the context of content script, popup scripts and background scripts. Read this
SO Answer: Difference between popup script, background and content script
Wrong use of window.location.pathname : May be you wanted to access the path of current active tab instead of popup. Once you understand the difference between popup and content script then you will be easily figure out this point. Read this
SO Answer: How to get url of active tab ?
Thanks to #Abraham for adding points 3 and 4 in this answer. Hope it helps!!

Categories

Resources