views:

559

answers:

7

I'd like to make an XML document in JavaScript then have a save dialog appear.

  1. It's OK if they have to click before the save can occur.
  2. It's *not* OK if I *have* to use IE to achieve this (I don't even need to support it at all). However, Windows is a required platform (so Firefox or Chrome are the preferred browsers if I can only do this in one browser).
  3. It's *not* OK if I need a web server. But conversely, I don't want to require the JavaScript to be run on a local file only, i.e. elevated privileges -- if possible. That is, I'd like to to run locally or on a *static* host. But just locally is OK.
  4. It's OK to have to bend over backwards to do this. The file won't be very big, but internet access might either be there, be spotty or just not be a possibility at all -- see (3).

So far the only ideas I have seen are to save the XML to an iframe and save that document -- but it seems that you can only do this in IE? Also, that I could construct a data URI and place that in a link. My fear here is that it will just open the XML file in the window, rather than prompt the user to save it.

I know that if I require the JavaScript to be local, I can raise privileges and just directly save the file (or hopefully cause a save dialog box to appear). However, I'd much prefer a solution where I do not require raised privileges (even a Firefox 3.6 only solution).

I apologize if this offends anyone's sensibilities (for example, not supporting every browser). I basically want to write an offline application and Javascript/HTML/CSS seem to be the best candidate considering the complexity of the requirements and the time available. However, I have this single requirement of being able to save data that must be overcome before I can choose this line of development.

A: 

Are you looking for something like this?

If PHP is ok, if would be much easier.

tr4656
Thank you tr4656, no I am already familiar with the XML api available in JS. I am trying to get that xml saved to the local disk *through a user prompted save dialog*. Similarly (and this is a separate question), I am also wanting to prompt the user to load a file (but again without a web server involved). Barring any of that, I'll settle for a convincing argument (even a historical one) on why it's less secure (rather than just having to believe it).
Adam Luter
@Adam - I agree with you that this whole security argument is somewhat bogus or at the very least, unexplained.
Moshe
A: 

Is localhost PHP server ok? Web traditionally can't save to hard drive because of security concerns. PHP can push files though it requires a server.

Print to PDF plugins are available for available for all browsers. Install once, print to PDF forever. Then, you can use a javascript or Flash to call a Print function.

Also, if you are developing for an environment where internet access is spotty, conwider using VB.NET or some other desktop language.

EDIT:

You can use the browser's Print function.

