I'm trying to dynamically generate an anchor for a given content (documents and/or images stored on Cloudinary.io, in this case), but the documents I'm storing have a hash value rather than a filename (i.e.: c9eed62bd1534c382a3b89241b24b1ddd17b3793 instead of sample.pdf).
Here's the function I'm using to generate the anchor:
function download(url, download) {
if (url) {
var a = document.createElement('a');
if (a) {
a.href = url;
a.download = download || '';
a.target = '_blank';
a.click();
}
}
}
The problem I have is, when I execute the function, the browser downloads the file for me, but with the name in the href attribute rather than the download attribute.
This is the event I use to fire the download:
$('.link').on('click', function (e) {
download($(this).data('url'), $(this).data('name'));
});
And this is a sample HTML element containing the data to trigger the event:
<span class="link" data-url="http://res.cloudinary.com/dxsky7h00/raw/upload/v1483364241/627ec3e4afa08749ac4aff8d2917a38f586a5790" data-name="fs545554545454.xls"><i class="icon-file-o"></i>fs545554545454</span>
Maybe I understood the download attribute for the <a> element in a wrong way, but I thought, when specified, it forces the browser to download the resource rather than trying to open it on one hand and, on the other hand, if download="something" is used, the resource will be downloaded with the name being 'something' rather than what's in the href attribute.
What am I missing for this sample function to work?
EDIT I'm currently testing this on Chrome 55.0.2883.87 (64-bit), but as this entry on caniuse.com states, it's compatible
#tsh asked the right question. The problem lies in the fact the href attribute references an external resource, hence we're dealing with a cross-origin reference and the browser won't let me download it with another name.
I tested it with a local file and it worked, so the problem lies within my implementation. Thanks to all anyway :)
Related
In my application, i am trying to download html of current page which is with same domain name. I have written some method to download the html and it is downloading.
But, i have tried to open it in chrome as well as edge and it is not opening. But, in IE it is opening and displaying text of noscript tag (We're sorry but app doesn't work properly without JavaScript enabled.Please enable it to continue.).
I am inputting intranet site URL and clicking the download button. Here is my method below.
downloadHtml() {
let url = this.urlInput; // input text v-model value
fetch(url)
.then((res) => res.text())
.then((html) => this.downloadAsFile("report.html", html)); // by this name it is downloading
},
downloadAsFile(name, text) {
const link = this.createDownloadableLink(name, text);
const clickEvent = new MouseEvent("click");
link.dispatchEvent(clickEvent);
},
createDownloadableLink(fileName, content) {
let link = document.createElement("a");
link.href = 'data:attachment/text,' + encodeURIComponent(document.documentElement.outerHTML);
link.target = '_blank';
link.download = fileName;
return link;
},
**The problems are :
1. The app root signifies the public/index.html and that downloaded html is this one not the current page's html.
2. Chrome or Edge is not opening that html page even i checked browser is javascript enabled.
So, what i have to change the download the current page html?
The problem is that an HTML file in not an application/octet-stream file type. The mime type of an HTML page is text/html
I'm unsure of the way you try to create your download link. I don't have time to test it, but there is the way I do it usually using the createObjectURL API :
async function fetchHTML(url) {
let content = await fetch(url).then(resp => resp.text());
let file = new Blob([content],{type:'text/html'});
let href = window.URL.createObjectURL(file);
let a = document.createElement('a');
a.href = href;
a.setAttribute('download', 'report.html');
document.body.appendChild(a);
a.dispatchEvent(new MouseEvent('click'));
}
Another problem is that you don't append your link into the DOM in the code you provided. So the DOM cannot trigger your mouse event and so starting the download (it's needed by some browsers).
With the good mime type, the file in a proper format and a link in to the dom, it should be ok.
I'd like to set the file name and format of a "non-typical file", for a lack of better words. The files are stored at locations such as the following...
let link = https://.../videoplayback?ipbits=0&initcwndb...D134213BA9465CB74DFD36CDE47BF.102638C4A9F3ACA357F79EE747DD5F49F1E0F0DE
When one downloads such files, even if they are completely different files, they always end up being saved with the same name and never a file extension.
I've tried url.download = link + '.mp4', but this has no effect whatsoever.
How can I do this?
According to the MDN for anchor tags with the download attribute:
Can be used with blob: URLs and data: URLs, to make it easy for users
to download content that is generated programmatically using
JavaScript (e.g. a picture created using an online drawing Web app).
If the HTTP header Content-Disposition: is present and gives a
different filename than this attribute, the HTTP header has priority
over this attribute.
If this attribute is present and Content-Disposition: is set to
inline, Firefox gives priority to Content-Disposition, like for the
filename case, while Chrome gives priority to the download attribute.
This attribute is only honored for links to resources with the
same-origin.
So if you are dynamically generating these links and they come from your own server - you can set the filename. A cross-origin request will not work!
You may be able use ajax to fetch the file as a blob and trick the browser into thinking that the data is not cross-origin. See this answer for one possible implementation.
One approach would be to perform a HEAD request before setting .download property of <a> element to determine the Content-Type of the requested resource, use a JSON string, JavaScript object or other key, value pair data storage format to reflect pairs of valid MIME types to valid file extensions corresponding to the MIME type property. Use .indexOf(), RegExp or other filtering method to determine if there is a match between the property name of the string or object and the value of the property, if true store the extension value and concatenate the extension to the suggested file name.
If the file is not served with CORS headers you can try using a proxy to make HEAD of GET request to get the Content-Type header before setting the .download attribute.
It should be noted that the .download attribute is only a suggestion to the user for the filename. The user can change the name of the file at any time, including deleting the file extension, for whatever reason they may or may not have. Or not download the resource at all.
const mimeTypeExtensions = {
"text/plain": ".txt",
"video/mp4": ".mp4",
/* valid MIME types and corresponding extensions */
}
const a = document.querySelector("a");
a.addEventListener("click", event => {
if (!a.download) {
event.preventDefault();
fetch(a.href, {method: "HEAD"})
.then(response => {
const mimeType = response.headers.get("content-type");
let fileExtension = "";
for (let [key, prop] of Object.entries(mimeTypeExtensions)) {
if (key.indexOf(mimeType) > -1) {
fileExtension = prop;
break;
};
}
a.download = `filename${fileExtension}`;
a.click();
})
.catch(err => console.error(err))
}
});
click
Here is an easy option if you don't mind adding a library. FileSaver.js handles these cases well while hiding the ugly details. I was going to go into how you could create Blob, write the contents of the download into it, and then create an anchor tag with an Object URL created from the Blob, but FileSaver handles that already and you could look at the source if you really wanted.
Just modify the following to add some checks and logic for determining filename/filetype and you should be able to tackle your use case.
<script src="cdn-to-FileSaver.js"></script>
<script>
var url = ...;
fetch(url).then((response) => {
var blob = response.blob();
var filename = 'song.mp4';
saveAs(blob, filename);
});
</script>
First of all let me clarify that what I'm trying to do is for locally use only, users will have direct access to the html page.
What I'm trying to do is basically append and save text to an HTML file.
This is what I have.
HTML (index.html)
<div id="receiver"></div>
<button id="insertButton">Insert</button>
JS
$(document).ready( function() {
$('#insertButton').click(function(){
$('#receiver').append('<h1>Hi,</h1>','<p>How are you?</p>');
})
});
What I don't know is how to save the file (index.html) after the appending. Any idea how to do that? Is this even possible with Javascript or jQuery?
You could change your handler to do this:
$(document).ready( function() {
$('#insertButton').click(function(){
$('#receiver').append('<h1>Hi,</h1>','<p>How are you?</p>');
// Save the page's HTML to a file that is automatically downloaded.
// We make a Blob that contains the data to download.
var file = new window.Blob([document.documentElement.innerHTML], { type: "text/html" });
var URL = window.webkitURL || window.URL;
// This is the URL that will download the data.
var downloadUrl = URL.createObjectURL(file);
var a = document.createElement("a");
// This sets the file name.
a.download = "source.htm";
a.href = downloadUrl;
// Actually perform the download.
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
})
});
You should take a look at the compatibility matrix and documentation of URL over at MDN. Notably URL is not available for IE 9 or earlier. Same for Blob.
If I understand it correctly, you need it on local machine and for temporary usage then you can store it in cookies.
So whenever you load the page, check if cookie available, if yes then load data from cookies or load the fresh data.
You can use this data, unless and until cookies are not cleared.
Hope this helps...
Don't need any javascript. After the html is appended, just press Ctrl+S to save the file locally with modified html.
I'm trying to get a full URL using getData() after a drop event of an image:
function drop(e) {
e.stopPropagation();
e.preventDefault();
var url = e.dataTransfer.getData("url") || e.dataTransfer.getData("text/uri-list");
alert(url);
...
}
When I drop my image and capture the event my url = "http://localhost" and does not include the full url to the image. What is the correct way to capture the full url from a dropped image?
Thanks for your time.
As of this writing there is no way to get the full path of an uploaded file. The File API does not provide the full path name. This is what the specification says
The name of the file; on getting, this must return the name of the file as a string. There are numerous file name variations on different systems; this is merely the name of the file, without path information.
So there is no way you can get it as of now. This is done for security concerns.
Hope that helps :)
This question already has answers here:
How to create a file in memory for user to download, but not through server?
(22 answers)
Closed 6 years ago.
Typically, HTML pages can have link to documents (PDF, etc...) which can be downloaded from the server.
Assuming a Javascript enabled webpage, is it possible to dynamically create a text document (for example) from within the user browser and add a link to download this document without a round trip to the server (or a minimal one)?
In other word, the user would click on a button, the javascript would generate randoms numbers (for example), and put them in a structure. Then, the javascript (JQuery for example) would add a link to the page to download the result as a text file from the structure.
This objective is to keep all (or at least most) of the workload on the user side.
Is this feasible, if yes how?
Here's a solution I've created, that allows you to create and download a file in a single click:
<html>
<body>
<button onclick='download_file("my_file.txt", dynamic_text())'>Download</button>
<script>
function dynamic_text() {
return "create your dynamic text here";
}
function download_file(name, contents, mime_type) {
mime_type = mime_type || "text/plain";
var blob = new Blob([contents], {type: mime_type});
var dlink = document.createElement('a');
dlink.download = name;
dlink.href = window.URL.createObjectURL(blob);
dlink.onclick = function(e) {
// revokeObjectURL needs a delay to work properly
var that = this;
setTimeout(function() {
window.URL.revokeObjectURL(that.href);
}, 1500);
};
dlink.click();
dlink.remove();
}
</script>
</body>
</html>
I created this by adapting the code from this HTML5 demo and messing around with things until it worked, so I'm sure there are problems with it (please comment or edit if you have improvements!) but it's a working, single-click solution.
(at least, it works for me on the latest version of Chrome in Windows 7)
By appending a data URI to the page, you can embed a document within the page that can be downloaded. The data portion of the string can be dynamically concatenated using Javascript. You can choose to format it as a URL encoded string or as base64 encoded. When it is base64 encoded, the browser will download the contents as a file. You will have to add a script or jQuery plugin to do the encoding. Here is an example with static data:
jQuery('body').prepend(jQuery('<a/>').attr('href','data:text/octet-stream;base64,SGVsbG8gV29ybGQh').text('Click to download'))
A PDF file? No. A txt file. Yes. With the recent HTML5 blob URIs. A very basic form of your code would look something like this:
window.URL = window.webkitURL || window.URL;
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
var file = new window.BlobBuilder(),
number = Math.random().toString(); //In the append method next, it has to be a string
file.append(number); //Your random number is put in the file
var a = document.createElement('a');
a.href = window.URL.createObjectURL(file.getBlob('text/plain'));
a.download = 'filename.txt';
a.textContent = 'Download file!';
document.body.appendChild(a);
You can use the other methods mentioned in the other answers as a fallback, perhaps, since BlobBuilder probably isn't supported very well.
Demo
Note: BlobBuilder seems to be deprecated. Refer to this answer to see how to use Blob instead of BlobBuilder. Thanks to #limonte for the heads up.