I'm new to Chrome extension development, I need to make something sample with extension.
I Need to add JavaScript file to all sites I browse when the extension enabled, this is the code i want to add to all pages
<script type="text/javascript" src="web-retina-emulator.js"></script>
This file make pages look like when the website on retina display.
Is there easy way to make this happen?
You can use this basic structure to add JavaScript file to all sites when the extension enabled.
Method 1
If web-retina-emulator.js is an individual file which do not use global variables or functions of pages where it is injected it is suggested to use this method
Advantage:
It has access to certain sections of chrome API*
Draw Back
It can not use javascript variables and functions of pages where it is injected.
Demonstration
manifest.json
{
"name":"Custom Script",
"description":"http://stackoverflow.com/questions/14165629/add-javascript-file-to-all-sites-i-browse",
"version":"1",
"manifest_version":2,
"content_scripts":[{
"matches":["<all_urls>"],
"js":["web-retina-emulator.js"],
}
]
}
Method 2
If web-retina-emulator.js need some javascript methods or variables of pages, use this approach
Advantage:
It has access to javascript variables and methods of pages
Draw Back
It can not use chrome API*.
Demonstration
manifest.json
{
"name":"Custom Script",
"description":"http://stackoverflow.com/questions/14165629/add-javascript-file-to-all-sites-i-browse",
"version":"1",
"manifest_version":2,
"content_scripts":[{
"matches":["<all_urls>"],
"js":["myscript.js"],
}
]
}
myscript.js
var script = document.createElement('script'); // Create a Script Tag
script.src = chrome.extension.getURL("web-retina-emulator.js"); //Fetch the content script
script.onload = function () {
this.parentNode.removeChild(this); //Remove script after script executed
};
(document.head || document.documentElement).appendChild(script); //ADD script tag
//to head or Html element
Method 3
Inserting code into a page programmatically is useful when your JavaScript or CSS code shouldn't be injected into every single page that matches the pattern — for example, if you want a script to run only when the user clicks a browser action's icon.
Demonstration
background.html
chrome.tabs.executeScript(null,
{file:"web-retina-emulator.js"});
manifest.json
Ensure permissions are set in manifest file
"permissions": [
"tabs", "http://*/*"
],
References
Content Scripts
Execute Script API
Check out tampermonkey. It's the chrome equivalent to greasemonkey.
Related
I have many websites that has the following script tag in the head section:
<html>
<head>
<script>
window.doSomething(someObject);
</script>
</head>
<body>
.....
</body>
</html>
Now, I want to inject a script before any page loads so that these websites will have the access to the function doSomething which is defined my custom script. How do I make sure that my custom script is executed before any of the scripts in the HTML file?
I don't want to modify the front-end code. I thought of using extensions but they run after all the scripts on the page. Is there a way I can do this?
Even a Chrome specific way would suffice.
Declaratively injected scripts in Chrome extensions can be configured to run at document start:
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"run_at": "document_start",
"js": ["contentScript.js"]
}
],
...
}
Unfortunately that's not the whole story, because injected scripts run in an isolated environment, so you can't modify the window object of the page itself. You can, however, modify the DOM (which is still empty at this point) to add a <script> element that loads a script from your extension, as described in Method 1 in this answer. That second script will then run in the context of the page itself, and can do whatever it likes.
Is there a development tool or Chrome / Firefox extension that lets you replace the contents of a specific URL with my own custom content?
I'm not looking for a simple /etc/hosts file change, because I want to replace a URL, not just a domain.
In a Chrome extension, the webRequest API can be used to redirect URLs to a different URL. This other URL can be another online page, but also a page within your Chrome extension.
A simple example for the webRequest API, and a list of other options can be found in this answer.
Note: If you just want to add / change something on a specific page, Content scripts may be more suitable. You can then change the content of a specific page by standard DOM methods.
In Firefox, you can use the page-mod module of the Addon SDK to implement the Content script.
chrome.tab API will let you to make any related changes to a tab in a window.
References:
a) Tabs API
b) Basic Chrome Extension architecture.
You can refer this Sample Extension for changing all URL's in a current tab to Google.co.in
manifest.json
This is a core file where we register all chrome extension content, ensure it is with all permissions.
{
"name":"Tabs Demo",
"description":"This Demonstrates Demo of Tabs",
"browser_action":{
"default_icon":"screen.png",
"default_popup":"popup.html"
},
"permissions":["tabs"],
"manifest_version":2,
"version":"1"
}
popup.html
Trivial HTML file referring to a JS file to pass CSP.
<!doctype html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
</body>
</html>
popup.js
function tabsfunction() {
//fetching all tabs in window
chrome.tabs.getAllInWindow(function (tabs) {
// Iterating through tabs
for (tab in tabs) {
//Updating each tab URL to custom url
chrome.tabs.update(tabs[tab].id, {
"url": /*You can place any URL you want here*/
"https://www.google.co.in/"
}, function () {
//Call back
console.log("Completed");
});
}
});
}
//Binging a function on document events
document.addEventListener("DOMContentLoaded", tabsfunction);
Let me know if you need more information.
This is what I have here:
"manifest.json"
{..."permissions": [
"https:/mywebsite.com/"],"content_scripts": [{
"matches" : ["http://*/*", "https://*/*"],
"js": ["js/jquery-1.7.2.min.js", "contentScript1.js", "contentScript2.js"],
"all_frames" : true,
"run_at": "document_end"
} ]}
"contentScript1.js"
$(document).ready(function() {
$('#someDiv').load('https://mywebsite.com/index.html');}
"contentScript2.js"
function showMessage()
{alert ('Hello World!');}
"index.html"
<img src="https://mywebsite.com/images/myimage.png">
What I m actually doing here is injecting a clickable picture to the code of the the page that I m visiting and I expect that by clicking the picture a "Hello World" message will be appeared. Despite the fact that the content scripts and the picture are loaded succesfully, when I click on the image the function is not called and I get the following error in the console:
Uncaught ReferenceError: showMessage is not defined
I suppose that it cannot find the function as it is looking for it in the website that I have injected the code and not in the content scripts. But why is that, I mean if I call the function within the content script when it is loaded and not by clicking the image, the message appears. Can anyone get me out of here?
You did not understand my solution to avoid conflicts does not work with your current code. Instead of using $.noConflict, you're wrapping your script injection function in a $().ready method.
You have to remove jQuery from the "js" part of the manifest:
"js": ["contentScript1.js"],
And contentScript1.js
function injectJs(srcFile) {
var scr = document.createElement('script');
scr.src = srcFile;
document.getElementsByTagName('head')[0].appendChild(scr);
}
injectJs(chrome.extension.getURL('js/jquery-min.js'));
injectJs(chrome.extension.getURL('js/yourscript.js'));
Don't forget to add js/yourscript.js to web_accessible_resources, so that it can be used:
"web_accessible_resources": [
"index3.html",
"js/jquery-min.js"
"js/yourscript.js"
]
In js/yourscript.js, wrap your function logic in an anonymous function in conjunction with $.noConflict. $.noConflict(true) is used to avoid conflicts with scripts in the page. It restores the original value of $ and jQuery.
(function(jQuery, $) {
// Here, you can do anything you want.
// jQuery and $ refer to the same jQuery object from `js/jquery-min.js`
})(jQuery, jQuery.noConflict(true));
After looking at your question again, I noticed that you're loading content through ajax: $('#someDiv').load(...). When the script is injected, it runs in the scope of the page. That's why your AJAX call fails: The request is blocked because of the Same origin policy.
Now, we can use a different approach to fix your code. Instead of moving the logic from Content script to the page (by an injected script), we modify the page index.html. The click event is not pre-set, but added in the content script. For example:
"index.html":
<img src="https://mywebsite.com/images/myimage.png">
"contentscript2.js":
$('#showMessage').click(showMessage);
I think I m gonna answer my own question:
The reason that this happening is because content scripts run in an isolated world
see: http://code.google.com/chrome/extensions/content_scripts.html#execution-environment
So, you simply cannot call functions, once you injected some html code, in content_scripts to perform some work in the current page of user.
What you have to do is to inject your scripts in the page as you do with html code.
So:
(1) add the files you want to inject in web resources in your manifest file
see: http://code.google.com/chrome/extensions/manifest.html#web_accessible_resources
"web_accessible_resources": [
"Script2.js",
"index.html",
"jquery-1.7.2.min.js"]
(2) in contentScript1.js (load this as a content_script)
//inject your javascript files to the head of the page
function injectJs(srcFile) {
var scr = document.createElement('script');
scr.type="text/javascript";
scr.src=srcFile;
document.getElementsByTagName('head')[0].appendChild(scr);
}
injectJs(chrome.extension.getURL('jquery-1.7.2.min.js'));
injectJs(chrome.extension.getURL('Script2.js'));
//inject your html by loading query and passing your html page
$(document).ready(function() {
$('#someDiv').load(chrome.extension.getURL('./index.html'));}
That's all!
I'd like to make a very simple extensions that slightly alters how the Downloads page looks. Changing the History page might be interesting too, but that's for later.
Is there a way to do that?
I tried making a Content Script extension, with "chrome://downloads" as match in manifest.json. Chrome won't allow that and responds with an error when packaging the extension.
Is there another simple way? It has to be simple, because changes would be simple, because all chrome:// pages are built with HTML, JS and CSS.
edit
After trying with background scripts a little...
I can't get chrome.tabs.executeScript to work! I added in background.html:
chrome.browserAction.onClicked.addListener(function(tab) {
alert(this.document.body.innerHTML);
alert(chrome.tabs.executeScript(null, {
code : "document.body.style.backgroundColor = 'red';"
}));
});
And I added this in manifest.json to add a (invisible) 'browser action button':
,"browser_action": {
/* "popup": "background.html",*/
"name": "Alter page"
}
The onClicked event fires both alerts (first is background.html's body, second is undefined). But the code (a string with document.body.style.backgroundColor = 'red';) doesn't execute! And ofcourse there's no debugging for extensions like this =)
Any tips anyone? I'm trying to get a hold of the tab's window.document (not background.html's window.document!). An injected script (that's what chrome.tabs.executeScript is supposed to do) should do that.
PS
I'm stealing from make_page_red/manifest and make_page_red/background.html
The 'extension' I have so far: http://hotblocks.nl/js/downloads.rar
EDIT
I found out what I want to achieve is possible with just CSS. I don't need to inject javascript. Does that make it easier? Does that make it possible? =)
According to this documentation, chrome:// URLs are an invalid scheme so they won't be matched:
A match pattern is essentially a URL that begins with a permitted scheme (http, https, file, or ftp), and that can contain '*' characters.
I would look into using override pages instead.
As requested, here's my extension that can at least load when chrome://downloads is loaded, although as I said, I don't think you can modify the page even if you know that's the page you're viewing.
manifest.json
{
"name": "Test",
"version": "0.0.1",
"background_page": "background.html",
"permissions": [
"tabs"
]
}
background.html
<script>
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab)
{
if (tab.status == "complete")
{
alert(tab.url);
// should alert 'chrome://downloads' on that page. You can
// check for this url here and then do whatever you want
}
});
</script>
Update: Since Chrome 31 there is an API for extensions that allows access to Chrome's downloads: https://developer.chrome.com/extensions/downloads
There's also an API that allows access to list and manage other installed extensions: https://developer.chrome.com/extensions/management
(Previous Answer)
Unfortunately, there's not currently an API for Chrome extensions to access information about a user's downloads. It's a widely requested feature, though, and there's some discussion among Chrome developers here: http://code.google.com/p/chromium/issues/detail?id=12133
Star the issue if it's a feature that you'd like to see, and you'll receive email updates.
As this page shows, there is no API to override the downloads page... However, there is a way to make a file you have made replace the chrome://downloads/ page whenever it is loaded using javascript in your background page...
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if(changeInfo.status === "loading"){
if(tab.url === "chrome://downloads/"){
chrome.tabs.update(tab.id, {url: "REPLACEMENT.html"});
}
}
});
Essentially what this does is - As soon as the page chrome://downloads begins loading (using the tabs.onUpdated API), the page is redirected to REPLACEMENT.html (Using tabs.update API)... There is no visible delay in the tab update
as this script is run before the chrome://downloads page begins loading... You can use a similar code in your file by pressing CTRL + U on the downloads page to view and copy its source code
I want to create a tab by clicking on the browser action button and then insert a content script or execute a script. So far, its not working well.
Background.html
chrome.browserAction.onClicked.addListener(function(tab)
{
chrome.tabs.create({url: "Dreamer.html"}, function(tab) //Dreamer.html is a file in my extension
{
//Add a script
chrome.tabs.executeScript(tab.id, {file:'Dreamer.js'});
});
});
Manifest.json
{
"name" : " Dreamer",
"version" : "0.1",
"description" : "My extensionr",
"browser_action" : {"default_icon" : "App/AppData/Images/icon.png", "default_title":"Start Dreamer" },
"background_page" : "App/AppData/background.html",
"content_scripts" :[{"matches":["http://*/*"],"js":["app/view/UIManager.js"]}],
"permissions": [ "cookies", "tabs", "http://*/*", "https://*/*" ]
}
i get this error in the background page
Error during tabs.executeScript: Cannot access contents of url "chrome-extension://femiindgnlfpdpajimkmldpgpccngfmd/Dreamer.html". Extension manifest must request permission to access this host.
I would really like to know how to create a tab(new tab) and run a script immediately
EDIT:
The kind of application i am creating requires the following actions:
-Allow user to create new tab by clicking the browserAction button
-On creation of the new tab, a file in my extension (Dreamer.html) is opened
-Add a content script or execute a script in the new tab
Thanks
Is there any particular reason you need to inject the script? Since both Dreamer.html and Dreamer.js seem to be hardcoded, you could just include <script type="text/javascript" src="Dreamer.js"></script> in the former, right?
As a side benefit, if you need it to send info to the background page, you can access it directly with chrome.extension.getBackgroundPage() instead of setting up complex listeners that usually come with content scripts, too.
Injecting content scripts is for injecting scripts outside the extension sandbox. Dreamer.html, however, is a part of the extension.
Edit
If you do want an (unwieldy) example of how to execute a script in an extension page, see here:
http://code.google.com/p/chromium/issues/detail?id=30756#c11
I don't think it applies to your case, however.