2015-02-15 20:05:21 -07:00
( function ( global ) {
function isArray ( arr ) {
return Object . prototype . toString . call ( arr ) === '[object Array]' ;
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
function foreach ( arr , handler ) {
if ( isArray ( arr ) ) {
for ( var i = 0 ; i < arr . length ; i ++ ) {
handler ( arr [ i ] ) ;
}
}
else
handler ( arr ) ;
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
function D ( fn ) {
var status = 'pending' ,
doneFuncs = [ ] ,
failFuncs = [ ] ,
progressFuncs = [ ] ,
resultArgs = null ,
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
promise = {
done : function ( ) {
for ( var i = 0 ; i < arguments . length ; i ++ ) {
// skip any undefined or null arguments
if ( ! arguments [ i ] ) {
continue ;
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
if ( isArray ( arguments [ i ] ) ) {
var arr = arguments [ i ] ;
for ( var j = 0 ; j < arr . length ; j ++ ) {
// immediately call the function if the deferred has been resolved
if ( status === 'resolved' ) {
arr [ j ] . apply ( this , resultArgs ) ;
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
doneFuncs . push ( arr [ j ] ) ;
}
}
else {
// immediately call the function if the deferred has been resolved
if ( status === 'resolved' ) {
arguments [ i ] . apply ( this , resultArgs ) ;
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
doneFuncs . push ( arguments [ i ] ) ;
}
}
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
return this ;
} ,
fail : function ( ) {
for ( var i = 0 ; i < arguments . length ; i ++ ) {
// skip any undefined or null arguments
if ( ! arguments [ i ] ) {
continue ;
}
if ( isArray ( arguments [ i ] ) ) {
var arr = arguments [ i ] ;
for ( var j = 0 ; j < arr . length ; j ++ ) {
// immediately call the function if the deferred has been resolved
if ( status === 'rejected' ) {
arr [ j ] . apply ( this , resultArgs ) ;
}
failFuncs . push ( arr [ j ] ) ;
}
}
else {
// immediately call the function if the deferred has been resolved
if ( status === 'rejected' ) {
arguments [ i ] . apply ( this , resultArgs ) ;
}
failFuncs . push ( arguments [ i ] ) ;
}
}
return this ;
} ,
always : function ( ) {
return this . done . apply ( this , arguments ) . fail . apply ( this , arguments ) ;
} ,
progress : function ( ) {
for ( var i = 0 ; i < arguments . length ; i ++ ) {
// skip any undefined or null arguments
if ( ! arguments [ i ] ) {
continue ;
}
if ( isArray ( arguments [ i ] ) ) {
var arr = arguments [ i ] ;
for ( var j = 0 ; j < arr . length ; j ++ ) {
// immediately call the function if the deferred has been resolved
if ( status === 'pending' ) {
progressFuncs . push ( arr [ j ] ) ;
}
}
}
else {
// immediately call the function if the deferred has been resolved
if ( status === 'pending' ) {
progressFuncs . push ( arguments [ i ] ) ;
}
}
}
return this ;
} ,
then : function ( ) {
// fail callbacks
if ( arguments . length > 1 && arguments [ 1 ] ) {
this . fail ( arguments [ 1 ] ) ;
}
// done callbacks
if ( arguments . length > 0 && arguments [ 0 ] ) {
this . done ( arguments [ 0 ] ) ;
}
// notify callbacks
if ( arguments . length > 2 && arguments [ 2 ] ) {
this . progress ( arguments [ 2 ] ) ;
}
} ,
promise : function ( obj ) {
if ( obj == null ) {
return promise ;
} else {
for ( var i in promise ) {
obj [ i ] = promise [ i ] ;
}
return obj ;
}
} ,
state : function ( ) {
return status ;
} ,
debug : function ( ) {
console . log ( '[debug]' , doneFuncs , failFuncs , status ) ;
} ,
isRejected : function ( ) {
return status === 'rejected' ;
} ,
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
isResolved : function ( ) {
return status === 'resolved' ;
} ,
2015-02-15 17:33:06 -07:00
2015-02-15 20:05:21 -07:00
pipe : function ( done , fail , progress ) {
return D ( function ( def ) {
foreach ( done , function ( func ) {
// filter function
if ( typeof func === 'function' ) {
deferred . done ( function ( ) {
var returnval = func . apply ( this , arguments ) ;
// if a new deferred/promise is returned, its state is passed to the current deferred/promise
if ( returnval && typeof returnval === 'function' ) {
returnval . promise ( ) . then ( def . resolve , def . reject , def . notify ) ;
}
else { // if new return val is passed, it is passed to the piped done
def . resolve ( returnval ) ;
}
} ) ;
}
else {
deferred . done ( def . resolve ) ;
}
} ) ;
foreach ( fail , function ( func ) {
if ( typeof func === 'function' ) {
deferred . fail ( function ( ) {
var returnval = func . apply ( this , arguments ) ;
if ( returnval && typeof returnval === 'function' ) {
returnval . promise ( ) . then ( def . resolve , def . reject , def . notify ) ;
} else {
def . reject ( returnval ) ;
}
} ) ;
}
else {
deferred . fail ( def . reject ) ;
}
} ) ;
} ) . promise ( ) ;
}
} ,
deferred = {
resolveWith : function ( context ) {
if ( status === 'pending' ) {
status = 'resolved' ;
var args = resultArgs = ( arguments . length > 1 ) ? arguments [ 1 ] : [ ] ;
for ( var i = 0 ; i < doneFuncs . length ; i ++ ) {
doneFuncs [ i ] . apply ( context , args ) ;
}
}
return this ;
} ,
rejectWith : function ( context ) {
if ( status === 'pending' ) {
status = 'rejected' ;
var args = resultArgs = ( arguments . length > 1 ) ? arguments [ 1 ] : [ ] ;
for ( var i = 0 ; i < failFuncs . length ; i ++ ) {
failFuncs [ i ] . apply ( context , args ) ;
}
}
return this ;
} ,
notifyWith : function ( context ) {
if ( status === 'pending' ) {
var args = resultArgs = ( arguments . length > 1 ) ? arguments [ 1 ] : [ ] ;
for ( var i = 0 ; i < progressFuncs . length ; i ++ ) {
progressFuncs [ i ] . apply ( context , args ) ;
}
}
return this ;
} ,
resolve : function ( ) {
return this . resolveWith ( this , arguments ) ;
} ,
reject : function ( ) {
return this . rejectWith ( this , arguments ) ;
} ,
notify : function ( ) {
return this . notifyWith ( this , arguments ) ;
}
}
var obj = promise . promise ( deferred ) ;
if ( fn ) {
fn . apply ( obj , [ obj ] ) ;
}
return obj ;
}
D . when = function ( ) {
if ( arguments . length < 2 ) {
var obj = arguments . length ? arguments [ 0 ] : undefined ;
if ( obj && ( typeof obj . isResolved === 'function' && typeof obj . isRejected === 'function' ) ) {
return obj . promise ( ) ;
}
else {
return D ( ) . resolve ( obj ) . promise ( ) ;
}
}
else {
return ( function ( args ) {
var df = D ( ) ,
size = args . length ,
done = 0 ,
rp = new Array ( size ) ; // resolve params: params of each resolve, we need to track down them to be able to pass them in the correct order if the master needs to be resolved
for ( var i = 0 ; i < args . length ; i ++ ) {
( function ( j ) {
var obj = null ;
if ( args [ j ] . done ) {
args [ j ] . done ( function ( ) { rp [ j ] = ( arguments . length < 2 ) ? arguments [ 0 ] : arguments ; if ( ++ done == size ) { df . resolve . apply ( df , rp ) ; } } )
. fail ( function ( ) { df . reject ( arguments ) ; } ) ;
} else {
obj = args [ j ] ;
args [ j ] = new Deferred ( ) ;
args [ j ] . done ( function ( ) { rp [ j ] = ( arguments . length < 2 ) ? arguments [ 0 ] : arguments ; if ( ++ done == size ) { df . resolve . apply ( df , rp ) ; } } )
. fail ( function ( ) { df . reject ( arguments ) ; } ) . resolve ( obj ) ;
}
} ) ( i ) ;
2015-02-15 17:33:06 -07:00
}
2015-02-15 20:05:21 -07:00
return df . promise ( ) ;
} ) ( arguments ) ;
}
}
global . Deferred = D ;
} ) ( window ) ;
( function ( globalScope ) {
globalScope . DeferredBuilder = {
Deferred : function ( ) {
return new globalScope . Deferred ( ) ;
2015-02-15 17:33:06 -07:00
} ,
2015-02-15 20:05:21 -07:00
when : function ( promises ) {
return globalScope . Deferred . when ( promises ) ;
2015-02-15 17:33:06 -07:00
}
2015-02-15 20:05:21 -07:00
2015-02-15 17:33:06 -07:00
} ;
} ) ( window ) ;