2015-09-25 17:00:08 +02:00
/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
! function ( a , b ) { "object" == typeof module && "object" == typeof module . exports ? module . exports = a . document ? b ( a , ! 0 ) : function ( a ) { if ( ! a . document ) throw new Error ( "jQuery requires a window with a document" ) ; return b ( a ) } : b ( a ) } ( "undefined" != typeof window ? window : this , function ( a , b ) { var c = [ ] , d = c . slice , e = c . concat , f = c . push , g = c . indexOf , h = { } , i = h . toString , j = h . hasOwnProperty , k = { } , l = "1.11.3" , m = function ( a , b ) { return new m . fn . init ( a , b ) } , n = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g , o = /^-ms-/ , p = /-([\da-z])/gi , q = function ( a , b ) { return b . toUpperCase ( ) } ; m . fn = m . prototype = { jquery : l , constructor : m , selector : "" , length : 0 , toArray : function ( ) { return d . call ( this ) } , get : function ( a ) { return null != a ? 0 > a ? this [ a + this . length ] : this [ a ] : d . call ( this ) } , pushStack : function ( a ) { var b = m . merge ( this . constructor ( ) , a ) ; return b . prevObject = this , b . context = this . context , b } , each : function ( a , b ) { return m . each ( this , a , b ) } , map : function ( a ) { return this . pushStack ( m . map ( this , function ( b , c ) { return a . call ( b , c , b ) } ) ) } , slice : function ( ) { return this . pushStack ( d . apply ( this , arguments ) ) } , first : function ( ) { return this . eq ( 0 ) } , last : function ( ) { return this . eq ( - 1 ) } , eq : function ( a ) { var b = this . length , c = + a + ( 0 > a ? b : 0 ) ; return this . pushStack ( c >= 0 && b > c ? [ this [ c ] ] : [ ] ) } , end : function ( ) { return this . prevObject || this . constructor ( null ) } , push : f , sort : c . sort , splice : c . splice } , m . extend = m . fn . extend = function ( ) { var a , b , c , d , e , f , g = arguments [ 0 ] || { } , h = 1 , i = arguments . length , j = ! 1 ; for ( "boolean" == typeof g && ( j = g , g = arguments [ h ] || { } , h ++ ) , "object" == typeof g || m . isFunction ( g ) || ( g = { } ) , h === i && ( g = this , h -- ) ; i > h ; h ++ ) if ( null != ( e = arguments [ h ] ) ) for ( d in e ) a = g [ d ] , c = e [ d ] , g !== c && ( j && c && ( m . isPlainObject ( c ) || ( b = m . isArray ( c ) ) ) ? ( b ? ( b = ! 1 , f = a && m . isArray ( a ) ? a : [ ] ) : f = a && m . isPlainObject ( a ) ? a : { } , g [ d ] = m . extend ( j , f , c ) ) : void 0 !== c && ( g [ d ] = c ) ) ; return g } , m . extend ( { expando : "jQuery" + ( l + Math . random ( ) ) . replace ( /\D/g , "" ) , isReady : ! 0 , error : function ( a ) { throw new Error ( a ) } , noop : function ( ) { } , isFunction : function ( a ) { return "function" === m . type ( a ) } , isArray : Array . isArray || function ( a ) { return "array" === m . type ( a ) } , isWindow : function ( a ) { return null != a && a == a . window } , isNumeric : function ( a ) { return ! m . isArray ( a ) && a - parseFloat ( a ) + 1 >= 0 } , isEmptyObject : function ( a ) { var b ; for ( b in a ) return ! 1 ; return ! 0 } , isPlainObject : function ( a ) { var b ; if ( ! a || "object" !== m . type ( a ) || a . nodeType || m . isWindow ( a ) ) return ! 1 ; try { if ( a . constructor && ! j . call ( a , "constructor" ) && ! j . call ( a . constructor . prototype , "isPrototypeOf" ) ) return ! 1 } catch ( c ) { return ! 1 } if ( k . ownLast ) for ( b in a ) return j . call ( a , b ) ; for ( b in a ) ; return void 0 === b || j . call ( a , b ) } , type : function ( a ) { return null == a ? a + "" : "object" == typeof a || "function" == typeof a ? h [ i . call ( a ) ] || "object" : typeof a } , globalEval : function ( b ) { b && m . trim ( b ) && ( a . execScript || function ( b ) { a . eval . call ( a , b ) } ) ( b ) } , camelCase : function ( a ) { return a . replace ( o , "ms-" ) . replace ( p , q ) } , nodeName : function ( a , b ) { return a . nodeName && a . nodeName . toLowerCase ( ) === b . toLowerCase ( ) } , each : function ( a , b , c ) { var d , e = 0 , f = a . length , g = r ( a ) ; if ( c ) { if ( g ) { for ( ; f > e ; e ++ ) if ( d = b . apply ( a [ e ] , c ) , d === ! 1 ) break } else for ( e in a ) if ( d = b . apply ( a [ e ] , c ) , d === ! 1 ) break } else if ( g ) { for ( ; f > e ; e ++ ) if ( d = b . call ( a [ e ] , e , a [ e ] ) , d === ! 1 ) break } else for ( e in a ) if ( d = b . call ( a [ e ] , e , a [ e ] ) , d === ! 1 ) break ; return a } , trim : function ( a ) { return null == a ? "" : ( a + "" ) . replace ( n , "" ) } , makeArray : function ( a , b ) { var c = b || [ ] ; return null != a && ( r ( Object ( a ) ) ? m . merge ( c , "string" == typeof a ? [ a ] : a ) : f . call ( c , a ) ) , c } , inArray : function ( a , b , c ) { var d ; if ( b ) { if ( g ) return g . call ( b , a , c ) ; for ( d = b . length , c = c ? 0 > c ? Math . max ( 0 , d + c ) : c : 0 ; d > c ; c ++ ) if ( c in b && b [ c ] === a ) return c } return - 1 } , merge : function ( a , b ) { var c = + b . length , d = 0 , e = a . length ; while ( c > d ) a [ e ++ ] = b [ d ++ ] ; if ( c !== c ) while ( void 0 !== b [ d ] ) a [ e ++ ] = b [ d ++ ] ; return a . length = e , a } , grep : function ( a , b , c ) { for ( var d , e = [ ] , f = 0 , g = a . length , h = ! c ; g > f ; f ++ ) d = ! b ( a [ f ] , f ) , d !== h && e . push ( a [ f ] ) ; return e } , map : function ( a , b , c ) { var d , f = 0 , g = a . length , h = r ( a ) , i = [ ] ; if ( h ) for ( ; g > f ; f ++ ) d = b ( a [ f ] , f , c ) , null != d && i . push ( d ) ; else for ( f in a ) d = b ( a [ f ] , f , c ) , null != d && i . push ( d ) ; return e . apply ( [ ] , i ) } , guid : 1 , proxy : function ( a , b ) { var c , e , f ; return "string" == typeof b && ( f = a [ b ] , b = a , a = f ) , m . isFunction ( a ) ? ( c = d . call ( arguments , 2 ) , e = function ( ) { return a . apply ( b || this , c . concat ( d . call ( arguments ) ) ) } , e . guid = a . guid = a . guid || m . guid ++ , e ) : void 0 } , now : function ( ) { return + new Date } , support : k } ) , m . each (
return ! 0 } function Q ( a , b , d , e ) { if ( m . acceptData ( a ) ) { var f , g , h = m . expando , i = a . nodeType , j = i ? m . cache : a , k = i ? a [ h ] : a [ h ] && h ; if ( k && j [ k ] && ( e || j [ k ] . data ) || void 0 !== d || "string" != typeof b ) return k || ( k = i ? a [ h ] = c . pop ( ) || m . guid ++ : h ) , j [ k ] || ( j [ k ] = i ? { } : { toJSON : m . noop } ) , ( "object" == typeof b || "function" == typeof b ) && ( e ? j [ k ] = m . extend ( j [ k ] , b ) : j [ k ] . data = m . extend ( j [ k ] . data , b ) ) , g = j [ k ] , e || ( g . data || ( g . data = { } ) , g = g . data ) , void 0 !== d && ( g [ m . camelCase ( b ) ] = d ) , "string" == typeof b ? ( f = g [ b ] , null == f && ( f = g [ m . camelCase ( b ) ] ) ) : f = g , f } } function R ( a , b , c ) { if ( m . acceptData ( a ) ) { var d , e , f = a . nodeType , g = f ? m . cache : a , h = f ? a [ m . expando ] : m . expando ; if ( g [ h ] ) { if ( b && ( d = c ? g [ h ] : g [ h ] . data ) ) { m . isArray ( b ) ? b = b . concat ( m . map ( b , m . camelCase ) ) : b in d ? b = [ b ] : ( b = m . camelCase ( b ) , b = b in d ? [ b ] : b . split ( " " ) ) , e = b . length ; while ( e -- ) delete d [ b [ e ] ] ; if ( c ? ! P ( d ) : ! m . isEmptyObject ( d ) ) return } ( c || ( delete g [ h ] . data , P ( g [ h ] ) ) ) && ( f ? m . cleanData ( [ a ] , ! 0 ) : k . deleteExpando || g != g . window ? delete g [ h ] : g [ h ] = null ) } } } m . extend ( { cache : { } , noData : { "applet " : ! 0 , "embed " : ! 0 , "object " : "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" } , hasData : function ( a ) { return a = a . nodeType ? m . cache [ a [ m . expando ] ] : a [ m . expando ] , ! ! a && ! P ( a ) } , data : function ( a , b , c ) { return Q ( a , b , c ) } , removeData : function ( a , b ) { return R ( a , b ) } , _data : function ( a , b , c ) { return Q ( a , b , c , ! 0 ) } , _removeData : function ( a , b ) { return R ( a , b , ! 0 ) } } ) , m . fn . extend ( { data : function ( a , b ) { var c , d , e , f = this [ 0 ] , g = f && f . attributes ; if ( void 0 === a ) { if ( this . length && ( e = m . data ( f ) , 1 === f . nodeType && ! m . _data ( f , "parsedAttrs" ) ) ) { c = g . length ; while ( c -- ) g [ c ] && ( d = g [ c ] . name , 0 === d . indexOf ( "data-" ) && ( d = m . camelCase ( d . slice ( 5 ) ) , O ( f , d , e [ d ] ) ) ) ; m . _data ( f , "parsedAttrs" , ! 0 ) } return e } return "object" == typeof a ? this . each ( function ( ) { m . data ( this , a ) } ) : arguments . length > 1 ? this . each ( function ( ) { m . data ( this , a , b ) } ) : f ? O ( f , a , m . data ( f , a ) ) : void 0 } , removeData : function ( a ) { return this . each ( function ( ) { m . removeData ( this , a ) } ) } } ) , m . extend ( { queue : function ( a , b , c ) { var d ; return a ? ( b = ( b || "fx" ) + "queue" , d = m . _data ( a , b ) , c && ( ! d || m . isArray ( c ) ? d = m . _data ( a , b , m . makeArray ( c ) ) : d . push ( c ) ) , d || [ ] ) : void 0 } , dequeue : function ( a , b ) { b = b || "fx" ; var c = m . queue ( a , b ) , d = c . length , e = c . shift ( ) , f = m . _queueHooks ( a , b ) , g = function ( ) { m . dequeue ( a , b ) } ; "inprogress" === e && ( e = c . shift ( ) , d -- ) , e && ( "fx" === b && c . unshift ( "inprogress" ) , delete f . stop , e . call ( a , g , f ) ) , ! d && f && f . empty . fire ( ) } , _queueHooks : function ( a , b ) { var c = b + "queueHooks" ; return m . _data ( a , c ) || m . _data ( a , c , { empty : m . Callbacks ( "once memory" ) . add ( function ( ) { m . _removeData ( a , b + "queue" ) , m . _removeData ( a , c ) } ) } ) } } ) , m . fn . extend ( { queue : function ( a , b ) { var c = 2 ; return "string" != typeof a && ( b = a , a = "fx" , c -- ) , arguments . length < c ? m . queue ( this [ 0 ] , a ) : void 0 === b ? this : this . each ( function ( ) { var c = m . queue ( this , a , b ) ; m . _queueHooks ( this , a ) , "fx" === a && "inprogress" !== c [ 0 ] && m . dequeue ( this , a ) } ) } , dequeue : function ( a ) { return this . each ( function ( ) { m . dequeue ( this , a ) } ) } , clearQueue : function ( a ) { return this . queue ( a || "fx" , [ ] ) } , promise : function ( a , b ) { var c , d = 1 , e = m . Deferred ( ) , f = this , g = this . length , h = function ( ) { -- d || e . resolveWith ( f , [ f ] ) } ; "string" != typeof a && ( b = a , a = void 0 ) , a = a || "fx" ; while ( g -- ) c = m . _data ( f [ g ] , a + "queueHooks" ) , c && c . empty && ( d ++ , c . empty . add ( h ) ) ; return h ( ) , e . promise ( b ) } } ) ; var S = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ . source , T = [ "Top" , "Right" , "Bottom" , "Left" ] , U = function ( a , b ) { return a = b || a , "none" === m . css ( a , "display" ) || ! m . contains ( a . ownerDocument , a ) } , V = m . access = function ( a , b , c , d , e , f , g ) { var h = 0 , i = a . length , j = null == c ; if ( "object" === m . type ( c ) ) { e = ! 0 ; for ( h in c ) m . access ( a , b , h , c [ h ] , ! 0 , f , g ) } else if ( void 0 !== d && ( e = ! 0 , m . isFunction ( d ) || ( g = ! 0 ) , j && ( g ? ( b . call ( a , d ) , b = null ) : ( j = b , b = function ( a , b , c ) { return j . call ( m ( a ) , c ) } ) ) , b ) ) for ( ; i > h ; h ++ ) b ( a [ h ] , c , g ? d : d . call ( a [ h ] , h , b ( a [ h ] , c ) ) ) ; return e ? a : j ? b . call ( a ) : i ? b ( a [ 0 ] , c ) : f } , W = /^(?:checkbox|radio)$/i ; ! function ( ) { var a = y . createElement ( "input" ) , b = y . createElement ( "div" ) , c = y . createDocumentFragment ( ) ; if ( b . innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>" , k . leadingWhitespace = 3 === b . firstChild . nodeType , k . tbody = ! b . getElementsByTagName ( "tbody" ) . length , k . htmlSerialize = ! ! b . getElementsByTagName ( "link" ) . length , k . html5Clone = "<:nav></:nav>" !== y . createElement ( "nav" ) . cloneNode ( ! 0 ) . outerHTML , a . type = "checkbox" , a . checked = ! 0 , c . appendChild ( a ) , k . appendChecked = a . checked , b . innerHTML = " < textarea > x < / t e x
return new Za . prototype . init ( a , b , c , d , e ) } m . Tween = Za , Za . prototype = { constructor : Za , init : function ( a , b , c , d , e , f ) { this . elem = a , this . prop = c , this . easing = e || "swing" , this . options = b , this . start = this . now = this . cur ( ) , this . end = d , this . unit = f || ( m . cssNumber [ c ] ? "" : "px" ) } , cur : function ( ) { var a = Za . propHooks [ this . prop ] ; return a && a . get ? a . get ( this ) : Za . propHooks . _default . get ( this ) } , run : function ( a ) { var b , c = Za . propHooks [ this . prop ] ; return this . options . duration ? this . pos = b = m . easing [ this . easing ] ( a , this . options . duration * a , 0 , 1 , this . options . duration ) : this . pos = b = a , this . now = ( this . end - this . start ) * b + this . start , this . options . step && this . options . step . call ( this . elem , this . now , this ) , c && c . set ? c . set ( this ) : Za . propHooks . _default . set ( this ) , this } } , Za . prototype . init . prototype = Za . prototype , Za . propHooks = { _default : { get : function ( a ) { var b ; return null == a . elem [ a . prop ] || a . elem . style && null != a . elem . style [ a . prop ] ? ( b = m . css ( a . elem , a . prop , "" ) , b && "auto" !== b ? b : 0 ) : a . elem [ a . prop ] } , set : function ( a ) { m . fx . step [ a . prop ] ? m . fx . step [ a . prop ] ( a ) : a . elem . style && ( null != a . elem . style [ m . cssProps [ a . prop ] ] || m . cssHooks [ a . prop ] ) ? m . style ( a . elem , a . prop , a . now + a . unit ) : a . elem [ a . prop ] = a . now } } } , Za . propHooks . scrollTop = Za . propHooks . scrollLeft = { set : function ( a ) { a . elem . nodeType && a . elem . parentNode && ( a . elem [ a . prop ] = a . now ) } } , m . easing = { linear : function ( a ) { return a } , swing : function ( a ) { return . 5 - Math . cos ( a * Math . PI ) / 2 } } , m . fx = Za . prototype . init , m . fx . step = { } ; var $a , _a , ab = /^(?:toggle|show|hide)$/ , bb = new RegExp ( "^(?:([+-])=|)(" + S + ")([a-z%]*)$" , "i" ) , cb = /queueHooks$/ , db = [ ib ] , eb = { "*" : [ function ( a , b ) { var c = this . createTween ( a , b ) , d = c . cur ( ) , e = bb . exec ( b ) , f = e && e [ 3 ] || ( m . cssNumber [ a ] ? "" : "px" ) , g = ( m . cssNumber [ a ] || "px" !== f && + d ) && bb . exec ( m . css ( c . elem , a ) ) , h = 1 , i = 20 ; if ( g && g [ 3 ] !== f ) { f = f || g [ 3 ] , e = e || [ ] , g = + d || 1 ; do h = h || ".5" , g /= h , m . style ( c . elem , a , g + f ) ; while ( h !== ( h = c . cur ( ) / d ) && 1 !== h && -- i ) } return e && ( g = c . start = + g || + d || 0 , c . unit = f , c . end = e [ 1 ] ? g + ( e [ 1 ] + 1 ) * e [ 2 ] : + e [ 2 ] ) , c } ] } ; function fb ( ) { return setTimeout ( function ( ) { $a = void 0 } ) , $a = m . now ( ) } function gb ( a , b ) { var c , d = { height : a } , e = 0 ; for ( b = b ? 1 : 0 ; 4 > e ; e += 2 - b ) c = T [ e ] , d [ "margin" + c ] = d [ "padding" + c ] = a ; return b && ( d . opacity = d . width = a ) , d } function hb ( a , b , c ) { for ( var d , e = ( eb [ b ] || [ ] ) . concat ( eb [ "*" ] ) , f = 0 , g = e . length ; g > f ; f ++ ) if ( d = e [ f ] . call ( c , b , a ) ) return d } function ib ( a , b , c ) { var d , e , f , g , h , i , j , l , n = this , o = { } , p = a . style , q = a . nodeType && U ( a ) , r = m . _data ( a , "fxshow" ) ; c . queue || ( h = m . _queueHooks ( a , "fx" ) , null == h . unqueued && ( h . unqueued = 0 , i = h . empty . fire , h . empty . fire = function ( ) { h . unqueued || i ( ) } ) , h . unqueued ++ , n . always ( function ( ) { n . always ( function ( ) { h . unqueued -- , m . queue ( a , "fx" ) . length || h . empty . fire ( ) } ) } ) ) , 1 === a . nodeType && ( "height" in b || "width" in b ) && ( c . overflow = [ p . overflow , p . overflowX , p . overflowY ] , j = m . css ( a , "display" ) , l = "none" === j ? m . _data ( a , "olddisplay" ) || Fa ( a . nodeName ) : j , "inline" === l && "none" === m . css ( a , "float" ) && ( k . inlineBlockNeedsLayout && "inline" !== Fa ( a . nodeName ) ? p . zoom = 1 : p . display = "inline-block" ) ) , c . overflow && ( p . overflow = "hidden" , k . shrinkWrapBlocks ( ) || n . always ( function ( ) { p . overflow = c . overflow [ 0 ] , p . overflowX = c . overflow [ 1 ] , p . overflowY = c . overflow [ 2 ] } ) ) ; for ( d in b ) if ( e = b [ d ] , ab . exec ( e ) ) { if ( delete b [ d ] , f = f || "toggle" === e , e === ( q ? "hide" : "show" ) ) { if ( "show" !== e || ! r || void 0 === r [ d ] ) continue ; q = ! 0 } o [ d ] = r && r [ d ] || m . style ( a , d ) } else j = void 0 ; if ( m . isEmptyObject ( o ) ) "inline" === ( "none" === j ? Fa ( a . nodeName ) : j ) && ( p . display = j ) ; else { r ? "hidden" in r && ( q = r . hidden ) : r = m . _data ( a , "fxshow" , { } ) , f && ( r . hidden = ! q ) , q ? m ( a ) . show ( ) : n . done ( function ( ) { m ( a ) . hide ( ) } ) , n . done ( function ( ) { var b ; m . _removeData ( a , "fxshow" ) ; for ( b in o ) m . style ( a , b , o [ b ] ) } ) ; for ( d in o ) g = hb ( q ? r [ d ] : 0 , d , n ) , d in r || ( r [ d ] = g . start , q && ( g . end = g . start , g . start = "width" === d || "height" === d ? 1 : 0 ) ) } } function jb ( a , b ) { var c , d , e , f , g ; for ( c in a ) if ( d = m . camelCase ( c ) , e = b [ d ] , f = a [ c ] , m . isArray ( f ) && ( e = f [ 1 ] , f = a [ c ] = f [ 0 ] ) , c !== d && ( a [ d ] = f , delete a [ c ] ) , g = m . cssHooks [ d ] , g && "expand" in g ) { f = g . expand ( f ) , delete a [ d ] ; for ( c in f ) c in a || ( a [ c ] = f [ c ] , b [ c ] = e ) } else b [ d ] = e } function kb ( a , b , c ) { var d , e , f = 0 , g = db . length , h = m . Deferred ( ) . always ( function ( ) { delete i . elem } ) , i = function ( ) { if ( e ) return ! 1 ; for ( var b = $a || fb ( ) , c = Math . max ( 0 , j . startTime + j . duration - b ) , d = c / j . duration || 0 , f = 1 - d , g = 0 , i = j . tweens . length ; i > g ; g ++ ) j . tweens [ g ] . run ( f ) ; return h . notifyWith ( a , [ j , f , c ] ) , 1 > f && i ? c : ( h . resolveWith ( a , [ j ] ) , ! 1 ) } , j = h
2015-09-25 06:58:38 +02:00
/ * *
* http : //github.com/valums/file-uploader
*
* Multiple file upload component with progress - bar , drag - and - drop .
* © 2010 Andrew Valums ( andrew ( at ) valums . com )
*
* Licensed under GNU GPL 2 or later and GNU LGPL 2 or later , see license . txt .
* /
//
// Helper functions
//
var qq = qq || { } ;
/ * *
* Adds all missing properties from second obj to first obj
* /
qq . extend = function ( first , second ) {
for ( var prop in second ) {
first [ prop ] = second [ prop ] ;
}
} ;
/ * *
* Searches for a given element in the array , returns - 1 if it is not present .
* @ param { Number } [ from ] The index at which to begin the search
* /
qq . indexOf = function ( arr , elt , from ) {
if ( arr . indexOf ) return arr . indexOf ( elt , from ) ;
from = from || 0 ;
var len = arr . length ;
if ( from < 0 ) from += len ;
for ( ; from < len ; from ++ ) {
if ( from in arr && arr [ from ] === elt ) {
return from ;
}
}
return - 1 ;
} ;
qq . getUniqueId = ( function ( ) {
var id = 0 ;
return function ( ) { return id ++ ; } ;
} ) ( ) ;
//
// Events
qq . attach = function ( element , type , fn ) {
if ( element . addEventListener ) {
element . addEventListener ( type , fn , false ) ;
} else if ( element . attachEvent ) {
element . attachEvent ( 'on' + type , fn ) ;
}
} ;
qq . detach = function ( element , type , fn ) {
if ( element . removeEventListener ) {
element . removeEventListener ( type , fn , false ) ;
} else if ( element . attachEvent ) {
element . detachEvent ( 'on' + type , fn ) ;
}
} ;
qq . preventDefault = function ( e ) {
if ( e . preventDefault ) {
e . preventDefault ( ) ;
} else {
e . returnValue = false ;
}
} ;
//
// Node manipulations
/ * *
* Insert node a before node b .
* /
qq . insertBefore = function ( a , b ) {
b . parentNode . insertBefore ( a , b ) ;
} ;
qq . remove = function ( element ) {
element . parentNode . removeChild ( element ) ;
} ;
qq . contains = function ( parent , descendant ) {
// compareposition returns false in this case
if ( parent == descendant ) return true ;
if ( parent . contains ) {
return parent . contains ( descendant ) ;
} else {
return ! ! ( descendant . compareDocumentPosition ( parent ) & 8 ) ;
}
} ;
/ * *
* Creates and returns element from html string
* Uses innerHTML to create an element
* /
qq . toElement = ( function ( ) {
var div = document . createElement ( 'div' ) ;
return function ( html ) {
div . innerHTML = html ;
var element = div . firstChild ;
div . removeChild ( element ) ;
return element ;
} ;
} ) ( ) ;
//
// Node properties and attributes
/ * *
* Sets styles for an element .
* Fixes opacity in IE6 - 8.
* /
qq . css = function ( element , styles ) {
if ( styles . opacity != null ) {
if ( typeof element . style . opacity != 'string' && typeof ( element . filters ) != 'undefined' ) {
styles . filter = 'alpha(opacity=' + Math . round ( 100 * styles . opacity ) + ')' ;
}
}
qq . extend ( element . style , styles ) ;
} ;
qq . hasClass = function ( element , name ) {
var re = new RegExp ( '(^| )' + name + '( |$)' ) ;
return re . test ( element . className ) ;
} ;
qq . addClass = function ( element , name ) {
if ( ! qq . hasClass ( element , name ) ) {
element . className += ' ' + name ;
}
} ;
qq . removeClass = function ( element , name ) {
var re = new RegExp ( '(^| )' + name + '( |$)' ) ;
element . className = element . className . replace ( re , ' ' ) . replace ( /^\s+|\s+$/g , "" ) ;
} ;
qq . setText = function ( element , text ) {
element . innerText = text ;
element . textContent = text ;
} ;
//
// Selecting elements
qq . children = function ( element ) {
var children = [ ] ,
child = element . firstChild ;
while ( child ) {
if ( child . nodeType == 1 ) {
children . push ( child ) ;
}
child = child . nextSibling ;
}
return children ;
} ;
qq . getByClass = function ( element , className ) {
if ( element . querySelectorAll ) {
return element . querySelectorAll ( '.' + className ) ;
}
var result = [ ] ;
var candidates = element . getElementsByTagName ( "*" ) ;
var len = candidates . length ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( qq . hasClass ( candidates [ i ] , className ) ) {
result . push ( candidates [ i ] ) ;
}
}
return result ;
} ;
/ * *
* obj2url ( ) takes a json - object as argument and generates
* a querystring . pretty much like jQuery . param ( )
*
* how to use :
*
* ` qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value'); `
*
* will result in :
*
* ` http://any.url/upload?otherParam=value&a=b&c=d `
*
* @ param Object JSON - Object
* @ param String current querystring - part
* @ return String encoded querystring
* /
qq . obj2url = function ( obj , temp , prefixDone ) {
var uristrings = [ ] ,
prefix = '&' ,
add = function ( nextObj , i ) {
var nextTemp = temp
? ( /\[\]$/ . test ( temp ) ) // prevent double-encoding
? temp
: temp + '[' + i + ']'
: i ;
if ( ( nextTemp != 'undefined' ) && ( i != 'undefined' ) ) {
uristrings . push (
( typeof nextObj === 'object' )
? qq . obj2url ( nextObj , nextTemp , true )
: ( Object . prototype . toString . call ( nextObj ) === '[object Function]' )
? encodeURIComponent ( nextTemp ) + '=' + encodeURIComponent ( nextObj ( ) )
: encodeURIComponent ( nextTemp ) + '=' + encodeURIComponent ( nextObj )
) ;
}
} ;
if ( ! prefixDone && temp ) {
prefix = ( /\?/ . test ( temp ) ) ? ( /\?$/ . test ( temp ) ) ? '' : '&' : '?' ;
uristrings . push ( temp ) ;
uristrings . push ( qq . obj2url ( obj ) ) ;
} else if ( ( Object . prototype . toString . call ( obj ) === '[object Array]' ) && ( typeof obj != 'undefined' ) ) {
// we wont use a for-in-loop on an array (performance)
for ( var i = 0 , len = obj . length ; i < len ; ++ i ) {
add ( obj [ i ] , i ) ;
}
} else if ( ( typeof obj != 'undefined' ) && ( obj !== null ) && ( typeof obj === "object" ) ) {
// for anything else but a scalar, we will use for-in-loop
for ( var i in obj ) {
add ( obj [ i ] , i ) ;
}
} else {
uristrings . push ( encodeURIComponent ( temp ) + '=' + encodeURIComponent ( obj ) ) ;
}
return uristrings . join ( prefix )
. replace ( /^&/ , '' )
. replace ( /%20/g , '+' ) ;
} ;
//
//
// Uploader Classes
//
//
var qq = qq || { } ;
/ * *
* Creates upload button , validates upload , but doesn ' t create file list or dd .
* /
qq . FileUploaderBasic = function ( o ) {
this . _options = {
// set to true to see the server response
debug : false ,
action : '/upload' ,
params : { } ,
button : null ,
multiple : true ,
maxConnections : 3 ,
// validation
allowedExtensions : [ ] ,
sizeLimit : 2147483648 ,
minSizeLimit : 0 ,
// events
// return false to cancel submit
onSubmit : function ( id , fileName ) { document . getElementById ( "toggleme" ) . style . display = "block" ; } ,
onProgress : function ( id , fileName , loaded , total ) { } ,
onComplete : function ( id , fileName , responseJSON ) { } ,
onCancel : function ( id , fileName ) { } ,
// messages
messages : {
typeError : "{file} has invalid extension. Only {extensions} are allowed." ,
//sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
sizeError : "test" ,
minSizeError : "{file} is too small, minimum file size is {minSizeLimit}." ,
emptyError : "{file} is empty, please select files again without it." ,
onLeave : "The files are being uploaded, if you leave now the upload will be cancelled."
} ,
showMessage : function ( message ) {
if ( message == "test" ) {
if ( confirm ( "Uploading a large file, redirecting to a stable uploader. \nCancel if you currently have files already uploaded." ) ) {
document . getElementById ( "html5" ) . style . display = "none" ;
document . getElementById ( "flash" ) . style . display = "block" ;
//window.location = "/stable";
}
}
else {
alert ( message ) ;
}
}
} ;
qq . extend ( this . _options , o ) ;
// number of files being uploaded
this . _filesInProgress = 0 ;
this . _handler = this . _createUploadHandler ( ) ;
if ( this . _options . button ) {
this . _button = this . _createUploadButton ( this . _options . button ) ;
}
this . _preventLeaveInProgress ( ) ;
} ;
qq . FileUploaderBasic . prototype = {
setParams : function ( params ) {
this . _options . params = params ;
} ,
getInProgress : function ( ) {
return this . _filesInProgress ;
} ,
_createUploadButton : function ( element ) {
var self = this ;
return new qq . UploadButton ( {
element : element ,
multiple : this . _options . multiple && qq . UploadHandlerXhr . isSupported ( ) ,
onChange : function ( input ) {
self . _onInputChange ( input ) ;
}
} ) ;
} ,
_createUploadHandler : function ( ) {
var self = this ,
handlerClass ;
if ( qq . UploadHandlerXhr . isSupported ( ) ) {
handlerClass = 'UploadHandlerXhr' ;
} else {
handlerClass = 'UploadHandlerForm' ;
}
var handler = new qq [ handlerClass ] ( {
debug : this . _options . debug ,
action : this . _options . action ,
maxConnections : this . _options . maxConnections ,
onProgress : function ( id , fileName , loaded , total ) {
self . _onProgress ( id , fileName , loaded , total ) ;
self . _options . onProgress ( id , fileName , loaded , total ) ;
} ,
onComplete : function ( id , fileName , result ) {
self . _onComplete ( id , fileName , result ) ;
self . _options . onComplete ( id , fileName , result ) ;
} ,
onCancel : function ( id , fileName ) {
self . _onCancel ( id , fileName ) ;
self . _options . onCancel ( id , fileName ) ;
}
} ) ;
return handler ;
} ,
_preventLeaveInProgress : function ( ) {
var self = this ;
qq . attach ( window , 'beforeunload' , function ( e ) {
if ( ! self . _filesInProgress ) { return ; }
var e = e || window . event ;
// for ie, ff
e . returnValue = self . _options . messages . onLeave ;
// for webkit
return self . _options . messages . onLeave ;
} ) ;
} ,
_onSubmit : function ( id , fileName ) {
this . _filesInProgress ++ ;
} ,
_onProgress : function ( id , fileName , loaded , total ) {
} ,
_onComplete : function ( id , fileName , result ) {
this . _filesInProgress -- ;
if ( result . error ) {
this . _options . showMessage ( result . error ) ;
}
} ,
_onCancel : function ( id , fileName ) {
this . _filesInProgress -- ;
} ,
_onInputChange : function ( input ) {
if ( this . _handler instanceof qq . UploadHandlerXhr ) {
this . _uploadFileList ( input . files ) ;
} else {
if ( this . _validateFile ( input ) ) {
this . _uploadFile ( input ) ;
}
}
this . _button . reset ( ) ;
} ,
_uploadFileList : function ( files ) {
for ( var i = 0 ; i < files . length ; i ++ ) {
if ( ! this . _validateFile ( files [ i ] ) ) {
return ;
}
}
for ( var i = 0 ; i < files . length ; i ++ ) {
this . _uploadFile ( files [ i ] ) ;
}
} ,
_uploadFile : function ( fileContainer ) {
var id = this . _handler . add ( fileContainer ) ;
var fileName = this . _handler . getName ( id ) ;
if ( this . _options . onSubmit ( id , fileName ) !== false ) {
this . _onSubmit ( id , fileName ) ;
this . _handler . upload ( id , this . _options . params ) ;
}
} ,
_validateFile : function ( file ) {
var name , size ;
if ( file . value ) {
// it is a file input
// get input value and remove path to normalize
name = file . value . replace ( /.*(\/|\\)/ , "" ) ;
} else {
// fix missing properties in Safari
name = file . fileName != null ? file . fileName : file . name ;
size = file . fileSize != null ? file . fileSize : file . size ;
}
if ( ! this . _isAllowedExtension ( name ) ) {
this . _error ( 'typeError' , name ) ;
return false ;
} else if ( size === 0 ) {
this . _error ( 'emptyError' , name ) ;
return false ;
} else if ( size && this . _options . sizeLimit && size > this . _options . sizeLimit ) {
this . _error ( 'sizeError' , name ) ;
return false ;
} else if ( size && size < this . _options . minSizeLimit ) {
this . _error ( 'minSizeError' , name ) ;
return false ;
}
return true ;
} ,
_error : function ( code , fileName ) {
var message = this . _options . messages [ code ] ;
function r ( name , replacement ) { message = message . replace ( name , replacement ) ; }
r ( '{file}' , this . _formatFileName ( fileName ) ) ;
r ( '{extensions}' , this . _options . allowedExtensions . join ( ', ' ) ) ;
r ( '{sizeLimit}' , this . _formatSize ( this . _options . sizeLimit ) ) ;
r ( '{minSizeLimit}' , this . _formatSize ( this . _options . minSizeLimit ) ) ;
this . _options . showMessage ( message ) ;
} ,
_formatFileName : function ( name ) {
if ( name . length > 33 ) {
name = name . slice ( 0 , 19 ) + '...' + name . slice ( - 13 ) ;
}
return name ;
} ,
_isAllowedExtension : function ( fileName ) {
var ext = ( - 1 !== fileName . indexOf ( '.' ) ) ? fileName . replace ( /.*[.]/ , '' ) . toLowerCase ( ) : '' ;
var allowed = this . _options . allowedExtensions ;
if ( ! allowed . length ) { return true ; }
for ( var i = 0 ; i < allowed . length ; i ++ ) {
if ( allowed [ i ] . toLowerCase ( ) == ext ) { return true ; }
}
return false ;
} ,
_formatSize : function ( bytes ) {
var i = - 1 ;
do {
bytes = bytes / 1024 ;
i ++ ;
} while ( bytes > 99 ) ;
return Math . max ( bytes , 0.1 ) . toFixed ( 1 ) + [ 'kB' , 'MB' , 'GB' , 'TB' , 'PB' , 'EB' ] [ i ] ;
}
} ;
/ * *
* Class that creates upload widget with drag - and - drop and file list
* @ inherits qq . FileUploaderBasic
* /
qq . FileUploader = function ( o ) {
// call parent constructor
qq . FileUploaderBasic . apply ( this , arguments ) ;
// additional options
qq . extend ( this . _options , {
element : null ,
// if set, will be used instead of qq-upload-list in template
listElement : null ,
template : '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
'<div class="qq-upload-button">Click or Drop file(s)</div>' +
'<div id="toggleme" class="qq-upload-list"></div>' +
'</div>' ,
// template for one item in file list
fileTemplate : '<li>' +
'<span class="qq-upload-file"></span>' +
'<span class="qq-upload-spinner"></span>' +
'<span class="qq-upload-size"></span>' +
'<a class="qq-upload-cancel" href="#">Cancel</a>' +
'<span class="qq-upload-failed-text">Failed</span>' +
'</li>' ,
classes : {
// used to get elements from templates
button : 'qq-upload-button' ,
drop : 'qq-upload-drop-area' ,
dropActive : 'qq-upload-drop-area-active' ,
list : 'qq-upload-list' ,
file : 'qq-upload-file' ,
spinner : 'qq-upload-spinner' ,
size : 'qq-upload-size' ,
cancel : 'qq-upload-cancel' ,
// added to list item when upload completes
// used in css to hide progress spinner
success : 'qq-upload-success' ,
fail : 'qq-upload-fail'
}
} ) ;
// overwrite options with user supplied
qq . extend ( this . _options , o ) ;
this . _element = this . _options . element ;
this . _element . innerHTML = this . _options . template ;
this . _listElement = this . _options . listElement || this . _find ( this . _element , 'list' ) ;
this . _classes = this . _options . classes ;
this . _button = this . _createUploadButton ( this . _find ( this . _element , 'button' ) ) ;
this . _bindCancelEvent ( ) ;
this . _setupDragDrop ( ) ;
} ;
// inherit from Basic Uploader
qq . extend ( qq . FileUploader . prototype , qq . FileUploaderBasic . prototype ) ;
qq . extend ( qq . FileUploader . prototype , {
/ * *
* Gets one of the elements listed in this . _options . classes
* * /
_find : function ( parent , type ) {
var element = qq . getByClass ( parent , this . _options . classes [ type ] ) [ 0 ] ;
if ( ! element ) {
throw new Error ( 'element not found ' + type ) ;
}
return element ;
} ,
_setupDragDrop : function ( ) {
var self = this ,
dropArea = this . _find ( this . _element , 'drop' ) ;
var dz = new qq . UploadDropZone ( {
element : dropArea ,
onEnter : function ( e ) {
qq . addClass ( dropArea , self . _classes . dropActive ) ;
e . stopPropagation ( ) ;
} ,
onLeave : function ( e ) {
e . stopPropagation ( ) ;
} ,
onLeaveNotDescendants : function ( e ) {
qq . removeClass ( dropArea , self . _classes . dropActive ) ;
} ,
onDrop : function ( e ) {
dropArea . style . display = 'none' ;
qq . removeClass ( dropArea , self . _classes . dropActive ) ;
self . _uploadFileList ( e . dataTransfer . files ) ;
}
} ) ;
dropArea . style . display = 'none' ;
qq . attach ( document , 'dragenter' , function ( e ) {
if ( ! dz . _isValidFileDrag ( e ) ) return ;
dropArea . style . display = 'block' ;
} ) ;
qq . attach ( document , 'dragleave' , function ( e ) {
if ( ! dz . _isValidFileDrag ( e ) ) return ;
var relatedTarget = document . elementFromPoint ( e . clientX , e . clientY ) ;
// only fire when leaving document out
if ( ! relatedTarget || relatedTarget . nodeName == "HTML" ) {
dropArea . style . display = 'none' ;
}
} ) ;
} ,
_onSubmit : function ( id , fileName ) {
qq . FileUploaderBasic . prototype . _onSubmit . apply ( this , arguments ) ;
this . _addToList ( id , fileName ) ;
} ,
_onProgress : function ( id , fileName , loaded , total ) {
qq . FileUploaderBasic . prototype . _onProgress . apply ( this , arguments ) ;
var item = this . _getItemByFileId ( id ) ;
var size = this . _find ( item , 'size' ) ;
size . style . display = 'inline' ;
var text ;
if ( loaded != total ) {
text = Math . round ( loaded / total * 100 ) + '% from ' + this . _formatSize ( total ) ;
} else {
text = this . _formatSize ( total ) ;
}
qq . setText ( size , text ) ;
} ,
_onComplete : function ( id , fileName , result ) {
qq . FileUploaderBasic . prototype . _onComplete . apply ( this , arguments ) ;
// mark completed
var item = this . _getItemByFileId ( id ) ;
qq . remove ( this . _find ( item , 'cancel' ) ) ;
qq . remove ( this . _find ( item , 'spinner' ) ) ;
if ( result ) {
qq . addClass ( item , this . _classes . success ) ;
item . innerHTML = '<a target="_blank" href="' + result . url + '">' + result . url + '</a> <br />'
} else {
qq . addClass ( item , this . _classes . fail ) ;
}
} ,
_addToList : function ( id , fileName ) {
var item = qq . toElement ( this . _options . fileTemplate ) ;
item . qqFileId = id ;
var fileElement = this . _find ( item , 'file' ) ;
qq . setText ( fileElement , this . _formatFileName ( fileName ) ) ;
this . _find ( item , 'size' ) . style . display = 'none' ;
this . _listElement . appendChild ( item ) ;
} ,
_getItemByFileId : function ( id ) {
var item = this . _listElement . firstChild ;
// there can't be txt nodes in dynamically created list
// and we can use nextSibling
while ( item ) {
if ( item . qqFileId == id ) return item ;
item = item . nextSibling ;
}
} ,
/ * *
* delegate click event for cancel link
* * /
_bindCancelEvent : function ( ) {
var self = this ,
list = this . _listElement ;
qq . attach ( list , 'click' , function ( e ) {
e = e || window . event ;
var target = e . target || e . srcElement ;
if ( qq . hasClass ( target , self . _classes . cancel ) ) {
qq . preventDefault ( e ) ;
var item = target . parentNode ;
self . _handler . cancel ( item . qqFileId ) ;
qq . remove ( item ) ;
}
} ) ;
}
} ) ;
qq . UploadDropZone = function ( o ) {
this . _options = {
element : null ,
onEnter : function ( e ) { } ,
onLeave : function ( e ) { } ,
// is not fired when leaving element by hovering descendants
onLeaveNotDescendants : function ( e ) { } ,
onDrop : function ( e ) { }
} ;
qq . extend ( this . _options , o ) ;
this . _element = this . _options . element ;
this . _disableDropOutside ( ) ;
this . _attachEvents ( ) ;
} ;
qq . UploadDropZone . prototype = {
_disableDropOutside : function ( e ) {
// run only once for all instances
if ( ! qq . UploadDropZone . dropOutsideDisabled ) {
qq . attach ( document , 'dragover' , function ( e ) {
if ( e . dataTransfer ) {
e . dataTransfer . dropEffect = 'none' ;
e . preventDefault ( ) ;
}
} ) ;
qq . UploadDropZone . dropOutsideDisabled = true ;
}
} ,
_attachEvents : function ( ) {
var self = this ;
qq . attach ( self . _element , 'dragover' , function ( e ) {
if ( ! self . _isValidFileDrag ( e ) ) return ;
var effect = e . dataTransfer . effectAllowed ;
if ( effect == 'move' || effect == 'linkMove' ) {
e . dataTransfer . dropEffect = 'move' ; // for FF (only move allowed)
} else {
e . dataTransfer . dropEffect = 'copy' ; // for Chrome
}
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
} ) ;
qq . attach ( self . _element , 'dragenter' , function ( e ) {
if ( ! self . _isValidFileDrag ( e ) ) return ;
self . _options . onEnter ( e ) ;
} ) ;
qq . attach ( self . _element , 'dragleave' , function ( e ) {
if ( ! self . _isValidFileDrag ( e ) ) return ;
self . _options . onLeave ( e ) ;
var relatedTarget = document . elementFromPoint ( e . clientX , e . clientY ) ;
// do not fire when moving a mouse over a descendant
if ( qq . contains ( this , relatedTarget ) ) return ;
self . _options . onLeaveNotDescendants ( e ) ;
} ) ;
qq . attach ( self . _element , 'drop' , function ( e ) {
if ( ! self . _isValidFileDrag ( e ) ) return ;
e . preventDefault ( ) ;
self . _options . onDrop ( e ) ;
} ) ;
} ,
_isValidFileDrag : function ( e ) {
var dt = e . dataTransfer ,
// do not check dt.types.contains in webkit, because it crashes safari 4
isWebkit = navigator . userAgent . indexOf ( "AppleWebKit" ) > - 1 ;
// dt.effectAllowed is none in Safari 5
// dt.types.contains check is for firefox
return dt && dt . effectAllowed != 'none' &&
( dt . files || ( ! isWebkit && dt . types . contains && dt . types . contains ( 'Files' ) ) ) ;
}
} ;
qq . UploadButton = function ( o ) {
this . _options = {
element : null ,
// if set to true adds multiple attribute to file input
multiple : false ,
// name attribute of file input
name : 'file' ,
onChange : function ( input ) { } ,
hoverClass : 'qq-upload-button-hover' ,
focusClass : 'qq-upload-button-focus'
} ;
qq . extend ( this . _options , o ) ;
this . _element = this . _options . element ;
// make button suitable container for input
qq . css ( this . _element , {
position : 'relative' ,
overflow : 'hidden' ,
// Make sure browse button is in the right side
// in Internet Explorer
direction : 'ltr'
} ) ;
this . _input = this . _createInput ( ) ;
} ;
qq . UploadButton . prototype = {
/* returns file input element */
getInput : function ( ) {
return this . _input ;
} ,
/* cleans/recreates the file input */
reset : function ( ) {
if ( this . _input . parentNode ) {
qq . remove ( this . _input ) ;
}
qq . removeClass ( this . _element , this . _options . focusClass ) ;
this . _input = this . _createInput ( ) ;
} ,
_createInput : function ( ) {
var input = document . createElement ( "input" ) ;
if ( this . _options . multiple ) {
input . setAttribute ( "multiple" , "multiple" ) ;
}
input . setAttribute ( "type" , "file" ) ;
input . setAttribute ( "name" , this . _options . name ) ;
qq . css ( input , {
position : 'absolute' ,
// in Opera only 'browse' button
// is clickable and it is located at
// the right side of the input
right : 0 ,
top : 0 ,
fontFamily : 'Arial' ,
// 4 persons reported this, the max values that worked for them were 243, 236, 236, 118
fontSize : '118px' ,
margin : 0 ,
padding : 0 ,
cursor : 'pointer' ,
opacity : 0
} ) ;
this . _element . appendChild ( input ) ;
var self = this ;
qq . attach ( input , 'change' , function ( ) {
self . _options . onChange ( input ) ;
} ) ;
qq . attach ( input , 'mouseover' , function ( ) {
qq . addClass ( self . _element , self . _options . hoverClass ) ;
} ) ;
qq . attach ( input , 'mouseout' , function ( ) {
qq . removeClass ( self . _element , self . _options . hoverClass ) ;
} ) ;
qq . attach ( input , 'focus' , function ( ) {
qq . addClass ( self . _element , self . _options . focusClass ) ;
} ) ;
qq . attach ( input , 'blur' , function ( ) {
qq . removeClass ( self . _element , self . _options . focusClass ) ;
} ) ;
// IE and Opera, unfortunately have 2 tab stops on file input
// which is unacceptable in our case, disable keyboard access
if ( window . attachEvent ) {
// it is IE or Opera
input . setAttribute ( 'tabIndex' , "-1" ) ;
}
return input ;
}
} ;
/ * *
* Class for uploading files , uploading itself is handled by child classes
* /
qq . UploadHandlerAbstract = function ( o ) {
this . _options = {
debug : false ,
action : '/testest' ,
// maximum number of concurrent uploads
maxConnections : 999 ,
onProgress : function ( id , fileName , loaded , total ) { } ,
onComplete : function ( id , fileName , response ) { } ,
onCancel : function ( id , fileName ) { }
} ;
qq . extend ( this . _options , o ) ;
this . _queue = [ ] ;
// params for files in queue
this . _params = [ ] ;
} ;
qq . UploadHandlerAbstract . prototype = {
log : function ( str ) {
if ( this . _options . debug && window . console ) console . log ( '[uploader] ' + str ) ;
} ,
/ * *
* Adds file or file input to the queue
* @ returns id
* * /
add : function ( file ) { } ,
/ * *
* Sends the file identified by id and additional query params to the server
* /
upload : function ( id , params ) {
var len = this . _queue . push ( id ) ;
var copy = { } ;
qq . extend ( copy , params ) ;
this . _params [ id ] = copy ;
// if too many active uploads, wait...
if ( len <= this . _options . maxConnections ) {
this . _upload ( id , this . _params [ id ] ) ;
}
} ,
/ * *
* Cancels file upload by id
* /
cancel : function ( id ) {
this . _cancel ( id ) ;
this . _dequeue ( id ) ;
} ,
/ * *
* Cancells all uploads
* /
cancelAll : function ( ) {
for ( var i = 0 ; i < this . _queue . length ; i ++ ) {
this . _cancel ( this . _queue [ i ] ) ;
}
this . _queue = [ ] ;
} ,
/ * *
* Returns name of the file identified by id
* /
getName : function ( id ) { } ,
/ * *
* Returns size of the file identified by id
* /
getSize : function ( id ) { } ,
/ * *
* Returns id of files being uploaded or
* waiting for their turn
* /
getQueue : function ( ) {
return this . _queue ;
} ,
/ * *
* Actual upload method
* /
_upload : function ( id ) { } ,
/ * *
* Actual cancel method
* /
_cancel : function ( id ) { } ,
/ * *
* Removes element from queue , starts upload of next
* /
_dequeue : function ( id ) {
var i = qq . indexOf ( this . _queue , id ) ;
this . _queue . splice ( i , 1 ) ;
var max = this . _options . maxConnections ;
if ( this . _queue . length >= max && i < max ) {
var nextId = this . _queue [ max - 1 ] ;
this . _upload ( nextId , this . _params [ nextId ] ) ;
}
}
} ;
/ * *
* Class for uploading files using form and iframe
* @ inherits qq . UploadHandlerAbstract
* /
qq . UploadHandlerForm = function ( o ) {
qq . UploadHandlerAbstract . apply ( this , arguments ) ;
this . _inputs = { } ;
} ;
// @inherits qq.UploadHandlerAbstract
qq . extend ( qq . UploadHandlerForm . prototype , qq . UploadHandlerAbstract . prototype ) ;
qq . extend ( qq . UploadHandlerForm . prototype , {
add : function ( fileInput ) {
fileInput . setAttribute ( 'name' , 'qqfile' ) ;
var id = 'qq-upload-handler-iframe' + qq . getUniqueId ( ) ;
this . _inputs [ id ] = fileInput ;
// remove file input from DOM
if ( fileInput . parentNode ) {
qq . remove ( fileInput ) ;
}
return id ;
} ,
getName : function ( id ) {
// get input value and remove path to normalize
return this . _inputs [ id ] . value . replace ( /.*(\/|\\)/ , "" ) ;
} ,
_cancel : function ( id ) {
this . _options . onCancel ( id , this . getName ( id ) ) ;
delete this . _inputs [ id ] ;
var iframe = document . getElementById ( id ) ;
if ( iframe ) {
// to cancel request set src to something else
// we use src="javascript:false;" because it doesn't
// trigger ie6 prompt on https
iframe . setAttribute ( 'src' , 'javascript:false;' ) ;
qq . remove ( iframe ) ;
}
} ,
_upload : function ( id , params ) {
var input = this . _inputs [ id ] ;
if ( ! input ) {
throw new Error ( 'file with passed id was not added, or already uploaded or cancelled' ) ;
}
var fileName = this . getName ( id ) ;
var iframe = this . _createIframe ( id ) ;
var form = this . _createForm ( iframe , params ) ;
form . appendChild ( input ) ;
var self = this ;
this . _attachLoadEvent ( iframe , function ( ) {
self . log ( 'iframe loaded' ) ;
var response = self . _getIframeContentJSON ( iframe ) ;
self . _options . onComplete ( id , fileName , response ) ;
self . _dequeue ( id ) ;
delete self . _inputs [ id ] ;
// timeout added to fix busy state in FF3.6
setTimeout ( function ( ) {
qq . remove ( iframe ) ;
} , 1 ) ;
} ) ;
form . submit ( ) ;
qq . remove ( form ) ;
return id ;
} ,
_attachLoadEvent : function ( iframe , callback ) {
qq . attach ( iframe , 'load' , function ( ) {
// when we remove iframe from dom
// the request stops, but in IE load
// event fires
if ( ! iframe . parentNode ) {
return ;
}
// fixing Opera 10.53
if ( iframe . contentDocument &&
iframe . contentDocument . body &&
iframe . contentDocument . body . innerHTML == "false" ) {
// In Opera event is fired second time
// when body.innerHTML changed from false
// to server response approx. after 1 sec
// when we upload file with iframe
return ;
}
callback ( ) ;
} ) ;
} ,
/ * *
* Returns json object received by iframe from server .
* /
_getIframeContentJSON : function ( iframe ) {
// iframe.contentWindow.document - for IE<7
var doc = iframe . contentDocument ? iframe . contentDocument : iframe . contentWindow . document ,
response ;
this . log ( "converting iframe's innerHTML to JSON" ) ;
this . log ( "innerHTML = " + doc . body . innerHTML ) ;
try {
response = eval ( "(" + doc . body . innerHTML + ")" ) ;
} catch ( err ) {
response = { } ;
}
return response ;
} ,
/ * *
* Creates iframe with unique name
* /
_createIframe : function ( id ) {
// We can't use following code as the name attribute
// won't be properly registered in IE6, and new window
// on form submit will open
// var iframe = document.createElement('iframe');
// iframe.setAttribute('name', id);
var iframe = qq . toElement ( '<iframe src="javascript:false;" name="' + id + '" />' ) ;
// src="javascript:false;" removes ie6 prompt on https
iframe . setAttribute ( 'id' , id ) ;
iframe . style . display = 'none' ;
document . body . appendChild ( iframe ) ;
return iframe ;
} ,
/ * *
* Creates form , that will be submitted to iframe
* /
_createForm : function ( iframe , params ) {
// We can't use the following code in IE6
// var form = document.createElement('form');
// form.setAttribute('method', 'post');
// form.setAttribute('enctype', 'multipart/form-data');
// Because in this case file won't be attached to request
var form = qq . toElement ( '<form method="post" enctype="multipart/form-data"></form>' ) ;
var queryString = qq . obj2url ( params , this . _options . action ) ;
form . setAttribute ( 'action' , queryString ) ;
form . setAttribute ( 'target' , iframe . name ) ;
form . style . display = 'none' ;
document . body . appendChild ( form ) ;
return form ;
}
} ) ;
/ * *
* Class for uploading files using xhr
* @ inherits qq . UploadHandlerAbstract
* /
qq . UploadHandlerXhr = function ( o ) {
qq . UploadHandlerAbstract . apply ( this , arguments ) ;
this . _files = [ ] ;
this . _xhrs = [ ] ;
// current loaded size in bytes for each file
this . _loaded = [ ] ;
} ;
// static method
qq . UploadHandlerXhr . isSupported = function ( ) {
var input = document . createElement ( 'input' ) ;
input . type = 'file' ;
return (
'multiple' in input &&
typeof File != "undefined" &&
typeof ( new XMLHttpRequest ( ) ) . upload != "undefined" ) ;
} ;
// @inherits qq.UploadHandlerAbstract
qq . extend ( qq . UploadHandlerXhr . prototype , qq . UploadHandlerAbstract . prototype )
qq . extend ( qq . UploadHandlerXhr . prototype , {
/ * *
* Adds file to the queue
* Returns id to use with upload , cancel
* * /
add : function ( file ) {
if ( ! ( file instanceof File ) ) {
throw new Error ( 'Passed obj in not a File (in qq.UploadHandlerXhr)' ) ;
}
return this . _files . push ( file ) - 1 ;
} ,
getName : function ( id ) {
var file = this . _files [ id ] ;
// fix missing name in Safari 4
return file . fileName != null ? file . fileName : file . name ;
} ,
getSize : function ( id ) {
var file = this . _files [ id ] ;
return file . fileSize != null ? file . fileSize : file . size ;
} ,
/ * *
* Returns uploaded bytes for file identified by id
* /
getLoaded : function ( id ) {
return this . _loaded [ id ] || 0 ;
} ,
/ * *
* Sends the file identified by id and additional query params to the server
* @ param { Object } params name - value string pairs
* /
_upload : function ( id , params ) {
var file = this . _files [ id ] ,
name = this . getName ( id ) ,
size = this . getSize ( id ) ;
this . _loaded [ id ] = 0 ;
var xhr = this . _xhrs [ id ] = new XMLHttpRequest ( ) ;
var self = this ;
xhr . upload . onprogress = function ( e ) {
if ( e . lengthComputable ) {
self . _loaded [ id ] = e . loaded ;
self . _options . onProgress ( id , name , e . loaded , e . total ) ;
}
} ;
xhr . onreadystatechange = function ( ) {
if ( xhr . readyState == 4 ) {
self . _onComplete ( id , xhr ) ;
}
} ;
// build query string
params = params || { } ;
params [ 'qqfile' ] = name ;
var queryString = qq . obj2url ( params , this . _options . action ) ;
xhr . open ( "POST" , queryString , true ) ;
xhr . setRequestHeader ( "X-Requested-With" , "XMLHttpRequest" ) ;
xhr . setRequestHeader ( "X-File-Name" , encodeURIComponent ( name ) ) ;
xhr . setRequestHeader ( "Content-Type" , "application/octet-stream" ) ;
xhr . setRequestHeader ( "Accept" , "application/json" ) ;
xhr . send ( file ) ;
} ,
_onComplete : function ( id , xhr ) {
// the request was aborted/cancelled
if ( ! this . _files [ id ] ) return ;
var name = this . getName ( id ) ;
var size = this . getSize ( id ) ;
this . _options . onProgress ( id , name , size , size ) ;
if ( xhr . status == 200 ) {
this . log ( "xhr - server response received" ) ;
this . log ( "responseText = " + xhr . responseText ) ;
var response ;
try {
response = eval ( "(" + xhr . responseText + ")" ) ;
} catch ( err ) {
response = { } ;
}
this . _options . onComplete ( id , name , response ) ;
} else {
this . _options . onComplete ( id , name , { } ) ;
}
this . _files [ id ] = null ;
this . _xhrs [ id ] = null ;
this . _dequeue ( id ) ;
} ,
_cancel : function ( id ) {
this . _options . onCancel ( id , this . getName ( id ) ) ;
this . _files [ id ] = null ;
if ( this . _xhrs [ id ] ) {
this . _xhrs [ id ] . abort ( ) ;
this . _xhrs [ id ] = null ;
}
}
} ) ;
var uploader = new qq . FileUploader ( {
element : document . getElementById ( 'file-uploader' ) ,
action : '/upload' ,
params : {
expires : $ ( '#expires' ) . val ( ) ,
randomize : true ,
} ,
messages : {
typeError : "{file} has invalid extension. Only {extensions} are allowed." ,
sizeError : "{file} is too large, maximum file size is {sizeLimit}." ,
minSizeError : "{file} is too small, minimum file size is {minSizeLimit}." ,
emptyError : "{file} is empty, please select files again without it." ,
onLeave : "The files are being uploaded, if you leave now the upload will be cancelled."
} ,
showMessage : function ( message ) {
alert ( message ) ;
} ,
} ) ;