I'm trying to do the following:
A grid with a lot of files is shown to the user
The user selects as many files as he wants
The user should be prompted for each file for the target location
Each file should be downloaded one after another
I can't find a good solution for this because:
I need a cross browser solution (no plugins) but i can rely on IE10+ and HTML5
The files should not be downloaded as a zip file or any other archive
Using document.write for inserting multiple iframes feels bad and is discouraged by most browsers
I managed to build a possible example of downloading multiple files using the HTML FileSystem API. I ran into a few problems while building this which I'll note down below. Beware that this is just an example and could be improved by a lot (code-wise and feature-wise).
I stopped developing because I was unable to transfer binary files but maybe someone can give me a clue on how to do this. (I struggle with binary ajax transfers and JSON at the moment. (I can't say if it's possible to transfer images/binaries over ajax at all).
Published Sourcecode on GitHub:
https://github.com/posixpascal/FileSystem-API-Example
A few things to note:
Your users have to click 'Allow this webpage to download multiple files' as soon as the popup is visible. Otherwise it won't work.
This uses heavy I/O operations on the server side (at least with my
code). one should rewrite that before using this script.
Be aware of this issue: https://code.google.com/p/chromium/issues/detail?id=94314
Users with non-latin characters in their Windows Username aren't able to download the files.
You can't resume the download if you using TEMPORARY FileSystem Storage. (Chrome throws an error on my machine when I try to access the downloaded files twice)
Also be aware of loops, because it can screw other peoples browsers.
Youtube Example: https://www.youtube.com/watch?v=F9T4i4qrYtc&list=UUi1sRIczZxhsuWPPUK7xxTA
Live Example: http://pascalraszyk.de/_broken_do_not_use/
All I can say is that this is not a solution at the moment and the API isn't ready for the mass. You can add further support by using Flash and other utils to compensate lack of FileSystem API support.
How it works:
As soon as the user clicks on the download link, my script gathers information about the files using a server side PHP script. After that it requests a few chunks until the filesize from the locally stored file matches the one sent by the php script.
As soon as the file is ready, I create an invisible a tag and set href to "filesystem:myurl.de/theFile" and trigger a click event on that link. I also add 'download' property so the browser is forced to download .txt files as well.
This is not a fully solution to your problem but you can check the sourcecode and hopefully built something to suit your needs. I guess you already moved on to a different approach to download multiple files.
I found a solution that works (for me) in all browsers. It's does not feel that good on the code side (at first) but it seems pretty stable to me on different browsers and different machines.
Chrome will ask the user to allow the site to download multiple files. IE doesn't care at all.
var onDownload = function(){
var docs = module.getSelectedElements();
for(var i = 0; i < docs.length; i ++) {
(function(){
var doc = docs[i];
window.setTimeout(function(){
$jq("#downloadIframe").attr("src", doc.url);
}, i * 500);
})();
}
};
Related
My app creates an excel file, server side, from a database extraction.
A post request sends parameters to the server that the server then uses to query the database.
The server uses these parameters to extract data convert the data to an excel file (xlsx), then saves the file with a certain file-name as per the parameters sent to the server.
The server responds to the post request by sending the file-name to the browser.
The browser then creates a link using the filename and other predefined parameters to download the file by the following instructions:
var link = 'http://host-name/path-to-file/excel-file.xlxs'; // the link that is created by the js in the browser
window.location = link; // the file is downloaded
This works in chrome, firefox, opera and safari, in these browsers, the file downloads no problem.
However; when running in Microsoft-edge, the file is not downloaded and this appears in the page.
Someone was facing similar issue in some versions of IE and had to set Cache-Control header to make the download working properly:
response.Cache.SetCacheability(HttpCacheability.Private);
Source
The issue here is that this method of downloading files is not actually downloading the file. I was using javascript to instruct the browser to open the excel file, window.location = link;. Which tells the browser, go to a that link, and open whatever you find at that address. Which is normally an HTML file or something else transpiled into HTML. This can in some cases be also be a .pdf or the sort of file that modern web-browsers are able to interpret and run.
Now, the reason this was mostly working is; browsers like chrome and firefox are smart enough to know that they cannot interpret and display excel files, so instead, they download them. Pretty smart right. However; microsoft-edge is not so clever as its more proven compatriots. It tries to interpret and run the file, which of course it cannot. What this then leads to; is a grand display of nonsense; as you can see from screen-grab in my question above.
My problem here was actually a deeper rooted issue of technology mismatch. I had since migrated to using a more modern stack, replacing my plain node.js server with express. Moving the front-end out of a cross-origin tomcat java-container application-server model (which was causing most of my headaches on a daily bases since I was coding javascript) to a same-origin environment using webpack along with express.
And as you might know, using webpack brings a whole new dimension to the front-end that was not available before when we were using the 'old approach' to web-dev.
Most of the improvements in using webpack came from its ability to bring 'node.js' to the front end.
It has made my life as a dev 150% easier and the type of problem as described in my question above is now a thing of the past. javascript for the win! The moral for me here is that sometimes that aren't any quick fixes, and you just have to do things properly.
I have a web app (sencha/phonegap) that includes a feature allowing users to click on buttons that link to Wikipedia articles. This obviously works fine if the device has internet access, but I get numerous requests to make the app work when the app is offline too. To accomplish this, I'd like to give the user the option to download the linked articles/webpages for offline access. When the device does not have internet access, the app would instead display the saved version (which might be stale/out-of-date, but is better than nothing). What are possible ways to accomplish this task?
My first thought was to somehow use the html manifest to cache the pages in the phone's browser, which sounds possible on the Android browser, but iOS apparently has a 5MB browser cache limit - too small.
My next thought was to save the needed html & associated files and bundle them up inside the app. But this seems a rather cumbersome approach, the app becomes much larger than it needs to be, and the webpages are stale back to the date the app was installed.
Using javascript, is it possible to download webpages, which I could then save (on the sd card, for example) for access later?
Or is there a more elegant approach?
If anyone could point me in the right direction it would be much appreciated.
In pure Javascript you can make an Ajax request to download a page. Then you can use the FileWriter to write the responseText to a file on the file system. However, that won't help you when it comes to images. You'll need to use the FileTransfer.download() command to get the binary image files.
If I were you I'd:
Use AJAX to download the html.
Parse the html looking for images.
Use FileTransfer.download to get the images.
I am all too aware of the fact that even with the new FileAPI it's not possible to access the local path of a file added using a file input field or drag-and-drop. Whether or not this is good, bad or ugly is not the issue here. According to the FileAPI specs local file access is not to be implemented, and so I'm not holding my breath.
But let's just pretend I'm in a situation with the following fixed parameters:
Developing an HTML5 application only to be used internally at a company
.NET used for backend (needed due to interop with APIs)
Can specify/control exactly which browser and version should be used with the application
Need to access files that are usually located on a network share, but possibly also locally at a user's workstation
And by access I don't mean access file data, but rather be able to relay a file drag-and-drop/select event to some other API by feeding the third party the file's local path, so that the third party can pick up the file and do some sort of work on it. This can be likened to using an input[type=file] field as you would an OpenFileDialog in .NET - i.e. the point is to feed the application a file path, not an actual file.
I realise that out of the box this is probably not possible. But I also think that there must be some sort of solution to the problem.
Some ideas I've been toying with are:
Using browser specific methods for allowing "secure features"
Not sure if possible - tired using some of these features to no avail
Would limit the app to a specific version of a browser as the functionality could potentially be removed in the future
Something like a Chrome extension could possibly do the trick
Using some sort of companion application installed locally on a clients computer that takes care of all on-disk file handling, possibly communicating with the HTML5 client using websockets or the like.
A potentially pretty messy solution
Would probably confuse the users a bit at first
Submitting the selected file data to the server, storing it at specific path and sending this new path to the third party.
Would constitute a lot of sending files over the company network, some 100+ MB in size
Would not be able to do any in-place changes to a file a user has selected
... and that's about it.
Any snazzy suggestions? Wise words? Helpful links? Snarky comments?
Thanks.
Edit: For anyone curious about it, this was very simple using Silverlight as per jgauffin's suggestion below.
From the Silverlight codebehind (using elevated privileges):
private void fileBtn_Click(object sender, RoutedEventArgs e)
{
//prompt file select dialog in Silverlight:
var dlg = new OpenFileDialog();
dlg.ShowDialog();
//call JavaScript method and feed it the file path:
HtmlPage.Window.Invoke("onFileSelected", dlg.File.FullName);
}
You'll probably have to use something that runs in the browser like flash or silverlight.
Since it's an internal app I would use silverlight as everything else is in .NET. It should be enought to only make the file access part in the plugin.
Here is an article about local file access: https://www.wintellect.com/silverlight-4-s-new-local-file-system-support/
does the server hosting the site have access to the network of pc's?
you could just list all the files that way.. build a small ajax script like a file dialog that will have php or whatever sending back the structure
no plugins needed, works on all browsers... :)
I'm developing a web app that needs some sort of filesystem access. Ideally I'd want to be able to "Open..." a file into the app and then "Save" the file back to local filesystem at the location that the user opened it from.
Currently, we use a java applet to achieve this functionality, but since java is going out of style, we're needing to do this with javascript and html5.
Obviously, this can't be done because of security reasons built into browsers, so I'm trying to somewhat emulate it.
I'm using the html5 file api to successfully import/open the files, so that's half the battle. The hard part is getting the saving feature. I'm getting close using an iframe and content-disposition, but problems arise when browsers are set to automatically download the files to a downloads folder... users may get confused and be unable to locate the file they just downloaded.
So, my question is this: is there some sort of onSave event or some kind of way for the browser's "Save As..." window to return at least the filename that the user saved the file under?
Also, I've looked into the filesystem/fileWriter html5 apis, but from my understanding they're limited to only a sandboxed area of the local filesystem and only available in chrome dev releases.
Any help would be appreciated!
No, there is no way to do that with pure JavaScript. You can manage to trigger a download with data URIs or an iframe with some headers but you can't circumvent the browsers' download managers.
You can either use a Flash or Java applet to handle the saving for you, or ask the user to right click on the link and do save as, then he might be able to choose the destination.
One popular option using Flash is Downloadify.
I have a couple of solutions, but none of them work perfectly.
Platform
ASP.NET / VB.NET / .NET 2.0
IIS 6
IE6 (primarily), with some IE7; Firefox not necessary, but useful
Allowed 3rd Party Options
Flash
ActiveX (would like to avoid)
Java (would like to avoid)
Current Attempts
Gmail Style: You can use javascript to add new Upload elements (input type='file'), then upload them all at once with the click of a button. This works, but still requires a lot of clicks. (I was able to use an invisible ActiveX control to detect things like File Size, which would be useful.)
Flash Uploader: I discovered a couple of Flash Upload controls that use a 1x1 flash file to act as the uploader, callable by javascript. (One such control is FancyUpload, another is Dojo's Multiple File Uploader, yet another is one by darick_c at CodeProject.) These excited me, but I quickly ran into two issues:
Flash 10 will break the functionality that is used to call the multiple file upload dialogue box. The workaround is to use a transparent flash frame, or just use a flash button to call the dialogue box. That's not a huge deal.
The integrated windows authentication used on our intranet is not used when the Flash file attempts to upload the files, prompting the user for credentials. The workaround for this is to use cookieless sessions, which would be a nightmare for our project due to several other reasons.
Java Uploader: I noticed several Java-based multiple-file uploaders, but most of the appear to cost money. If I found one that worked really well, I could arrange to purchase it. I'd just rather not. I also don't like the look of most of them. I liked FancyUpload because it interacted with html/javascript so that I could easily style and manage it any way I want.
ActiveX Uploader: I found an ActiveX solution as well. It appears that ActiveX will work. I would just write my own instead of buying that one. This will be my last resort, I think.
Resolution
I would love to be able to use something like FancyUpload. If I can just get by the credentials prompt some way, it would be perfect. But, from my research, it appears that the only real workaround is cookieless sessions, which I just can't do.
So, the question is: Is there a way to resolve the issues presented above OR is there a different solution that I have not listed which accomplishes the same goal?
I don't think there is any work around for the integrated windows authentication. What you could possibly do is save the files to a generic unprotected folder and, in the case of swfupload, use a handler to move the file when its fully uploaded
You could try SWFUpload as well - it would fit in your Flash Uploader "category".
Our company uses https://ajaxuploader.com which supports this feature.
In Internet Explorer, FileReference.upload (flash upload) will send cookies along as well.
This behavior breaks only when running in other browsers.
#davidinbcn.myopenid.co: That's basically how I solved this issue. But, in an effort to provide a more detailed answer, I'm posting my solution here.
The Solution!
Create two web applications, or websites, or whatever.
Application A is a simple web application. The purpose of this application is to receive file uploads and save them to the proper place. Set this up as an anonymous access allowed. Then make a single ASPX page that accepts posted files and saves them to a given location. (I'm doing this on an intranet. Internet sites may be exposing themselves to security issues by doing this. Take extra precautions if that is the case.) The code behind for this page would look something like this:
Dim uploads As HttpFileCollection = HttpContext.Current.Request.Files
If uploads.Count > 0 Then
UploadFiles(uploads)
Else
result = "error"
err = "File Not Uploaded"
End If
Application B is your primary site that will allow file uploads. Set this up as an authenticated web application that does not allow anonymous access. Then, place the FancyUpload (or similar solution) on a page on this site. Configure it to post its files to Application A's upload ASPX page.