views:

1405

answers:

11

Javascript can manipulate the document the browser is displaying, so the following:

<script>
    document.write("<table><tr><td>Hola</td><td>Adios</td></tr></table>");
</script>

Will make the browser display a table just like if it was the original HTML document:

<table>
    <tr>
        <td>Hola</td>
        <td>Adios</td>
    </tr>
</table>

Is there a way I can save/serve this document content?

Currently we have some nicely generated reports using Ext-js, what I would like to do is to have the "text/html" version of it ( I mean, something that doesn't require javascript )

So at the end of the page I would add a button : "Save as blaba" and the document should display the text/plain version.

The only way I could think right now is, to write the content into a javascript variable like:

 var content = document.toString(); // or something magic like that.
 // post it to the server

Then post that value to the server, and have the server present that value.

 <%=request.getParameter("content-text")%>

But looks very tricky.

Is there an alternative?

EDIT

Ok, I almost got it. Now I just need the new window to pop up so the option "would you like to save it shows"

This is what I've got so far

<script>
    document.write("<div id='content'><table><tr><td>Hola</td><td>Adios</td></tr></table></div>");
    function saveAs(){
        var sMarkup =  document.getElementById('content').innerHTML; 
        var oNewDoc = document.open('application/vnd.ms-excel');        
        oNewDoc.write( sMarkup + "<hr>" );
        oNewDoc.close();
    }
</script>

<input type="button" value="Save as" onClick="saveAs()"/>

The line:

    var oNewDoc = document.open('application/vnd.ms-excel');

Should specify the new content type, but it is being ignored.

+7  A: 

Unless its being saved client side with File -> Save Page As..., you will have to do exactly what you are proposing, posting $('body').html() to your server and process it as text.

voyager
File-Save page as: would save "document.write('html... etc etc ) isn't? I would like something like "File-Save as" and the saved that would be "<html><table...etc" is that possible?
OscarRyz
@Oscar Reyes: You could make a button that would open a new window with only the table with javascript, and save that.
voyager
I'm stuck in the "... open a new window" part :-/
OscarRyz
@Oscar Reyes: you will have to do it serverside nevertheless. You have to get the full client table, post it to the server and open the new "page" in a new window. I'll try to be more explicative later.
voyager
A: 

Is your javascript AJAX which fetches the document.writeln() content from the server, or are you already generating that content when the page is served to the user ? Because if it's the former, I see no reason why you can't save any variables / queries in the session of whatever server-side technology your using and then just generate the plain text stuff from those. Otherwise, you'll have to folow voyager's suggestion above.

Alex Marshall
The former. The reason I don't want to generate plain text version's is because although it is feasible, it is very likely that a) They go out of sync with the javascript version ( adding columns, doing some calculations etc have to be change on both sides js and serverside ) b) The js library was use precisely to save us from doing all the formatting by hand.
OscarRyz
+4  A: 

This link seems to explain exactly how to solve your problem.

DVK
Looks like what I'm looking for, but I can't find how this "magic" function should work: saveHTML( htmlContent ) ...
OscarRyz
Try: `saveHTML($('body').html())`
Paul Lammertsma
A: 

Please... pretty please... use Firefox and Firebug. You will be able to see and edit the live HTML, and CSS. It has a nice debugger... don't work that hard.

elcuco
Uh?... so... do you think I'm doing this to debug? No, no no no no, is not for that purpose. Let's saaaay... mhh that I want to save the table ..... to .. .mmhh ok to open it with Excel .. that's it I said it. If I let excel process the javascript, who knows what can happen. Excel already opens quite nicely html tables :P
OscarRyz
@Oscar Reyes: send it serverside and give the user the resulting `html` file to be opened in Excel.
voyager
@Oscar: right click the table in firebug, then click edit. Now you can copy the HTML.If you need something more automatic - then repost the rendered HTML back to serverside as many folks recommended.
elcuco
A: 

Since you're using Ext JS, you probably have a Store object that provides data to the grid? You should be able to extract the data you need by walking through the Store, and then format it the way you want. I don't think scraping the data from the generated HTML is ideal.

Once you grab the data you need from the grid and format it into text, you could POST it to the backend to initiate a download (with Content-Disposition: attachment etc.)

