How to download a file via a Chrome Content Script? - google-chrome-extension

This SO answer details how to download a file via a Chrome Extension, but I am using a Content Script, which has limited access to Chrome's APIs. In other words, I don't have access to the chrome.downloads object. I also tried this vanilla JS solution, but it did not work for me. Does anyone have a solution for Content Scripts or know why the second solution doesn't work?

Write a background page or event page and do it from there using the example in your linked answer. Communicate from/to the content script with chrome messages.

If you mean causing a file to be downloaded to the user's computer, this code will work in a Chrome extension content script or in the JS script an a regular webpage:
Firstly, you can cause a file to download without any JS at all by simply adding the "download" attribute to an anchor tag. With this tag, instead of navigating to the URL in the "href" attribute, the URL will be downloaded.
<a href="http://website.com/example_1.txt" download="saved_as_filename.txt" id="downloader">
static download link</a>
To update the URL dynamically:
var theURL = 'http://foo.com/example_2.txt';
$('#downloader').click(function() {
$(this).attr('href',theURL);
});
If you want the download to be initiated by something other than clicking on a link, you can simulate a click on the link. Note that .trigger() won't work for this purpose. Instead you can use document.createEvent:
$('#downloader').css('display','none');
function initiateDownload(someURL) {
theURL = someURL;
var event = document.createEvent("MouseEvent");
event.initMouseEvent("click", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
// dispatch event won't work on a jQuery object, so use getElementById
var el = document.getElementById('downloader');
el.dispatchEvent(event);
}
initiateDownload('example_3.txt');

Related

How would I make a chrome extension to block each tab's favicons?

I'm trying to replace all favicons with a Chrome extension with some Javascript. In order to do that I need to find the dom element that contains the favicon.
On most websites I can do something similar to this:
document.querySelector('link[rel="icon"]').href = "//data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
However on some websites such as apple.com, I can't figure out the dom element that contains the favicon by just viewing the page source, how would I go about blocking the favicon in that case?
I realized I was going about this all wrong. Instead of trying to replace the html element after the page was loaded, I should just block the network request which fetches the favicon.
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
return {cancel: ["favicon.ico", "favicon"].includes(details.url.split('/').pop().split('?')[0].split('#')[0]) };
},
{urls: ["<all_urls>"]},
["blocking"]);

Chrome Extension: access separate html documents from contentscript

I have a Chrome extension that loads/injects a contentscript.js This script appends html and css to the webpage.
Currently I have the html and css written into my contentscript. What I would like is for the css itself, as well as the body of my new elements to be in separate document, mostly so it looks better than having html and css as text in a .js document.
Then in the contentscript I would do something like
node = the_html_doc.html
document.getElementsByTagName("body")[0].appendChild(node);
But how do I access such a separate document from my contentscript? It needs to be available in all tabs (I use the activeTab permission), not just the url in the manifest "matches".
A better solution would be to use a background script. What I did was to make a file called background.html that would store nothing but templates. I then had my background script (background.js) setup to communicate with my content script (content.js). The content script would send a message to the background script with a command indicating it wants a template. Leveraging jQuery, i can easily select and return a template to my content script which can then be injected into the page.
Here is the code (bits an pieces):
background.html
<div id="template-1"></div>
<div id="template-2"></div>
...
background.js
chrome.runtime.onMessage.addListener(function(cmd, sender, sendResponse){
c = JSON.parse(cmd);
if(c.cmd == "GET_TEMPLATE"){
//respond with the template referenced by c.selector
sendResponse($(c.selector).outerHTML);
}
});
content.js
var command = {cmd:"GET_TEMPLATE", selector:"#template-1"};
chrome.runtime.sendMessage(JSON.stringify(command), function(response) {
//and here you should get your template
console.log(response);
//you can start using jQuery like $(response) to alter it
});
This method has worked flawlessly for me. I not only use commands here but I use them everywhere now, it works well with message passing.
You might be able to use the web_accessible_resources manifest setting, then in your content script you can just inject a link element that points to the chrome.extension.getURL(<filename>) value for the CSS, and inject a script element of type text/html with an id, and then fetch the contents of that node and use those for your appendChild call.