Moshe
Moshe, thank you for your reply. (read my other comments on using a webserver, local or otherwise, and also about using something other than html/js/css). I *have* to use XML, it's just a requirement (and not a really horrible one considering the data). But I didn't mention in my question (because it was a separate question) that I need to be able to load the same XML file later too (so, printing to PDF would be great, except I'd not be able to load from it). Using the print function is clever, but I don't think it would work for XML data.
Adam Luter
@Adam - I don't see anything wrong with XML. Why wouldn't print work for XML data? You can output the XML as a plain text to the browser. Loading the XML can be done either with Flash or with jQuery as XML can be loaded into the browser like any other (text/html) file can.
Moshe
Guh, I hate AJAX comment boxes, because I always end up losing the contents after finishing a box and then having an accident (like hitting backspace after hitting tab accidentally). Anyway -- I was saying I think the print+XML route is, at the least, too difficult for a user. Maybe even worse than saying "hey click here, then choose save/as, then click back" (if I went the route where I could bring the XML up as it's own page). I just want it to be a normal save/load routine for the user's sanity/sake. (So, it looks like Flash could help me out, or elevated privileges).
Adam Luter
+2  A: 

Without any more insight into your specific requirements, I would not recommend a pure Javascript/HTML solution. From a user perspective you would probably get the best results writing a native application. However if it will be faster to use Javascript/HTML, I recommend using a local application hosting a lightweight web server to serve up your content. That way you can cleanly handle the file saving server-side while focusing the bulk of your effort on the front-end application.

You can code up a web server in - for example - Python or Ruby using very few lines of code and without 3rd party libraries. For example, see:


"""
Serves files out of its current directory.
Doesn't handle POST requests.
"""
import SocketServer
import SimpleHTTPServer

PORT = 8080

def move():
    """ sample function to be called via a URL"""
    return 'hi'

class CustomHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        #Sample values in self for URL: http://localhost:8080/jsxmlrpc-0.3/
        #self.path  '/jsxmlrpc-0.3/'
        #self.raw_requestline   'GET /jsxmlrpc-0.3/ HTTP/1.1rn'
        #self.client_address    ('127.0.0.1', 3727)
        if self.path=='/move':
            #This URL will trigger our sample function and send what it returns back to the browser
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(move()) #call sample function here
            return
        else:
            #serve files, and directory listings by following self.path from
            #current working directory
            SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)

httpd = SocketServer.ThreadingTCPServer(('localhost', PORT),CustomHandler)

print "serving at port", PORT
httpd.serve_forever()

Finally - Depending on who will be using your application, you also have the option of compiling a Python program into a Frozen Binary so the end user does not have to have Python installed on their machine.

Justin Ethier
Thank you Justin for your very thorough reply. My ideal here is that the file could be a local html (or local folder of html, etc.) *or* on a static host (cheap) when there is net. Based on the resources I have, I do not want to develop a "real" app. (But if I did, I'd probably pick Ruby or Python). Freezing Python is a big plus if I broke down. But I really just want to stick to a static html/js/css "web" app (minus the web). The application is a "basic enter data, then a guided process for composing it". The UI will be pretty basic and I just need to save/load state as XML.
Adam Luter
You're welcome. I think if you are planning to go with a html/js/css solution, however, you will still want a back-end - albeit a minimalist one.
Justin Ethier
+1  A: 

Javascript is not allowed to write to a local machine. Your question is similar to this one.

I suggest creating a simple desktop app.

Bill Paetzke
Thanks Bill, I know this is the standard answer, I'd like some rational why the DOM thinks that `<a href="mydoc.txt">Click</a>` is secure enough to prompt the user to save the file (and in many of today's browser's it doesn't even prompt...). But if I used JS to create the txt file say some psuedo-code like: `<a onclick="window.promptSave('It was a dark and stormy night...', 'text/plain', 'mydoc.txt')">Click</a>`, this is somehow inherently less secure? Theoretically, it should be less secure to have to ask the network for the data again, since this isn't a secure connection (http vs https).
Adam Luter
A: 

With IE you could use document.execCommand, but I note that IE is not an option.

Here's something that looks like it might help, although it will not prompt with SaveAs dialog, https://developer.mozilla.org/en/Code_snippets/File_I%2F%2FOL.

Jonathan
Jonathan, your link is broken, but my guess it's the elevated privilege code I mention in the 2nd lower paragraph. Thanks though! :)
Adam Luter
+2  A: 

How about this downloadify script?

Which is based on Flash and jQuery, which can prompt you dialog box to save file in your computer.

Downloadify.create('downloadify',{
  filename: function(){
    return document.getElementById('filename').value;
  },
  data: function(){ 
    return document.getElementById('data').value;
  },
  onComplete: function(){ 
    alert('Your File Has Been Saved!'); 
  },
  onCancel: function(){ 
    alert('You have cancelled the saving of this file.');
  },
  onError: function(){ 
    alert('You must put something in the File Contents or there will be nothing to save!'); 
  },
  swf: 'media/downloadify.swf',
  downloadImage: 'images/download.png',
  width: 100,
  height: 30,
  transparent: true,
  append: false
});
S.Mark
Flash is the only way I've ever seen to do what you are asking. This answer (jQuery / event driven) is a very elegant solution.
Jonathan Julian
Yeah this is probably going to be the only answer to my question -- even if I don't *want* to rely on flash. (I didn't say so up there though :P ). I can always rely on flash *or* elevated privileges. S.Mark, do you know if there is an equivalent for loading a file via javascript? (Again, of course, prompting the user).
Adam Luter
If someone doesn't mind clarifying this point -- I work *with* flash developers, but never with flash myself -- the site says it's compiled for online use only. I assume that I could get it compiled to work locally too?
Adam Luter
@Adam - Yea, you could compile for local usage - but not "too". In the "Publish Settings" dialog, Flash asks if you want "Network Access" only, or "Local Access" only. Unless we are not referring to the same thing.
Moshe
@Moshe, Thanks for the tidbit -- I've never worked *in* flash before. That'd be *OK* since I could do network access, and then rely on elevated privileges for local access. But it means I'll probably just start with elevated privileges and only do flash when I'm done and want it to work on a static web host.
Adam Luter
A: 

One simple but odd way to do this that doesn't require any Flash is to create an <a/> with a data URI for its href. This even has pretty good cross-browser support, although for IE it must be at least version 8 and the URI must be < 32k. It looks like someone else on SO has more to say on the topic.

Jacob
Yeah but as I note in my comment to the question, a data uri won't work in the case of wanting any sort of sane filename.
Adam Luter