javascript - Detect when browser receives file download -


i have page allows user download dynamically-generated file. takes long time generate, i'd show "waiting" indicator. problem is, can't figure out how detect when browser has received file, can hide indicator.

i'm making request in hidden form, posts server, , targets hidden iframe results. don't replace entire browser window result. listen "load" event on iframe, in hope fire when download complete.

i return "content-disposition: attachment" header file, causes browser show "save" dialog. browser doesn't fire "load" event in iframe.

one approach tried using multi-part response. send empty html file, attached downloadable file. example:

content-type: multipart/x-mixed-replace;boundary="abcde"  --abcde content-type: text/html  --abcde content-type: application/vnd.fdf content-disposition: attachment; filename=foo.fdf  file-content --abcde 

this works in firefox; receives empty html file, fires "load" event, shows "save" dialog downloadable file. fails on ie , safari; ie fires "load" event doesn't download file, , safari downloads file (with wrong name , content-type), , doesn't fire "load" event.

a different approach might make call start file creation, poll server until it's ready, download already-created file. i'd rather avoid creating temporary files on server.

does have better idea?

one possible solution uses javascript on client.

the client algorithm:

  1. generate random unique token.
  2. submit download request, , include token in get/post field.
  3. show "waiting" indicator.
  4. start timer, , every second or so, cookie named "filedownloadtoken" (or whatever decide).
  5. if cookie exists, , value matches token, hide "waiting" indicator.

the server algorithm:

  1. look get/post field in request.
  2. if has non-empty value, drop cookie (e.g. "filedownloadtoken"), , set value token's value.

client source code (javascript):

function getcookie( name ) {   var parts = document.cookie.split(name + "=");   if (parts.length == 2) return parts.pop().split(";").shift(); }  function expirecookie( cname ) {     document.cookie =          encodeuricomponent(cname) + "=deleted; expires=" + new date( 0 ).toutcstring(); }  function setcursor( docstyle, buttonstyle ) {     document.getelementbyid( "doc" ).style.cursor = docstyle;     document.getelementbyid( "button-id" ).style.cursor = buttonstyle; }  function setformtoken() {     var downloadtoken = new date().gettime();     document.getelementbyid( "downloadtoken" ).value = downloadtoken;     return downloadtoken; }  var downloadtimer; var attempts = 30;  // prevents double-submits waiting cookie server. function blockresubmit() {     var downloadtoken = setformtoken();     setcursor( "wait", "wait" );      downloadtimer = window.setinterval( function() {         var token = getcookie( "downloadtoken" );          if( (token == downloadtoken) || (attempts == 0) ) {             unblocksubmit();         }          attempts--;     }, 1000 ); }  function unblocksubmit() {   setcursor( "auto", "pointer" );   window.clearinterval( downloadtimer );   expirecookie( "downloadtoken" );   attempts = 30; } 

example server code (php):

$token = "downloadtoken";  // sets cookie when download begins browser can // unblock submit button (thus helping prevent multiple clicks). // false parameter allows cookie exposed javascript. $this->setcookietoken( $token, $_get[ $token ], false );  $result = $this->sendfile(); 

where:

public function setcookietoken(     $cookiename, $cookievalue, $httponly = true, $secure = false ) {      // see: http://stackoverflow.com/a/1459794/59087     // see: http://shiflett.org/blog/2006/mar/server-name-versus-http-host     // see: http://stackoverflow.com/a/3290474/59087     setcookie(         $cookiename,         $cookievalue,         2147483647,            // expires january 1, 2038         "/",                   // path         $_server["http_host"], // domain         $secure,               // use true on https         $httponly              // set true $auth_cookie_name     ); } 

Comments

Popular posts from this blog

PHP and MySQL WP -

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

go - golang pprof for c library code -