views:

289

answers:

7

I have a button which sets window.location to a php file which generates a feed which is then downloaded. However, as the files vary in size due to what data is put into the feed it can sometimes take a while from the click of the button to the file dialog popping up.

What I would like to be able to do is click the button and display a loading.gif until the dialog / file is complete.

Any ideas would be cool!

Cheers

+1  A: 

before setting window.location you could display a hidden div with your gif

MasterMax1313
And how do we know when to hide it again?
Serhii
hide it after the window.location i would imagine.
MasterMax1313
Yeah... that's not gonna work
Josh Stodola
A: 

You will have to use AJAX to communicate to the server to discover the exact size of the file you are downloading. Then you have something to test against. There is no way to know the size of the expected payload from the client side only.

See Justin Johnson's comment. The file is asynchronous so there's no way to determine the file size, having the file processed once via ajax then once again afterwards isn't really an option as sometimes the file can be a huge load on the database. :)
Joel
Even if you have the size, then how do you detect when the dialog has popped up / the file has completed.
Joel
You could use the document blur event to get a fair indication of when the dialog has appeared and focus to tell when the user has returned to the page. It's not foolproof though.
Sohnee
@Joel You dont have to download the file twice. It is the job of the server to know the details of the assets it is serving to you. You just have to use AJAX to get that meta-data. If the server is not prepared to give that information to you then you have extra work to do server side, perhaps using PHP to ensure that data is ready for you to receive dynamically. Then you have to compare that data to the actual size of the file. You will need to have some sort of command line script that continually outputs the size of the file to a location in your DOM that can be read by JavaScript.
A: 

Is it possible for you to use an iframe to load the feed and then check the readyState of the iframe/document using an interval? So the process would be:

  • Load a window containing an iframe of width and height 100% and a loading.gif over the iframe.
  • Set a timer checking for the iframe.contentWindow.document.readyState property
  • Once readyState == complete, show the save file dialog.

One downside is, for most browsers the PHP file would need to be on the same domain (on IE you can just check the readyState property of the iframe).

Andy E
+5  A: 

I'm not really sure why you need to check the size of the file at all? If you use ajax to dynamically do the get/post, and all you are doing is trying to show a loading icon while this is happening, its fairly simple to throw up an asynchronous activity indicator. For instance, with jquery:

$("#loading").ajaxStart(function(){
   $(this).show();
});

$("#loading").ajaxStop(function(){
   $(this).hide();
});

$("#feeds").load("feeds.php?id=89734258972347895");

The above code sets a DOM object with id "loading" to show and hide when any asynchronous request has been initiated and stopped. .load(url) loads the content of the url into the div #feeds. If you are setting the content-disposition: attachment header with php, it will automatically initiate a file download window, even though it has been loaded asynchronously into a div. This is also possible without jquery of course, there's just a bunch of browser compatibility javascript and its not as easy as simply subscribing to the ajaxStart and ajaxStop events to show and hide your loading img.

Josh

Josh
+1  A: 

It's old school, but this can be done very easily with server push

<?php
  $separator = "end_of_section_marker";
  header('Content-type: multipart/x-mixed-replace;boundary=$separator');
  print "\n--$separator\n";
  print "Content-type: text/html\n\n";
  // Send placeholder message here
  print "--$separator\n";
  ob_flush();
  flush();
  // Start long processing here
  print "Content-type: text/html\n\n";
  // send data here
  print "--$separator--\n";
?>

Just adjust the content-types for the data you're sending. $separator can be any value so long as it does not appear in the data being sent.

Devon_C_Miller
+1  A: 

A method I've used in the past works like this...

  • Set window.location to a loading page, and pass the destination page in the querystring. The loading page should display an animated gif or whatever you prefer to demonstrate that processing is taking place. The loading page should IMMEDIATELY redirect to the destination page passed in the querystring (along with any other applicable querystring parameters).

EDIT: The loading page should redirect to the destination page using javascript (set window.location to the URL provided in the querystring). This is an important point, because if you redirect on the server-side the loading page won't get displayed.

EDIT 2: If your loading page is a php file, you can check the to-be-downloaded file's size and display an estimated download time to the user (along with an animated "loading" gif), or whatnot.

  • The destination page should render with buffering enabled (call ob_start() before you render any content). With buffering enabled, nothing is sent to the browser until the entire page is rendered. Meanwhile your loading page from step 1 will continue to be displayed.
CodeToaster
Yes, this should work and it's easy to implement. +1
Ates Goral
A: 

Just make the RSS generating script show image you want (output image's HTML, then flush output buffer and start data generation). At the end of the data generation do:

<?php
print '<script>window.location = "http://www.newlocation.com"&lt;/script&gt;'

That's all.

FractalizeR
Also, please note "Some versions of Microsoft Internet Explorer will only start to display the page after they have received 256 bytes of output, so you may need to send extra whitespace before flushing to get those browsers to display the page. "
FractalizeR