If you're not concerned with being cross-browser, you can also use the data: URL scheme to initiate a download without involving the backend.

Ates Goral
I would rather generate the table serverside before going into that. But that's exactly what I'm trying to avoid.
OscarRyz
+2  A: 

You are getting close to the answer I thinks. The problem is that 'document.open(...)' can only take standard mime-types such as 'text/html', 'text/plain' and a few others

And because of that your code should be:

<script>
    document.write("<div id='content'><table><tr><td>Hola</td><td>Adios</td></tr></table></div>");
    function saveAs(){
        var sMarkup =  document.getElementById('content').innerHTML; 
        var oNewDoc = document.open('text/html');        
        oNewDoc.write( sMarkup + "<hr>" );
        oNewDoc.close();
    }
</script>

<input type="button" value="Save as" onClick="saveAs()"/>

Hope this helps.

NawaMan
+1  A: 

If it's just a report, you could use server-side JavaScript to generate it, and then serve it up with whatever MIME type you need...

Kev
(...thus avoiding a round trip.)
Kev
It is actually. Can you point me in the right direction towards server-side javascript please? I have no idea.
OscarRyz
What platform is your server?
Kev
I've never used it, but SpiderMonkey ( http://www.mozilla.org/js/spidermonkey/ ) will let you run JS from the command-line ( http://blog.ianbicking.org/jslint-command-line.html ). I guess you could then set up SpiderMonkey as a handler for your server-side scripts. There's also Jaxer if you want a more end-to-end package.
Kev
+1  A: 

I dont think that sending your html to the server is a tricky solution. You just have to remember to give a link to your user to download this file. This can be done using a traditional POST, or even using AJAX. It depends on how you want your users to interact if your page.

Using traditional post, you could put all the html content in the value attribute of an input type hidden in your page, named "html_content" or something like that, and when the user clicks in the button "save" you send your user to another page with a link do the file. You send the html to server, a script creates a file in a filesystem with an unique name, and returns a download link.

Using AJAX, you just need to do an AJAX POST passing this variable, and then your script returns a download link, and you dynamically put it in your html - without reloading your page, like it was "only cliente side".

Either way, you'll return a link to the resource you just created in your filesystem with a html extension. Remember to generate unique names in your server for each generated file to avoid collisions.

Beware though that using innerHTML in IE 6 (I dont know if this is a IE family behavior or just about the 6 version) uppercases all tags and removes quotes from attributes. If you're planning to do some post processing in your html, be careful.

I dont know how jQuery or other JS libraries behaves in such situations. I would suggest using it though, they have plenty of browser compatibility checks to abstract all these hacks we use.

GmonC
Obrigado GmonC. Actually there is no need to save the content in the file system. The same request could generate the content and by setting the mime-type to: `'application/vnd.ms-excel'` I could have the client to treat the content as if it was excel. What I would try to avoid ( if possible ) is to do the round trip back and forward because the content may be large already. I have selected an alternative, still, I think I'll use this version for non ie browsers.
OscarRyz
Obrigado for the explanation. I understand now that if the document is too large, it would be a waste of time. It's going to work, but it isn't an optimal solution. Still needed for non ie browsers though. Now you're going to need to create a condition in your js, "if not ie do the server approach, else download excel". Good luck!
GmonC
+1  A: 

Here's my code to save the generated content[client-side] by the JavaScript to the local C: drive in MSWord[.doc] format.

<script>

    document.write("<div id='content'><table><tr><td>Holaa</td><td>Adiosa</td></tr></table></div>"); 
    function saveAs()
     {
      var wordObj=new ActiveXObject("Word.Application");
      var docText;
      var obj;
      var textToWrite = document.getElementById('content').innerHTML;
      if (wordObj != null)
      {
       wordObj.Visible = false;
       wordDoc=wordObj.Documents.Add();
       wordObj.Selection.TypeText(textToWrite);
       wordDoc.SaveAs("C:\\Eureka.doc");
       wordObj.Quit();
       document.write("The content has been written to 'C:\\Eureka.doc'");//Print on webpage 
      }
     }
</script>

<body>

<input type="button" value="Save in C:" onclick="saveAs()"/> 

