2014-03-21 18:11:18 +01:00
/ * *
* jquery - html5 - upload
*
* @ author Mikhail Dektyarev < mihail . dektyarow @ gmail . com >
* @ link https : //github.com/mihaild/jquery-html5-upload
* /
2011-09-02 00:07:30 +02:00
( function ( $ ) {
jQuery . fn . html5 _upload = function ( options ) {
var available _events = [ 'onStart' , 'onStartOne' , 'onProgress' , 'onFinishOne' , 'onFinish' , 'onError' ] ;
var options = jQuery . extend ( {
onStart : function ( event , total ) {
return true ;
} ,
onStartOne : function ( event , name , number , total ) {
return true ;
} ,
onProgress : function ( event , progress , name , number , total ) {
} ,
onFinishOne : function ( event , response , name , number , total ) {
} ,
onFinish : function ( event , total ) {
} ,
onError : function ( event , name , error ) {
} ,
onBrowserIncompatible : function ( ) {
alert ( "Sorry, but your browser is incompatible with uploading files using HTML5 (at least, with current preferences.\n Please install the latest version of Firefox, Safari or Chrome" ) ;
} ,
autostart : true ,
autoclear : true ,
stopOnFirstError : false ,
sendBoundary : false ,
fieldName : 'user_file[]' , //ignore if sendBoundary is false
method : 'post' ,
STATUSES : {
'STARTED' : 'Запуск' ,
'PROGRESS' : 'Загрузка' ,
'LOADED' : 'Обработка' ,
'FINISHED' : 'Завершено'
} ,
headers : {
"Cache-Control" : "no-cache" ,
"X-Requested-With" : "XMLHttpRequest" ,
2014-03-21 18:11:18 +01:00
"X-File-Name" : function ( file ) { return encodeURIComponent ( file . fileName ? file . fileName : file . name ) ; } ,
"X-File-Size" : function ( file ) { return file . fileSize ? file . fileSize : file . size ; } ,
2011-09-02 00:07:30 +02:00
"Content-Type" : function ( file ) {
if ( ! options . sendBoundary ) return 'multipart/form-data' ;
return false ;
}
} ,
setName : function ( text ) { } ,
setStatus : function ( text ) { } ,
setProgress : function ( value ) { } ,
genName : function ( file , number , total ) {
return file + "(" + ( number + 1 ) + " из " + total + ")" ;
} ,
genStatus : function ( progress , finished ) {
if ( finished ) {
return options . STATUSES [ 'FINISHED' ] ;
}
if ( progress == 0 ) {
return options . STATUSES [ 'STARTED' ] ;
}
else if ( progress == 1 ) {
return options . STATUSES [ 'LOADED' ] ;
}
else {
return options . STATUSES [ 'PROGRESS' ] ;
}
} ,
genProgress : function ( loaded , total ) {
return loaded / total ;
}
} , options ) ;
function upload ( ) {
var files = this . files ;
var total = files . length ;
var $this = $ ( this ) ;
2012-03-28 23:01:51 +02:00
if ( ! $this . triggerHandler ( 'onStart.html5_upload' , [ total ] ) ) {
2011-09-02 00:07:30 +02:00
return false ;
}
this . disabled = true ;
var uploaded = 0 ;
var xhr = this . html5 _upload [ 'xhr' ] ;
this . html5 _upload [ 'continue_after_abort' ] = true ;
function upload _file ( number ) {
if ( number == total ) {
2012-03-28 23:01:51 +02:00
$this . trigger ( 'onFinish.html5_upload' , [ total ] ) ;
2011-09-02 00:07:30 +02:00
options . setStatus ( options . genStatus ( 1 , true ) ) ;
$this . attr ( "disabled" , false ) ;
if ( options . autoclear ) {
$this . val ( "" ) ;
}
return ;
}
var file = files [ number ] ;
2012-04-06 00:31:01 +02:00
var fileName = file . fileName ? file . fileName : file . name ;
var fileSize = file . fileSize ? file . fileSize : file . size ;
if ( ! $this . triggerHandler ( 'onStartOne.html5_upload' , [ fileName , number , total ] ) ) {
2011-09-02 00:07:30 +02:00
return upload _file ( number + 1 ) ;
}
options . setStatus ( options . genStatus ( 0 ) ) ;
2012-04-06 00:31:01 +02:00
options . setName ( options . genName ( fileName , number , total ) ) ;
options . setProgress ( options . genProgress ( 0 , fileSize ) ) ;
2011-09-02 00:07:30 +02:00
xhr . upload [ 'onprogress' ] = function ( rpe ) {
2012-04-06 00:31:01 +02:00
$this . trigger ( 'onProgress.html5_upload' , [ rpe . loaded / rpe . total , fileName , number , total ] ) ;
2011-09-02 00:07:30 +02:00
options . setStatus ( options . genStatus ( rpe . loaded / rpe . total ) ) ;
options . setProgress ( options . genProgress ( rpe . loaded , rpe . total ) ) ;
} ;
xhr . onload = function ( load ) {
2012-04-06 00:31:01 +02:00
$this . trigger ( 'onFinishOne.html5_upload' , [ xhr . responseText , fileName , number , total ] ) ;
2011-09-02 00:07:30 +02:00
options . setStatus ( options . genStatus ( 1 , true ) ) ;
2012-04-06 00:31:01 +02:00
options . setProgress ( options . genProgress ( fileSize , fileSize ) ) ;
2011-09-02 00:07:30 +02:00
upload _file ( number + 1 ) ;
} ;
xhr . onabort = function ( ) {
if ( $this [ 0 ] . html5 _upload [ 'continue_after_abort' ] ) {
upload _file ( number + 1 ) ;
}
else {
$this . attr ( "disabled" , false ) ;
if ( options . autoclear ) {
$this . val ( "" ) ;
}
}
} ;
xhr . onerror = function ( e ) {
2012-04-06 00:31:01 +02:00
$this . trigger ( 'onError.html5_upload' , [ fileName , e ] ) ;
2011-09-02 00:07:30 +02:00
if ( ! options . stopOnFirstError ) {
upload _file ( number + 1 ) ;
}
} ;
xhr . open ( options . method , typeof ( options . url ) == "function" ? options . url ( number ) : options . url , true ) ;
$ . each ( options . headers , function ( key , val ) {
val = typeof ( val ) == "function" ? val ( file ) : val ; // resolve value
if ( val === false ) return true ; // if resolved value is boolean false, do not send this header
xhr . setRequestHeader ( key , val ) ;
} ) ;
if ( ! options . sendBoundary ) {
xhr . send ( file ) ;
}
else {
if ( window . FormData ) { //Many thanks to scottt.tw
var f = new FormData ( ) ;
f . append ( typeof ( options . fieldName ) == "function" ? options . fieldName ( ) : options . fieldName , file ) ;
2011-09-08 22:32:58 +02:00
if ( typeof ( options . beforeSend ) == "function" ) { options . beforeSend ( f ) ; } // Give eGW a chance to interfere
2011-09-02 00:07:30 +02:00
xhr . send ( f ) ;
}
else if ( file . getAsBinary ) { //Thanks to jm.schelcher
var boundary = '------multipartformboundary' + ( new Date ) . getTime ( ) ;
var dashdash = '--' ;
var crlf = '\r\n' ;
/* Build RFC2388 string. */
var builder = '' ;
builder += dashdash ;
builder += boundary ;
builder += crlf ;
builder += 'Content-Disposition: form-data; name="' + ( typeof ( options . fieldName ) == "function" ? options . fieldName ( ) : options . fieldName ) + '"' ;
//thanks to oyejo...@gmail.com for this fix
2012-04-06 00:31:01 +02:00
fileName = unescape ( encodeURIComponent ( fileName ) ) ; //encode_utf8
2011-09-02 00:07:30 +02:00
builder += '; filename="' + fileName + '"' ;
builder += crlf ;
builder += 'Content-Type: application/octet-stream' ;
builder += crlf ;
builder += crlf ;
/* Append binary data. */
builder += file . getAsBinary ( ) ;
builder += crlf ;
2011-09-08 22:32:58 +02:00
// Give eGW a chance to interfere
2014-03-21 18:11:18 +01:00
if ( typeof ( options . beforeSend ) == "function" ) {
2011-09-08 22:32:58 +02:00
builder += dashdash ;
builder += boundary ;
builder += crlf ;
builder += options . beforeSend ( ) ;
builder += crlf ;
}
2011-09-02 00:07:30 +02:00
/* Write boundary. */
builder += dashdash ;
builder += boundary ;
builder += dashdash ;
builder += crlf ;
xhr . setRequestHeader ( 'content-type' , 'multipart/form-data; boundary=' + boundary ) ;
xhr . sendAsBinary ( builder ) ;
}
else {
options . onBrowserIncompatible ( ) ;
}
}
}
upload _file ( 0 ) ;
return true ;
}
return this . each ( function ( ) {
this . html5 _upload = {
xhr : new XMLHttpRequest ( ) ,
continue _after _abort : true
} ;
if ( options . autostart ) {
$ ( this ) . bind ( 'change' , upload ) ;
}
for ( event in available _events ) {
if ( options [ available _events [ event ] ] ) {
2012-03-28 23:01:51 +02:00
$ ( this ) . bind ( available _events [ event ] + ".html5_upload" , options [ available _events [ event ] ] ) ;
2011-09-02 00:07:30 +02:00
}
}
$ ( this )
2012-03-28 23:01:51 +02:00
. bind ( 'start.html5_upload' , upload )
. bind ( 'cancelOne.html5_upload' , function ( ) {
2011-09-02 00:07:30 +02:00
this . html5 _upload [ 'xhr' ] . abort ( ) ;
} )
2012-03-28 23:01:51 +02:00
. bind ( 'cancelAll.html5_upload' , function ( ) {
2011-09-02 00:07:30 +02:00
this . html5 _upload [ 'continue_after_abort' ] = false ;
this . html5 _upload [ 'xhr' ] . abort ( ) ;
} )
2012-03-28 23:01:51 +02:00
. bind ( 'destroy.html5_upload' , function ( ) {
2011-09-02 00:07:30 +02:00
this . html5 _upload [ 'continue_after_abort' ] = false ;
this . xhr . abort ( ) ;
delete this . html5 _upload ;
2012-03-28 23:01:51 +02:00
$ ( this ) . unbind ( '.html5_upload' ) . unbind ( 'change' , upload ) ;
2011-09-02 00:07:30 +02:00
} ) ;
} ) ;
} ;
} ) ( jQuery ) ;