2017-09-01 14:28:46 +02:00
/ * *
* Plupload - multi - runtime File Uploader
2019-11-03 16:31:02 +01:00
* v2 . 3.6
2017-09-01 14:28:46 +02:00
*
* Copyright 2013 , Moxiecode Systems AB
* Released under GPL License .
*
* License : http : //www.plupload.com/license
* Contributing : http : //www.plupload.com/contributing
*
2019-11-03 16:31:02 +01:00
* Date : 2017 - 11 - 03
2017-09-01 14:28:46 +02:00
* /
2019-11-03 16:31:02 +01:00
; ( function ( global , factory ) {
var extract = function ( ) {
var ctx = { } ;
factory . apply ( ctx , arguments ) ;
return ctx . plupload ;
} ;
if ( typeof define === "function" && define . amd ) {
define ( "plupload" , [ './moxie' ] , extract ) ;
} else if ( typeof module === "object" && module . exports ) {
module . exports = extract ( require ( './moxie' ) ) ;
} else {
global . plupload = extract ( global . moxie ) ;
}
} ( this || window , function ( moxie ) {
2017-09-01 14:28:46 +02:00
/ * *
* Plupload . js
*
* Copyright 2013 , Moxiecode Systems AB
* Released under GPL License .
*
* License : http : //www.plupload.com/license
* Contributing : http : //www.plupload.com/contributing
* /
2019-11-03 16:31:02 +01:00
; ( function ( exports , o , undef ) {
2017-09-01 14:28:46 +02:00
2019-11-03 16:31:02 +01:00
var delay = window . setTimeout ;
var fileFilters = { } ;
var u = o . core . utils ;
var Runtime = o . runtime . Runtime ;
2017-09-01 14:28:46 +02:00
// convert plupload features to caps acceptable by mOxie
2019-11-03 16:31:02 +01:00
function normalizeCaps ( settings ) {
2017-09-01 14:28:46 +02:00
var features = settings . required _features , caps = { } ;
function resolve ( feature , value , strict ) {
// Feature notation is deprecated, use caps (this thing here is required for backward compatibility)
2019-11-03 16:31:02 +01:00
var map = {
2017-09-01 14:28:46 +02:00
chunks : 'slice_blob' ,
jpgresize : 'send_binary_string' ,
pngresize : 'send_binary_string' ,
progress : 'report_upload_progress' ,
multi _selection : 'select_multiple' ,
dragdrop : 'drag_and_drop' ,
drop _element : 'drag_and_drop' ,
headers : 'send_custom_headers' ,
urlstream _upload : 'send_binary_string' ,
canSendBinary : 'send_binary' ,
triggerDialog : 'summon_file_dialog'
} ;
if ( map [ feature ] ) {
caps [ map [ feature ] ] = value ;
} else if ( ! strict ) {
caps [ feature ] = value ;
}
}
if ( typeof ( features ) === 'string' ) {
plupload . each ( features . split ( /\s*,\s*/ ) , function ( feature ) {
resolve ( feature , true ) ;
} ) ;
} else if ( typeof ( features ) === 'object' ) {
plupload . each ( features , function ( value , feature ) {
resolve ( feature , value ) ;
} ) ;
} else if ( features === true ) {
// check settings for required features
2019-11-03 16:31:02 +01:00
if ( settings . chunk _size && settings . chunk _size > 0 ) {
2017-09-01 14:28:46 +02:00
caps . slice _blob = true ;
}
2019-11-03 16:31:02 +01:00
if ( ! plupload . isEmptyObj ( settings . resize ) || settings . multipart === false ) {
2017-09-01 14:28:46 +02:00
caps . send _binary _string = true ;
}
2019-11-03 16:31:02 +01:00
if ( settings . http _method ) {
caps . use _http _method = settings . http _method ;
}
2017-09-01 14:28:46 +02:00
plupload . each ( settings , function ( value , feature ) {
resolve ( feature , ! ! value , true ) ; // strict check
} ) ;
}
return caps ;
}
2019-11-03 16:31:02 +01:00
/ * *
* @ module plupload
2017-09-01 14:28:46 +02:00
* @ static
* /
var plupload = {
/ * *
* Plupload version will be replaced on build .
*
* @ property VERSION
* @ for Plupload
* @ static
* @ final
* /
2019-11-03 16:31:02 +01:00
VERSION : '2.3.6' ,
2017-09-01 14:28:46 +02:00
/ * *
* The state of the queue before it has started and after it has finished
*
* @ property STOPPED
* @ static
* @ final
* /
STOPPED : 1 ,
/ * *
* Upload process is running
*
* @ property STARTED
* @ static
* @ final
* /
STARTED : 2 ,
/ * *
* File is queued for upload
*
* @ property QUEUED
* @ static
* @ final
* /
QUEUED : 1 ,
/ * *
* File is being uploaded
*
* @ property UPLOADING
* @ static
* @ final
* /
UPLOADING : 2 ,
/ * *
* File has failed to be uploaded
*
* @ property FAILED
* @ static
* @ final
* /
FAILED : 4 ,
/ * *
* File has been uploaded successfully
*
* @ property DONE
* @ static
* @ final
* /
DONE : 5 ,
// Error constants used by the Error event
/ * *
* Generic error for example if an exception is thrown inside Silverlight .
*
* @ property GENERIC _ERROR
* @ static
* @ final
* /
GENERIC _ERROR : - 100 ,
/ * *
* HTTP transport error . For example if the server produces a HTTP status other than 200.
*
* @ property HTTP _ERROR
* @ static
* @ final
* /
HTTP _ERROR : - 200 ,
/ * *
* Generic I / O error . For example if it wasn ' t possible to open the file stream on local machine .
*
* @ property IO _ERROR
* @ static
* @ final
* /
IO _ERROR : - 300 ,
/ * *
* @ property SECURITY _ERROR
* @ static
* @ final
* /
SECURITY _ERROR : - 400 ,
/ * *
* Initialization error . Will be triggered if no runtime was initialized .
*
* @ property INIT _ERROR
* @ static
* @ final
* /
INIT _ERROR : - 500 ,
/ * *
2019-11-03 16:31:02 +01:00
* File size error . If the user selects a file that is too large or is empty it will be blocked and
* an error of this type will be triggered .
2017-09-01 14:28:46 +02:00
*
* @ property FILE _SIZE _ERROR
* @ static
* @ final
* /
FILE _SIZE _ERROR : - 600 ,
/ * *
* File extension error . If the user selects a file that isn ' t valid according to the filters setting .
*
* @ property FILE _EXTENSION _ERROR
* @ static
* @ final
* /
FILE _EXTENSION _ERROR : - 601 ,
/ * *
* Duplicate file error . If prevent _duplicates is set to true and user selects the same file again .
*
* @ property FILE _DUPLICATE _ERROR
* @ static
* @ final
* /
FILE _DUPLICATE _ERROR : - 602 ,
/ * *
* Runtime will try to detect if image is proper one . Otherwise will throw this error .
*
* @ property IMAGE _FORMAT _ERROR
* @ static
* @ final
* /
IMAGE _FORMAT _ERROR : - 700 ,
/ * *
* While working on files runtime may run out of memory and will throw this error .
*
* @ since 2.1 . 2
* @ property MEMORY _ERROR
* @ static
* @ final
* /
MEMORY _ERROR : - 701 ,
/ * *
* Each runtime has an upper limit on a dimension of the image it can handle . If bigger , will throw this error .
*
* @ property IMAGE _DIMENSIONS _ERROR
* @ static
* @ final
* /
IMAGE _DIMENSIONS _ERROR : - 702 ,
2019-11-03 16:31:02 +01:00
/ * *
* Expose whole moxie ( # 1469 ) .
*
* @ property moxie
* @ type Object
* @ final
* /
moxie : o ,
2017-09-01 14:28:46 +02:00
/ * *
* Mime type lookup table .
*
* @ property mimeTypes
* @ type Object
* @ final
* /
2019-11-03 16:31:02 +01:00
mimeTypes : u . Mime . mimes ,
2017-09-01 14:28:46 +02:00
/ * *
* In some cases sniffing is the only way around : (
* /
2019-11-03 16:31:02 +01:00
ua : u . Env ,
2017-09-01 14:28:46 +02:00
/ * *
* Gets the true type of the built - in object ( better version of typeof ) .
* @ credits Angus Croll ( http : //javascriptweblog.wordpress.com/)
*
* @ method typeOf
* @ static
* @ param { Object } o Object to check .
* @ return { String } Object [ [ Class ] ]
* /
2019-11-03 16:31:02 +01:00
typeOf : u . Basic . typeOf ,
2017-09-01 14:28:46 +02:00
/ * *
* Extends the specified object with another object .
*
* @ method extend
* @ static
* @ param { Object } target Object to extend .
* @ param { Object . . } obj Multiple objects to extend with .
* @ return { Object } Same as target , the extended object .
* /
2019-11-03 16:31:02 +01:00
extend : u . Basic . extend ,
2017-09-01 14:28:46 +02:00
/ * *
* Generates an unique ID . This is 99.99 % unique since it takes the current time and 5 random numbers .
* The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages
* to get 5 the same random numbers between 0 - 65535 it also uses a counter so each call will be guaranteed to be page unique .
* It ' s more probable for the earth to be hit with an asteriod . You can also if you want to be 100 % sure set the plupload . guidPrefix property
* to an user unique key .
*
* @ method guid
* @ static
* @ return { String } Virtually unique id .
* /
2019-11-03 16:31:02 +01:00
guid : u . Basic . guid ,
2017-09-01 14:28:46 +02:00
/ * *
* Get array of DOM Elements by their ids .
2019-11-03 16:31:02 +01:00
*
2017-09-01 14:28:46 +02:00
* @ method get
* @ param { String } id Identifier of the DOM Element
* @ return { Array }
* /
getAll : function get ( ids ) {
var els = [ ] , el ;
if ( plupload . typeOf ( ids ) !== 'array' ) {
ids = [ ids ] ;
}
var i = ids . length ;
while ( i -- ) {
el = plupload . get ( ids [ i ] ) ;
if ( el ) {
els . push ( el ) ;
}
}
return els . length ? els : null ;
} ,
/ * *
Get DOM element by id
@ method get
@ param { String } id Identifier of the DOM Element
@ return { Node }
* /
2019-11-03 16:31:02 +01:00
get : u . Dom . get ,
2017-09-01 14:28:46 +02:00
/ * *
* Executes the callback function for each item in array / object . If you return false in the
* callback it will break the loop .
*
* @ method each
* @ static
* @ param { Object } obj Object to iterate .
* @ param { function } callback Callback function to execute for each item .
* /
2019-11-03 16:31:02 +01:00
each : u . Basic . each ,
2017-09-01 14:28:46 +02:00
/ * *
* Returns the absolute x , y position of an Element . The position will be returned in a object with x , y fields .
*
* @ method getPos
* @ static
* @ param { Element } node HTML element or element id to get x , y position from .
* @ param { Element } root Optional root element to stop calculations at .
* @ return { object } Absolute position of the specified element object with x , y fields .
* /
2019-11-03 16:31:02 +01:00
getPos : u . Dom . getPos ,
2017-09-01 14:28:46 +02:00
/ * *
* Returns the size of the specified node in pixels .
*
* @ method getSize
* @ static
* @ param { Node } node Node to get the size of .
* @ return { Object } Object with a w and h property .
* /
2019-11-03 16:31:02 +01:00
getSize : u . Dom . getSize ,
2017-09-01 14:28:46 +02:00
/ * *
* Encodes the specified string .
*
* @ method xmlEncode
* @ static
* @ param { String } s String to encode .
* @ return { String } Encoded string .
* /
xmlEncode : function ( str ) {
var xmlEncodeChars = { '<' : 'lt' , '>' : 'gt' , '&' : 'amp' , '"' : 'quot' , '\'' : '#39' } , xmlEncodeRegExp = /[<>&\"\']/g ;
return str ? ( '' + str ) . replace ( xmlEncodeRegExp , function ( chr ) {
return xmlEncodeChars [ chr ] ? '&' + xmlEncodeChars [ chr ] + ';' : chr ;
} ) : str ;
} ,
/ * *
* Forces anything into an array .
*
* @ method toArray
* @ static
* @ param { Object } obj Object with length field .
* @ return { Array } Array object containing all items .
* /
2019-11-03 16:31:02 +01:00
toArray : u . Basic . toArray ,
2017-09-01 14:28:46 +02:00
/ * *
* Find an element in array and return its index if present , otherwise return - 1.
*
* @ method inArray
* @ static
* @ param { mixed } needle Element to find
* @ param { Array } array
* @ return { Int } Index of the element , or - 1 if not found
* /
2019-11-03 16:31:02 +01:00
inArray : u . Basic . inArray ,
/ * *
Recieve an array of functions ( usually async ) to call in sequence , each function
receives a callback as first argument that it should call , when it completes . Finally ,
after everything is complete , main callback is called . Passing truthy value to the
callback as a first argument will interrupt the sequence and invoke main callback
immediately .
@ method inSeries
@ static
@ param { Array } queue Array of functions to call in sequence
@ param { Function } cb Main callback that is called in the end , or in case of error
* /
inSeries : u . Basic . inSeries ,
2017-09-01 14:28:46 +02:00
/ * *
* Extends the language pack object with new items .
*
* @ method addI18n
* @ static
* @ param { Object } pack Language pack items to add .
* @ return { Object } Extended language pack object .
* /
2019-11-03 16:31:02 +01:00
addI18n : o . core . I18n . addI18n ,
2017-09-01 14:28:46 +02:00
/ * *
* Translates the specified string by checking for the english string in the language pack lookup .
*
* @ method translate
* @ static
* @ param { String } str String to look for .
* @ return { String } Translated string or the input string if it wasn ' t found .
* /
2019-11-03 16:31:02 +01:00
translate : o . core . I18n . translate ,
/ * *
* Pseudo sprintf implementation - simple way to replace tokens with specified values .
*
* @ param { String } str String with tokens
* @ return { String } String with replaced tokens
* /
sprintf : u . Basic . sprintf ,
2017-09-01 14:28:46 +02:00
/ * *
* Checks if object is empty .
*
* @ method isEmptyObj
* @ static
* @ param { Object } obj Object to check .
* @ return { Boolean }
* /
2019-11-03 16:31:02 +01:00
isEmptyObj : u . Basic . isEmptyObj ,
2017-09-01 14:28:46 +02:00
/ * *
* Checks if specified DOM element has specified class .
*
* @ method hasClass
* @ static
* @ param { Object } obj DOM element like object to add handler to .
* @ param { String } name Class name
* /
2019-11-03 16:31:02 +01:00
hasClass : u . Dom . hasClass ,
2017-09-01 14:28:46 +02:00
/ * *
* Adds specified className to specified DOM element .
*
* @ method addClass
* @ static
* @ param { Object } obj DOM element like object to add handler to .
* @ param { String } name Class name
* /
2019-11-03 16:31:02 +01:00
addClass : u . Dom . addClass ,
2017-09-01 14:28:46 +02:00
/ * *
* Removes specified className from specified DOM element .
*
* @ method removeClass
* @ static
* @ param { Object } obj DOM element like object to add handler to .
* @ param { String } name Class name
* /
2019-11-03 16:31:02 +01:00
removeClass : u . Dom . removeClass ,
2017-09-01 14:28:46 +02:00
/ * *
* Returns a given computed style of a DOM element .
*
* @ method getStyle
* @ static
* @ param { Object } obj DOM element like object .
* @ param { String } name Style you want to get from the DOM element
* /
2019-11-03 16:31:02 +01:00
getStyle : u . Dom . getStyle ,
2017-09-01 14:28:46 +02:00
/ * *
* Adds an event handler to the specified object and store reference to the handler
* in objects internal Plupload registry ( @ see removeEvent ) .
*
* @ method addEvent
* @ static
* @ param { Object } obj DOM element like object to add handler to .
* @ param { String } name Name to add event listener to .
* @ param { Function } callback Function to call when event occurs .
* @ param { String } ( optional ) key that might be used to add specifity to the event record .
* /
2019-11-03 16:31:02 +01:00
addEvent : u . Events . addEvent ,
2017-09-01 14:28:46 +02:00
/ * *
* Remove event handler from the specified object . If third argument ( callback )
* is not specified remove all events with the specified name .
*
* @ method removeEvent
* @ static
* @ param { Object } obj DOM element to remove event listener ( s ) from .
* @ param { String } name Name of event listener to remove .
* @ param { Function | String } ( optional ) might be a callback or unique key to match .
* /
2019-11-03 16:31:02 +01:00
removeEvent : u . Events . removeEvent ,
2017-09-01 14:28:46 +02:00
/ * *
* Remove all kind of events from the specified object
*
* @ method removeAllEvents
* @ static
* @ param { Object } obj DOM element to remove event listeners from .
* @ param { String } ( optional ) unique key to match , when removing events .
* /
2019-11-03 16:31:02 +01:00
removeAllEvents : u . Events . removeAllEvents ,
2017-09-01 14:28:46 +02:00
/ * *
* Cleans the specified name from national characters ( diacritics ) . The result will be a name with only a - z , 0 - 9 and _ .
*
* @ method cleanName
* @ static
* @ param { String } s String to clean up .
* @ return { String } Cleaned string .
* /
cleanName : function ( name ) {
var i , lookup ;
// Replace diacritics
lookup = [
/[\300-\306]/g , 'A' , /[\340-\346]/g , 'a' ,
/\307/g , 'C' , /\347/g , 'c' ,
/[\310-\313]/g , 'E' , /[\350-\353]/g , 'e' ,
/[\314-\317]/g , 'I' , /[\354-\357]/g , 'i' ,
/\321/g , 'N' , /\361/g , 'n' ,
/[\322-\330]/g , 'O' , /[\362-\370]/g , 'o' ,
/[\331-\334]/g , 'U' , /[\371-\374]/g , 'u'
] ;
for ( i = 0 ; i < lookup . length ; i += 2 ) {
name = name . replace ( lookup [ i ] , lookup [ i + 1 ] ) ;
}
// Replace whitespace
name = name . replace ( /\s+/g , '_' ) ;
// Remove anything else
name = name . replace ( /[^a-z0-9_\-\.]+/gi , '' ) ;
return name ;
} ,
/ * *
* Builds a full url out of a base URL and an object with items to append as query string items .
*
* @ method buildUrl
* @ static
* @ param { String } url Base URL to append query string items to .
* @ param { Object } items Name / value object to serialize as a querystring .
* @ return { String } String with url + serialized query string items .
* /
2019-11-03 16:31:02 +01:00
buildUrl : function ( url , items ) {
2017-09-01 14:28:46 +02:00
var query = '' ;
plupload . each ( items , function ( value , name ) {
query += ( query ? '&' : '' ) + encodeURIComponent ( name ) + '=' + encodeURIComponent ( value ) ;
} ) ;
if ( query ) {
url += ( url . indexOf ( '?' ) > 0 ? '&' : '?' ) + query ;
}
return url ;
} ,
/ * *
* Formats the specified number as a size string for example 1024 becomes 1 KB .
*
* @ method formatSize
* @ static
* @ param { Number } size Size to format as string .
* @ return { String } Formatted size string .
* /
formatSize : function ( size ) {
if ( size === undef || /\D/ . test ( size ) ) {
return plupload . translate ( 'N/A' ) ;
}
function round ( num , precision ) {
return Math . round ( num * Math . pow ( 10 , precision ) ) / Math . pow ( 10 , precision ) ;
}
var boundary = Math . pow ( 1024 , 4 ) ;
// TB
if ( size > boundary ) {
return round ( size / boundary , 1 ) + " " + plupload . translate ( 'tb' ) ;
}
// GB
if ( size > ( boundary /= 1024 ) ) {
return round ( size / boundary , 1 ) + " " + plupload . translate ( 'gb' ) ;
}
// MB
if ( size > ( boundary /= 1024 ) ) {
return round ( size / boundary , 1 ) + " " + plupload . translate ( 'mb' ) ;
}
// KB
if ( size > 1024 ) {
return Math . round ( size / 1024 ) + " " + plupload . translate ( 'kb' ) ;
}
return size + " " + plupload . translate ( 'b' ) ;
} ,
/ * *
* Parses the specified size string into a byte value . For example 10 kb becomes 10240.
*
* @ method parseSize
* @ static
* @ param { String | Number } size String to parse or number to just pass through .
* @ return { Number } Size in bytes .
* /
2019-11-03 16:31:02 +01:00
parseSize : u . Basic . parseSizeStr ,
2017-09-01 14:28:46 +02:00
/ * *
* A way to predict what runtime will be choosen in the current environment with the
* specified settings .
*
* @ method predictRuntime
* @ static
* @ param { Object | String } config Plupload settings to check
* @ param { String } [ runtimes ] Comma - separated list of runtimes to check against
* @ return { String } Type of compatible runtime
* /
predictRuntime : function ( config , runtimes ) {
var up , runtime ;
up = new plupload . Uploader ( config ) ;
2019-11-03 16:31:02 +01:00
runtime = Runtime . thatCan ( up . getOption ( ) . required _features , runtimes || config . runtimes ) ;
2017-09-01 14:28:46 +02:00
up . destroy ( ) ;
return runtime ;
} ,
/ * *
* Registers a filter that will be executed for each file added to the queue .
* If callback returns false , file will not be added .
*
* Callback receives two arguments : a value for the filter as it was specified in settings . filters
* and a file to be filtered . Callback is executed in the context of uploader instance .
*
* @ method addFileFilter
* @ static
* @ param { String } name Name of the filter by which it can be referenced in settings . filters
* @ param { String } cb Callback - the actual routine that every added file must pass
* /
addFileFilter : function ( name , cb ) {
fileFilters [ name ] = cb ;
}
} ;
plupload . addFileFilter ( 'mime_types' , function ( filters , file , cb ) {
if ( filters . length && ! filters . regexp . test ( file . name ) ) {
this . trigger ( 'Error' , {
code : plupload . FILE _EXTENSION _ERROR ,
message : plupload . translate ( 'File extension error.' ) ,
file : file
} ) ;
cb ( false ) ;
} else {
cb ( true ) ;
}
} ) ;
plupload . addFileFilter ( 'max_file_size' , function ( maxSize , file , cb ) {
var undef ;
maxSize = plupload . parseSize ( maxSize ) ;
// Invalid file size
if ( file . size !== undef && maxSize && file . size > maxSize ) {
this . trigger ( 'Error' , {
code : plupload . FILE _SIZE _ERROR ,
message : plupload . translate ( 'File size error.' ) ,
file : file
} ) ;
cb ( false ) ;
} else {
cb ( true ) ;
}
} ) ;
plupload . addFileFilter ( 'prevent_duplicates' , function ( value , file , cb ) {
if ( value ) {
var ii = this . files . length ;
while ( ii -- ) {
// Compare by name and size (size might be 0 or undefined, but still equivalent for both)
if ( file . name === this . files [ ii ] . name && file . size === this . files [ ii ] . size ) {
this . trigger ( 'Error' , {
code : plupload . FILE _DUPLICATE _ERROR ,
message : plupload . translate ( 'Duplicate file error.' ) ,
file : file
} ) ;
cb ( false ) ;
return ;
}
}
}
cb ( true ) ;
} ) ;
2019-11-03 16:31:02 +01:00
plupload . addFileFilter ( 'prevent_empty' , function ( value , file , cb ) {
if ( value && ! file . size && file . size !== undef ) {
this . trigger ( 'Error' , {
code : plupload . FILE _SIZE _ERROR ,
message : plupload . translate ( 'File size error.' ) ,
file : file
} ) ;
cb ( false ) ;
} else {
cb ( true ) ;
}
} ) ;
2017-09-01 14:28:46 +02:00
/ * *
@ class Uploader
@ constructor
@ param { Object } settings For detailed information about each option check documentation .
@ param { String | DOMElement } settings . browse _button id of the DOM element or DOM element itself to use as file dialog trigger .
@ param { Number | String } [ settings . chunk _size = 0 ] Chunk size in bytes to slice the file into . Shorcuts with b , kb , mb , gb , tb suffixes also supported . ` e.g. 204800 or "204800b" or "200kb" ` . By default - disabled .
@ param { String | DOMElement } [ settings . container ] id of the DOM element or DOM element itself that will be used to wrap uploader structures . Defaults to immediate parent of the ` browse_button ` element .
@ param { String | DOMElement } [ settings . drop _element ] id of the DOM element or DOM element itself to use as a drop zone for Drag - n - Drop .
@ param { String } [ settings . file _data _name = "file" ] Name for the file field in Multipart formated message .
@ param { Object } [ settings . filters = { } ] Set of file type filters .
@ param { String | Number } [ settings . filters . max _file _size = 0 ] Maximum file size that the user can pick , in bytes . Optionally supports b , kb , mb , gb , tb suffixes . ` e.g. "10mb" or "1gb" ` . By default - not set . Dispatches ` plupload.FILE_SIZE_ERROR ` .
2019-11-03 16:31:02 +01:00
@ param { Array } [ settings . filters . mime _types = [ ] ] List of file types to accept , each one defined by title and list of extensions . ` e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"} ` . Dispatches ` plupload.FILE_EXTENSION_ERROR `
2017-09-01 14:28:46 +02:00
@ param { Boolean } [ settings . filters . prevent _duplicates = false ] Do not let duplicates into the queue . Dispatches ` plupload.FILE_DUPLICATE_ERROR ` .
2019-11-03 16:31:02 +01:00
@ param { Boolean } [ settings . filters . prevent _empty = true ] Do not let empty files into the queue ( IE10 is known to hang for example when trying to upload such ) . Dispatches ` plupload.FILE_SIZE_ERROR ` .
@ param { String } [ settings . flash _swf _url ] URL of the Flash swf .
2017-09-01 14:28:46 +02:00
@ param { Object } [ settings . headers ] Custom headers to send with the upload . Hash of name / value pairs .
2019-11-03 16:31:02 +01:00
@ param { String } [ settings . http _method = "POST" ] HTTP method to use during upload ( only PUT or POST allowed ) .
2017-09-01 14:28:46 +02:00
@ param { Number } [ settings . max _retries = 0 ] How many times to retry the chunk or file , before triggering Error event .
@ param { Boolean } [ settings . multipart = true ] Whether to send file and additional parameters as Multipart formated message .
@ param { Object } [ settings . multipart _params ] Hash of key / value pairs to send with every file upload .
@ param { Boolean } [ settings . multi _selection = true ] Enable ability to select multiple files at once in file dialog .
@ param { String | Object } [ settings . required _features ] Either comma - separated list or hash of required features that chosen runtime should absolutely possess .
@ param { Object } [ settings . resize ] Enable resizng of images on client - side . Applies to ` image/jpeg ` and ` image/png ` only . ` e.g. {width : 200, height : 200, quality : 90, crop: true} `
@ param { Number } [ settings . resize . width ] If image is bigger , it will be resized .
@ param { Number } [ settings . resize . height ] If image is bigger , it will be resized .
@ param { Number } [ settings . resize . quality = 90 ] Compression quality for jpegs ( 1 - 100 ) .
@ param { Boolean } [ settings . resize . crop = false ] Whether to crop images to exact dimensions . By default they will be resized proportionally .
2019-11-03 16:31:02 +01:00
@ param { String } [ settings . runtimes = "html5,flash,silverlight,html4" ] Comma separated list of runtimes , that Plupload will try in turn , moving to the next if previous fails .
@ param { String } [ settings . silverlight _xap _url ] URL of the Silverlight xap .
@ param { Boolean } [ settings . send _chunk _number = true ] Whether to send chunks and chunk numbers , or total and offset bytes .
2017-09-01 14:28:46 +02:00
@ param { Boolean } [ settings . send _file _name = true ] Whether to send file name as additional argument - 'name' ( required for chunked uploads and some other cases where file name cannot be sent via normal ways ) .
2019-11-03 16:31:02 +01:00
@ param { String } settings . url URL of the server - side upload handler .
@ param { Boolean } [ settings . unique _names = false ] If true will generate unique filenames for uploaded files .
2017-09-01 14:28:46 +02:00
* /
plupload . Uploader = function ( options ) {
/ * *
Fires when the current RunTime has been initialized .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event Init
@ param { plupload . Uploader } uploader Uploader instance sending the event .
* /
/ * *
Fires after the init event incase you need to perform actions there .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event PostInit
@ param { plupload . Uploader } uploader Uploader instance sending the event .
* /
/ * *
Fires when the option is changed in via uploader . setOption ( ) .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event OptionChanged
@ since 2.1
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { String } name Name of the option that was changed
@ param { Mixed } value New value for the specified option
@ param { Mixed } oldValue Previous value of the option
* /
/ * *
Fires when the silverlight / flash or other shim needs to move .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event Refresh
@ param { plupload . Uploader } uploader Uploader instance sending the event .
* /
/ * *
Fires when the overall state is being changed for the upload queue .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event StateChanged
@ param { plupload . Uploader } uploader Uploader instance sending the event .
* /
/ * *
Fires when browse _button is clicked and browse dialog shows .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event Browse
@ since 2.1 . 2
@ param { plupload . Uploader } uploader Uploader instance sending the event .
2019-11-03 16:31:02 +01:00
* /
2017-09-01 14:28:46 +02:00
/ * *
Fires for every filtered file before it is added to the queue .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event FileFiltered
@ since 2.1
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file Another file that has to be added to the queue .
* /
/ * *
Fires when the file queue is changed . In other words when files are added / removed to the files array of the uploader instance .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event QueueChanged
@ param { plupload . Uploader } uploader Uploader instance sending the event .
2019-11-03 16:31:02 +01:00
* /
2017-09-01 14:28:46 +02:00
/ * *
Fires after files were filtered and added to the queue .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event FilesAdded
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { Array } files Array of file objects that were added to queue by the user .
* /
/ * *
Fires when file is removed from the queue .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event FilesRemoved
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { Array } files Array of files that got removed .
* /
/ * *
Fires just before a file is uploaded . Can be used to cancel the upload for the specified file
by returning false from the handler .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event BeforeUpload
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file File to be uploaded .
* /
/ * *
Fires when a file is to be uploaded by the runtime .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event UploadFile
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file File to be uploaded .
* /
/ * *
Fires while a file is being uploaded . Use this event to update the current file upload progress .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event UploadProgress
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file File that is currently being uploaded .
2019-11-03 16:31:02 +01:00
* /
/ * *
* Fires just before a chunk is uploaded . This event enables you to override settings
* on the uploader instance before the chunk is uploaded .
*
* @ event BeforeChunkUpload
* @ param { plupload . Uploader } uploader Uploader instance sending the event .
* @ param { plupload . File } file File to be uploaded .
* @ param { Object } args POST params to be sent .
* @ param { Blob } chunkBlob Current blob .
* @ param { offset } offset Current offset .
* /
2017-09-01 14:28:46 +02:00
/ * *
Fires when file chunk is uploaded .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event ChunkUploaded
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file File that the chunk was uploaded for .
@ param { Object } result Object with response properties .
@ param { Number } result . offset The amount of bytes the server has received so far , including this chunk .
@ param { Number } result . total The size of the file .
@ param { String } result . response The response body sent by the server .
@ param { Number } result . status The HTTP status code sent by the server .
@ param { String } result . responseHeaders All the response headers as a single string .
* /
/ * *
Fires when a file is successfully uploaded .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event FileUploaded
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { plupload . File } file File that was uploaded .
@ param { Object } result Object with response properties .
@ param { String } result . response The response body sent by the server .
@ param { Number } result . status The HTTP status code sent by the server .
@ param { String } result . responseHeaders All the response headers as a single string .
* /
/ * *
Fires when all files in a queue are uploaded .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event UploadComplete
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { Array } files Array of file objects that was added to queue / selected by the user .
* /
/ * *
Fires when a error occurs .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event Error
@ param { plupload . Uploader } uploader Uploader instance sending the event .
@ param { Object } error Contains code , message and sometimes file and other details .
@ param { Number } error . code The plupload error code .
@ param { String } error . message Description of the error ( uses i18n ) .
* /
/ * *
Fires when destroy method is called .
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
@ event Destroy
@ param { plupload . Uploader } uploader Uploader instance sending the event .
* /
var uid = plupload . guid ( )
, settings
, files = [ ]
, preferred _caps = { }
, fileInputs = [ ]
, fileDrops = [ ]
, startTime
, total
, disabled = false
, xhr
;
// Private methods
function uploadNext ( ) {
var file , count = 0 , i ;
if ( this . state == plupload . STARTED ) {
// Find first QUEUED file
for ( i = 0 ; i < files . length ; i ++ ) {
if ( ! file && files [ i ] . status == plupload . QUEUED ) {
file = files [ i ] ;
if ( this . trigger ( "BeforeUpload" , file ) ) {
file . status = plupload . UPLOADING ;
this . trigger ( "UploadFile" , file ) ;
}
} else {
count ++ ;
}
}
// All files are DONE or FAILED
if ( count == files . length ) {
if ( this . state !== plupload . STOPPED ) {
this . state = plupload . STOPPED ;
this . trigger ( "StateChanged" ) ;
}
this . trigger ( "UploadComplete" , files ) ;
}
}
}
function calcFile ( file ) {
file . percent = file . size > 0 ? Math . ceil ( file . loaded / file . size * 100 ) : 100 ;
calc ( ) ;
}
function calc ( ) {
var i , file ;
2019-11-03 16:31:02 +01:00
var loaded ;
var loadedDuringCurrentSession = 0 ;
2017-09-01 14:28:46 +02:00
// Reset stats
total . reset ( ) ;
// Check status, size, loaded etc on all files
for ( i = 0 ; i < files . length ; i ++ ) {
file = files [ i ] ;
if ( file . size !== undef ) {
// We calculate totals based on original file size
total . size += file . origSize ;
// Since we cannot predict file size after resize, we do opposite and
// interpolate loaded amount to match magnitude of total
2019-11-03 16:31:02 +01:00
loaded = file . loaded * file . origSize / file . size ;
if ( ! file . completeTimestamp || file . completeTimestamp > startTime ) {
loadedDuringCurrentSession += loaded ;
}
total . loaded += loaded ;
2017-09-01 14:28:46 +02:00
} else {
total . size = undef ;
}
if ( file . status == plupload . DONE ) {
total . uploaded ++ ;
} else if ( file . status == plupload . FAILED ) {
total . failed ++ ;
} else {
total . queued ++ ;
}
}
// If we couldn't calculate a total file size then use the number of files to calc percent
if ( total . size === undef ) {
total . percent = files . length > 0 ? Math . ceil ( total . uploaded / files . length * 100 ) : 0 ;
} else {
2019-11-03 16:31:02 +01:00
total . bytesPerSec = Math . ceil ( loadedDuringCurrentSession / ( ( + new Date ( ) - startTime || 1 ) / 1000.0 ) ) ;
2017-09-01 14:28:46 +02:00
total . percent = total . size > 0 ? Math . ceil ( total . loaded / total . size * 100 ) : 0 ;
}
}
function getRUID ( ) {
var ctrl = fileInputs [ 0 ] || fileDrops [ 0 ] ;
if ( ctrl ) {
return ctrl . getRuntime ( ) . uid ;
}
return false ;
}
function bindEventListeners ( ) {
this . bind ( 'FilesAdded FilesRemoved' , function ( up ) {
up . trigger ( 'QueueChanged' ) ;
up . refresh ( ) ;
} ) ;
this . bind ( 'CancelUpload' , onCancelUpload ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
this . bind ( 'BeforeUpload' , onBeforeUpload ) ;
this . bind ( 'UploadFile' , onUploadFile ) ;
this . bind ( 'UploadProgress' , onUploadProgress ) ;
this . bind ( 'StateChanged' , onStateChanged ) ;
this . bind ( 'QueueChanged' , calc ) ;
this . bind ( 'Error' , onError ) ;
this . bind ( 'FileUploaded' , onFileUploaded ) ;
this . bind ( 'Destroy' , onDestroy ) ;
}
function initControls ( settings , cb ) {
var self = this , inited = 0 , queue = [ ] ;
// common settings
var options = {
runtime _order : settings . runtimes ,
required _caps : settings . required _features ,
2019-11-03 16:31:02 +01:00
preferred _caps : preferred _caps ,
swf _url : settings . flash _swf _url ,
xap _url : settings . silverlight _xap _url
2017-09-01 14:28:46 +02:00
} ;
// add runtime specific options if any
plupload . each ( settings . runtimes . split ( /\s*,\s*/ ) , function ( runtime ) {
if ( settings [ runtime ] ) {
options [ runtime ] = settings [ runtime ] ;
}
} ) ;
// initialize file pickers - there can be many
if ( settings . browse _button ) {
plupload . each ( settings . browse _button , function ( el ) {
queue . push ( function ( cb ) {
2019-11-03 16:31:02 +01:00
var fileInput = new o . file . FileInput ( plupload . extend ( { } , options , {
2017-09-01 14:28:46 +02:00
accept : settings . filters . mime _types ,
name : settings . file _data _name ,
multiple : settings . multi _selection ,
container : settings . container ,
browse _button : el
} ) ) ;
fileInput . onready = function ( ) {
2019-11-03 16:31:02 +01:00
var info = Runtime . getInfo ( this . ruid ) ;
2017-09-01 14:28:46 +02:00
// for backward compatibility
2019-11-03 16:31:02 +01:00
plupload . extend ( self . features , {
2017-09-01 14:28:46 +02:00
chunks : info . can ( 'slice_blob' ) ,
multipart : info . can ( 'send_multipart' ) ,
multi _selection : info . can ( 'select_multiple' )
} ) ;
inited ++ ;
fileInputs . push ( this ) ;
cb ( ) ;
} ;
fileInput . onchange = function ( ) {
self . addFile ( this . files ) ;
} ;
fileInput . bind ( 'mouseenter mouseleave mousedown mouseup' , function ( e ) {
if ( ! disabled ) {
if ( settings . browse _button _hover ) {
if ( 'mouseenter' === e . type ) {
2019-11-03 16:31:02 +01:00
plupload . addClass ( el , settings . browse _button _hover ) ;
2017-09-01 14:28:46 +02:00
} else if ( 'mouseleave' === e . type ) {
2019-11-03 16:31:02 +01:00
plupload . removeClass ( el , settings . browse _button _hover ) ;
2017-09-01 14:28:46 +02:00
}
}
if ( settings . browse _button _active ) {
if ( 'mousedown' === e . type ) {
2019-11-03 16:31:02 +01:00
plupload . addClass ( el , settings . browse _button _active ) ;
2017-09-01 14:28:46 +02:00
} else if ( 'mouseup' === e . type ) {
2019-11-03 16:31:02 +01:00
plupload . removeClass ( el , settings . browse _button _active ) ;
2017-09-01 14:28:46 +02:00
}
}
}
} ) ;
fileInput . bind ( 'mousedown' , function ( ) {
self . trigger ( 'Browse' ) ;
} ) ;
fileInput . bind ( 'error runtimeerror' , function ( ) {
fileInput = null ;
cb ( ) ;
} ) ;
fileInput . init ( ) ;
} ) ;
} ) ;
}
// initialize drop zones
if ( settings . drop _element ) {
plupload . each ( settings . drop _element , function ( el ) {
queue . push ( function ( cb ) {
2019-11-03 16:31:02 +01:00
var fileDrop = new o . file . FileDrop ( plupload . extend ( { } , options , {
2017-09-01 14:28:46 +02:00
drop _zone : el
} ) ) ;
fileDrop . onready = function ( ) {
2019-11-03 16:31:02 +01:00
var info = Runtime . getInfo ( this . ruid ) ;
2017-09-01 14:28:46 +02:00
// for backward compatibility
2019-11-03 16:31:02 +01:00
plupload . extend ( self . features , {
2017-09-01 14:28:46 +02:00
chunks : info . can ( 'slice_blob' ) ,
multipart : info . can ( 'send_multipart' ) ,
dragdrop : info . can ( 'drag_and_drop' )
} ) ;
inited ++ ;
fileDrops . push ( this ) ;
cb ( ) ;
} ;
fileDrop . ondrop = function ( ) {
self . addFile ( this . files ) ;
} ;
fileDrop . bind ( 'error runtimeerror' , function ( ) {
fileDrop = null ;
cb ( ) ;
} ) ;
fileDrop . init ( ) ;
} ) ;
} ) ;
}
2019-11-03 16:31:02 +01:00
plupload . inSeries ( queue , function ( ) {
2017-09-01 14:28:46 +02:00
if ( typeof ( cb ) === 'function' ) {
cb ( inited ) ;
}
} ) ;
}
2019-11-03 16:31:02 +01:00
function resizeImage ( blob , params , runtimeOptions , cb ) {
var img = new o . image . Image ( ) ;
2017-09-01 14:28:46 +02:00
try {
img . onload = function ( ) {
// no manipulation required if...
if ( params . width > this . width &&
params . height > this . height &&
params . quality === undef &&
params . preserve _headers &&
! params . crop
) {
this . destroy ( ) ;
2019-11-03 16:31:02 +01:00
cb ( blob ) ;
} else {
// otherwise downsize
img . downsize ( params . width , params . height , params . crop , params . preserve _headers ) ;
2017-09-01 14:28:46 +02:00
}
} ;
img . onresize = function ( ) {
2019-11-03 16:31:02 +01:00
var resizedBlob = this . getAsBlob ( blob . type , params . quality ) ;
2017-09-01 14:28:46 +02:00
this . destroy ( ) ;
2019-11-03 16:31:02 +01:00
cb ( resizedBlob ) ;
2017-09-01 14:28:46 +02:00
} ;
2019-11-03 16:31:02 +01:00
img . bind ( 'error runtimeerror' , function ( ) {
this . destroy ( ) ;
2017-09-01 14:28:46 +02:00
cb ( blob ) ;
2019-11-03 16:31:02 +01:00
} ) ;
2017-09-01 14:28:46 +02:00
2019-11-03 16:31:02 +01:00
img . load ( blob , runtimeOptions ) ;
2017-09-01 14:28:46 +02:00
} catch ( ex ) {
cb ( blob ) ;
}
}
function setOption ( option , value , init ) {
var self = this , reinitRequired = false ;
function _setOption ( option , value , init ) {
var oldValue = settings [ option ] ;
switch ( option ) {
case 'max_file_size' :
if ( option === 'max_file_size' ) {
settings . max _file _size = settings . filters . max _file _size = value ;
}
break ;
case 'chunk_size' :
if ( value = plupload . parseSize ( value ) ) {
settings [ option ] = value ;
settings . send _file _name = true ;
}
break ;
case 'multipart' :
settings [ option ] = value ;
if ( ! value ) {
settings . send _file _name = true ;
}
break ;
2019-11-03 16:31:02 +01:00
case 'http_method' :
settings [ option ] = value . toUpperCase ( ) === 'PUT' ? 'PUT' : 'POST' ;
break ;
2017-09-01 14:28:46 +02:00
case 'unique_names' :
settings [ option ] = value ;
if ( value ) {
settings . send _file _name = true ;
}
break ;
case 'filters' :
// for sake of backward compatibility
if ( plupload . typeOf ( value ) === 'array' ) {
value = {
mime _types : value
} ;
}
if ( init ) {
plupload . extend ( settings . filters , value ) ;
} else {
settings . filters = value ;
}
// if file format filters are being updated, regenerate the matching expressions
if ( value . mime _types ) {
2019-11-03 16:31:02 +01:00
if ( plupload . typeOf ( value . mime _types ) === 'string' ) {
value . mime _types = o . core . utils . Mime . mimes2extList ( value . mime _types ) ;
}
value . mime _types . regexp = ( function ( filters ) {
2017-09-01 14:28:46 +02:00
var extensionsRegExp = [ ] ;
plupload . each ( filters , function ( filter ) {
plupload . each ( filter . extensions . split ( /,/ ) , function ( ext ) {
if ( /^\s*\*\s*$/ . test ( ext ) ) {
extensionsRegExp . push ( '\\.*' ) ;
} else {
extensionsRegExp . push ( '\\.' + ext . replace ( new RegExp ( '[' + ( '/^$.*+?|()[]{}\\' . replace ( /./g , '\\$&' ) ) + ']' , 'g' ) , '\\$&' ) ) ;
}
} ) ;
} ) ;
return new RegExp ( '(' + extensionsRegExp . join ( '|' ) + ')$' , 'i' ) ;
2019-11-03 16:31:02 +01:00
} ( value . mime _types ) ) ;
settings . filters . mime _types = value . mime _types ;
2017-09-01 14:28:46 +02:00
}
break ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
case 'resize' :
2019-11-03 16:31:02 +01:00
if ( value ) {
settings . resize = plupload . extend ( {
preserve _headers : true ,
crop : false
} , value ) ;
2017-09-01 14:28:46 +02:00
} else {
2019-11-03 16:31:02 +01:00
settings . resize = false ;
2017-09-01 14:28:46 +02:00
}
break ;
case 'prevent_duplicates' :
settings . prevent _duplicates = settings . filters . prevent _duplicates = ! ! value ;
break ;
// options that require reinitialisation
case 'container' :
case 'browse_button' :
case 'drop_element' :
value = 'container' === option
? plupload . get ( value )
: plupload . getAll ( value )
2019-11-03 16:31:02 +01:00
;
2017-09-01 14:28:46 +02:00
case 'runtimes' :
case 'multi_selection' :
2019-11-03 16:31:02 +01:00
case 'flash_swf_url' :
case 'silverlight_xap_url' :
2017-09-01 14:28:46 +02:00
settings [ option ] = value ;
if ( ! init ) {
reinitRequired = true ;
}
break ;
default :
settings [ option ] = value ;
}
if ( ! init ) {
self . trigger ( 'OptionChanged' , option , value , oldValue ) ;
}
}
if ( typeof ( option ) === 'object' ) {
plupload . each ( option , function ( value , option ) {
_setOption ( option , value , init ) ;
} ) ;
} else {
_setOption ( option , value , init ) ;
}
if ( init ) {
// Normalize the list of required capabilities
settings . required _features = normalizeCaps ( plupload . extend ( { } , settings ) ) ;
// Come up with the list of capabilities that can affect default mode in a multi-mode runtimes
preferred _caps = normalizeCaps ( plupload . extend ( { } , settings , {
required _features : true
} ) ) ;
} else if ( reinitRequired ) {
self . trigger ( 'Destroy' ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
initControls . call ( self , settings , function ( inited ) {
if ( inited ) {
2019-11-03 16:31:02 +01:00
self . runtime = Runtime . getInfo ( getRUID ( ) ) . type ;
2017-09-01 14:28:46 +02:00
self . trigger ( 'Init' , { runtime : self . runtime } ) ;
self . trigger ( 'PostInit' ) ;
} else {
self . trigger ( 'Error' , {
code : plupload . INIT _ERROR ,
message : plupload . translate ( 'Init error.' )
} ) ;
}
} ) ;
}
}
// Internal event handlers
function onBeforeUpload ( up , file ) {
// Generate unique target filenames
if ( up . settings . unique _names ) {
var matches = file . name . match ( /\.([^.]+)$/ ) , ext = "part" ;
if ( matches ) {
ext = matches [ 1 ] ;
}
file . target _name = file . id + '.' + ext ;
}
}
function onUploadFile ( up , file ) {
2019-11-03 16:31:02 +01:00
var url = up . settings . url ;
var chunkSize = up . settings . chunk _size ;
var retries = up . settings . max _retries ;
var features = up . features ;
var offset = 0 ;
var blob ;
var runtimeOptions = {
runtime _order : up . settings . runtimes ,
required _caps : up . settings . required _features ,
preferred _caps : preferred _caps ,
swf _url : up . settings . flash _swf _url ,
xap _url : up . settings . silverlight _xap _url
} ;
2017-09-01 14:28:46 +02:00
// make sure we start at a predictable offset
if ( file . loaded ) {
offset = file . loaded = chunkSize ? chunkSize * Math . floor ( file . loaded / chunkSize ) : 0 ;
}
function handleError ( ) {
if ( retries -- > 0 ) {
delay ( uploadNextChunk , 1000 ) ;
} else {
file . loaded = offset ; // reset all progress
up . trigger ( 'Error' , {
code : plupload . HTTP _ERROR ,
message : plupload . translate ( 'HTTP Error.' ) ,
file : file ,
response : xhr . responseText ,
status : xhr . status ,
responseHeaders : xhr . getAllResponseHeaders ( )
} ) ;
}
}
function uploadNextChunk ( ) {
2019-11-03 16:31:02 +01:00
var chunkBlob , args = { } , curChunkSize ;
2017-09-01 14:28:46 +02:00
// make sure that file wasn't cancelled and upload is not stopped in general
if ( file . status !== plupload . UPLOADING || up . state === plupload . STOPPED ) {
return ;
}
// send additional 'name' parameter only if required
if ( up . settings . send _file _name ) {
args . name = file . target _name || file . name ;
}
2019-11-03 16:31:02 +01:00
if ( chunkSize && features . chunks && blob . size > chunkSize ) { // blob will be of type string if it was loaded in memory
2017-09-01 14:28:46 +02:00
curChunkSize = Math . min ( chunkSize , blob . size - offset ) ;
chunkBlob = blob . slice ( offset , offset + curChunkSize ) ;
} else {
curChunkSize = blob . size ;
chunkBlob = blob ;
}
// If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller
if ( chunkSize && features . chunks ) {
// Setup query string arguments
if ( up . settings . send _chunk _number ) {
args . chunk = Math . ceil ( offset / chunkSize ) ;
args . chunks = Math . ceil ( blob . size / chunkSize ) ;
} else { // keep support for experimental chunk format, just in case
args . offset = offset ;
args . total = blob . size ;
}
}
2019-11-03 16:31:02 +01:00
if ( up . trigger ( 'BeforeChunkUpload' , file , args , chunkBlob , offset ) ) {
uploadChunk ( args , chunkBlob , curChunkSize ) ;
}
}
function uploadChunk ( args , chunkBlob , curChunkSize ) {
var formData ;
xhr = new o . xhr . XMLHttpRequest ( ) ;
2017-09-01 14:28:46 +02:00
// Do we have upload progress support
if ( xhr . upload ) {
xhr . upload . onprogress = function ( e ) {
file . loaded = Math . min ( file . size , offset + e . loaded ) ;
up . trigger ( 'UploadProgress' , file ) ;
} ;
}
xhr . onload = function ( ) {
// check if upload made itself through
2019-11-03 16:31:02 +01:00
if ( xhr . status < 200 || xhr . status >= 400 ) {
2017-09-01 14:28:46 +02:00
handleError ( ) ;
return ;
}
retries = up . settings . max _retries ; // reset the counter
// Handle chunk response
if ( curChunkSize < blob . size ) {
chunkBlob . destroy ( ) ;
offset += curChunkSize ;
file . loaded = Math . min ( offset , blob . size ) ;
up . trigger ( 'ChunkUploaded' , file , {
offset : file . loaded ,
total : blob . size ,
response : xhr . responseText ,
status : xhr . status ,
responseHeaders : xhr . getAllResponseHeaders ( )
} ) ;
// stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them
2019-11-03 16:31:02 +01:00
if ( plupload . ua . browser === 'Android Browser' ) {
2017-09-01 14:28:46 +02:00
// doesn't harm in general, but is not required anywhere else
up . trigger ( 'UploadProgress' , file ) ;
2019-11-03 16:31:02 +01:00
}
2017-09-01 14:28:46 +02:00
} else {
file . loaded = file . size ;
}
chunkBlob = formData = null ; // Free memory
// Check if file is uploaded
if ( ! offset || offset >= blob . size ) {
// If file was modified, destory the copy
if ( file . size != file . origSize ) {
blob . destroy ( ) ;
blob = null ;
}
up . trigger ( 'UploadProgress' , file ) ;
file . status = plupload . DONE ;
2019-11-03 16:31:02 +01:00
file . completeTimestamp = + new Date ( ) ;
2017-09-01 14:28:46 +02:00
up . trigger ( 'FileUploaded' , file , {
response : xhr . responseText ,
status : xhr . status ,
responseHeaders : xhr . getAllResponseHeaders ( )
} ) ;
} else {
// Still chunks left
delay ( uploadNextChunk , 1 ) ; // run detached, otherwise event handlers interfere
}
} ;
xhr . onerror = function ( ) {
handleError ( ) ;
} ;
xhr . onloadend = function ( ) {
this . destroy ( ) ;
} ;
// Build multipart request
if ( up . settings . multipart && features . multipart ) {
2019-11-03 16:31:02 +01:00
xhr . open ( up . settings . http _method , url , true ) ;
2017-09-01 14:28:46 +02:00
// Set custom headers
plupload . each ( up . settings . headers , function ( value , name ) {
xhr . setRequestHeader ( name , value ) ;
} ) ;
2019-11-03 16:31:02 +01:00
formData = new o . xhr . FormData ( ) ;
2017-09-01 14:28:46 +02:00
// Add multipart params
plupload . each ( plupload . extend ( args , up . settings . multipart _params ) , function ( value , name ) {
formData . append ( name , value ) ;
} ) ;
// Add file and send it
formData . append ( up . settings . file _data _name , chunkBlob ) ;
2019-11-03 16:31:02 +01:00
xhr . send ( formData , runtimeOptions ) ;
2017-09-01 14:28:46 +02:00
} else {
// if no multipart, send as binary stream
url = plupload . buildUrl ( up . settings . url , plupload . extend ( args , up . settings . multipart _params ) ) ;
2019-11-03 16:31:02 +01:00
xhr . open ( up . settings . http _method , url , true ) ;
2017-09-01 14:28:46 +02:00
// Set custom headers
plupload . each ( up . settings . headers , function ( value , name ) {
xhr . setRequestHeader ( name , value ) ;
} ) ;
2019-11-03 16:31:02 +01:00
// do not set Content-Type, if it was defined previously (see #1203)
if ( ! xhr . hasRequestHeader ( 'Content-Type' ) ) {
xhr . setRequestHeader ( 'Content-Type' , 'application/octet-stream' ) ; // Binary stream header
}
xhr . send ( chunkBlob , runtimeOptions ) ;
2017-09-01 14:28:46 +02:00
}
}
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
blob = file . getSource ( ) ;
// Start uploading chunks
2019-11-03 16:31:02 +01:00
if ( ! plupload . isEmptyObj ( up . settings . resize ) && plupload . inArray ( blob . type , [ 'image/jpeg' , 'image/png' ] ) !== - 1 ) {
2017-09-01 14:28:46 +02:00
// Resize if required
2019-11-03 16:31:02 +01:00
resizeImage ( blob , up . settings . resize , runtimeOptions , function ( resizedBlob ) {
2017-09-01 14:28:46 +02:00
blob = resizedBlob ;
file . size = resizedBlob . size ;
uploadNextChunk ( ) ;
} ) ;
} else {
uploadNextChunk ( ) ;
}
}
function onUploadProgress ( up , file ) {
calcFile ( file ) ;
}
function onStateChanged ( up ) {
if ( up . state == plupload . STARTED ) {
// Get start time to calculate bps
startTime = ( + new Date ( ) ) ;
} else if ( up . state == plupload . STOPPED ) {
// Reset currently uploading files
for ( var i = up . files . length - 1 ; i >= 0 ; i -- ) {
if ( up . files [ i ] . status == plupload . UPLOADING ) {
up . files [ i ] . status = plupload . QUEUED ;
calc ( ) ;
}
}
}
}
function onCancelUpload ( ) {
if ( xhr ) {
xhr . abort ( ) ;
}
}
function onFileUploaded ( up ) {
calc ( ) ;
// Upload next file but detach it from the error event
// since other custom listeners might want to stop the queue
delay ( function ( ) {
uploadNext . call ( up ) ;
} , 1 ) ;
}
function onError ( up , err ) {
if ( err . code === plupload . INIT _ERROR ) {
up . destroy ( ) ;
}
// Set failed status if an error occured on a file
else if ( err . code === plupload . HTTP _ERROR ) {
err . file . status = plupload . FAILED ;
2019-11-03 16:31:02 +01:00
err . file . completeTimestamp = + new Date ( ) ;
2017-09-01 14:28:46 +02:00
calcFile ( err . file ) ;
// Upload next file but detach it from the error event
// since other custom listeners might want to stop the queue
if ( up . state == plupload . STARTED ) { // upload in progress
up . trigger ( 'CancelUpload' ) ;
delay ( function ( ) {
uploadNext . call ( up ) ;
} , 1 ) ;
}
}
}
function onDestroy ( up ) {
up . stop ( ) ;
// Purge the queue
plupload . each ( files , function ( file ) {
file . destroy ( ) ;
} ) ;
files = [ ] ;
if ( fileInputs . length ) {
plupload . each ( fileInputs , function ( fileInput ) {
fileInput . destroy ( ) ;
} ) ;
fileInputs = [ ] ;
}
if ( fileDrops . length ) {
plupload . each ( fileDrops , function ( fileDrop ) {
fileDrop . destroy ( ) ;
} ) ;
fileDrops = [ ] ;
}
preferred _caps = { } ;
disabled = false ;
startTime = xhr = null ;
total . reset ( ) ;
}
// Default settings
settings = {
chunk _size : 0 ,
file _data _name : 'file' ,
filters : {
mime _types : [ ] ,
2019-11-03 16:31:02 +01:00
max _file _size : 0 ,
2017-09-01 14:28:46 +02:00
prevent _duplicates : false ,
2019-11-03 16:31:02 +01:00
prevent _empty : true
2017-09-01 14:28:46 +02:00
} ,
2019-11-03 16:31:02 +01:00
flash _swf _url : 'js/Moxie.swf' ,
http _method : 'POST' ,
max _retries : 0 ,
multipart : true ,
multi _selection : true ,
resize : false ,
runtimes : Runtime . order ,
2017-09-01 14:28:46 +02:00
send _file _name : true ,
2019-11-03 16:31:02 +01:00
send _chunk _number : true ,
silverlight _xap _url : 'js/Moxie.xap'
2017-09-01 14:28:46 +02:00
} ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
setOption . call ( this , options , null , true ) ;
// Inital total state
2019-11-03 16:31:02 +01:00
total = new plupload . QueueProgress ( ) ;
2017-09-01 14:28:46 +02:00
// Add public methods
plupload . extend ( this , {
/ * *
* Unique id for the Uploader instance .
*
* @ property id
* @ type String
* /
id : uid ,
uid : uid , // mOxie uses this to differentiate between event targets
/ * *
* Current state of the total uploading progress . This one can either be plupload . STARTED or plupload . STOPPED .
* These states are controlled by the stop / start methods . The default value is STOPPED .
*
* @ property state
* @ type Number
* /
state : plupload . STOPPED ,
/ * *
* Map of features that are available for the uploader runtime . Features will be filled
* before the init event is called , these features can then be used to alter the UI for the end user .
* Some of the current features that might be in this map is : dragdrop , chunks , jpgresize , pngresize .
*
* @ property features
* @ type Object
* /
features : { } ,
/ * *
* Current runtime name .
*
* @ property runtime
* @ type String
* /
runtime : null ,
/ * *
* Current upload queue , an array of File instances .
*
* @ property files
* @ type Array
* @ see plupload . File
* /
files : files ,
/ * *
* Object with name / value settings .
*
* @ property settings
* @ type Object
* /
settings : settings ,
/ * *
* Total progess information . How many files has been uploaded , total percent etc .
*
* @ property total
* @ type plupload . QueueProgress
* /
total : total ,
/ * *
* Initializes the Uploader instance and adds internal event listeners .
*
* @ method init
* /
init : function ( ) {
var self = this , opt , preinitOpt , err ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
preinitOpt = self . getOption ( 'preinit' ) ;
if ( typeof ( preinitOpt ) == "function" ) {
preinitOpt ( self ) ;
} else {
plupload . each ( preinitOpt , function ( func , name ) {
self . bind ( name , func ) ;
} ) ;
}
bindEventListeners . call ( self ) ;
// Check for required options
plupload . each ( [ 'container' , 'browse_button' , 'drop_element' ] , function ( el ) {
if ( self . getOption ( el ) === null ) {
err = {
code : plupload . INIT _ERROR ,
2019-11-03 16:31:02 +01:00
message : plupload . sprintf ( plupload . translate ( "%s specified, but cannot be found." ) , el )
2017-09-01 14:28:46 +02:00
}
return false ;
}
} ) ;
if ( err ) {
return self . trigger ( 'Error' , err ) ;
}
if ( ! settings . browse _button && ! settings . drop _element ) {
return self . trigger ( 'Error' , {
code : plupload . INIT _ERROR ,
2019-11-03 16:31:02 +01:00
message : plupload . translate ( "You must specify either browse_button or drop_element." )
2017-09-01 14:28:46 +02:00
} ) ;
}
initControls . call ( self , settings , function ( inited ) {
var initOpt = self . getOption ( 'init' ) ;
if ( typeof ( initOpt ) == "function" ) {
initOpt ( self ) ;
} else {
plupload . each ( initOpt , function ( func , name ) {
self . bind ( name , func ) ;
} ) ;
}
if ( inited ) {
2019-11-03 16:31:02 +01:00
self . runtime = Runtime . getInfo ( getRUID ( ) ) . type ;
2017-09-01 14:28:46 +02:00
self . trigger ( 'Init' , { runtime : self . runtime } ) ;
self . trigger ( 'PostInit' ) ;
} else {
self . trigger ( 'Error' , {
code : plupload . INIT _ERROR ,
message : plupload . translate ( 'Init error.' )
} ) ;
}
} ) ;
} ,
/ * *
* Set the value for the specified option ( s ) .
*
* @ method setOption
* @ since 2.1
* @ param { String | Object } option Name of the option to change or the set of key / value pairs
* @ param { Mixed } [ value ] Value for the option ( is ignored , if first argument is object )
* /
setOption : function ( option , value ) {
setOption . call ( this , option , value , ! this . runtime ) ; // until runtime not set we do not need to reinitialize
} ,
/ * *
* Get the value for the specified option or the whole configuration , if not specified .
2019-11-03 16:31:02 +01:00
*
2017-09-01 14:28:46 +02:00
* @ method getOption
* @ since 2.1
* @ param { String } [ option ] Name of the option to get
* @ return { Mixed } Value for the option or the whole set
* /
getOption : function ( option ) {
if ( ! option ) {
return settings ;
}
return settings [ option ] ;
} ,
/ * *
* Refreshes the upload instance by dispatching out a refresh event to all runtimes .
* This would for example reposition flash / silverlight shims on the page .
*
* @ method refresh
* /
refresh : function ( ) {
if ( fileInputs . length ) {
plupload . each ( fileInputs , function ( fileInput ) {
fileInput . trigger ( 'Refresh' ) ;
} ) ;
}
this . trigger ( 'Refresh' ) ;
} ,
/ * *
* Starts uploading the queued files .
*
* @ method start
* /
start : function ( ) {
if ( this . state != plupload . STARTED ) {
this . state = plupload . STARTED ;
this . trigger ( 'StateChanged' ) ;
uploadNext . call ( this ) ;
}
} ,
/ * *
* Stops the upload of the queued files .
*
* @ method stop
* /
stop : function ( ) {
if ( this . state != plupload . STOPPED ) {
this . state = plupload . STOPPED ;
this . trigger ( 'StateChanged' ) ;
this . trigger ( 'CancelUpload' ) ;
}
} ,
/ * *
* Disables / enables browse button on request .
*
* @ method disableBrowse
* @ param { Boolean } disable Whether to disable or enable ( default : true )
* /
disableBrowse : function ( ) {
disabled = arguments [ 0 ] !== undef ? arguments [ 0 ] : true ;
if ( fileInputs . length ) {
plupload . each ( fileInputs , function ( fileInput ) {
fileInput . disable ( disabled ) ;
} ) ;
}
this . trigger ( 'DisableBrowse' , disabled ) ;
} ,
/ * *
* Returns the specified file object by id .
*
* @ method getFile
* @ param { String } id File id to look for .
* @ return { plupload . File } File object or undefined if it wasn ' t found ;
* /
getFile : function ( id ) {
var i ;
for ( i = files . length - 1 ; i >= 0 ; i -- ) {
if ( files [ i ] . id === id ) {
return files [ i ] ;
}
}
} ,
/ * *
* Adds file to the queue programmatically . Can be native file , instance of Plupload . File ,
2019-11-03 16:31:02 +01:00
* instance of mOxie . File , input [ type = "file" ] element , or array of these . Fires FilesAdded ,
2017-09-01 14:28:46 +02:00
* if any files were added to the queue . Otherwise nothing happens .
*
* @ method addFile
* @ since 2.0
* @ param { plupload . File | mOxie . File | File | Node | Array } file File or files to add to the queue .
* @ param { String } [ fileName ] If specified , will be used as a name for the file
* /
addFile : function ( file , fileName ) {
var self = this
2019-11-03 16:31:02 +01:00
, queue = [ ]
2017-09-01 14:28:46 +02:00
, filesAdded = [ ]
, ruid
;
function filterFile ( file , cb ) {
var queue = [ ] ;
2019-11-03 16:31:02 +01:00
plupload . each ( self . settings . filters , function ( rule , name ) {
2017-09-01 14:28:46 +02:00
if ( fileFilters [ name ] ) {
queue . push ( function ( cb ) {
fileFilters [ name ] . call ( self , rule , file , function ( res ) {
cb ( ! res ) ;
} ) ;
} ) ;
}
} ) ;
2019-11-03 16:31:02 +01:00
plupload . inSeries ( queue , cb ) ;
2017-09-01 14:28:46 +02:00
}
/ * *
* @ method resolveFile
* @ private
2019-11-03 16:31:02 +01:00
* @ param { moxie . file . File | moxie . file . Blob | plupload . File | File | Blob | input [ type = "file" ] } file
2017-09-01 14:28:46 +02:00
* /
function resolveFile ( file ) {
2019-11-03 16:31:02 +01:00
var type = plupload . typeOf ( file ) ;
2017-09-01 14:28:46 +02:00
2019-11-03 16:31:02 +01:00
// moxie.file.File
if ( file instanceof o . file . File ) {
2017-09-01 14:28:46 +02:00
if ( ! file . ruid && ! file . isDetached ( ) ) {
if ( ! ruid ) { // weird case
return false ;
}
file . ruid = ruid ;
file . connectRuntime ( ruid ) ;
}
resolveFile ( new plupload . File ( file ) ) ;
}
2019-11-03 16:31:02 +01:00
// moxie.file.Blob
else if ( file instanceof o . file . Blob ) {
2017-09-01 14:28:46 +02:00
resolveFile ( file . getSource ( ) ) ;
file . destroy ( ) ;
2019-11-03 16:31:02 +01:00
}
2017-09-01 14:28:46 +02:00
// plupload.File - final step for other branches
else if ( file instanceof plupload . File ) {
if ( fileName ) {
file . name = fileName ;
}
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
queue . push ( function ( cb ) {
// run through the internal and user-defined filters, if any
filterFile ( file , function ( err ) {
if ( ! err ) {
// make files available for the filters by updating the main queue directly
files . push ( file ) ;
// collect the files that will be passed to FilesAdded event
2019-11-03 16:31:02 +01:00
filesAdded . push ( file ) ;
2017-09-01 14:28:46 +02:00
self . trigger ( "FileFiltered" , file ) ;
}
delay ( cb , 1 ) ; // do not build up recursions or eventually we might hit the limits
} ) ;
} ) ;
2019-11-03 16:31:02 +01:00
}
2017-09-01 14:28:46 +02:00
// native File or blob
2019-11-03 16:31:02 +01:00
else if ( plupload . inArray ( type , [ 'file' , 'blob' ] ) !== - 1 ) {
resolveFile ( new o . file . File ( null , file ) ) ;
}
2017-09-01 14:28:46 +02:00
// input[type="file"]
2019-11-03 16:31:02 +01:00
else if ( type === 'node' && plupload . typeOf ( file . files ) === 'filelist' ) {
2017-09-01 14:28:46 +02:00
// if we are dealing with input[type="file"]
2019-11-03 16:31:02 +01:00
plupload . each ( file . files , resolveFile ) ;
}
2017-09-01 14:28:46 +02:00
// mixed array of any supported types (see above)
else if ( type === 'array' ) {
fileName = null ; // should never happen, but unset anyway to avoid funny situations
2019-11-03 16:31:02 +01:00
plupload . each ( file , resolveFile ) ;
2017-09-01 14:28:46 +02:00
}
}
ruid = getRUID ( ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
resolveFile ( file ) ;
if ( queue . length ) {
2019-11-03 16:31:02 +01:00
plupload . inSeries ( queue , function ( ) {
2017-09-01 14:28:46 +02:00
// if any files left after filtration, trigger FilesAdded
if ( filesAdded . length ) {
self . trigger ( "FilesAdded" , filesAdded ) ;
}
} ) ;
}
} ,
/ * *
* Removes a specific file .
*
* @ method removeFile
* @ param { plupload . File | String } file File to remove from queue .
* /
removeFile : function ( file ) {
var id = typeof ( file ) === 'string' ? file : file . id ;
for ( var i = files . length - 1 ; i >= 0 ; i -- ) {
if ( files [ i ] . id === id ) {
return this . splice ( i , 1 ) [ 0 ] ;
}
}
} ,
/ * *
2019-11-03 16:31:02 +01:00
* Removes part of the queue and returns the files removed . This will also trigger the
* FilesRemoved and QueueChanged events .
2017-09-01 14:28:46 +02:00
*
* @ method splice
2019-11-03 16:31:02 +01:00
* @ param { Number } [ start = 0 ] Start index to remove from .
* @ param { Number } [ length ] Number of files to remove ( defaults to number of files in the queue ) .
2017-09-01 14:28:46 +02:00
* @ return { Array } Array of files that was removed .
* /
splice : function ( start , length ) {
// Splice and trigger events
var removed = files . splice ( start === undef ? 0 : start , length === undef ? files . length : length ) ;
// if upload is in progress we need to stop it and restart after files are removed
var restartRequired = false ;
if ( this . state == plupload . STARTED ) { // upload in progress
plupload . each ( removed , function ( file ) {
if ( file . status === plupload . UPLOADING ) {
restartRequired = true ; // do not restart, unless file that is being removed is uploading
return false ;
}
} ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
if ( restartRequired ) {
this . stop ( ) ;
}
}
this . trigger ( "FilesRemoved" , removed ) ;
// Dispose any resources allocated by those files
plupload . each ( removed , function ( file ) {
file . destroy ( ) ;
} ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
if ( restartRequired ) {
this . start ( ) ;
}
return removed ;
} ,
/ * *
Dispatches the specified event name and its arguments to all listeners .
@ method trigger
@ param { String } name Event name to fire .
@ param { Object . . } Multiple arguments to pass along to the listener functions .
* /
// override the parent method to match Plupload-like event logic
dispatchEvent : function ( type ) {
var list , args , result ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
type = type . toLowerCase ( ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
list = this . hasEventListener ( type ) ;
if ( list ) {
// sort event list by priority
list . sort ( function ( a , b ) { return b . priority - a . priority ; } ) ;
2019-11-03 16:31:02 +01:00
2017-09-01 14:28:46 +02:00
// first argument should be current plupload.Uploader instance
args = [ ] . slice . call ( arguments ) ;
args . shift ( ) ;
args . unshift ( this ) ;
for ( var i = 0 ; i < list . length ; i ++ ) {
// Fire event, break chain if false is returned
if ( list [ i ] . fn . apply ( list [ i ] . scope , args ) === false ) {
return false ;
}
}
}
return true ;
} ,
/ * *
Check whether uploader has any listeners to the specified event .
@ method hasEventListener
@ param { String } name Event name to check for .
* /
/ * *
Adds an event listener by name .
@ method bind
@ param { String } name Event name to listen for .
@ param { function } fn Function to call ones the event gets fired .
@ param { Object } [ scope ] Optional scope to execute the specified function in .
@ param { Number } [ priority = 0 ] Priority of the event handler - handlers with higher priorities will be called first
* /
bind : function ( name , fn , scope , priority ) {
// adapt moxie EventTarget style to Plupload-like
plupload . Uploader . prototype . bind . call ( this , name , fn , priority , scope ) ;
} ,
/ * *
Removes the specified event listener .
@ method unbind
@ param { String } name Name of event to remove .
@ param { function } fn Function to remove from listener .
* /
/ * *
Removes all event listeners .
@ method unbindAll
* /
/ * *
* Destroys Plupload instance and cleans after itself .
*
* @ method destroy
* /
destroy : function ( ) {
this . trigger ( 'Destroy' ) ;
settings = total = null ; // purge these exclusively
this . unbindAll ( ) ;
}
} ) ;
} ;
2019-11-03 16:31:02 +01:00
plupload . Uploader . prototype = o . core . EventTarget . instance ;
2017-09-01 14:28:46 +02:00
/ * *
* Constructs a new file instance .
*
* @ class File
* @ constructor
2019-11-03 16:31:02 +01:00
*
2017-09-01 14:28:46 +02:00
* @ param { Object } file Object containing file properties
* @ param { String } file . name Name of the file .
* @ param { Number } file . size File size .
* /
plupload . File = ( function ( ) {
var filepool = { } ;
function PluploadFile ( file ) {
plupload . extend ( this , {
/ * *
* File id this is a globally unique id for the specific file .
*
* @ property id
* @ type String
* /
id : plupload . guid ( ) ,
/ * *
* File name for example "myfile.gif" .
*
* @ property name
* @ type String
* /
name : file . name || file . fileName ,
/ * *
* File type , ` e.g image/jpeg `
*
* @ property type
* @ type String
* /
type : file . type || '' ,
2019-11-03 16:31:02 +01:00
/ * *
* Relative path to the file inside a directory
*
* @ property relativePath
* @ type String
* @ default ''
* /
relativePath : file . relativePath || '' ,
2017-09-01 14:28:46 +02:00
/ * *
* File size in bytes ( may change after client - side manupilation ) .
*
* @ property size
* @ type Number
* /
2019-11-03 16:31:02 +01:00
size : file . fileSize || file . size ,
2017-09-01 14:28:46 +02:00
/ * *
* Original file size in bytes .
*
* @ property origSize
* @ type Number
* /
2019-11-03 16:31:02 +01:00
origSize : file . fileSize || file . size ,
2017-09-01 14:28:46 +02:00
/ * *
* Number of bytes uploaded of the files total size .
*
* @ property loaded
* @ type Number
* /
loaded : 0 ,
/ * *
* Number of percentage uploaded of the file .
*
* @ property percent
* @ type Number
* /
percent : 0 ,
/ * *
* Status constant matching the plupload states QUEUED , UPLOADING , FAILED , DONE .
*
* @ property status
* @ type Number
* @ see plupload
* /
status : plupload . QUEUED ,
/ * *
* Date of last modification .
*
* @ property lastModifiedDate
* @ type { String }
* /
lastModifiedDate : file . lastModifiedDate || ( new Date ( ) ) . toLocaleString ( ) , // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
2019-11-03 16:31:02 +01:00
/ * *
* Set when file becomes plupload . DONE or plupload . FAILED . Is used to calculate proper plupload . QueueProgress . bytesPerSec .
* @ private
* @ property completeTimestamp
* @ type { Number }
* /
completeTimestamp : 0 ,
2017-09-01 14:28:46 +02:00
/ * *
* Returns native window . File object , when it ' s available .
*
* @ method getNative
* @ return { window . File } or null , if plupload . File is of different origin
* /
getNative : function ( ) {
var file = this . getSource ( ) . getSource ( ) ;
2019-11-03 16:31:02 +01:00
return plupload . inArray ( plupload . typeOf ( file ) , [ 'blob' , 'file' ] ) !== - 1 ? file : null ;
2017-09-01 14:28:46 +02:00
} ,
/ * *
* Returns mOxie . File - unified wrapper object that can be used across runtimes .
*
* @ method getSource
* @ return { mOxie . File } or null
* /
getSource : function ( ) {
if ( ! filepool [ this . id ] ) {
return null ;
}
return filepool [ this . id ] ;
} ,
/ * *
* Destroys plupload . File object .
*
* @ method destroy
* /
destroy : function ( ) {
var src = this . getSource ( ) ;
if ( src ) {
src . destroy ( ) ;
delete filepool [ this . id ] ;
}
}
} ) ;
filepool [ this . id ] = file ;
}
return PluploadFile ;
} ( ) ) ;
/ * *
* Constructs a queue progress .
*
* @ class QueueProgress
* @ constructor
* /
plupload . QueueProgress = function ( ) {
var self = this ; // Setup alias for self to reduce code size when it's compressed
/ * *
* Total queue file size .
*
* @ property size
* @ type Number
* /
self . size = 0 ;
/ * *
* Total bytes uploaded .
*
* @ property loaded
* @ type Number
* /
self . loaded = 0 ;
/ * *
* Number of files uploaded .
*
* @ property uploaded
* @ type Number
* /
self . uploaded = 0 ;
/ * *
* Number of files failed to upload .
*
* @ property failed
* @ type Number
* /
self . failed = 0 ;
/ * *
* Number of files yet to be uploaded .
*
* @ property queued
* @ type Number
* /
self . queued = 0 ;
/ * *
* Total percent of the uploaded bytes .
*
* @ property percent
* @ type Number
* /
self . percent = 0 ;
/ * *
* Bytes uploaded per second .
*
* @ property bytesPerSec
* @ type Number
* /
self . bytesPerSec = 0 ;
/ * *
* Resets the progress to its initial values .
*
* @ method reset
* /
self . reset = function ( ) {
self . size = self . loaded = self . uploaded = self . failed = self . queued = self . percent = self . bytesPerSec = 0 ;
} ;
} ;
2019-11-03 16:31:02 +01:00
exports . plupload = plupload ;
} ( this , moxie ) ) ;
2017-09-01 14:28:46 +02:00
2019-11-03 16:31:02 +01:00
} ) ) ;