</body>

I quickly worked on ur issue and came up with this piece of code. Hope I understood your issue correctly.

The contraints in my code are

  • File format is .doc and not .xls.
  • Secondly, The file is saved in a static location and not the user specified location[can be optimized].
  • And, the code uses ActiveX and I didnot check the working in server-side environment.

These need to be addressed in the upcoming versions. (:

Peace.

chong
:-O would it work for .xls???
OscarRyz
Good to know that I'm in the correct path.Yeah, Am working on to that (.xls format). Will post the code soon.
chong
Please view my updated code for opening the generated table in xls format here: http://stackoverflow.com/questions/1479020/save-the-document-generated-by-javascript/1606092#1606092
chong
+3  A: 

Depending on your browser support requirements, you could use data URIs

Core for proof of concept (tested in Firefox 3.5.3):

document.write("<div id='content'><table><tr><td>Hola</td><td>Adios</td></tr></table></div>");
function extract(){
  return document.getElementById('content').innerHTML; 
}
function dataURI(s){
  return 'data:application/vnd.ms-excel;base64,' + encode64(s);
}
document.write('<a href="' + dataURI(extract()) + '">open</a>');

I pulled base 64 encode/decode from examples online. Careful: the one I grabbed included a URI encode before base 64 encode that messed me up for a while.

Justin Love
+2  A: 

Hello Oscar, Here's the upgraded version to open the table contents in .xls format.

<head>
<script>

      document.write("<table id='targetTable'><tr><td>Hola</td><td>Adios</td></tr><tr><td>eins</td><td>zwei</td></table>"); 
     function saveAsXLS()
     {
      var xlObj = new ActiveXObject("Excel.Application");
      var xlBook = xlObj.Workbooks.Add();
      var xlSheet = xlBook.Worksheets(1);
      for (var y=0;y<targetTable.rows.length;y++) // targetTable=id of the table
      {
       for (var x=0;x<targetTable.rows(y).cells.length;x++)
       {
        xlSheet.Cells(y+1,x+1)=targetTable.rows(y).cells(x).innerText;
       }
      } 
      xlObj.Visible=true;
      document.write("The table contents are opened in a new Excel sheet.");//Print on webpage 
     }
</script>
</head>
<body>  
<input type="button" value="Open table in Excel!" onclick="saveAsXLS()"/> 
</body>

This code is tested in IE6 and is using ActiveXObject control.

  • The table I've used here is of order 2x2 and the individual contents are mapped respectively into the excel sheet.
  • Unlike the .doc version, this does not save the file in client's system. It opens the application with the table content and the client has to save it.

Hope this helps in answering ur question. Lemme know if u face any issues.

Peace.

chong
This looks very promising. I've tried in ie7 and I'm getting the following error. I'll try it with ie6 ( my target ) in a while and ledt you know the result: http://img11.imageshack.us/img11/8444/capturatx.png The error message reads: *The atomization server could not create the object*
OscarRyz
This code works fine if it is run locally[without the server environment]. To make it work in 'server' environment, you need to change some security settings to allow the creation of ActiveXObject in ur server system. Hit Tools>Internet Options>Security Tab>Custom Level> make sure "prompt" is selected for "Download signed and unsigned activeX controls".Then u'll get a prompt when the code is run. If that didn't help, try changing other related activeX options. But make sure u have an updated antivirus program b4 changing the security settings, if in case something goes wierd. :p
chong
I ran this as local html file, see the image: http://img11.imageshack.us/img11/8444/capturatx.png
OscarRyz
ie6 give the same error: http://img514.imageshack.us/img514/9154/capturadepantalla200910p.png
OscarRyz
Ohh I see, I need to have MS-excell installed right?
OscarRyz
fantastic!! :pYes of course, you need MS Office!! ^_^
chong
doh! I guess if I don't the js-object will become undefined. I can handle that and say something like "You need MS-Office installed to save it as excel" etcetc ... grrrreat!!!! Thank you chong
OscarRyz
Be warn you chong. Those reputation points are highly addictive... ;)
OscarRyz
Glad that it worked for you! 121!!Sweet:) My debut answer got me 100 reputation points! ¡muchas gracias Oscar! :D
chong