Chrome Extension that copies image URL on click

I'm brand new to making Chrome Extensions and have done the simple tutorials, but I'm having trouble finding what I need. I want the extension to allow a user to chose an image on a webpage, and then copy the URL for that image into the extension. Can anyone help me out? I'm sure if I see an example I'd get a better grasp on how extensions can interact with a page.
From what I understand of your question, I'd say you want to create a context menu item that shows up when you right-click an image. For example, in your background script, use:
chrome.contextMenus.create({
title: "Use URL of image somehow",
contexts:["image"],
onclick: function(info) {
handleImageURL(info.srcUrl);
}
});
function handleImageURL(url) {
// now do something with the URL string in the background page
}
This will add a context menu item that shows up on all pages, but only when you right-click on images. When the user selects it, the onclick handler of the menu item fires handleImageURL with the URL of the image as the argument. The URL can be processed in any way you like, e.g., saved in a localStorage list, sent to a server via Ajax, or passed in a message to a listening content script in the current tab.
EDIT with alternative:
You might want a content script that gets injected into every page. The script could bind an event listener to every image element at load time:
// in my_content_script.js...
var imgs = document.getElementsByTagName("img");
for(var i = 0, i < imgs.length; ++i) {
imgs[i].addEventListener("click", function() {
alert(this.src);
// do things with the image URL, this.src
});
}
To inject it into all subdomains of example.com, your manifest would include:
...
"content_scripts": {
"matches":["*://*.example.com/*"],
"scripts":["my_content_script.js"]
},
...
Note that this pure-JS solution doesn't attach listeners to images dynamically added after load time. To do that in your content script with jQuery, use:
$(document).on("click", " img", function() {
alert(this.src);
});
And add your jQuery file name to the scripts array in your manifest, next to my_content_script.js.
Based on this Google Chrome Extension sample:
var images = [].slice.apply(document.getElementsByTagName('img'));
var imageURLs = images.map(function(image) {
return image.src;
});
chrome.extension.sendRequest(images);
For a more detailed example (e.g. how to handle the request), you can check out this extension I wrote called Image Downloader

Chrome Tab Extensions: getCurrent vs. getSelected?

I'm writing a Chrome extension. As part of the extension, I want to get the URL of the tab that the extension was called from. What's the difference between using:
chrome.tabs.getSelected(null, function(tab) { var myTabUrl = tab.url; });
and
chrome.tabs.getCurrent(function(tab) { var myTabUrl = tab.url; });
?
Method chrome.tabs.getSelected has been deprecated. You should use chrome.tabs.query instead now.
You can't find the official doc for obsolete method chrome.tabs.getSelected. Here is the doc for method chrome.tabs.query.
getCurrent should be what you need, getSelected is a tab that is currently selected in a browser. When they could be different - maybe your extension runs some background cronjob in tabs, so that tab could be not currently selected by a user.
Ok I got it all wrong apparently. getCurrent should be used only inside extension's own pages that have a tab associated with them (options.html for example), you can't use it from a background or popup page. getSelected is a tab that is currently selected in a browser.
As to your original question - you probably need neither of those two. If you are sending a request from a content script to a background page, then the tab this request is being made from is passed as a sender parameter.
For those who is looking for working example of chrome.tabs.query instead of deprecated chrome.tabs.getSelected:
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function (tabs) {
var myTabUrl = tabs[0].url;
});

chrome extension inject in frameset code

i develop some extension for google grome
i inject at document_end event my js (+jquery)
i set in manifest allFrames: true
my match url has frameset
my goal get element by id inside one of frame
i do
//wait for load my frame
$("frame[name='header']).load(function() {
//here I need get element by id inside this frame
});
how to do this properly?
PS: my frame is from the same domain
You dont need to do document load, I assume your doing this from a content script. Just place the "run_at" manifest to be document_end and within your content script you check if the current URL is that frame page, then you will be in that Domain.
Something like this:
if(location.href == 'http://someweb.com/path/to/page.html') {
var foo = document.getElementById('foo')
Something like that will get you started.

Resources